Explorar el Código

Binary dumps, customizable IO streams, ctor interop. - yeah too many changes for a single commit :(

Xanathar hace 10 años
padre
commit
8cf65c4690
Se han modificado 31 ficheros con 1064 adiciones y 170 borrados
  1. 47 0
      src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs
  2. 2 0
      src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.csproj
  3. 1 1
      src/MoonSharp.Interpreter/CoreLib/IO/FileUserData.cs
  4. 32 0
      src/MoonSharp.Interpreter/CoreLib/IO/StandardIOFileUserDataBase.cs
  5. 0 47
      src/MoonSharp.Interpreter/CoreLib/IO/StdioFileUserData.cs
  6. 18 5
      src/MoonSharp.Interpreter/CoreLib/IoModule.cs
  7. 28 0
      src/MoonSharp.Interpreter/CoreLib/StringModule.cs
  8. 3 0
      src/MoonSharp.Interpreter/DataTypes/Closure.cs
  9. 33 0
      src/MoonSharp.Interpreter/DataTypes/SymbolRef.cs
  10. 115 0
      src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs
  11. 18 0
      src/MoonSharp.Interpreter/Execution/Scopes/ClosureContext.cs
  12. 13 5
      src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs
  13. 191 73
      src/MoonSharp.Interpreter/Execution/VM/Instruction.cs
  14. 5 3
      src/MoonSharp.Interpreter/Execution/VM/OpCode.cs
  15. 1 8
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
  16. 1 1
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs
  17. 1 2
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
  18. 60 0
      src/MoonSharp.Interpreter/IO/BinDumpBinaryReader.cs
  19. 84 0
      src/MoonSharp.Interpreter/IO/BinDumpBinaryWriter.cs
  20. 167 0
      src/MoonSharp.Interpreter/IO/UndisposableStream.cs
  21. 10 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs
  22. 28 9
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataMethodDescriptor.cs
  23. 3 2
      src/MoonSharp.Interpreter/Loaders/ClassicLuaScriptLoader.cs
  24. 22 1
      src/MoonSharp.Interpreter/Loaders/IScriptLoader.cs
  25. 8 1
      src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj
  26. 140 7
      src/MoonSharp.Interpreter/Script.cs
  27. 4 0
      src/MoonSharp.Interpreter/ScriptOptions.cs
  28. 1 1
      src/MoonSharp.Interpreter/Tree/Antlr_Interface/Loader_Antlr.cs
  29. 7 1
      src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs
  30. 6 1
      src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs
  31. 15 2
      src/MoonSharp/Program.cs

+ 47 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs

@@ -242,6 +242,32 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1912", res.String);
 		}
 
+		public void Test_ConstructorAndConcatMethodSemicolon(InteropAccessMode opt)
+		{
+			UserData.UnregisterType<SomeClass>();
+
+			string script = @"    
+				myobj = mytype.__new();
+				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
+				x = myobj:ConcatI(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
+				return x;";
+
+			Script S = new Script();
+
+			SomeClass obj = new SomeClass();
+
+			UserData.RegisterType<SomeClass>(opt);
+
+			S.Globals["mytype"] = typeof(SomeClass);
+
+			DynValue res = S.DoString(script);
+
+			Assert.AreEqual(DataType.String, res.Type);
+			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1912", res.String);
+		}
+
+
+
 		public void Test_ConcatMethodStaticSimplifiedSyntax(InteropAccessMode opt)
 		{
 			UserData.UnregisterType<SomeClass>();
@@ -349,6 +375,27 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Test_ConcatMethodSemicolon(InteropAccessMode.Preoptimized);
 		}
 
+
+		[Test]
+		public void Interop_ConstructorAndConcatMethodSemicolon_None()
+		{
+			Test_ConstructorAndConcatMethodSemicolon(InteropAccessMode.Reflection);
+		}
+
+		[Test]
+		public void Interop_ConstructorAndConcatMethodSemicolon_Lazy()
+		{
+			Test_ConstructorAndConcatMethodSemicolon(InteropAccessMode.LazyOptimized);
+		}
+
+		[Test]
+		public void Interop_ConstructorAndConcatMethodSemicolon_Precomputed()
+		{
+			Test_ConstructorAndConcatMethodSemicolon(InteropAccessMode.Preoptimized);
+		}
+
+
+
 		[Test]
 		public void Interop_ConcatMethodStatic_None()
 		{

+ 2 - 0
src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.csproj

@@ -77,6 +77,7 @@
     <Otherwise />
   </Choose>
   <ItemGroup>
+    <Compile Include="EndToEnd\BinaryDumpTests.cs" />
     <Compile Include="EndToEnd\ClosureTests.cs" />
     <Compile Include="EndToEnd\CoroutineTests.cs" />
     <Compile Include="EndToEnd\DynamicTests.cs" />
@@ -99,6 +100,7 @@
     <Compile Include="TestMore\TapRunner.cs" />
     <Compile Include="TestMore\TestMoreTests.cs" />
     <Compile Include="TestRunner.cs" />
+    <Compile Include="Units\BinDumpStreamTests.cs" />
     <Compile Include="Units\FastStackTests.cs" />
     <Compile Include="Units\InteropTests.cs" />
   </ItemGroup>

+ 1 - 1
src/MoonSharp.Interpreter/CoreLib/IO/FileUserData.cs

@@ -6,7 +6,7 @@ using System.Text;
 
 namespace MoonSharp.Interpreter.CoreLib.IO
 {
-	class FileUserData : StreamFileUserDataBase
+	public class FileUserData : StreamFileUserDataBase
 	{
 		public FileUserData(string filename, Encoding encoding, string mode)
 		{

+ 32 - 0
src/MoonSharp.Interpreter/CoreLib/IO/StandardIOFileUserDataBase.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.CoreLib.IO
+{
+	public class StandardIOFileUserDataBase : StreamFileUserDataBase
+	{
+		protected override string Close()
+		{
+			return ("cannot close standard file");
+		}
+
+		public static StandardIOFileUserDataBase CreateInputStream(Stream stream)
+		{
+			var f = new StandardIOFileUserDataBase();
+			f.Initialize(stream, new StreamReader(stream), null);
+			return f;
+		}
+
+		public static StandardIOFileUserDataBase CreateOutputStream(Stream stream)
+		{
+			var f = new StandardIOFileUserDataBase();
+			f.Initialize(stream, null, new StreamWriter(stream));
+			return f;
+		}
+
+	}
+
+}

+ 0 - 47
src/MoonSharp.Interpreter/CoreLib/IO/StdioFileUserData.cs

@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace MoonSharp.Interpreter.CoreLib.IO
-{
-	class StandardIOFileUserDataBase : StreamFileUserDataBase
-	{
-		protected override string Close()
-		{
-			return ("cannot close standard file");
-		}
-	}
-
-
-	class StdinFileUserData : StandardIOFileUserDataBase
-	{
-		public StdinFileUserData()
-		{
-			Stream stream = Console.OpenStandardInput();
-			StreamReader reader = new StreamReader(stream);
-			Initialize(stream, reader, null);
-		}
-	}
-
-	class StdoutFileUserData : StandardIOFileUserDataBase
-	{
-		public StdoutFileUserData()
-		{
-			Stream stream = Console.OpenStandardOutput();
-			StreamWriter writer = new StreamWriter(stream);
-			Initialize(stream, null, writer);
-		}
-	}
-
-	class StderrFileUserData : StandardIOFileUserDataBase
-	{
-		public StderrFileUserData()
-		{
-			Stream stream = Console.OpenStandardError();
-			StreamWriter writer = new StreamWriter(stream);
-			Initialize(stream, null, writer);
-		}
-	}
-}

+ 18 - 5
src/MoonSharp.Interpreter/CoreLib/IoModule.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using MoonSharp.Interpreter.CoreLib.IO;
@@ -10,7 +11,7 @@ namespace MoonSharp.Interpreter.CoreLib
 	[MoonSharpModule(Namespace = "io")]
 	public class IoModule
 	{
-		enum DefaultFiles
+		public enum DefaultFiles
 		{
 			In,
 			Out,
@@ -26,9 +27,9 @@ namespace MoonSharp.Interpreter.CoreLib
 			meta.Set("__index", __index);
 			ioTable.MetaTable = meta;
 
-			stdin = new StdinFileUserData();
-			stdout = new StdoutFileUserData();
-			stderr = new StderrFileUserData();
+			stdin = StandardIOFileUserDataBase.CreateInputStream(Console.OpenStandardInput());
+			stdout = StandardIOFileUserDataBase.CreateOutputStream(Console.OpenStandardOutput());
+			stderr = StandardIOFileUserDataBase.CreateOutputStream(Console.OpenStandardError());
 		}
 
 		private static DynValue __index_callback(ScriptExecutionContext executionContext, CallbackArguments args)
@@ -77,10 +78,22 @@ namespace MoonSharp.Interpreter.CoreLib
 
 		static void SetDefaultFile(ScriptExecutionContext executionContext, DefaultFiles file, FileUserDataBase fileHandle)
 		{
-			Table R = executionContext.GetScript().Registry;
+			SetDefaultFile(executionContext.GetScript(), file, fileHandle);
+		}
+
+		public static void SetDefaultFile(Script script, DefaultFiles file, FileUserDataBase fileHandle)
+		{
+			Table R = script.Registry;
 			R.Set("853BEAAF298648839E2C99D005E1DF94_" + file.ToString(), UserData.Create(fileHandle));
 		}
 
+		public static void SetDefaultFile(Script script, DefaultFiles file, Stream stream)
+		{
+			if (file == DefaultFiles.In)
+				SetDefaultFile(script, file, StandardIOFileUserDataBase.CreateInputStream(stream));
+			else
+				SetDefaultFile(script, file, StandardIOFileUserDataBase.CreateOutputStream(stream));
+		}
 
 
 		[MoonSharpMethod]

+ 28 - 0
src/MoonSharp.Interpreter/CoreLib/StringModule.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using MoonSharp.Interpreter.CoreLib.StringLib;
@@ -10,6 +11,8 @@ namespace MoonSharp.Interpreter.CoreLib
 	[MoonSharpModule(Namespace="string")]
 	public class StringModule
 	{
+		public const string BASE64_DUMP_HEADER = "MoonSharp_dump_b64::";
+
 		public static void MoonSharpInit(Table globalTable, Table stringTable)
 		{
 			Table stringMetatable = new Table(globalTable.OwnerScript);
@@ -17,6 +20,31 @@ namespace MoonSharp.Interpreter.CoreLib
 			globalTable.OwnerScript.SetTypeMetatable(DataType.String, stringMetatable);
 		}
 
+
+		[MoonSharpMethod]
+		public static DynValue dump(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			DynValue fn = args.AsType(0, "dump", DataType.Function, false);
+
+			try
+			{
+				byte[] bytes;
+				using (MemoryStream ms = new MemoryStream())
+				{
+					executionContext.GetScript().Dump(fn, ms);
+					ms.Seek(0, SeekOrigin.Begin);
+					bytes = ms.GetBuffer();
+				}
+				string base64 = Convert.ToBase64String(bytes);
+				return DynValue.NewString(BASE64_DUMP_HEADER + base64);
+			}
+			catch (Exception ex)
+			{
+				throw new ScriptRuntimeException(ex.Message);
+			}
+		}
+
+
 		[MoonSharpMethod]
 		public static DynValue @char(ScriptExecutionContext executionContext, CallbackArguments args)
 		{

+ 3 - 0
src/MoonSharp.Interpreter/DataTypes/Closure.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using MoonSharp.Interpreter.Execution;
@@ -106,5 +107,7 @@ namespace MoonSharp.Interpreter
 
 
 
+
+
 	}
 }

+ 33 - 0
src/MoonSharp.Interpreter/DataTypes/SymbolRef.cs

@@ -4,6 +4,7 @@ using MoonSharp.Interpreter.Diagnostics;
 using System.Linq;
 using System.Text;
 using System.Diagnostics;
+using System.IO;
 
 namespace MoonSharp.Interpreter
 {
@@ -55,5 +56,37 @@ namespace MoonSharp.Interpreter
 			else
 				return string.Format("{2} : {0}[{1}]", i_Type, i_Index, i_Name);
 		}
+
+		internal void WriteBinary(BinaryWriter bw)
+		{
+			bw.Write((byte)this.i_Type);
+			bw.Write(i_Index);
+			bw.Write(i_Name);
+		}
+
+		internal static SymbolRef ReadBinary(BinaryReader br)
+		{
+			SymbolRef that = new SymbolRef();
+			that.i_Type = (SymbolRefType)br.ReadByte();
+			that.i_Index = br.ReadInt32();
+			that.i_Name = br.ReadString();
+			return that;
+		}
+
+		internal void WriteBinaryEnv(BinaryWriter bw, Dictionary<SymbolRef, int> symbolMap)
+		{
+			if (this.i_Env != null)
+				bw.Write(symbolMap[i_Env]);
+			else
+				bw.Write(-1);
+		}
+
+		internal void ReadBinaryEnv(BinaryReader br, SymbolRef[] symbolRefs)
+		{
+			int idx = br.ReadInt32();
+
+			if (idx >= 0)
+				i_Env = symbolRefs[idx];
+		}
 	}
 }

+ 115 - 0
src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs

@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Execution.VM;
+
+namespace MoonSharp.Interpreter.Execution
+{
+	[Flags]
+	internal enum InstructionFieldUsage
+	{
+		None = 0,
+		Symbol = 0x1,
+		SymbolList = 0x2,
+		Name = 0x4,
+		Value = 0x8,
+		NumVal = 0x10,
+		NumVal2 = 0x20,
+		NumValAsCodeAddress = 0x8010
+	}
+
+	internal static class InstructionFieldUsage_Extensions
+	{
+		internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
+		{
+			switch (op)
+			{
+				case OpCode.TblInitN:
+				case OpCode.Scalar:
+				case OpCode.IterUpd:
+				case OpCode.IterPrep:
+				case OpCode.NewTable:
+				case OpCode.Concat:
+				case OpCode.LessEq:
+				case OpCode.Less:
+				case OpCode.Eq:
+				case OpCode.Add:
+				case OpCode.Sub:
+				case OpCode.Mul:
+				case OpCode.Div:
+				case OpCode.Mod:
+				case OpCode.Not:
+				case OpCode.Len:
+				case OpCode.Neg:
+				case OpCode.Power:
+				case OpCode.CNot:
+				case OpCode.ToBool:
+					return InstructionFieldUsage.None;
+				case OpCode.Pop:
+				case OpCode.Copy:
+				case OpCode.TblInitI:
+				case OpCode.ExpTuple:
+				case OpCode.Incr:
+				case OpCode.ToNum:
+				case OpCode.Ret:
+				case OpCode.MkTuple:
+					return InstructionFieldUsage.NumVal;
+				case OpCode.Jump:
+				case OpCode.Jf:
+				case OpCode.JNil:
+				case OpCode.JFor:
+				case OpCode.JtOrPop:
+				case OpCode.JfOrPop:
+					return InstructionFieldUsage.NumValAsCodeAddress;
+				case OpCode.Swap:
+				case OpCode.Enter:
+				case OpCode.Leave:
+				case OpCode.Exit:
+					return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
+				case OpCode.Local:
+				case OpCode.Upvalue:
+					return InstructionFieldUsage.Symbol;
+				case OpCode.IndexSet:
+					return InstructionFieldUsage.Symbol | InstructionFieldUsage.Value | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
+				case OpCode.StoreLcl:
+				case OpCode.StoreUpv:
+					return InstructionFieldUsage.Symbol | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
+				case OpCode.Index:
+				case OpCode.Literal:
+					return InstructionFieldUsage.Value;
+				case OpCode.Args:
+					return InstructionFieldUsage.SymbolList;
+				case OpCode.BeginFn:
+					return InstructionFieldUsage.SymbolList | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
+				case OpCode.Closure:
+					return InstructionFieldUsage.SymbolList | InstructionFieldUsage.NumVal;
+				case OpCode.Nop:
+				case OpCode.Debug:
+				case OpCode.Invalid:
+					return InstructionFieldUsage.Name;
+				case OpCode.FuncMeta:
+				case OpCode.Call:
+				case OpCode.ThisCall:
+					return InstructionFieldUsage.NumVal | InstructionFieldUsage.Name;
+				default:
+					throw new NotImplementedException(string.Format("InstructionFieldUsage for instruction {0}", (int)op));
+			}
+		}
+	}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}

+ 18 - 0
src/MoonSharp.Interpreter/Execution/Scopes/ClosureContext.cs

@@ -7,6 +7,14 @@ namespace MoonSharp.Interpreter.Execution
 {
 	public class ClosureContext : List<DynValue>
 	{
+		public enum UpvaluesType
+		{
+			None,
+			Environment,
+			Closure
+		}
+
+
 		public string[] Symbols { get; private set; }
 
 		internal ClosureContext(SymbolRef[] symbols, IEnumerable<DynValue> values)
@@ -19,5 +27,15 @@ namespace MoonSharp.Interpreter.Execution
 		{
 			Symbols = new string[0];
 		}
+
+		public UpvaluesType GetUpvaluesType()
+		{
+			if (Symbols.Length == 0)
+				return UpvaluesType.None;
+			else if (Symbols.Length == 1 && Symbols[0] == WellKnownSymbols.ENV)
+				return UpvaluesType.Environment;
+			else
+				return UpvaluesType.Closure;
+		}
 	}
 }

+ 13 - 5
src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs

@@ -220,16 +220,24 @@ namespace MoonSharp.Interpreter.Execution.VM
 			return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.IterUpd });
 		}
 
+		public Instruction Emit_FuncMeta(string funcName)
+		{
+			return AppendInstruction(new Instruction(m_CurrentSourceRef)
+			{
+				OpCode = OpCode.FuncMeta,
+				Name = funcName
+			});
+		}
 
-		public Instruction Emit_BeginFn(RuntimeScopeFrame m_StackFrame, string funcName)
+
+		public Instruction Emit_BeginFn(RuntimeScopeFrame stackFrame)
 		{
 			return AppendInstruction(new Instruction(m_CurrentSourceRef)
 			{
 				OpCode = OpCode.BeginFn,
-				SymbolList = m_StackFrame.DebugSymbols.ToArray(),
-				NumVal = m_StackFrame.Count,
-				NumVal2 = m_StackFrame.ToFirstBlock,
-				Name = funcName
+				SymbolList = stackFrame.DebugSymbols.ToArray(),
+				NumVal = stackFrame.Count,
+				NumVal2 = stackFrame.ToFirstBlock,
 			});
 		}
 

+ 191 - 73
src/MoonSharp.Interpreter/Execution/VM/Instruction.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using MoonSharp.Interpreter.Debugging;
@@ -8,86 +9,50 @@ namespace MoonSharp.Interpreter.Execution.VM
 {
 	internal class Instruction
 	{
-		public OpCode OpCode;
-		public SymbolRef Symbol;
-		public SymbolRef[] SymbolList;
-		public string Name;
-		public DynValue Value;
-		public int NumVal;
-		public int NumVal2;
-		public SourceRef SourceCodeRef;
-
-		public Instruction(SourceRef sourceref)
+		internal OpCode OpCode;
+		internal SymbolRef Symbol;
+		internal SymbolRef[] SymbolList;
+		internal string Name;
+		internal DynValue Value;
+		internal int NumVal;
+		internal int NumVal2;
+		internal SourceRef SourceCodeRef;
+
+		internal Instruction(SourceRef sourceref)
 		{
 			SourceCodeRef = sourceref;
 		}
 
 		public override string ToString()
 		{
-			string append = "";
+			string append = this.OpCode.ToString().ToUpperInvariant();
 
-			switch (OpCode)
-			{
-				case OpCode.Closure:
-					append = string.Format("{0}{1:X8}({2})", GenSpaces(), NumVal, string.Join(",", SymbolList.Select(s => s.ToString()).ToArray()));
-					break;
-				case OpCode.Args:
-					append = string.Format("{0}({1})", GenSpaces(), string.Join(",", SymbolList.Select(s => s.ToString()).ToArray()));
-					break;
-				case OpCode.Debug:
-					return string.Format("[[ {0} ]]", Name);
-				case OpCode.Literal:
-				case OpCode.Index:
-					append = string.Format("{0}{1}", GenSpaces(), PurifyFromNewLines(Value));
-					break;
-				case OpCode.IndexSet:
-					append = string.Format("{0}{1} <- {2}:{3}", GenSpaces(), PurifyFromNewLines(Value), NumVal, NumVal2);
-					break;
-				case OpCode.Nop:
-					append = string.Format("{0}#{1}", GenSpaces(), Name);
-					break;
-				case OpCode.Call:
-				case OpCode.Ret:
-				case OpCode.MkTuple:
-				case OpCode.ExpTuple:
-				case OpCode.Incr:
-				case OpCode.Pop:
-				case OpCode.Copy:
-					append = string.Format("{0}{1}", GenSpaces(), NumVal);
-					break;
-				case OpCode.Enter:
-				case OpCode.Leave:
-				case OpCode.Exit:
-				case OpCode.Swap:
-					append = string.Format("{0}{1},{2}", GenSpaces(), NumVal, NumVal2);
-					break;
-				case OpCode.BeginFn:
-					append = string.Format("{0}{1}:{2},{3}", GenSpaces(), Name, NumVal, NumVal2);
-					break;
-				case OpCode.Local:
-				case OpCode.Upvalue:
-					append = string.Format("{0}{1}", GenSpaces(), Symbol);
-					break;
-				case OpCode.StoreUpv:
-				case OpCode.StoreLcl:
-					append = string.Format("{0}{1} <- {2}:{3}", GenSpaces(), Symbol, NumVal, NumVal2);
-					break;
-				case OpCode.JtOrPop:
-				case OpCode.JfOrPop:
-				case OpCode.Jf:
-				case OpCode.Jump:
-				case OpCode.JFor:
-				case OpCode.JNil:
-					append = string.Format("{0}{1:X8}", GenSpaces(), NumVal);
-					break;
-				case OpCode.Invalid:
-					append = string.Format("{0}{1}", GenSpaces(), Name ?? "(null)");
-					break;
-				default:
-					break;
-			}
+			int usage = (int)OpCode.GetFieldUsage();
+
+			if (usage != 0)
+				append += GenSpaces();
+
+			if ((this.OpCode == VM.OpCode.FuncMeta) ||((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress))
+				append += " " + NumVal.ToString("X8");
+			else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+				append += " " + NumVal.ToString();
+
+			if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+				append += " " + NumVal2.ToString();
+
+			if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+				append += " " + Name;
+
+			if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+				append += " " + PurifyFromNewLines(Value);
 
-			return this.OpCode.ToString().ToUpperInvariant() + append;
+			if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+				append += " " + Symbol;
+
+			if (((usage & ((int)InstructionFieldUsage.SymbolList)) != 0) && (SymbolList != null))
+				append += " " + string.Join(",", SymbolList.Select(s => s.ToString()).ToArray());
+
+			return append;
 		}
 
 		private string PurifyFromNewLines(DynValue Value)
@@ -103,7 +68,160 @@ namespace MoonSharp.Interpreter.Execution.VM
 			return new string(' ', 10 - this.OpCode.ToString().Length);
 		}
 
-		
+		internal void WriteBinary(BinaryWriter wr, int baseAddress, Dictionary<SymbolRef, int> symbolMap)
+		{
+			wr.Write((byte)this.OpCode);
+
+			int usage = (int)OpCode.GetFieldUsage();
+
+			if ((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress)
+				wr.Write(this.NumVal - baseAddress);
+			else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+				wr.Write(this.NumVal);
+
+			if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+				wr.Write(this.NumVal2);
+
+			if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+				wr.Write(Name);
+
+			if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+				DumpValue(wr, Value);
+
+			if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+				WriteSymbol(wr, Symbol, symbolMap);
+
+			if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+			{
+				wr.Write(this.SymbolList.Length);
+				for (int i = 0; i < this.SymbolList.Length; i++)
+					WriteSymbol(wr, SymbolList[i], symbolMap);
+			}
+		}
+
+		private static void WriteSymbol(BinaryWriter wr, SymbolRef symbolRef, Dictionary<SymbolRef, int> symbolMap)
+		{
+			int id = (symbolRef == null) ? -1 : symbolMap[symbolRef];
+			wr.Write(id);
+		}
+
+		private static SymbolRef ReadSymbol(BinaryReader rd, SymbolRef[] deserializedSymbols)
+		{
+			int id = rd.ReadInt32();
+
+			if (id < 0) return null;
+			return deserializedSymbols[id];
+		}
+
+		internal static Instruction ReadBinary(SourceRef chunkRef, BinaryReader rd, int baseAddress, Table envTable, SymbolRef[] deserializedSymbols)
+		{
+			Instruction that = new Instruction(chunkRef);
 
+			that.OpCode = (OpCode)rd.ReadByte();
+
+			int usage = (int)that.OpCode.GetFieldUsage();
+
+			if ((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress)
+				that.NumVal = rd.ReadInt32() + baseAddress;
+			else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+				that.NumVal = rd.ReadInt32();
+
+			if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+				that.NumVal2 = rd.ReadInt32();
+
+			if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+				that.Name = rd.ReadString();
+
+			if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+				that.Value = ReadValue(rd, envTable);
+
+			if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+				that.Symbol = ReadSymbol(rd, deserializedSymbols);
+
+			if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+			{
+				int len = rd.ReadInt32();
+				that.SymbolList = new SymbolRef[len];
+
+				for (int i = 0; i < that.SymbolList.Length; i++)
+					that.SymbolList[i] = ReadSymbol(rd, deserializedSymbols);
+			}
+
+			return that;
+		}
+
+		private static DynValue ReadValue(BinaryReader rd, Table envTable)
+		{
+			bool isnull = !rd.ReadBoolean();
+
+			if (isnull) return null;
+
+			DataType dt = (DataType)rd.ReadByte();
+
+			switch (dt)
+			{
+				case DataType.Nil:
+					return DynValue.NewNil();
+				case DataType.Void:
+					return DynValue.Void;
+				case DataType.Boolean:
+					return DynValue.NewBoolean(rd.ReadBoolean());
+				case DataType.Number:
+					return DynValue.NewNumber(rd.ReadDouble());
+				case DataType.String:
+					return DynValue.NewString(rd.ReadString());
+				case DataType.Table :
+					return DynValue.NewTable(envTable);
+				default:
+					throw new NotSupportedException(string.Format("Unsupported type in chunk dump : {0}", dt));
+			}
+		}
+
+
+		private void DumpValue(BinaryWriter wr, DynValue value)
+		{
+			if (value == null)
+			{
+				wr.Write(false);
+				return;
+			}
+
+			wr.Write(true);
+			wr.Write((byte)value.Type);
+
+			switch (value.Type)
+			{
+				case DataType.Nil:
+				case DataType.Void:
+				case DataType.Table:
+					break;
+				case DataType.Boolean:
+					wr.Write(value.Boolean);
+					break;
+				case DataType.Number:
+					wr.Write(value.Number);
+					break;
+				case DataType.String:
+					wr.Write(value.String);
+					break;
+				default:
+					throw new NotSupportedException(string.Format("Unsupported type in chunk dump : {0}", value.Type));
+			}
+		}
+
+		internal void GetSymbolReferences(out SymbolRef[] symbolList, out SymbolRef symbol)
+		{
+			int usage = (int)OpCode.GetFieldUsage();
+
+			symbol = null;
+			symbolList = null;
+
+			if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+				symbol = this.Symbol;
+
+			if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+				symbolList = this.SymbolList;
+
+		}
 	}
 }

+ 5 - 3
src/MoonSharp.Interpreter/Execution/VM/OpCode.cs

@@ -5,12 +5,10 @@ using System.Text;
 
 namespace MoonSharp.Interpreter.Execution.VM
 {
-
-	internal enum OpCode
+	internal enum OpCode 
 	{
 		// Meta-opcodes
 		Nop,		// Does not perform any operation.
-		Invalid,	// Crashes the executor with an unrecoverable NotImplementedException.
 		Debug,		// Does not perform any operation. Used to help debugging.
 
 		// Stack ops and assignment
@@ -31,6 +29,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		Enter,		// Enters a new stack frame
 		Leave,		// Leaves a stack frame
 		Exit,		// Leaves every stack frame up and including the topmost function frame, plus it exits the topmost closure
+		FuncMeta,	// Injects function metadata used for reflection things (dumping, debugging)
 		BeginFn,	// Adjusts for start of function, taking in parameters and allocating locals
 		Args,		// Takes the arguments passed to a function and sets the appropriate symbols in the local scope
 		Call,		// Calls the function specified on the specified element from the top of the v-stack. If the function is a MoonSharp function, it pushes its numeric value on the v-stack, then pushes the current PC onto the x-stack, enters the function closure and jumps to the function first instruction. If the function is a CLR function, it pops the function value from the v-stack, then invokes the function synchronously and finally pushes the result on the v-stack.
@@ -74,5 +73,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 		// Iterators
 		IterPrep,   // Prepares an iterator for execution 
 		IterUpd,	// Updates the var part of an iterator
+
+		// Meta
+		Invalid,	// Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum
 	}
 }

+ 1 - 8
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading;
@@ -155,13 +156,5 @@ namespace MoonSharp.Interpreter.Execution.VM
 		{
 			return GetCurrentSourceRef(m_SavedInstructionPtr);
 		}
-
-
-
-
-
-
-
-
 	}
 }

+ 1 - 1
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs

@@ -255,7 +255,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 				var I = m_RootChunk.Code[c.Debug_EntryPoint];
 
-				string callname = I.OpCode == OpCode.BeginFn ? I.Name : null;
+				string callname = I.OpCode == OpCode.FuncMeta ? I.Name : null;
 
 				if (c.ClrFunction != null)
 				{

+ 1 - 2
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs

@@ -36,6 +36,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 					{
 						case OpCode.Nop:
 						case OpCode.Debug:
+						case OpCode.FuncMeta:
 							break;
 						case OpCode.Pop:
 							m_ValueStack.RemoveLast(i.NumVal);
@@ -549,8 +550,6 @@ namespace MoonSharp.Interpreter.Execution.VM
 			m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
 		}
 
-
-
 		private void ExecBeginFn(Instruction i)
 		{
 			CallStackItem c = m_ExecutionStack.Peek();

+ 60 - 0
src/MoonSharp.Interpreter/IO/BinDumpBinaryReader.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.IO
+{
+	public class BinDumpBinaryReader : BinaryReader
+	{
+		public BinDumpBinaryReader(Stream s) : base(s) { }
+		public BinDumpBinaryReader(Stream s, Encoding e) : base(s, e) { }
+
+		List<string> m_Strings = new List<string>();
+
+		public override int ReadInt32()
+		{
+			sbyte b = base.ReadSByte();
+
+			if (b == 0x7F)
+				return (int)base.ReadInt16();
+			else if (b == 0x7E)
+				return (int)base.ReadInt32();
+			else
+				return (int)b;
+		}
+
+		public override uint ReadUInt32()
+		{
+			byte b = base.ReadByte();
+
+			if (b == 0x7F)
+				return (uint)base.ReadUInt16();
+			else if (b == 0x7E)
+				return (uint)base.ReadUInt32();
+			else
+				return (uint)b;
+		}
+
+		public override string ReadString()
+		{
+			int pos = ReadInt32();
+
+			if (pos < m_Strings.Count)
+			{
+				return m_Strings[pos];
+			}
+			else if (pos == m_Strings.Count)
+			{
+				string str = base.ReadString();
+				m_Strings.Add(str);
+				return str;
+			}
+			else
+			{
+				throw new DataMisalignedException("string map failure");
+			}
+		}
+	}
+}

+ 84 - 0
src/MoonSharp.Interpreter/IO/BinDumpBinaryWriter.cs

@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.IO
+{
+	public class BinDumpBinaryWriter : BinaryWriter
+	{
+		Dictionary<string, int> m_StringMap = new Dictionary<string, int>();
+
+		public BinDumpBinaryWriter(Stream s) : base(s) { }
+		public BinDumpBinaryWriter(Stream s, Encoding e) : base(s, e) { }
+
+		public override void Write(uint value)
+		{
+			byte v8 = (byte)value;
+
+			if ((uint)v8 == value && (v8 != 0x7F) && (v8 != 0x7E))
+			{
+				base.Write(v8);
+			}
+			else
+			{
+				ushort v16 = (ushort)value;
+
+				if ((uint)v16 == value)
+				{
+					base.Write((byte)0x7F);
+					base.Write(v16);
+				}
+				else
+				{
+					base.Write((byte)0x7E);
+					base.Write(value);
+				}
+			}
+		}
+
+		public override void Write(int value)
+		{
+			sbyte vsbyte = (sbyte)value;
+
+			if ((int)vsbyte == value && (vsbyte != 0x7F) && (vsbyte != 0x7E))
+			{
+				base.Write(vsbyte);
+			}
+			else
+			{
+				short vshort = (short)value;
+
+				if ((int)vshort == value)
+				{
+					base.Write((sbyte)0x7F);
+					base.Write(vshort);
+				}
+				else
+				{
+					base.Write((sbyte)0x7E);
+					base.Write(value);
+				}
+			}
+		}
+
+		public override void Write(string value)
+		{
+			int pos;
+
+			if (m_StringMap.TryGetValue(value, out pos))
+			{
+				this.Write(m_StringMap[value]);
+			}
+			else
+			{
+				pos = m_StringMap.Count;
+				m_StringMap[value] = pos;
+
+				this.Write(pos);
+				base.Write(value);
+			}
+		}
+	}
+}

+ 167 - 0
src/MoonSharp.Interpreter/IO/UndisposableStream.cs

@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.IO
+{
+	/// <summary>
+	/// An adapter over Stream which bypasses the Dispose and Close methods.
+	/// Used to work around the pesky wrappers .NET has over Stream (BinaryReader, StreamWriter, etc.) which think they
+	/// own the Stream and close them when they shouldn't. Damn.
+	/// </summary>
+	public class UndisposableStream : Stream
+	{
+		Stream m_Stream;
+
+		public UndisposableStream(Stream stream)
+		{
+			m_Stream = stream;
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+		}
+
+		public override void Close()
+		{
+		}
+
+
+		public override bool CanRead
+		{
+			get { return m_Stream.CanRead; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return m_Stream.CanSeek; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return m_Stream.CanWrite; }
+		}
+
+		public override void Flush()
+		{
+			m_Stream.Flush();
+		}
+
+		public override long Length
+		{
+			get { return m_Stream.Length; }
+		}
+
+		public override long Position
+		{
+			get { return m_Stream.Position; }
+			set { m_Stream.Position = value; }
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			return m_Stream.Read(buffer, offset, count);
+		}
+
+		public override long Seek(long offset, SeekOrigin origin)
+		{
+			return m_Stream.Seek(offset, origin);
+		}
+
+		public override void SetLength(long value)
+		{
+			m_Stream.SetLength(value);
+		}
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			m_Stream.Write(buffer, offset, count);
+		}
+
+		public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+		{
+			return m_Stream.BeginRead(buffer, offset, count, callback, state);
+		}
+
+		public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+		{
+			return m_Stream.BeginWrite(buffer, offset, count, callback, state);
+		}
+
+		public override bool CanTimeout
+		{
+			get { return m_Stream.CanTimeout; }
+		}
+
+		public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
+		{
+			return m_Stream.CreateObjRef(requestedType);
+		}
+
+		public override bool Equals(object obj)
+		{
+			return m_Stream.Equals(obj);
+		}
+
+		public override int GetHashCode()
+		{
+			return m_Stream.GetHashCode();
+		}
+
+		public override object InitializeLifetimeService()
+		{
+			return m_Stream.InitializeLifetimeService();
+		}
+
+		public override int ReadByte()
+		{
+			return m_Stream.ReadByte();
+		}
+
+		public override int ReadTimeout
+		{
+			get
+			{
+				return m_Stream.ReadTimeout;
+			}
+			set
+			{
+				m_Stream.ReadTimeout = value;
+			}
+		}
+
+		public override string ToString()
+		{
+			return m_Stream.ToString();
+		}
+
+		public override void WriteByte(byte value)
+		{
+			m_Stream.WriteByte(value);
+		}
+
+		public override int WriteTimeout
+		{
+			get
+			{
+				return m_Stream.WriteTimeout;
+			}
+			set
+			{
+				m_Stream.WriteTimeout = value;
+			}
+		}
+
+		public override void EndWrite(IAsyncResult asyncResult)
+		{
+			m_Stream.EndWrite(asyncResult);
+		}
+
+		public override int EndRead(IAsyncResult asyncResult)
+		{
+			return m_Stream.EndRead(asyncResult);
+		}
+	}
+}

+ 10 - 0
src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs

@@ -30,6 +30,16 @@ namespace MoonSharp.Interpreter.Interop
 
 			if (AccessMode != InteropAccessMode.HideMembers)
 			{
+				foreach (ConstructorInfo ci in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
+				{
+					if (CheckVisibility(ci.GetCustomAttributes(true), ci.IsPublic))
+					{
+						var md = new StandardUserDataMethodDescriptor(ci, this.AccessMode);
+						m_Methods.Add("__new", md);
+						break;
+					}
+				}
+
 				foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Static))
 				{
 					if (CheckVisibility(mi.GetCustomAttributes(true), mi.IsPublic))

+ 28 - 9
src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataMethodDescriptor.cs

@@ -12,10 +12,11 @@ namespace MoonSharp.Interpreter.Interop
 {
 	public class StandardUserDataMethodDescriptor
 	{
-		public MethodInfo MethodInfo { get; private set; }
+		public MethodBase MethodInfo { get; private set; }
 		public InteropAccessMode AccessMode { get; private set; }
 		public bool IsStatic { get; private set; }
 		public string Name { get; private set; }
+		public bool IsConstructor { get; private set; }
 
 		private Type[] m_Arguments;
 		private object[] m_Defaults;
@@ -23,7 +24,7 @@ namespace MoonSharp.Interpreter.Interop
 		private Action<object, object[]> m_OptimizedAction = null;
 		private bool m_IsAction = false;
 
-		public StandardUserDataMethodDescriptor(MethodInfo mi, InteropAccessMode accessMode = InteropAccessMode.Default)
+		public StandardUserDataMethodDescriptor(MethodBase mi, InteropAccessMode accessMode = InteropAccessMode.Default)
 		{
 			if (accessMode == InteropAccessMode.Default)
 				accessMode = UserData.DefaultAccessMode;
@@ -34,9 +35,19 @@ namespace MoonSharp.Interpreter.Interop
 			this.MethodInfo = mi;
 			this.AccessMode = accessMode;
 			this.Name = mi.Name;
-			this.IsStatic = mi.IsStatic;
 
-			m_IsAction = mi.ReturnType == typeof(void);
+			IsConstructor = (mi is ConstructorInfo);
+
+			this.IsStatic = mi.IsStatic || IsConstructor; // we consider the constructor to be a static method as far interop is concerned.
+
+			if (mi is ConstructorInfo)
+			{
+				m_IsAction = false;
+			}
+			else
+			{
+				m_IsAction = ((MethodInfo)mi).ReturnType == typeof(void);
+			}
 
 			m_Arguments = mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
 			m_Defaults = mi.GetParameters().Select(pi => pi.DefaultValue).ToArray();
@@ -52,7 +63,7 @@ namespace MoonSharp.Interpreter.Interop
 
 		public CallbackFunction GetCallbackFunction(Script script, object obj = null)
 		{
-			return new CallbackFunction(GetCallback(script, obj), this.MethodInfo.Name);
+			return new CallbackFunction(GetCallback(script, obj), this.Name);
 		}
 
 		public DynValue GetCallbackAsDynValue(Script script, object obj = null)
@@ -117,7 +128,10 @@ namespace MoonSharp.Interpreter.Interop
 			}
 			else
 			{
-				retv = MethodInfo.Invoke(obj, pars);
+				if (IsConstructor)
+					retv = ((ConstructorInfo)MethodInfo).Invoke(pars);
+				else
+					retv = MethodInfo.Invoke(obj, pars);
 			}
 
 			return ConversionHelper.ClrObjectToComplexMoonSharpValue(script, retv);
@@ -125,6 +139,11 @@ namespace MoonSharp.Interpreter.Interop
 
 		internal void Optimize()
 		{
+			MethodInfo methodInfo = this.MethodInfo as MethodInfo;
+
+			if (methodInfo == null)
+				return;
+
 			using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
 			{
 				var ep = Expression.Parameter(typeof(object[]), "pars");
@@ -143,15 +162,15 @@ namespace MoonSharp.Interpreter.Interop
 
 				if (IsStatic)
 				{
-					fn = Expression.Call(MethodInfo, args);
+					fn = Expression.Call(methodInfo, args);
 				}
 				else
 				{
-					fn = Expression.Call(inst, MethodInfo, args);
+					fn = Expression.Call(inst, methodInfo, args);
 				}
 
 
-				if (MethodInfo.ReturnType == typeof(void))
+				if (this.m_IsAction)
 				{
 					var lambda = Expression.Lambda<Action<object, object[]>>(fn, objinst, ep);
 					Interlocked.Exchange(ref m_OptimizedAction, lambda.Compile());

+ 3 - 2
src/MoonSharp.Interpreter/Loaders/ClassicLuaScriptLoader.cs

@@ -28,9 +28,10 @@ namespace MoonSharp.Interpreter.Loaders
 			}
 		}
 
-		public virtual string LoadFile(string file, Table globalContext)
+		public virtual object LoadFile(string file, Table globalContext)
 		{
-			return File.ReadAllText(file);
+			var stream = new FileStream(file, FileMode.Open, FileAccess.Read);
+			return stream;
 		}
 
 		public virtual string ResolveFileName(string filename, Table globalContext)

+ 22 - 1
src/MoonSharp.Interpreter/Loaders/IScriptLoader.cs

@@ -5,10 +5,31 @@ using System.Text;
 
 namespace MoonSharp.Interpreter.Loaders
 {
+	/// <summary>
+	/// 
+	/// </summary>
 	public interface IScriptLoader 
 	{
-		string LoadFile(string file, Table globalContext);
+		/// <summary>
+		/// Loads the file.
+		/// </summary>
+		/// <param name="file">The file.</param>
+		/// <param name="globalContext">The global context.</param>
+		/// <returns></returns>
+		object LoadFile(string file, Table globalContext);
+		/// <summary>
+		/// Resolves a filename [applying paths, etc.]
+		/// </summary>
+		/// <param name="filename">The filename.</param>
+		/// <param name="globalContext">The global context.</param>
+		/// <returns></returns>
 		string ResolveFileName(string filename, Table globalContext);
+		/// <summary>
+		/// Resolves the name of the module.
+		/// </summary>
+		/// <param name="modname">The modname.</param>
+		/// <param name="globalContext">The global context.</param>
+		/// <returns></returns>
 		string ResolveModuleName(string modname, Table globalContext);
 	}
 }

+ 8 - 1
src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj

@@ -87,7 +87,7 @@
     <Compile Include="CoreLib\IO\FileUserData.cs" />
     <Compile Include="CoreLib\IoModule.cs" />
     <Compile Include="CoreLib\IO\FileUserDataBase.cs" />
-    <Compile Include="CoreLib\IO\StdioFileUserData.cs" />
+    <Compile Include="CoreLib\IO\StandardIOFileUserDataBase.cs" />
     <Compile Include="CoreLib\IO\StreamFileUserDataBase.cs" />
     <Compile Include="CoreLib\LoadModule.cs" />
     <Compile Include="CoreLib\Bit32Module.cs" />
@@ -96,6 +96,13 @@
     <Compile Include="CoreLib\OsSystemModule.cs" />
     <Compile Include="CoreLib\OsTimeModule.cs" />
     <Compile Include="CoreLib\StringLib\KopiLua_StrLib.cs" />
+    <Compile Include="IO\BinDumpBinaryReader.cs" />
+    <Compile Include="IO\BinDumpBinaryWriter.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="IO\UndisposableStream.cs" />
+    <Compile Include="Execution\InstructionFieldUsage.cs" />
+    <Compile Include="Execution\VM\Processor\Processor_BinaryDump.cs" />
     <Compile Include="Interop\InteropRegistrationPolicy.cs" />
     <Compile Include="Interop\IUserDataType.cs" />
     <Compile Include="DataTypes\ScriptFunctionDelegate.cs" />

+ 140 - 7
src/MoonSharp.Interpreter/Script.cs

@@ -5,11 +5,13 @@ using System.Linq;
 using System.Text;
 using Antlr4.Runtime;
 using MoonSharp.Interpreter.CoreLib;
+using MoonSharp.Interpreter.DataStructs;
 using MoonSharp.Interpreter.Debugging;
 using MoonSharp.Interpreter.Diagnostics;
 using MoonSharp.Interpreter.Execution;
 using MoonSharp.Interpreter.Execution.VM;
 using MoonSharp.Interpreter.Interop;
+using MoonSharp.Interpreter.IO;
 using MoonSharp.Interpreter.Loaders;
 using MoonSharp.Interpreter.Tree;
 using MoonSharp.Interpreter.Tree.Expressions;
@@ -26,7 +28,7 @@ namespace MoonSharp.Interpreter
 		/// <summary>
 		/// The version of the MoonSharp engine
 		/// </summary>
-		public const string VERSION = "0.8.5.0"; 
+		public const string VERSION = "0.8.6.0"; 
 
 		/// <summary>
 		/// The Lua version being supported
@@ -155,6 +157,14 @@ namespace MoonSharp.Interpreter
 		/// </returns>
 		public DynValue LoadString(string code, Table globalTable = null, string codeFriendlyName = null)
 		{
+			if (code.StartsWith(StringModule.BASE64_DUMP_HEADER))
+			{
+				code = code.Substring(StringModule.BASE64_DUMP_HEADER.Length);
+				byte[] data = Convert.FromBase64String(code);
+				using (MemoryStream ms = new MemoryStream(data))
+					return LoadStream(ms, globalTable, codeFriendlyName);
+			}
+
 			string chunkName = string.Format("{0}", codeFriendlyName ?? "chunk_" + m_Sources.Count.ToString());
 
 			SourceCode source = new SourceCode(codeFriendlyName ?? chunkName, code, m_Sources.Count, this);
@@ -172,6 +182,72 @@ namespace MoonSharp.Interpreter
 			return MakeClosure(address);
 		}
 
+		/// <summary>
+		/// Loads a Lua/MoonSharp script from a System.IO.Stream. NOTE: This will *NOT* close the stream!
+		/// </summary>
+		/// <param name="stream">The stream containing code.</param>
+		/// <param name="globalTable">The global table to bind to this chunk.</param>
+		/// <param name="codeFriendlyName">Name of the code - used to report errors, etc.</param>
+		/// <returns>
+		/// A DynValue containing a function which will execute the loaded code.
+		/// </returns>
+		public DynValue LoadStream(Stream stream, Table globalTable = null, string codeFriendlyName = null)
+		{
+			Stream codeStream = new UndisposableStream(stream);
+
+			if (!Processor.IsDumpStream(codeStream))
+			{
+				using (StreamReader sr = new StreamReader(codeStream))
+				{
+					string scriptCode = sr.ReadToEnd();
+					return LoadString(scriptCode, globalTable, codeFriendlyName);
+				}
+			}
+			else
+			{
+				string chunkName = string.Format("{0}", codeFriendlyName ?? "dump_" + m_Sources.Count.ToString());
+
+				SourceCode source = new SourceCode(codeFriendlyName ?? chunkName, 
+					string.Format("-- This script was decoded from a binary dump - dump_{0}", m_Sources.Count),
+					m_Sources.Count, this);
+
+				m_Sources.Add(source);
+
+				bool hasUpvalues;
+				int address = m_MainProcessor.Undump(codeStream, m_Sources.Count - 1, globalTable ?? m_GlobalTable, out hasUpvalues);
+
+				SignalSourceCodeChange(source);
+				SignalByteCodeChange();
+
+				if (hasUpvalues)
+					return MakeClosure(address, globalTable ?? m_GlobalTable);
+				else
+					return MakeClosure(address);
+			}
+		}
+
+		/// <summary>
+		/// Dumps on the specified stream.
+		/// </summary>
+		/// <param name="stream">The stream.</param>
+		public void Dump(DynValue function, Stream stream)
+		{
+			if (function.Type != DataType.Function)
+				throw new ArgumentException("function arg is not a function!");
+
+			if (!stream.CanWrite)
+				throw new ArgumentException("stream is readonly!");
+
+			ClosureContext.UpvaluesType upvaluesType = function.Function.ClosureContext.GetUpvaluesType();
+
+			if (upvaluesType == ClosureContext.UpvaluesType.Closure)
+				throw new ArgumentException("function arg has upvalues other than _ENV");
+
+			UndisposableStream outStream = new UndisposableStream(stream);
+			m_MainProcessor.Dump(outStream, function.Function.EntryPointByteCodeLocation, upvaluesType == ClosureContext.UpvaluesType.Environment);
+		}
+
+
 		/// <summary>
 		/// Loads a string containing a Lua/MoonSharp script.
 		/// </summary>
@@ -184,8 +260,35 @@ namespace MoonSharp.Interpreter
 		public DynValue LoadFile(string filename, Table globalContext = null, string friendlyFilename = null)
 		{
 			filename = Options.ScriptLoader.ResolveFileName(filename, globalContext ?? m_GlobalTable);
+			object code = Options.ScriptLoader.LoadFile(filename, globalContext ?? m_GlobalTable);
 
-			return LoadString(Options.ScriptLoader.LoadFile(filename, globalContext ?? m_GlobalTable), globalContext, friendlyFilename ?? filename);
+			if (code is string)
+			{
+				return LoadString((string)code, globalContext, friendlyFilename ?? filename);
+			}
+			else if (code is byte[])
+			{
+				using(MemoryStream ms = new MemoryStream((byte[])code))
+					return LoadStream(ms, globalContext, friendlyFilename ?? filename);
+			}
+			else if (code is Stream)
+			{
+				try
+				{
+					return LoadStream((Stream)code, globalContext, friendlyFilename ?? filename);
+				}
+				finally
+				{
+					((Stream)code).Dispose();
+				}
+			}
+			else
+			{
+				if (code == null)
+					throw new InvalidCastException("Unexpected null from IScriptLoader.LoadFile");
+				else
+					throw new InvalidCastException(string.Format("Unsupported return type from IScriptLoader.LoadFile : {0}", code.GetType()));
+			}
 		}
 
 
@@ -203,6 +306,22 @@ namespace MoonSharp.Interpreter
 			return Call(func);
 		}
 
+
+		/// <summary>
+		/// Loads and executes a stream containing a Lua/MoonSharp script.
+		/// </summary>
+		/// <param name="stream">The stream.</param>
+		/// <param name="globalContext">The global context.</param>
+		/// <returns>
+		/// A DynValue containing the result of the processing of the loaded chunk.
+		/// </returns>
+		public DynValue DoStream(Stream stream, Table globalContext = null)
+		{
+			DynValue func = LoadStream(stream, globalContext);
+			return Call(func);
+		}
+
+
 		/// <summary>
 		/// Loads and executes a file containing a Lua/MoonSharp script.
 		/// </summary>
@@ -244,12 +363,26 @@ namespace MoonSharp.Interpreter
 		/// Creates a closure from a bytecode address.
 		/// </summary>
 		/// <param name="address">The address.</param>
+		/// <param name="envTable">The env table to create a 0-upvalue</param>
 		/// <returns></returns>
-		private DynValue MakeClosure(int address)
+		private DynValue MakeClosure(int address, Table envTable = null)
 		{
-			Closure c = new Closure(this, address,
-				new SymbolRef[0],
-				new DynValue[0]);
+			Closure c;
+
+			if (envTable == null)
+				c = new Closure(this, address, new SymbolRef[0], new DynValue[0]);
+			else
+			{
+				var syms = new SymbolRef[1] {
+					new SymbolRef() { i_Env = null, i_Index= 0, i_Name = WellKnownSymbols.ENV, i_Type =  SymbolRefType.DefaultEnv },
+				};
+
+				var vals = new DynValue[1] {
+					DynValue.NewTable(envTable)
+				};
+
+				c = new Closure(this, address, syms, vals);
+			}
 
 			return DynValue.NewClosure(c);
 		}
@@ -427,7 +560,7 @@ namespace MoonSharp.Interpreter
 			if (filename == null)
 				throw new ScriptRuntimeException("module '{0}' not found", modname);
 
-			DynValue func = LoadString(Options.ScriptLoader.LoadFile(filename, globalContext), globalContext, filename);
+			DynValue func = LoadFile(filename, globalContext, filename);
 			return func;
 		}
 

+ 4 - 0
src/MoonSharp.Interpreter/ScriptOptions.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using MoonSharp.Interpreter.Loaders;
@@ -52,6 +53,9 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		public bool UseLuaErrorLocations { get; set; }
 
+		public Stream Stdin { get; set; }
+		public Stream Stdout { get; set; }
+		public Stream Stderr { get; set; }
 
 		/// <summary>
 		/// Gets or sets a value indicating whether the thread check is enabled.

+ 1 - 1
src/MoonSharp.Interpreter/Tree/Antlr_Interface/Loader_Antlr.cs

@@ -138,7 +138,7 @@ namespace MoonSharp.Interpreter.Tree
 			//bytecode.Dump(string.Format(@"c:\temp\codedump_{0}.txt", sourceIdx));
 		}
 
-		//[Conditional("DEBUG_COMPILER")]
+		[Conditional("DEBUG_COMPILER")]
 		private static void Debug_DumpAst(LuaParser parser, int sourceIdx, Func<LuaParser, IParseTree> dumper)
 		{
 			try

+ 7 - 1
src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs

@@ -124,11 +124,16 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 
 		public int CompileBody(ByteCode bc, string friendlyName)
 		{
+			string funcName = friendlyName ?? "<" + this.m_Begin.FormatLocation(this.LoadingContext.Script, true) + ">";
+
 			bc.PushSourceRef(m_Begin);
 
 			Instruction I = bc.Emit_Jump(OpCode.Jump, -1);
 
-			bc.Emit_BeginFn(m_StackFrame, friendlyName ?? "<" + this.m_Begin.FormatLocation(this.LoadingContext.Script, true) + ">");
+			Instruction meta = bc.Emit_FuncMeta(funcName);
+			int metaip = bc.GetJumpPointForLastInstruction();
+
+			bc.Emit_BeginFn(m_StackFrame);
 
 			bc.LoopTracker.Loops.Push(new LoopBoundary());
 
@@ -154,6 +159,7 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 			bc.LoopTracker.Loops.Pop();
 
 			I.NumVal = bc.GetJumpPointForNextInstruction();
+			meta.NumVal = bc.GetJumpPointForLastInstruction() - metaip;
 
 			bc.PopSourceRef();
 

+ 6 - 1
src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs

@@ -36,7 +36,10 @@ namespace MoonSharp.Interpreter.Tree.Statements
 
 		public override void Compile(Execution.VM.ByteCode bc)
 		{
-			bc.Emit_BeginFn(m_StackFrame, "<chunk-root>");
+			Instruction meta = bc.Emit_FuncMeta("<chunk-root>");
+			int metaip = bc.GetJumpPointForLastInstruction();
+
+			bc.Emit_BeginFn(m_StackFrame);
 			bc.Emit_Args(m_VarArgs);
 
 			bc.Emit_Literal(DynValue.NewTable(m_GlobalEnv));
@@ -45,6 +48,8 @@ namespace MoonSharp.Interpreter.Tree.Statements
 
 			m_Block.Compile(bc);
 			bc.Emit_Ret(0);
+
+			meta.NumVal = bc.GetJumpPointForLastInstruction() - metaip;
 		}
 
 		public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol)

+ 15 - 2
src/MoonSharp/Program.cs

@@ -128,9 +128,22 @@ namespace MoonSharp
 			}
 			if (p == "!")
 			{
-				ParseCommand(S, "debug");
-				ParseCommand(S, @"run c:\temp\test.lua");
+				//ParseCommand(S, "debug");
+				//ParseCommand(S, @"run c:\temp\test.lua");
 			}
+			if (p == "wb")
+			{
+				DynValue chunk = S.LoadFile(@"c:\temp\test.lua");
+
+				using (Stream stream = new FileStream(@"c:\temp\test.bin", FileMode.Create, FileAccess.Write))
+					S.Dump(chunk, stream);
+			}
+			if (p == "rb")
+			{
+				DynValue chunk = S.LoadFile(@"c:\temp\test.bin");
+				chunk.Function.Call();
+			}
+
 		}
 
 		static void m_Server_DataReceivedAny(object sender, Utf8TcpPeerEventArgs e)