Browse Source

pairs/ipairs/next

Xanathar 11 years ago
parent
commit
83533f9d04
29 changed files with 700 additions and 184 deletions
  1. 4 4
      src/MoonSharp.Debugger/MainForm.cs
  2. 2 2
      src/MoonSharp.Debugger/ValueBrowser.cs
  3. 3 3
      src/MoonSharp.Interpreter.Tests/EndToEnd/LuaTestSuiteExtract.cs
  4. 4 4
      src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs
  5. 122 1
      src/MoonSharp.Interpreter.Tests/EndToEnd/TableTests.cs
  6. 41 0
      src/MoonSharp.Interpreter.Tests/EndToEnd/TailCallTests.cs
  7. 1 0
      src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.csproj
  8. 2 2
      src/MoonSharp.Interpreter.Tests/TestMore/TapRunner.cs
  9. 9 3
      src/MoonSharp.Interpreter/CoreLib/BasicMethods.cs
  10. 23 4
      src/MoonSharp.Interpreter/CoreLib/CoreLibModule.cs
  11. 83 0
      src/MoonSharp.Interpreter/CoreLib/TableIterators.cs
  12. 58 0
      src/MoonSharp.Interpreter/Execution/DataTypes/CallbackArguments.cs
  13. 4 4
      src/MoonSharp.Interpreter/Execution/DataTypes/CallbackFunction.cs
  14. 8 5
      src/MoonSharp.Interpreter/Execution/DataTypes/DataType.cs
  15. 49 73
      src/MoonSharp.Interpreter/Execution/DataTypes/RValue.cs
  16. 46 23
      src/MoonSharp.Interpreter/Execution/DataTypes/Table.cs
  17. 2 0
      src/MoonSharp.Interpreter/Execution/Script.cs
  18. 3 2
      src/MoonSharp.Interpreter/Execution/VM/Chunk.cs
  19. 1 0
      src/MoonSharp.Interpreter/Execution/VM/OpCode.cs
  20. 1 5
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
  21. 4 4
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs
  22. 45 0
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs
  23. 71 38
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
  24. 70 0
      src/MoonSharp.Interpreter/Modules/ModuleRegister.cs
  25. 13 0
      src/MoonSharp.Interpreter/Modules/MoonSharpMethodAttribute.cs
  26. 13 0
      src/MoonSharp.Interpreter/Modules/MoonSharpModuleAttribute.cs
  27. 11 0
      src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj
  28. 3 3
      src/MoonSharp/Program.cs
  29. 4 4
      src/PerformanceComparison/Program.cs

+ 4 - 4
src/MoonSharp.Debugger/MainForm.cs

@@ -48,14 +48,14 @@ namespace MoonSharp.Debugger
 		Script m_Script;
 		SynchronizationContext m_Ctx;
 
-		RValue Print(IList<RValue> values)
+		RValue Print(IExecutionContext executionContext, CallbackArguments values)
 		{
-			string prn = string.Join(" ", values.Select(v => v.AsString()).ToArray());
+			string prn = string.Join(" ", values.List.Select(v => v.AsString()).ToArray());
 			Console_WriteLine("{0}", prn);
 			return RValue.Nil;
 		}
 
-		RValue Assert(IList<RValue> values)
+		RValue Assert(IExecutionContext executionContext, CallbackArguments values)
 		{
 			if (!values[0].TestAsBoolean())
 				Console_WriteLine("ASSERT FAILED!");
@@ -63,7 +63,7 @@ namespace MoonSharp.Debugger
 			return RValue.Nil;
 		}
 
-		RValue XAssert(IList<RValue> values)
+		RValue XAssert(IExecutionContext executionContext, CallbackArguments values)
 		{
 			if (!values[1].TestAsBoolean())
 				Console_WriteLine("ASSERT FAILED! : {0}", values[0].ToString());

+ 2 - 2
src/MoonSharp.Debugger/ValueBrowser.cs

@@ -99,11 +99,11 @@ namespace MoonSharp.Debugger
 					txtString.Visible = true;
 					txtString.Text = "Value is a CLR function.";
 					break;
-				case DataType.UNSUPPORTED_UserData:
+				case DataType.UserData:
 					txtString.Visible = true;
 					txtString.Text = "Value is a CLR object (userdata).";
 					break;
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.Thread:
 					txtString.Visible = true;
 					txtString.Text = "Value is a coroutine.";
 					break;

+ 3 - 3
src/MoonSharp.Interpreter.Tests/EndToEnd/LuaTestSuiteExtract.cs

@@ -21,7 +21,7 @@ namespace MoonSharp.Interpreter.Tests
 
 			var globalCtx = new Table();
 			globalCtx[new RValue("xassert")] = new RValue(new CallbackFunction(
-				a =>
+				(x, a) =>
 				{
 					if (!a[1].TestAsBoolean())
 						failedTests.Add(a[0].String);
@@ -29,7 +29,7 @@ namespace MoonSharp.Interpreter.Tests
 					return RValue.Nil;
 				}));
 			globalCtx[new RValue("assert")] = new RValue(new CallbackFunction(
-			 a =>
+			 (x, a) =>
 			 {
 				 ++i;
 
@@ -39,7 +39,7 @@ namespace MoonSharp.Interpreter.Tests
 				 return RValue.Nil;
 			 }));
 
-			globalCtx[new RValue("print")] = new RValue(new CallbackFunction(a =>
+			globalCtx[new RValue("print")] = new RValue(new CallbackFunction((x, a) =>
 				{
 					// Debug.WriteLine(string.Join(" ", a.Select(v => v.AsString()).ToArray()));
 					return RValue.Nil;

+ 4 - 4
src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs

@@ -18,7 +18,7 @@ namespace MoonSharp.Interpreter.Tests
 			string script = "print(\"hello\", \"world\");";
 
 			var globalCtx = new Table();
-			globalCtx[new RValue("print")] = new RValue(new CallbackFunction(a => 
+			globalCtx[new RValue("print")] = new RValue(new CallbackFunction((x, a) => 
 			{
 				args = a.ToArray(); 
 				return new RValue(1234.0); 
@@ -42,7 +42,7 @@ namespace MoonSharp.Interpreter.Tests
 			string script = "local print = print; print(\"hello\", \"world\");";
 
 			var globalCtx = new Table();
-			globalCtx[new RValue("print")] = new RValue(new CallbackFunction(a => { args = a.ToArray(); return new RValue(1234.0); }));
+			globalCtx[new RValue("print")] = new RValue(new CallbackFunction((_x, a) => { args = a.ToArray(); return new RValue(1234.0); }));
 
 			RValue res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
 
@@ -62,7 +62,7 @@ namespace MoonSharp.Interpreter.Tests
 			string script = "return print(\"hello\", \"world\");";
 
 			var globalCtx = new Table();
-			globalCtx[new RValue("print")] = new RValue(new CallbackFunction(a => { args = a.ToArray(); return new RValue(1234.0); }));
+			globalCtx[new RValue("print")] = new RValue(new CallbackFunction((_x, a) => { args = a.ToArray(); return new RValue(1234.0); }));
 
 			RValue res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
 
@@ -121,7 +121,7 @@ namespace MoonSharp.Interpreter.Tests
 			";
 
 			var globalCtx = new Table();
-			globalCtx[new RValue("crash")] = new RValue(new CallbackFunction(a =>
+			globalCtx[new RValue("crash")] = new RValue(new CallbackFunction((_x, a) =>
 			{
 				throw new Exception("FAIL!");
 			}));

+ 122 - 1
src/MoonSharp.Interpreter.Tests/EndToEnd/TableTests.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Linq;
 using MoonSharp.Interpreter.Execution;
 using NUnit.Framework;
+using MoonSharp.Interpreter.CoreLib;
 
 namespace MoonSharp.Interpreter.Tests
 {
@@ -189,7 +190,7 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(1994, res.Number);
 		}
 
-
+		
 		[Test]
 		public void TableMethod6()
 		{
@@ -206,5 +207,125 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(true, res.TestAsBoolean());
 		}
 
+		[Test]
+		public void TableNextWithChangeInCollection()
+		{
+			string script = @"
+				x = { }
+
+				function copy(k, v)
+					x[k] = v;
+				end
+
+
+				t = 
+				{
+					a = 1,
+					b = 2,
+					c = 3,
+					d = 4,
+					e = 5
+				}
+
+				k,v = next(t, nil);
+				copy(k, v);
+
+				k,v = next(t, k);
+				copy(k, v);
+				v = nil;
+
+				k,v = next(t, k);
+				copy(k, v);
+
+				k,v = next(t, k);
+				copy(k, v);
+
+				k,v = next(t, k);
+				copy(k, v);
+
+				s = x.a .. '|' .. x.b .. '|' .. x.c .. '|' .. x.d .. '|' .. x.e
+
+				return s;";
+
+			Table globalCtx = new Table();
+
+			globalCtx.RegisterModuleType<TableIterators>();
+
+			RValue res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
+
+			Assert.AreEqual(DataType.String, res.Type);
+			Assert.AreEqual("1|2|3|4|5", res.String);
+		}
+
+
+		[Test]
+		public void TablePairsWithoutMetatable()
+		{
+			string script = @"
+				V = 0
+				K = ''
+
+				t = 
+				{
+					a = 1,
+					b = 2,
+					c = 3,
+					d = 4,
+					e = 5
+				}
+
+				for k, v in pairs(t) do
+					K = K .. k;
+					V = V + v;
+				end
+
+				return K, V;";
+
+			Table globalCtx = new Table();
+
+			globalCtx.RegisterModuleType<TableIterators>();
+
+			RValue res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
+
+			Assert.AreEqual(DataType.Tuple, res.Type);
+			Assert.AreEqual(DataType.String, res.Tuple[0].Type);
+			Assert.AreEqual(DataType.Number, res.Tuple[1].Type);
+			Assert.AreEqual(5, res.Tuple[0].String.Length);
+			Assert.AreEqual(15, res.Tuple[1].Number);
+		}
+
+		[Test]
+		public void TableIPairsWithoutMetatable()
+		{
+			string script = @"    
+				x = 0
+				y = 0
+
+				t = { 2, 4, 6, 8, 10, 12 };
+
+				for i,j in ipairs(t) do
+					x = x + i
+					y = y + j
+
+					if (i >= 3) then
+						break
+					end
+				end
+    
+				return x, y";
+
+			Table globalCtx = new Table();
+
+			globalCtx.RegisterModuleType<TableIterators>();
+
+			RValue res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
+
+			Assert.AreEqual(DataType.Tuple, res.Type);
+			Assert.AreEqual(2, res.Tuple.Length);
+			Assert.AreEqual(DataType.Number, res.Tuple[0].Type);
+			Assert.AreEqual(DataType.Number, res.Tuple[1].Type);
+			Assert.AreEqual(6, res.Tuple[0].Number);
+			Assert.AreEqual(12, res.Tuple[1].Number);
+		}
 	}
 }

+ 41 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/TailCallTests.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Execution;
+using NUnit.Framework;
+
+namespace MoonSharp.Interpreter.Tests.EndToEnd
+{
+	[TestFixture]
+	public class TailCallTests
+	{
+		[Test]
+		public void TailCallFromCLR()
+		{
+			string script = @"
+				function getResult(x)
+					return 156*x;  
+				end
+
+				return clrtail(9)";
+
+
+			var globalCtx = new Table();
+			globalCtx[new RValue("clrtail")] = new RValue(new CallbackFunction((xc, a) =>
+			{
+				LRef lref = LRef.Global("getResult");
+				RValue fn = xc.GetVar(lref);
+				RValue k3 = new RValue(a[0].Number / 3);
+
+				return new RValue(fn, k3);
+			}));
+
+			var res = MoonSharpInterpreter.LoadFromString(script).Execute(globalCtx);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(468, res.Number);
+		}
+
+	}
+}

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

@@ -74,6 +74,7 @@
   <ItemGroup>
     <Compile Include="EndToEnd\ClosureTests.cs" />
     <Compile Include="EndToEnd\LuaTestSuiteExtract.cs" />
+    <Compile Include="EndToEnd\TailCallTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="EndToEnd\SimpleTests.cs" />
     <Compile Include="EndToEnd\TableTests.cs" />

+ 2 - 2
src/MoonSharp.Interpreter.Tests/TestMore/TapRunner.cs

@@ -12,9 +12,9 @@ namespace MoonSharp.Interpreter.Tests
 	{
 		string m_File;
 
-		public RValue Print(IList<RValue> values)
+		public RValue Print(IExecutionContext exctx, CallbackArguments values)
 		{
-			string str = string.Join(" ", values.Select(s => s.AsString()).ToArray());
+			string str = string.Join(" ", values.List.Select(s => s.AsString()).ToArray());
 			Assert.IsFalse(str.Trim().StartsWith("not ok"), string.Format("TAP fail ({0}) : {1}", m_File, str));
 			return RValue.Nil;
 		}

+ 9 - 3
src/MoonSharp.Interpreter/CoreLib/BasicMethods.cs

@@ -14,9 +14,6 @@ namespace MoonSharp.Interpreter.CoreLib
 		public static RValue assert(RValue[] values) { return RValue.Nil; }
 		public static RValue collectgarbage(RValue[] values) { return RValue.Nil; }
 		public static RValue error(RValue[] values) { return RValue.Nil; }
-		public static RValue ipairs(RValue[] values) { return RValue.Nil; }
-		public static RValue pairs(RValue[] values) { return RValue.Nil; }
-		public static RValue next(RValue[] values) { return RValue.Nil; }
 		public static RValue pcall(RValue[] values) { return RValue.Nil; }
 		public static RValue xpcall(RValue[] values) { return RValue.Nil; }
 		public static RValue print(RValue[] values) { return RValue.Nil; }
@@ -28,10 +25,19 @@ namespace MoonSharp.Interpreter.CoreLib
 
 
 
+
+
+
+
 		// Unsupported (?) - will raise exceptions:
 		public static RValue load(RValue[] values) { return RValue.Nil; }
 		public static RValue loadfile(RValue[] values) { return RValue.Nil; }
 		public static RValue dofile(RValue[] values) { return RValue.Nil; }
 
+
+
+
+
+
 	}
 }

+ 23 - 4
src/MoonSharp.Interpreter/CoreLib/CoreLibModule.cs

@@ -2,15 +2,34 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using MoonSharp.Interpreter.CoreLib;
+using MoonSharp.Interpreter.Execution;
 
-namespace MoonSharp.Interpreter.CoreLib
+namespace MoonSharp.Interpreter
 {
-	public enum CoreLibModule
+	[Flags]
+	public enum CoreLibModules
 	{
-		TableIterators,
-		Metatables,
+		TableIterators = 0x1,
+		Metatables = 0x2,
 
 
+		Default_HardSandbox = TableIterators,
+		Default_SoftSandbox = Default_HardSandbox | Metatables,
+		Default = Default_SoftSandbox,
+	}
+
+	public static class CoreLib_Ext
+	{
+		public static Table RegisterCoreModules(this Table t, CoreLibModules modules = CoreLibModules.Default)
+		{
+			if ((modules & CoreLibModules.TableIterators) != 0)
+				t.RegisterModuleType<TableIterators>();
+
+
+			return t;
+		}
 
 	}
+
 }

+ 83 - 0
src/MoonSharp.Interpreter/CoreLib/TableIterators.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Execution;
+using MoonSharp.Interpreter.Execution.DataTypes;
+
+namespace MoonSharp.Interpreter.CoreLib
+{
+	[MoonSharpModule]
+	public class TableIterators
+	{
+		[MoonSharpMethod]
+		public static RValue ipairs(IExecutionContext executionContext, CallbackArguments args) 
+		{
+			RValue table = args[0];
+
+			RValue meta = executionContext.GetMetamethodTailCall(table, "__ipairs", args.ToArray());
+
+			return meta ?? new RValue(new RValue[] { new RValue(new CallbackFunction(__next_i)), table, new RValue(0) });
+		}
+
+		// pairs (t)
+		// -------------------------------------------------------------------------------------------------------------------
+		// If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call.
+		// Otherwise, returns three values: the next function, the table t, and nil, so that the construction
+		//     for k,v in pairs(t) do body end
+		// will iterate over all key–value pairs of table t.
+		// See function next for the caveats of modifying the table during its traversal. 
+		[MoonSharpMethod]
+		public static RValue pairs(IExecutionContext executionContext, CallbackArguments args) 
+		{
+			RValue table = args[0];
+
+			RValue meta = executionContext.GetMetamethodTailCall(table, "__pairs", args.ToArray());
+
+			return meta ?? new RValue(new RValue[] { new RValue(new CallbackFunction(next)), table });
+		}
+
+		// next (table [, index])
+		// -------------------------------------------------------------------------------------------------------------------
+		// Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an 
+		// index in this table. next returns the next index of the table and its associated value. 
+		// When called with nil as its second argument, next returns an initial index and its associated value. 
+		// When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, 
+		// then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.
+		// The order in which the indices are enumerated is not specified, even for numeric indices. 
+		// (To traverse a table in numeric order, use a numerical for.)
+		// The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. 
+		// You may however modify existing fields. In particular, you may clear existing fields. 
+		[MoonSharpMethod]
+		public static RValue next(IExecutionContext executionContext, CallbackArguments args) 
+		{
+			RValue table = args.AsType(0, "next", DataType.Table);
+			RValue index = args[1];
+
+			TablePair pair = table.Table.NextKey(index);
+
+			return new RValue(new RValue[] { pair.Key, pair.Value });
+		}
+
+		// __next_i (table [, index])
+		// -------------------------------------------------------------------------------------------------------------------
+		// Allows a program to traverse all fields of an array. index is an integer number
+		private static RValue __next_i(IExecutionContext executionContext, CallbackArguments args) 
+		{
+			RValue table = args.AsType(0, "__next_i", DataType.Table);
+			RValue index = args.AsType(1, "__next_i", DataType.Number);
+
+			int idx = ((int)index.Number) + 1;
+			RValue val = table.Table[idx];
+			
+			if (val.Type != DataType.Nil)
+			{
+				return new RValue(new RValue[] { new RValue(idx), val });
+			}
+			else
+			{
+				return RValue.Nil;
+			}
+		}
+	}
+}

+ 58 - 0
src/MoonSharp.Interpreter/Execution/DataTypes/CallbackArguments.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Execution
+{
+	public class CallbackArguments
+	{
+		IList<RValue> m_Args;
+
+		public CallbackArguments(IList<RValue> args)
+		{
+			m_Args = args;
+		}
+
+		public int Count
+		{
+			get { return m_Args.Count; }
+		}
+
+		public RValue this[int index]
+		{
+			get 
+			{
+				if (index < m_Args.Count)
+					return m_Args[index];
+
+				return RValue.Nil;
+			}
+		}
+
+		public IList<RValue> List { get { return m_Args; } }
+
+		public RValue[] ToArray()
+		{
+			return List.ToArray();
+		}
+
+		public void ThrowBadArgument(int argNum, string funcName, object expected, object got)
+		{
+			// bad argument #1 to 'next' (table expected, got number)
+			throw new ScriptRuntimeException(null, "bad argument #{0} to '{1}' ({2} expected, got {3}",
+				argNum + 1, funcName, expected, got);
+		}
+
+		public RValue AsType(int argNum, string funcName, DataType type)
+		{
+			if (this[argNum].Type != type)
+				ThrowBadArgument(argNum, funcName, type, this[argNum].Type);
+
+			return this[argNum];
+		}
+
+
+
+	}
+}

+ 4 - 4
src/MoonSharp.Interpreter/Execution/DataTypes/CallbackFunction.cs

@@ -7,16 +7,16 @@ namespace MoonSharp.Interpreter.Execution
 {
 	public sealed class CallbackFunction
 	{
-		Func<IList<RValue>, RValue> m_CallBack;
+		Func<IExecutionContext, CallbackArguments, RValue> m_CallBack;
 
-		public CallbackFunction(Func<IList<RValue>, RValue> callBack)
+		public CallbackFunction(Func<IExecutionContext, CallbackArguments, RValue> callBack)
 		{
 			m_CallBack = callBack;
 		}
 
-		public RValue Invoke(IList<RValue> args)
+		public RValue Invoke(IExecutionContext executionContext, IList<RValue> args)
 		{
-			return m_CallBack(args);
+			return m_CallBack(executionContext, new  CallbackArguments(args));
 		}
 
 	}

+ 8 - 5
src/MoonSharp.Interpreter/Execution/DataTypes/DataType.cs

@@ -8,6 +8,7 @@ namespace MoonSharp.Interpreter.Execution
 {
 	public enum DataType
 	{
+		// standard Lua types
 		Nil,
 		Boolean,
 		Number,
@@ -15,12 +16,12 @@ namespace MoonSharp.Interpreter.Execution
 		Function,
 		Table,
 		Tuple,
+		UserData,
+		Thread,
 
 		Symbol,
 		ClrFunction,
-
-		UNSUPPORTED_UserData,
-		UNSUPPORTED_Thread,
+		TailCallRequest,
 	}
 
 	public static class LuaTypeExtensions
@@ -43,11 +44,13 @@ namespace MoonSharp.Interpreter.Execution
 					return "function";
 				case DataType.Table:
 					return "table";
-				case DataType.UNSUPPORTED_UserData:
+				case DataType.UserData:
 					return "userdata";
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.Thread:
 					return "thread";
 				case DataType.Tuple:
+				case DataType.TailCallRequest:
+				case DataType.Symbol:
 				default:
 					throw new ScriptRuntimeException(null, "Unexpected LuaType {0}", type);
 			}

+ 49 - 73
src/MoonSharp.Interpreter/Execution/DataTypes/RValue.cs

@@ -23,120 +23,78 @@ namespace MoonSharp.Interpreter.Execution
 		public bool Boolean { get; private set; }
 		public string String { get; private set; }
 		public bool ReadOnly { get; internal set; }
-
 		public LRef Symbol { get; private set; }
-
-
+		public CallbackFunction Callback { get; set; }
+		public RValue Meta { get; private set; }
 
 		private int m_HashCode = -1;
 
 		public RValue()
 		{
-			AssignNil();
+			Type = DataType.Nil;
 		}
+
 		public RValue(bool v)
 		{
-			Assign(v);
+			Boolean = v;
+			Type = DataType.Boolean;
 		}
 		public RValue(double num)
 		{
-			Assign(num);
+			Number = num;
+			Type = DataType.Number;
+			m_HashCode = -1;
 		}
+
 		public RValue(LRef symbol)
 		{
 			this.Symbol = symbol;
 			this.Type = DataType.Symbol;
 		}
 
-
 		public RValue(string str)
 		{
-			Assign(str);
-		}
-
-
-		public RValue(Closure function)
-		{
-			Assign(function);
-		}
-
-		public RValue(CallbackFunction function)
-		{
-			Assign(function);
-		}
-
-		public RValue(Table table)
-		{
-			Assign(table);
-		}
-
-		public RValue(RValue[] tuple)
-		{
-			Assign(tuple);
-		}
-
-		private void AssignNil()
-		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
-			Type = DataType.Nil;
-			m_HashCode = -1;
-		}
-		private void Assign(bool v)
-		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
-			Boolean = v;
-			Type = DataType.Boolean;
-			m_HashCode = -1;
-		}
-		public void Assign(double num)
-		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
-			Number = num;
-			Type = DataType.Number;
-			m_HashCode = -1;
-		}
-
-		private void Assign(string str)
-		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
 			String = str;
 			Type = DataType.String;
 			m_HashCode = -1;
 		}
 
-		private void Assign(Closure function)
+
+		public RValue(Closure function)
 		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
 			Function = function;
 			Type = DataType.Function;
 			m_HashCode = -1;
 		}
 
-		private void Assign(CallbackFunction function)
+		public RValue(CallbackFunction function)
 		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
 			Callback = function;
 			Type = DataType.ClrFunction;
 			m_HashCode = -1;
 		}
 
-		private void Assign(Table table)
+		public RValue(Table table)
 		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
 			Table = table;
 			Type = DataType.Table;
 			m_HashCode = -1;
 		}
 
-		public void Assign(RValue[] tuple)
+		public RValue(RValue tailFn, params RValue[] args)
+		{
+			Meta = tailFn;
+			Tuple = args;
+			Type = DataType.TailCallRequest;
+		}
+
+		public RValue(RValue[] tuple)
 		{
-			if (this.ReadOnly) throw new ScriptRuntimeException(null, "Writing on r-value");
 			Tuple = tuple;
 			Type = DataType.Tuple;
 			m_HashCode = -1;
 		}
 
-
 		public RValue AsReadOnly()
 		{
 			if (ReadOnly)
@@ -164,6 +122,7 @@ namespace MoonSharp.Interpreter.Execution
 			v.Table = this.Table;
 			v.Tuple = this.Tuple;
 			v.Type = this.Type;
+			v.Meta = this.Meta;
 			v.m_HashCode = this.m_HashCode;
 			return v;
 		}
@@ -183,6 +142,7 @@ namespace MoonSharp.Interpreter.Execution
 			v.Table = this.Table;
 			v.Tuple = this.Tuple;
 			v.Type = this.Type;
+			v.Meta = this.Meta;
 			v.m_HashCode = this.m_HashCode;
 			return v;
 		}
@@ -210,9 +170,11 @@ namespace MoonSharp.Interpreter.Execution
 					return string.Join("\t", Tuple.Select(t => t.AsString()).ToArray());
 				case DataType.Symbol:
 					return "(Symbol -- INTERNAL!)";
-				case DataType.UNSUPPORTED_UserData:
+				case DataType.TailCallRequest:
+					return "(TailCallRequest -- INTERNAL!)";
+				case DataType.UserData:
 					return "(UserData)";
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.Thread:
 					return "(Thread)";
 				default:
 					return ToString();
@@ -239,11 +201,13 @@ namespace MoonSharp.Interpreter.Execution
 					return "(Table)";
 				case DataType.Tuple:
 					return string.Join(", ", Tuple.Select(t => t.ToString()).ToArray());
+				case DataType.TailCallRequest:
+					return "Tail:(" + string.Join(", ", Tuple.Select(t => t.ToString()).ToArray()) + ")";
 				case DataType.Symbol:
 					return Symbol.ToString();
-				case DataType.UNSUPPORTED_UserData:
+				case DataType.UserData:
 					return "(UserData)";
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.Thread:
 					return "(Thread)";
 				default:
 					return "(???)";
@@ -281,10 +245,11 @@ namespace MoonSharp.Interpreter.Execution
 					m_HashCode = baseValue ^ Table.GetHashCode();
 					break;
 				case DataType.Tuple:
+				case DataType.TailCallRequest:
 					m_HashCode = baseValue ^ Tuple.GetHashCode();
 					break;
-				case DataType.UNSUPPORTED_UserData:
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.UserData:
+				case DataType.Thread:
 				default:
 					m_HashCode = 999;
 					break;
@@ -317,9 +282,10 @@ namespace MoonSharp.Interpreter.Execution
 				case DataType.Table:
 					return Table == other.Table;
 				case DataType.Tuple:
+				case DataType.TailCallRequest:
 					return Tuple == other.Tuple;
-				case DataType.UNSUPPORTED_UserData:
-				case DataType.UNSUPPORTED_Thread:
+				case DataType.UserData:
+				case DataType.Thread:
 				default:
 					return object.ReferenceEquals(this, other);
 			}
@@ -423,6 +389,7 @@ namespace MoonSharp.Interpreter.Execution
 			this.Table = value.Table;
 			this.Tuple = value.Tuple;
 			this.Type = value.Type;
+			this.Meta = value.Meta;
 			this.m_HashCode = -1;
 		}
 
@@ -440,7 +407,16 @@ namespace MoonSharp.Interpreter.Execution
 
 
 
-		public CallbackFunction Callback { get; set; }
+
+		internal void AssignNumber(double num)
+		{
+			if (this.ReadOnly)
+				throw new InternalErrorException(null, "Writing on r-value");
+
+			if (this.Type != DataType.Number)
+				throw new InternalErrorException("Can't assign number to type {0}", this.Type);
+			this.Number = num;
+		}
 	}
 
 

+ 46 - 23
src/MoonSharp.Interpreter/Execution/DataTypes/Table.cs

@@ -72,16 +72,8 @@ namespace MoonSharp.Interpreter.Execution
 					}
 				}
 				
-				if (value.Type == DataType.Nil)
-				{
-					m_ValueMap.Remove(key);
-					m_CachedLength = -1;
-				}
-				else
-				{
-					if (m_ValueMap.Set(key, new TablePair(key, value)))
-						m_CachedLength = -1;
-				}
+				if (m_ValueMap.Set(key, new TablePair(key, value)))
+					CollectDeadKeys();
 			}
 		}
 
@@ -101,17 +93,22 @@ namespace MoonSharp.Interpreter.Execution
 			}
 			set
 			{
-				if (value.Type == DataType.Nil)
-				{
-					m_StringMap.Remove(key);
-				}
-				else
-				{
-					m_StringMap.Set(key, new TablePair(new RValue(key), value));
-				}
+				if (m_StringMap.Set(key, new TablePair(new RValue(key), value)))
+					CollectDeadKeys();
 			}
 		}
 
+
+		public RValue RawGet(string key)
+		{
+			var linkedListNode = m_StringMap.Find(key);
+
+			if (linkedListNode != null)
+				return linkedListNode.Value.Value;
+
+			return null;
+		}
+
 		public RValue this[int key]
 		{
 			get
@@ -120,13 +117,38 @@ namespace MoonSharp.Interpreter.Execution
 			}
 			set
 			{
-				if (value.Type == DataType.Nil)
+				if (m_ArrayMap.Set(key, new TablePair(new RValue(key), value)))
 				{
-					m_ArrayMap.Remove(key);
+					CollectDeadKeys();
+					m_CachedLength = -1;
 				}
-				else
+			}
+		}
+
+		private void CollectDeadKeys()
+		{
+			for (LinkedListNode<TablePair> node = m_Values.First; node != null; node = node.Next)
+			{
+				if (node.Value.Value.Type == DataType.Nil)
 				{
-					m_ArrayMap.Set(key, new TablePair(new RValue(key), value));
+					if (node.Value.Key.Type == DataType.Number)
+					{
+						int idx = GetIntegralKey(node.Value.Key.Number);
+						if (idx > 0)
+						{
+							m_ArrayMap.Remove(idx);
+							continue;
+						}
+					}
+
+					if (node.Value.Key.Type == DataType.String)
+					{
+						m_StringMap.Remove(node.Value.Key.String);
+					}
+					else
+					{
+						m_ValueMap.Remove(node.Value.Key);
+					}
 				}
 			}
 		}
@@ -168,7 +190,7 @@ namespace MoonSharp.Interpreter.Execution
 
 		private TablePair GetNextOf(LinkedListNode<TablePair> linkedListNode)
 		{
-			if (linkedListNode == null)
+			if (linkedListNode == null || linkedListNode.Next == null)
 				return TablePair.Nil;
 
 			return linkedListNode.Next.Value;
@@ -196,5 +218,6 @@ namespace MoonSharp.Interpreter.Execution
 		}
 
 
+
 	}
 }

+ 2 - 0
src/MoonSharp.Interpreter/Execution/Script.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using MoonSharp.Interpreter.CoreLib;
 using MoonSharp.Interpreter.Debugging;
 using MoonSharp.Interpreter.Diagnostics;
 using MoonSharp.Interpreter.Execution.VM;
@@ -46,6 +47,7 @@ namespace MoonSharp.Interpreter.Execution
 			}
 		}
 
+
 		public void AttachDebugger(IDebugger debugger)
 		{
 			if (debugger != null)

+ 3 - 2
src/MoonSharp.Interpreter/Execution/VM/Chunk.cs

@@ -67,9 +67,10 @@ namespace MoonSharp.Interpreter.Execution.VM
 			return Emit(new Instruction() { OpCode = OpCode.Pop, NumVal = num });
 		}
 
-		public Instruction Call(int argCount)
+		public void Call(int argCount)
 		{
-			return Emit(new Instruction() { OpCode = OpCode.Call, NumVal = argCount });
+			Emit(new Instruction() { OpCode = OpCode.Call, NumVal = argCount });
+			Emit(new Instruction() { OpCode = OpCode.TailChk });
 		}
 
 		public Instruction Load(LRef symref)

+ 1 - 0
src/MoonSharp.Interpreter/Execution/VM/OpCode.cs

@@ -31,6 +31,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		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 Moon# 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.
 		Ret,		// Pops the top n values of the v-stack. Then pops an X value from the v-stack. Then pops X values from the v-stack. Afterwards, it pushes the top n values popped in the first step, pops the top of the x-stack and jumps to that location.
+		TailChk,	// Checks if the return value from a Ret or Clr call is a tail call request, in case it repeats the call 
 
 		// Jumps
 		Jump,		// Jumps to the specified PC

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

@@ -11,8 +11,6 @@ namespace MoonSharp.Interpreter.Execution.VM
 	{
 		Chunk m_RootChunk;
 		Chunk m_CurChunk;
-		int m_InstructionPtr;
-		bool m_Terminate = false;
 
 		FastStack<RValue> m_ValueStack = new FastStack<RValue>(131072);
 		FastStack<CallStackItem> m_ExecutionStack = new FastStack<CallStackItem>(131072);
@@ -26,13 +24,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 		public Processor(Chunk rootChunk)
 		{
 			m_RootChunk = m_CurChunk = rootChunk;
-			m_InstructionPtr = 0;
 		}
 
 		public void Reset(Table global)
 		{
 			m_CurChunk = m_RootChunk;
-			m_InstructionPtr = 0;
 			m_GlobalTable = global;
 		}
 
@@ -47,7 +43,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				ReturnAddress = -1,
 			});
 
-			return Processing_Loop();
+			return Processing_Loop(0);
 		}
 	}
 }

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

@@ -17,7 +17,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 			m_DebuggerAttached = debugger;
 		}
 
-		private void ListenDebugger(Instruction instr)
+		private void ListenDebugger(Instruction instr, int instructionPtr)
 		{
 			if (instr.Breakpoint)
 			{
@@ -28,14 +28,14 @@ namespace MoonSharp.Interpreter.Execution.VM
 			if (m_DebuggerCurrentAction == DebuggerAction.ActionType.Run)
 				return;
 
-			if (m_DebuggerCurrentAction == DebuggerAction.ActionType.StepOver && m_DebuggerCurrentActionTarget != m_InstructionPtr)
+			if (m_DebuggerCurrentAction == DebuggerAction.ActionType.StepOver && m_DebuggerCurrentActionTarget != instructionPtr)
 				return;
 
 			RefreshDebugger();
 
 			while (true)
 			{
-				var action = m_DebuggerAttached.GetAction(m_InstructionPtr);
+				var action = m_DebuggerAttached.GetAction(instructionPtr);
 
 				switch (action.Action)
 				{
@@ -45,7 +45,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 						return;
 					case DebuggerAction.ActionType.StepOver:
 						m_DebuggerCurrentAction = DebuggerAction.ActionType.StepOver;
-						m_DebuggerCurrentActionTarget = m_InstructionPtr + 1;
+						m_DebuggerCurrentActionTarget = instructionPtr + 1;
 						return;
 					case DebuggerAction.ActionType.Run:
 						m_DebuggerCurrentAction = DebuggerAction.ActionType.Run;

+ 45 - 0
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+	sealed partial class Processor : IExecutionContext
+	{
+		RValue IExecutionContext.GetVar(LRef symref)
+		{
+			return this.GetGenericSymbol(symref);
+		}
+
+		void IExecutionContext.SetVar(LRef symref, RValue value)
+		{
+			AssignGenericSymbol(symref, value);
+		}
+
+		LRef IExecutionContext.FindVar(string name)
+		{
+			return FindRefByName(name);
+		}
+
+		RValue IExecutionContext.GetMetamethod(RValue value, string metamethod)
+		{
+			if (value.Meta == null)
+				return null;
+
+			if (value.Meta.Type != DataType.Table)
+				throw new InternalErrorException("Metatable is not a table!");
+
+			return value.Meta.Table.RawGet(metamethod);
+		}
+
+		RValue IExecutionContext.GetMetamethodTailCall(RValue value, string metamethod, params RValue[] args)
+		{
+			RValue meta = ((IExecutionContext)this).GetMetamethod(value, metamethod);
+
+			if (meta == null) return null;
+
+			return new RValue(meta, args);
+		}
+	}
+}

+ 71 - 38
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs

@@ -9,18 +9,18 @@ namespace MoonSharp.Interpreter.Execution.VM
 {
 	sealed partial class Processor
 	{
-		private RValue Processing_Loop()
+		private RValue Processing_Loop(int instructionPtr)
 		{
 			while (true)
 			{
-				Instruction i = m_CurChunk.Code[m_InstructionPtr];
+				Instruction i = m_CurChunk.Code[instructionPtr];
 
 				if (m_DebuggerAttached != null)
 				{
-					ListenDebugger(i);
+					ListenDebugger(i, instructionPtr);
 				}
 
-				++m_InstructionPtr;
+				++instructionPtr;
 
 				switch (i.OpCode)
 				{
@@ -67,20 +67,28 @@ namespace MoonSharp.Interpreter.Execution.VM
 						ExecLess(i);
 						break;
 					case OpCode.Call:
-						ExecCall(i);
+						instructionPtr = Internal_ExecCall(i.NumVal, instructionPtr);
 						break;
-					case OpCode.Jf:
-						JumpBool(i, false);
+					case OpCode.TailChk:
+						instructionPtr = ExecTailChk(i, instructionPtr);
 						break;
 					case OpCode.Not:
 						ExecNot(i);
 						break;
 					case OpCode.JfOrPop:
 					case OpCode.JtOrPop:
-						ExecShortCircuitingOperator(i);
+						instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
 						break;
 					case OpCode.JNil:
-						ExecJNil(i);
+						{
+							RValue v = m_ValueStack.Pop();
+
+							if (v.Type == DataType.Nil)
+								instructionPtr = i.NumVal;
+						}
+						break;
+					case OpCode.Jf:
+						instructionPtr = JumpBool(i, false, instructionPtr);
 						break;
 					case OpCode.Store:
 						ExecStore(i);
@@ -92,7 +100,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 						ExecAssign(i);
 						break;
 					case OpCode.Jump:
-						m_InstructionPtr = i.NumVal;
+						instructionPtr = i.NumVal;
 						break;
 					case OpCode.MkTuple:
 						m_ValueStack.Push(RValue.FromPotentiallyNestedTuple(StackTopToArrayReverse(i.NumVal, true)));
@@ -114,8 +122,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 						ExecArgs(i);
 						break;
 					case OpCode.Ret:
-						ExecRet(i);
-						if (m_InstructionPtr < 0)
+						instructionPtr = ExecRet(i);
+						if (instructionPtr < 0)
 							goto return_to_native_code;
 						break;
 					case OpCode.Incr:
@@ -128,7 +136,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 						ExecSymStorN(i);
 						break;
 					case OpCode.JFor:
-						ExecJFor(i);
+						instructionPtr = ExecJFor(i, instructionPtr);
 						break;
 					case OpCode.Index:
 						ExecIndexGet(i, false);
@@ -177,13 +185,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 
-		private void ExecJNil(Instruction i)
-		{
-			RValue v = m_ValueStack.Pop();
 
-			if (v.Type == DataType.Nil)
-				m_InstructionPtr = i.NumVal;
-		}
 
 		private void ExecIterUpd(Instruction i)
 		{
@@ -233,7 +235,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		}
 
 
-		private void ExecJFor(Instruction i)
+		private int ExecJFor(Instruction i, int instructionPtr)
 		{
 			double val = m_ValueStack.Peek(0).Number;
 			double step = m_ValueStack.Peek(1).Number;
@@ -242,7 +244,9 @@ namespace MoonSharp.Interpreter.Execution.VM
 			bool whileCond = (step > 0) ? val <= stop : val >= stop;
 
 			if (!whileCond)
-				m_InstructionPtr = i.NumVal;
+				return i.NumVal;
+			else
+				return instructionPtr;
 		}
 
 
@@ -259,7 +263,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				m_ValueStack.Push(top);
 			}
 
-			top.Assign(top.Number + btm.Number);
+			top.AssignNumber(top.Number + btm.Number);
 		}
 
 
@@ -271,7 +275,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		}
 
 
-		private void ExecRet(Instruction i)
+		private int ExecRet(Instruction i)
 		{
 			if (i.NumVal == 0)
 			{
@@ -279,7 +283,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				var argscnt = (int)(m_ValueStack.Pop().Number);
 				m_ValueStack.RemoveLast(argscnt + 1);
 				m_ValueStack.Push(RValue.Nil);
-				m_InstructionPtr = retpoint;
+				return retpoint;
 			}
 			else if (i.NumVal == 1)
 			{
@@ -288,7 +292,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				var argscnt = (int)(m_ValueStack.Pop().Number);
 				m_ValueStack.RemoveLast(argscnt + 1);
 				m_ValueStack.Push(retval);
-				m_InstructionPtr = retpoint;
+				return retpoint;
 			}
 			else
 			{
@@ -344,29 +348,29 @@ namespace MoonSharp.Interpreter.Execution.VM
 			}
 		}
 
-		private void ExecCall(Instruction i)
+		private int Internal_ExecCall(int argsCount, int instructionPtr)
 		{
-			RValue fn = m_ValueStack.Peek(i.NumVal);
+			RValue fn = m_ValueStack.Peek(argsCount);
 
 			if (fn.Type == DataType.ClrFunction)
 			{
-				IList<RValue> args = new Slice<RValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
-				//m_ValueStack.Pop();
-				var ret = fn.Callback.Invoke(args);
-				m_ValueStack.RemoveLast(i.NumVal + 1);
+				IList<RValue> args = new Slice<RValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
+				var ret = fn.Callback.Invoke(this, args);
+				m_ValueStack.RemoveLast(argsCount + 1);
 				m_ValueStack.Push(ret);
+				return instructionPtr;
 			}
 			else if (fn.Type == DataType.Function)
 			{
-				m_ValueStack.Push(new RValue(i.NumVal));
+				m_ValueStack.Push(new RValue(argsCount));
 				m_ExecutionStack.Push(new CallStackItem()
 				{
 					BasePointer = m_ValueStack.Count,
-					ReturnAddress = m_InstructionPtr,
+					ReturnAddress = instructionPtr,
 					Debug_EntryPoint = fn.Function.ByteCodeLocation,
 					ClosureScope = fn.Function.ClosureContext
 				});
-				m_InstructionPtr = fn.Function.ByteCodeLocation;
+				return fn.Function.ByteCodeLocation;
 			}
 			else
 			{
@@ -376,25 +380,54 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 
+		private int ExecTailChk(Instruction i, int instructionPtr)
+		{
+			RValue tail = m_ValueStack.Peek(0);
+
+			if (tail.Type == DataType.TailCallRequest)
+			{
+				m_ValueStack.Pop(); // discard tail call request
+
+				m_ValueStack.Push(tail.Meta);
+
+				for (int ii = 0; ii < tail.Tuple.Length; ii++ )
+					m_ValueStack.Push(tail.Tuple[ii]);
 
-		private void JumpBool(Instruction i, bool expectedValueForJump)
+				instructionPtr -= 1;
+				return Internal_ExecCall(tail.Tuple.Length, instructionPtr);
+			}
+
+
+			return instructionPtr;
+		}
+
+
+
+		private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
 		{
 			RValue op = m_ValueStack.Pop();
 
 			if (op.TestAsBoolean() == expectedValueForJump)
-				m_InstructionPtr = i.NumVal;
+				return i.NumVal;
+
+			return instructionPtr;
 		}
 
-		private void ExecShortCircuitingOperator(Instruction i)
+		private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
 		{
 			bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
 
 			RValue op = m_ValueStack.Peek();
 
 			if (op.TestAsBoolean() == expectedValToShortCircuit)
-				m_InstructionPtr = i.NumVal;
+			{
+				return i.NumVal;
+			}
 			else
+			{
 				m_ValueStack.Pop();
+				return instructionPtr;
+			}
 		}
 
 		private void Bool(Instruction i)

+ 70 - 0
src/MoonSharp.Interpreter/Modules/ModuleRegister.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using MoonSharp.Interpreter.Execution;
+
+namespace MoonSharp.Interpreter
+{
+	public static class ModuleRegister
+	{
+		public static Table RegisterModuleType(this Table table, Type t)
+		{
+			foreach (MethodInfo mi in t.GetMethods(BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public).Where(_mi => _mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0))
+			{
+				MoonSharpMethodAttribute attr = (MoonSharpMethodAttribute)mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).First();
+
+				ParameterInfo[] pi = mi.GetParameters();
+
+				if (pi.Length != 2 || pi[0].ParameterType != typeof(IExecutionContext)
+					|| pi[1].ParameterType != typeof(CallbackArguments) || mi.ReturnType != typeof(RValue))
+				{
+					throw new ArgumentException(string.Format("Method {0} does not have the right signature.", mi.Name));
+				}
+
+				Func<IExecutionContext, CallbackArguments, RValue> func = (Func<IExecutionContext, CallbackArguments, RValue>)Delegate.CreateDelegate(typeof(Func<IExecutionContext, CallbackArguments, RValue>), mi);
+
+				string name = (!string.IsNullOrEmpty(attr.Name)) ? attr.Name : mi.Name;
+
+				table[name] = new RValue(new CallbackFunction(func));
+			}
+
+			return table;
+		}
+
+		public static Table RegisterModuleType<T>(this Table table)
+		{
+			return RegisterModuleType(table, typeof(T));
+		}
+
+		public static Table RegisterModuleObject(this Table table, object o)
+		{
+			Type t = o.GetType();
+
+			foreach (MethodInfo mi in t.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Public).Where(_mi => _mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0))
+			{
+				MoonSharpMethodAttribute attr = (MoonSharpMethodAttribute)mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).First();
+
+				ParameterInfo[] pi = mi.GetParameters();
+
+				if (pi.Length != 2 || pi[0].ParameterType != typeof(IExecutionContext)
+					|| pi[1].ParameterType != typeof(CallbackArguments) || mi.ReturnType != typeof(RValue))
+				{
+					throw new ArgumentException(string.Format("Method {0} does not have the right signature.", mi.Name));
+				}
+
+				Func<IExecutionContext, CallbackArguments, RValue> func = (Func<IExecutionContext, CallbackArguments, RValue>)
+					Delegate.CreateDelegate(typeof(Func<IExecutionContext, CallbackArguments, RValue>), o, mi);
+
+				string name = (!string.IsNullOrEmpty(attr.Name)) ? attr.Name : mi.Name;
+
+				table[name] = new RValue(new CallbackFunction(func));
+			}
+
+			return table;
+		}
+
+
+	}
+}

+ 13 - 0
src/MoonSharp.Interpreter/Modules/MoonSharpMethodAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter
+{
+	[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
+	public sealed class MoonSharpMethodAttribute : Attribute
+	{
+		public string Name { get; set; }
+	}
+}

+ 13 - 0
src/MoonSharp.Interpreter/Modules/MoonSharpModuleAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter
+{
+	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
+	public sealed class MoonSharpModuleAttribute : Attribute
+	{
+		public string Namespace { get; set; }
+	}
+}

+ 11 - 0
src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj

@@ -76,6 +76,7 @@
     <Compile Include="CoreLib\BasicMethods.cs" />
     <Compile Include="CoreLib\CoreLibModule.cs" />
     <Compile Include="CoreLib\MetaTableMethods.cs" />
+    <Compile Include="CoreLib\TableIterators.cs" />
     <Compile Include="DataStructs\Extension_Methods.cs" />
     <Compile Include="DataStructs\FastStackDynamic.cs" />
     <Compile Include="DataStructs\LinkedListIndex.cs" />
@@ -91,9 +92,11 @@
     <Compile Include="Diagnostics\CodeChrono.cs" />
     <Compile Include="Errors\ScriptRuntimeException.cs" />
     <Compile Include="Errors\SyntaxErrorException.cs" />
+    <Compile Include="Execution\DataTypes\CallbackArguments.cs" />
     <Compile Include="Execution\DataTypes\Closure.cs" />
     <Compile Include="Execution\DataTypes\CallbackFunction.cs" />
     <Compile Include="Execution\DataTypes\TablePair.cs" />
+    <Compile Include="Execution\IExecutionContext.cs" />
     <Compile Include="Execution\Scopes\ClosureContext.cs" />
     <Compile Include="Execution\Scopes\LoopTracker.cs" />
     <Compile Include="Execution\Scopes\IClosureBuilder.cs" />
@@ -119,6 +122,7 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Execution\VM\Processor\Processor_Debugger.cs" />
+    <Compile Include="Execution\VM\Processor\Processor_IExecutionContext.cs" />
     <Compile Include="Execution\VM\Processor\Processor_InstructionLoop.cs" />
     <Compile Include="Execution\VM\Processor\Processor_Scope.cs" />
     <Compile Include="Execution\VM\Processor\Processor_UtilityFunctions.cs" />
@@ -128,6 +132,13 @@
     <Compile Include="Grammar\Lua.g4.parser.cs">
       <DependentUpon>Lua.g4</DependentUpon>
     </Compile>
+    <Compile Include="Modules\ModuleRegister.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Modules\MoonSharpMethodAttribute.cs" />
+    <Compile Include="Modules\MoonSharpModuleAttribute.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="Tree\IVariable.cs" />
     <Compile Include="MoonSharpInterpreter.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />

+ 3 - 3
src/MoonSharp/Program.cs

@@ -11,14 +11,14 @@ namespace MoonSharp
 {
 	class Program
 	{
-		static RValue Print(IList<RValue> values)
+		static RValue Print(IExecutionContext executionContext, CallbackArguments values)
 		{
-			string prn = string.Join(" ", values.Select(v => v.AsString()).ToArray());
+			string prn = string.Join(" ", values.List.Select(v => v.AsString()).ToArray());
 			Console.WriteLine("{0}", prn);
 			return RValue.Nil;
 		}
 
-		static RValue Read(IList<RValue> values)
+		static RValue Read(IExecutionContext executionContext, CallbackArguments values)
 		{
 			double d = double.Parse(Console.ReadLine());
 			return new RValue(d);

+ 4 - 4
src/PerformanceComparison/Program.cs

@@ -21,7 +21,7 @@ namespace PerformanceComparison
 		const int ITERATIONS = 1;
 #endif
 
-		static  string scriptText2 = @"
+		static  string scriptText = @"
 			function move(n, src, dst, via)
 				if n > 0 then
 					move(n - 1, src, via, dst)
@@ -34,7 +34,7 @@ namespace PerformanceComparison
 				move(4, 1, 2, 3)
 			end
 			";
-		static  string scriptText = @"
+		static  string scriptText2 = @"
 N = 8
  
 board = {}
@@ -86,9 +86,9 @@ end
 		static StringBuilder g_MoonSharpStr = new StringBuilder();
 		static StringBuilder g_NLuaStr = new StringBuilder();
 
-		public static RValue Print(IList<RValue> values)
+		public static RValue Print(IExecutionContext executionContext, CallbackArguments values)
 		{
-			foreach (var val in values)
+			foreach (var val in values.List)
 			{
 				g_MoonSharpStr.Append(val.AsString());
 			}