Browse Source

Void type, LuaState emulation begun

Xanathar 11 years ago
parent
commit
276651b245
35 changed files with 1853 additions and 125 deletions
  1. 2 2
      src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs
  2. 1 1
      src/MoonSharp.Interpreter.Tests/EndToEnd/StringLibTests.cs
  3. 7 2
      src/MoonSharp.Interpreter.Tests/EndToEnd/Utils.cs
  4. 3 0
      src/MoonSharp.Interpreter/CoreLib/BasicMethods.cs
  5. 2 3
      src/MoonSharp.Interpreter/CoreLib/CoroutineMethods.cs
  6. 9 2
      src/MoonSharp.Interpreter/CoreLib/StringLib/CaptureInfo.cs
  7. 987 0
      src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs
  8. 7 2
      src/MoonSharp.Interpreter/CoreLib/StringLib/MatchState.cs
  9. 18 10
      src/MoonSharp.Interpreter/CoreLib/StringLib/PatternMatching.cs
  10. 1 1
      src/MoonSharp.Interpreter/CoreLib/StringLib/StringRange.cs
  11. 0 0
      src/MoonSharp.Interpreter/CoreLib/StringLib/Tools.cs
  12. 1 1
      src/MoonSharp.Interpreter/CoreLib/StringModule.cs
  13. 2 2
      src/MoonSharp.Interpreter/CoreLib/TableModule.cs
  14. 8 8
      src/MoonSharp.Interpreter/DataStructs/FastStackDynamic.cs
  15. 24 12
      src/MoonSharp.Interpreter/DataTypes/CallbackArguments.cs
  16. 3 2
      src/MoonSharp.Interpreter/DataTypes/CallbackFunction.cs
  17. 7 0
      src/MoonSharp.Interpreter/DataTypes/DataType.cs
  18. 140 21
      src/MoonSharp.Interpreter/DataTypes/DynValue.cs
  19. 2 2
      src/MoonSharp.Interpreter/DataTypes/Table.cs
  20. 1 1
      src/MoonSharp.Interpreter/DataTypes/TablePair.cs
  21. 16 0
      src/MoonSharp.Interpreter/DataTypes/TypeValidationFlags.cs
  22. 49 32
      src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs
  23. 3 3
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs
  24. 9 8
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
  25. 1 1
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_UtilityFunctions.cs
  26. 15 0
      src/MoonSharp.Interpreter/Interop/ConversionHelper.cs
  27. 221 0
      src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs
  28. 218 0
      src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs
  29. 21 0
      src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaLBuffer.cs
  30. 51 0
      src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs
  31. 9 0
      src/MoonSharp.Interpreter/Interop/UserDataMethodDescriptor.cs
  32. 11 5
      src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj
  33. 2 2
      src/PerformanceComparison/CallbacksAndForthTests.cs
  34. 1 1
      src/PerformanceComparison/PerformanceComparison.csproj
  35. 1 1
      src/PerformanceComparison/app.config

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

@@ -27,7 +27,7 @@ namespace MoonSharp.Interpreter.Tests
 
 
 			DynValue res = S.DoString(script);
 			DynValue res = S.DoString(script);
 
 
-			Assert.AreEqual(DataType.Nil, res.Type);
+			Assert.AreEqual(DataType.Void, res.Type);
 			Assert.AreEqual(2, args.Count);
 			Assert.AreEqual(2, args.Count);
 			Assert.AreEqual(DataType.String, args[0].Type);
 			Assert.AreEqual(DataType.String, args[0].Type);
 			Assert.AreEqual("hello", args[0].String);
 			Assert.AreEqual("hello", args[0].String);
@@ -52,7 +52,7 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual("hello", args[0].String);
 			Assert.AreEqual("hello", args[0].String);
 			Assert.AreEqual(DataType.String, args[1].Type);
 			Assert.AreEqual(DataType.String, args[1].Type);
 			Assert.AreEqual("world", args[1].String);
 			Assert.AreEqual("world", args[1].String);
-			Assert.AreEqual(DataType.Nil, res.Type);
+			Assert.AreEqual(DataType.Void, res.Type);
 		}
 		}
 
 
 		[Test]
 		[Test]

+ 1 - 1
src/MoonSharp.Interpreter.Tests/EndToEnd/StringLibTests.cs

@@ -192,7 +192,7 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 				return tostring(t), a;
 				return tostring(t), a;
 			";
 			";
 			DynValue res = Script.RunString(script);
 			DynValue res = Script.RunString(script);
-			Utils.DynAssert(res, null, "yup");
+			Utils.DynAssert(res, DataType.Void, "yup");
 
 
 		}
 		}
 
 

+ 7 - 2
src/MoonSharp.Interpreter.Tests/EndToEnd/Utils.cs

@@ -11,7 +11,8 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 		public static void DynAssert(DynValue result, params object[] args)
 		public static void DynAssert(DynValue result, params object[] args)
 		{
 		{
 			if (args == null)
 			if (args == null)
-				args = new object[1] { null };
+				args = new object[1] { DataType.Void };
+
 
 
 			if (args.Length == 1)
 			if (args.Length == 1)
 			{
 			{
@@ -29,7 +30,11 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 
 
 		private static void DynAssertValue(object reference, DynValue dynValue)
 		private static void DynAssertValue(object reference, DynValue dynValue)
 		{
 		{
-			if (reference == null)
+			if (reference == (object)DataType.Void)
+			{
+				Assert.AreEqual(DataType.Void, dynValue.Type);
+			}
+			else if (reference == null)
 			{
 			{
 				Assert.AreEqual(DataType.Nil, dynValue.Type);
 				Assert.AreEqual(DataType.Nil, dynValue.Type);
 			}
 			}

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

@@ -221,6 +221,9 @@ namespace MoonSharp.Interpreter.CoreLib
 
 
 			for (int i = 0; i < args.Count; i++)
 			for (int i = 0; i < args.Count; i++)
 			{
 			{
+				if (args[i].IsVoid())
+					break;
+
 				if (i != 0)
 				if (i != 0)
 					sb.Append('\t');
 					sb.Append('\t');
 
 

+ 2 - 3
src/MoonSharp.Interpreter/CoreLib/CoroutineMethods.cs

@@ -28,14 +28,13 @@ namespace MoonSharp.Interpreter.CoreLib
 
 
 			DynValue v = create(executionContext, args);
 			DynValue v = create(executionContext, args);
 			DynValue c = DynValue.NewCallback(__wrap_wrapper);
 			DynValue c = DynValue.NewCallback(__wrap_wrapper);
-			c.Callback.Closure = new Table(executionContext.GetScript());
-			c.Callback.Closure.Set("_HANDLE", v);
+			c.Callback.AdditionalData = v;
 			return c;
 			return c;
 		}
 		}
 
 
 		public static DynValue __wrap_wrapper(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue __wrap_wrapper(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			DynValue handle = executionContext.Closure.Get("_HANDLE");
+			DynValue handle = (DynValue)executionContext.AdditionalData;
 			return handle.Coroutine.Resume(args.List.ToArray());
 			return handle.Coroutine.Resume(args.List.ToArray());
 		}
 		}
 
 

+ 9 - 2
src/MoonSharp.Interpreter/CoreLib/Patterns/CaptureInfo.cs → src/MoonSharp.Interpreter/CoreLib/StringLib/CaptureInfo.cs

@@ -1,4 +1,7 @@
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
+#if true
+
+
+// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
 //
 //
 // Copyright (C) 2013 Sheng Lunan
 // Copyright (C) 2013 Sheng Lunan
 //
 //
@@ -19,12 +22,16 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
-namespace MoonSharp.Interpreter.CoreLib.Patterns
+namespace MoonSharp.Interpreter.CoreLib.StringLib
 {
 {
 	class CaptureInfo
 	class CaptureInfo
 	{
 	{
+
 		public int Len;
 		public int Len;
 		public int Init;
 		public int Init;
 	}
 	}
 
 
 }
 }
+
+
+#endif

+ 987 - 0
src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs

@@ -0,0 +1,987 @@
+#if false
+//
+// This part taken from KopiLua - https://github.com/NLua/KopiLua
+//
+// =========================================================================================================
+//
+// Kopi Lua License
+// ----------------
+// MIT License for KopiLua
+// Copyright (c) 2012 LoDC
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all copies or substantial
+// portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ===============================================================================
+// Lua License
+// -----------
+// Lua is licensed under the terms of the MIT license reproduced below.
+// This means that Lua is free software and can be used for both academic
+// and commercial purposes at absolutely no cost.
+// For details and rationale, see http://www.lua.org/license.html .
+// ===============================================================================
+// Copyright (C) 1994-2008 Lua.org, PUC-Rio.
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+
+using ptrdiff_t = System.Int32;
+using lua_Integer = System.Int32;
+using LUA_INTFRM_T = System.Int64;
+using UNSIGNED_LUA_INTFRM_T = System.UInt64;
+using MoonSharp.Interpreter.Interop.LuaStateInterop;
+using MoonSharp.Interpreter.Execution;
+
+namespace MoonSharp.Interpreter.CoreLib.StringLib
+{
+
+	public class Lua : LuaBase
+	{
+		public const int LUA_MAXCAPTURES = 32;
+
+		private static ptrdiff_t posrelat(ptrdiff_t pos, uint len)
+		{
+			/* relative string position: negative means back from end */
+			if (pos < 0) pos += (ptrdiff_t)len + 1;
+			return (pos >= 0) ? pos : 0;
+		}
+
+		/*
+		** {======================================================
+		** PATTERN MATCHING
+		** =======================================================
+		*/
+
+
+		public const int CAP_UNFINISHED = (-1);
+		public const int CAP_POSITION = (-2);
+
+		public class MatchState
+		{
+
+			public MatchState()
+			{
+				for (int i = 0; i < LUA_MAXCAPTURES; i++)
+					capture[i] = new capture_();
+			}
+
+			public int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
+			public CharPtr src_init;  /* init of source string */
+			public CharPtr src_end;  /* end (`\0') of source string */
+			public LuaState L;
+			public int level;  /* total number of captures (finished or unfinished) */
+
+			public class capture_
+			{
+				public CharPtr init;
+				public ptrdiff_t len;
+			};
+			public capture_[] capture = new capture_[LUA_MAXCAPTURES];
+		};
+
+
+		public const int MAXCCALLS = 200;
+		public const char L_ESC = '%';
+		public const string SPECIALS = "^$*+?.([%-";
+
+
+		private static int check_capture(MatchState ms, int l)
+		{
+			l -= '1';
+			if (l < 0 || l >= ms.level || ms.capture[l].len == CAP_UNFINISHED)
+				return LuaLError(ms.L, "invalid capture index {0}", l + 1);
+			return l;
+		}
+
+
+
+		private static int capture_to_close(MatchState ms)
+		{
+			int level = ms.level;
+			for (level--; level >= 0; level--)
+				if (ms.capture[level].len == CAP_UNFINISHED) return level;
+			return LuaLError(ms.L, "invalid pattern capture");
+		}
+
+
+		private static CharPtr classend(MatchState ms, CharPtr p)
+		{
+			p = new CharPtr(p);
+			char c = p[0];
+			p = p.next();
+			switch (c)
+			{
+				case L_ESC:
+					{
+						if (p[0] == '\0')
+							LuaLError(ms.L, "malformed pattern (ends with " + LUA_QL("%%") + ")");
+						return p + 1;
+					}
+				case '[':
+					{
+						if (p[0] == '^') p = p.next();
+						do
+						{  /* look for a `]' */
+							if (p[0] == '\0')
+								LuaLError(ms.L, "malformed pattern (missing " + LUA_QL("]") + ")");
+							c = p[0];
+							p = p.next();
+							if (c == L_ESC && p[0] != '\0')
+								p = p.next();  /* skip escapes (e.g. `%]') */
+						} while (p[0] != ']');
+						return p + 1;
+					}
+				default:
+					{
+						return p;
+					}
+			}
+		}
+
+
+
+		private static int match_class(char c, char cl)
+		{
+			bool res;
+			switch (Char.ToLowerInvariant(cl))
+			{
+				case 'a': res = Char.IsLetter(c); break;
+				case 'c': res = Char.IsControl(c); break;
+				case 'd': res = Char.IsDigit(c); break;
+				case 'l': res = Char.IsLower(c); break;
+				case 'p': res = Char.IsPunctuation(c); break;
+				case 's': res = Char.IsWhiteSpace(c); break;
+				case 'u': res = Char.IsUpper(c); break;
+				case 'w': res = Char.IsLetterOrDigit(c); break;
+				case 'x': res = isxdigit((char)c); break;
+				case 'z': res = (c == 0); break;
+				default: return (cl == c) ? 1 : 0;
+			}
+			return (Char.IsLower(cl) ? (res ? 1 : 0) : ((!res) ? 1 : 0));
+		}
+
+		private static bool isxdigit(char p)
+		{
+			return Char.IsDigit(p) ||
+				p == 'a' || p == 'A' ||
+				p == 'b' || p == 'B' ||
+				p == 'c' || p == 'C' ||
+				p == 'd' || p == 'D' ||
+				p == 'e' || p == 'E' ||
+				p == 'f' || p == 'F';
+		}
+
+
+		private static int matchbracketclass(int c, CharPtr p, CharPtr ec)
+		{
+			int sig = 1;
+			if (p[1] == '^')
+			{
+				sig = 0;
+				p = p.next();  /* skip the `^' */
+			}
+			while ((p = p.next()) < ec)
+			{
+				if (p == L_ESC)
+				{
+					p = p.next();
+					if (match_class((char)c, (char)(p[0])) != 0)
+						return sig;
+				}
+				else if ((p[1] == '-') && (p + 2 < ec))
+				{
+					p += 2;
+					if ((byte)((p[-2])) <= c && (c <= (byte)p[0]))
+						return sig;
+				}
+				else if ((byte)(p[0]) == c) return sig;
+			}
+			return (sig == 0) ? 1 : 0;
+		}
+
+
+		private static int singlematch(int c, CharPtr p, CharPtr ep)
+		{
+			switch (p[0])
+			{
+				case '.': return 1;  /* matches any char */
+				case L_ESC: return match_class((char)c, (char)(p[1]));
+				case '[': return matchbracketclass(c, p, ep - 1);
+				default: return ((byte)(p[0]) == c) ? 1 : 0;
+			}
+		}
+
+
+		private static CharPtr matchbalance(MatchState ms, CharPtr s,
+										   CharPtr p)
+		{
+			if ((p[0] == 0) || (p[1] == 0))
+				LuaLError(ms.L, "unbalanced pattern");
+			if (s[0] != p[0]) return null;
+			else
+			{
+				int b = p[0];
+				int e = p[1];
+				int cont = 1;
+				while ((s = s.next()) < ms.src_end)
+				{
+					if (s[0] == e)
+					{
+						if (--cont == 0) return s + 1;
+					}
+					else if (s[0] == b) cont++;
+				}
+			}
+			return null;  /* string ends out of balance */
+		}
+
+
+		private static CharPtr max_expand(MatchState ms, CharPtr s,
+										 CharPtr p, CharPtr ep)
+		{
+			ptrdiff_t i = 0;  /* counts maximum expand for item */
+			while ((s + i < ms.src_end) && (singlematch((byte)(s[i]), p, ep) != 0))
+				i++;
+			/* keeps trying to match with the maximum repetitions */
+			while (i >= 0)
+			{
+				CharPtr res = match(ms, (s + i), ep + 1);
+				if (res != null) return res;
+				i--;  /* else didn't match; reduce 1 repetition to try again */
+			}
+			return null;
+		}
+
+
+		private static CharPtr min_expand(MatchState ms, CharPtr s,
+										 CharPtr p, CharPtr ep)
+		{
+			for (; ; )
+			{
+				CharPtr res = match(ms, s, ep + 1);
+				if (res != null)
+					return res;
+				else if ((s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0))
+					s = s.next();  /* try with one more repetition */
+				else return null;
+			}
+		}
+
+
+		private static CharPtr start_capture(MatchState ms, CharPtr s,
+											CharPtr p, int what)
+		{
+			CharPtr res;
+			int level = ms.level;
+			if (level >= LUA_MAXCAPTURES) LuaLError(ms.L, "too many captures");
+			ms.capture[level].init = s;
+			ms.capture[level].len = what;
+			ms.level = level + 1;
+			if ((res = match(ms, s, p)) == null)  /* match failed? */
+				ms.level--;  /* undo capture */
+			return res;
+		}
+
+
+		private static CharPtr end_capture(MatchState ms, CharPtr s,
+										  CharPtr p)
+		{
+			int l = capture_to_close(ms);
+			CharPtr res;
+			ms.capture[l].len = s - ms.capture[l].init;  /* close capture */
+			if ((res = match(ms, s, p)) == null)  /* match failed? */
+				ms.capture[l].len = CAP_UNFINISHED;  /* undo capture */
+			return res;
+		}
+
+
+		private static CharPtr match_capture(MatchState ms, CharPtr s, int l)
+		{
+			uint len;
+			l = check_capture(ms, l);
+			len = (uint)ms.capture[l].len;
+			if ((uint)(ms.src_end - s) >= len &&
+				memcmp(ms.capture[l].init, s, len) == 0)
+				return s + len;
+			else return null;
+		}
+
+
+
+		private static CharPtr match(MatchState ms, CharPtr s, CharPtr p)
+		{
+			s = new CharPtr(s);
+			p = new CharPtr(p);
+			if (ms.matchdepth-- == 0)
+				LuaLError(ms.L, "pattern too complex");
+		init: /* using goto's to optimize tail recursion */
+			switch (p[0])
+			{
+				case '(':
+					{  /* start capture */
+						if (p[1] == ')')  /* position capture? */
+							return start_capture(ms, s, p + 2, CAP_POSITION);
+						else
+							return start_capture(ms, s, p + 1, CAP_UNFINISHED);
+					}
+				case ')':
+					{  /* end capture */
+						return end_capture(ms, s, p + 1);
+					}
+				case L_ESC:
+					{
+						switch (p[1])
+						{
+							case 'b':
+								{  /* balanced string? */
+									s = matchbalance(ms, s, p + 2);
+									if (s == null) return null;
+									p += 4; goto init;  /* else return match(ms, s, p+4); */
+								}
+							case 'f':
+								{  /* frontier? */
+									CharPtr ep; char previous;
+									p += 2;
+									if (p[0] != '[')
+										LuaLError(ms.L, "missing " + LUA_QL("[") + " after " +
+														   LUA_QL("%%f") + " in pattern");
+									ep = classend(ms, p);  /* points to what is next */
+									previous = (s == ms.src_init) ? '\0' : s[-1];
+									if ((matchbracketclass((byte)(previous), p, ep - 1) != 0) ||
+									   (matchbracketclass((byte)(s[0]), p, ep - 1) == 0)) return null;
+									p = ep; goto init;  /* else return match(ms, s, ep); */
+								}
+							default:
+								{
+									if (Char.IsDigit((char)(p[1])))
+									{  /* capture results (%0-%9)? */
+										s = match_capture(ms, s, (byte)(p[1]));
+										if (s == null) return null;
+										p += 2; goto init;  /* else return match(ms, s, p+2) */
+									}
+									//ismeretlen hiba miatt lett ide átmásolva
+									{  /* it is a pattern item */
+										CharPtr ep = classend(ms, p);  /* points to what is next */
+										int m = (s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0) ? 1 : 0;
+										switch (ep[0])
+										{
+											case '?':
+												{  /* optional */
+													CharPtr res;
+													if ((m != 0) && ((res = match(ms, s + 1, ep + 1)) != null))
+														return res;
+													p = ep + 1; goto init;  /* else return match(ms, s, ep+1); */
+												}
+											case '*':
+												{  /* 0 or more repetitions */
+													return max_expand(ms, s, p, ep);
+												}
+											case '+':
+												{  /* 1 or more repetitions */
+													return ((m != 0) ? max_expand(ms, s + 1, p, ep) : null);
+												}
+											case '-':
+												{  /* 0 or more repetitions (minimum) */
+													return min_expand(ms, s, p, ep);
+												}
+											default:
+												{
+													if (m == 0) return null;
+													s = s.next(); p = ep; goto init;  /* else return match(ms, s+1, ep); */
+												}
+										}
+									}
+									//goto dflt;  /* case default */
+								}
+						}
+					}
+				case '\0':
+					{  /* end of pattern */
+						return s;  /* match succeeded */
+					}
+				case '$':
+					{
+						if (p[1] == '\0')  /* is the `$' the last char in pattern? */
+							return (s == ms.src_end) ? s : null;  /* check end of string */
+						else goto dflt;
+					}
+				default:
+				dflt:
+					{  /* it is a pattern item */
+						CharPtr ep = classend(ms, p);  /* points to what is next */
+						int m = (s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0) ? 1 : 0;
+						switch (ep[0])
+						{
+							case '?':
+								{  /* optional */
+									CharPtr res;
+									if ((m != 0) && ((res = match(ms, s + 1, ep + 1)) != null))
+										return res;
+									p = ep + 1; goto init;  /* else return match(ms, s, ep+1); */
+								}
+							case '*':
+								{  /* 0 or more repetitions */
+									return max_expand(ms, s, p, ep);
+								}
+							case '+':
+								{  /* 1 or more repetitions */
+									return ((m != 0) ? max_expand(ms, s + 1, p, ep) : null);
+								}
+							case '-':
+								{  /* 0 or more repetitions (minimum) */
+									return min_expand(ms, s, p, ep);
+								}
+							default:
+								{
+									if (m == 0) return null;
+									s = s.next(); p = ep; goto init;  /* else return match(ms, s+1, ep); */
+								}
+						}
+					}
+			}
+		}
+
+
+
+		private static CharPtr lmemfind(CharPtr s1, uint l1,
+									   CharPtr s2, uint l2)
+		{
+			if (l2 == 0) return s1;  /* empty strings are everywhere */
+			else if (l2 > l1) return null;  /* avoids a negative `l1' */
+			else
+			{
+				CharPtr init;  /* to search for a `*s2' inside `s1' */
+				l2--;  /* 1st char will be checked by `memchr' */
+				l1 = l1 - l2;  /* `s2' cannot be found after that */
+				while (l1 > 0 && (init = memchr(s1, s2[0], l1)) != null)
+				{
+					init = init.next();   /* 1st char is already checked */
+					if (memcmp(init, s2 + 1, l2) == 0)
+						return init - 1;
+					else
+					{  /* correct `l1' and `s1' to try again */
+						l1 -= (uint)(init - s1);
+						s1 = init;
+					}
+				}
+				return null;  /* not found */
+			}
+		}
+
+
+		private static void push_onecapture(MatchState ms, int i, CharPtr s,
+															CharPtr e)
+		{
+			if (i >= ms.level)
+			{
+				if (i == 0)  /* ms.level == 0, too */
+					LuaPushLString(ms.L, s, (uint)(e - s));  /* add whole match */
+				else
+					LuaLError(ms.L, "invalid capture index");
+			}
+			else
+			{
+				ptrdiff_t l = ms.capture[i].len;
+				if (l == CAP_UNFINISHED) LuaLError(ms.L, "unfinished capture");
+				if (l == CAP_POSITION)
+					LuaPushInteger(ms.L, ms.capture[i].init - ms.src_init + 1);
+				else
+					LuaPushLString(ms.L, ms.capture[i].init, (uint)l);
+			}
+		}
+
+
+		private static int push_captures(MatchState ms, CharPtr s, CharPtr e)
+		{
+			int i;
+			int nlevels = ((ms.level == 0) && (s != null)) ? 1 : ms.level;
+			LuaLCheckStack(ms.L, nlevels, "too many captures");
+			for (i = 0; i < nlevels; i++)
+				push_onecapture(ms, i, s, e);
+			return nlevels;  /* number of strings pushed */
+		}
+
+
+		private static int str_find_aux(LuaState L, int find)
+		{
+			uint l1, l2;
+			CharPtr s = LuaLCheckLString(L, 1, out l1);
+			CharPtr p = LuaLCheckLString(L, 2, out l2);
+			ptrdiff_t init = posrelat(LuaLOptInteger(L, 3, 1), l1) - 1;
+			if (init < 0) init = 0;
+			else if ((uint)(init) > l1) init = (ptrdiff_t)l1;
+			if ((find != 0) && ((LuaToBoolean(L, 4) != 0) ||  /* explicit request? */
+				strpbrk(p, SPECIALS) == null))
+			{  /* or no special characters? */
+				/* do a plain search */
+				CharPtr s2 = lmemfind(s + init, (uint)(l1 - init), p, (uint)(l2));
+				if (s2 != null)
+				{
+					LuaPushInteger(L, s2 - s + 1);
+					LuaPushInteger(L, (int)(s2 - s + l2));
+					return 2;
+				}
+			}
+			else
+			{
+				MatchState ms = new MatchState();
+				int anchor = 0;
+				if (p[0] == '^')
+				{
+					p = p.next();
+					anchor = 1;
+				}
+				CharPtr s1 = s + init;
+				ms.L = L;
+				ms.matchdepth = MAXCCALLS;
+				ms.src_init = s;
+				ms.src_end = s + l1;
+				do
+				{
+					CharPtr res;
+					ms.level = 0;
+					LuaAssert(ms.matchdepth == MAXCCALLS);
+					if ((res = match(ms, s1, p)) != null)
+					{
+						if (find != 0)
+						{
+							LuaPushInteger(L, s1 - s + 1);  /* start */
+							LuaPushInteger(L, res - s);   /* end */
+							return push_captures(ms, null, null) + 2;
+						}
+						else
+							return push_captures(ms, s1, res);
+					}
+				} while (((s1 = s1.next()) <= ms.src_end) && (anchor == 0));
+			}
+			LuaPushNil(L);  /* not found */
+			return 1;
+		}
+
+
+		private static int str_find(LuaState L)
+		{
+			return str_find_aux(L, 1);
+		}
+
+
+		private static int str_match(LuaState L)
+		{
+			return str_find_aux(L, 0);
+		}
+
+		private class GMatchAuxData
+		{
+			public CharPtr S;
+			public CharPtr P;
+			public uint LS;
+			public uint POS;
+		}
+
+
+		private static int gmatch_aux(LuaState L, GMatchAuxData auxdata)
+		{
+			MatchState ms = new MatchState();
+			uint ls = auxdata.LS;
+			CharPtr s = auxdata.S;
+			CharPtr p = auxdata.P;
+			CharPtr src;
+			ms.L = L;
+			ms.matchdepth = MAXCCALLS;
+			ms.src_init = s;
+			ms.src_end = s + ls;
+			for (src = s + auxdata.POS;
+				 src <= ms.src_end;
+				 src = src.next())
+			{
+				CharPtr e;
+				ms.level = 0;
+				LuaAssert(ms.matchdepth == MAXCCALLS);
+				if ((e = match(ms, src, p)) != null)
+				{
+					lua_Integer newstart = e - s;
+					if (e == src) newstart++;  /* empty match? go at least one position */
+					auxdata.POS = (uint)newstart;
+					return push_captures(ms, src, e);
+				}
+			}
+			return 0;  /* not found */
+		}
+
+
+		private static DynValue gmatch_aux_2(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			return executionContext.EmulateClassicCall(args, "gmatch",
+				L => gmatch_aux(L, (GMatchAuxData)executionContext.AdditionalData));
+		}
+
+
+		private static int gmatch(LuaState L)
+		{
+			CallbackFunction C = new CallbackFunction(gmatch_aux_2);
+			string s = L.Args.AsString(L.ExecutionContext, 1, "gmatch", false);
+			string p = L.Args.AsString(L.ExecutionContext, 1, "gmatch", false);
+
+
+			C.AdditionalData = new GMatchAuxData()
+			{
+				S = new CharPtr(s),
+				P = new CharPtr(p),
+				LS = (uint)s.Length,
+				POS = 0
+			};
+
+			L.ReturnValues.Add(DynValue.NewCallback(C));
+
+			return 1;
+		}
+
+
+		private static int gfind_nodef(LuaState L)
+		{
+			return LuaLError(L, LUA_QL("string.gfind") + " was renamed to " +
+								 LUA_QL("string.gmatch"));
+		}
+
+
+		private static void add_s(MatchState ms, LuaLBuffer b, CharPtr s,
+														   CharPtr e)
+		{
+			uint l, i;
+			CharPtr news = LuaToLString(ms.L, 3, out l);
+			for (i = 0; i < l; i++)
+			{
+				if (news[i] != L_ESC)
+					LuaLAddChar(b, news[i]);
+				else
+				{
+					i++;  /* skip ESC */
+					if (!Char.IsDigit((char)(news[i])))
+						LuaLAddChar(b, news[i]);
+					else if (news[i] == '0')
+						LuaLAddLString(b, s, (uint)(e - s));
+					else
+					{
+						push_onecapture(ms, news[i] - '1', s, e);
+						LuaLAddValue(b);  /* add capture to accumulated result */
+					}
+				}
+			}
+		}
+
+
+
+
+		private static void add_value(MatchState ms, LuaLBuffer b, CharPtr s,
+															   CharPtr e)
+		{
+			LuaState L = ms.L;
+			switch (LuaType(L, 3))
+			{
+				case LUA_TNUMBER:
+				case LUA_TSTRING:
+					{
+						add_s(ms, b, s, e);
+						return;
+					}
+				case LUA_TUSERDATA:
+				case LUA_TFUNCTION:
+					{
+						int n;
+						throw new NotImplementedException();
+						//LuaPushValue(L, 3);
+						//n = push_captures(ms, s, e);
+						//LuaCall(L, n, 1);
+						break;
+					}
+				case LUA_TTABLE:
+					{
+						push_onecapture(ms, 0, s, e);
+						LuaGetTable(L, 3);
+						break;
+					}
+			}
+			if (LuaToBoolean(L, -1) == 0)
+			{  /* nil or false? */
+				LuaPop(L, 1);
+				LuaPushLString(L, s, (uint)(e - s));  /* keep original text */
+			}
+			else if (LuaIsString(L, -1) == 0)
+				LuaLError(L, "invalid replacement value (a %s)", LuaLTypeName(L, -1));
+			LuaLAddValue(b);  /* add result to accumulator */
+		}
+
+
+
+		private static int str_gsub(LuaState L)
+		{
+			uint srcl;
+			CharPtr src = LuaLCheckLString(L, 1, out srcl);
+			CharPtr p = LuaLCheckString(L, 2);
+			int tr = LuaType(L, 3);
+			int max_s = LuaLOptInt(L, 4, (int)(srcl + 1));
+			int anchor = 0;
+			if (p[0] == '^')
+			{
+				p = p.next();
+				anchor = 1;
+			}
+			int n = 0;
+			MatchState ms = new MatchState();
+			LuaLBuffer b = new LuaLBuffer(L);
+			LuaLArgCheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
+							 tr == LUA_TFUNCTION || tr == LUA_TTABLE ||
+							 tr == LUA_TUSERDATA, 3,
+								"string/function/table expected");
+			LuaLBuffInit(L, b);
+			ms.L = L;
+			ms.matchdepth = MAXCCALLS;
+			ms.src_init = src;
+			ms.src_end = src + srcl;
+			while (n < max_s)
+			{
+				CharPtr e;
+				ms.level = 0;
+				LuaAssert(ms.matchdepth == MAXCCALLS);
+				e = match(ms, src, p);
+				if (e != null)
+				{
+					n++;
+					add_value(ms, b, src, e);
+				}
+				if ((e != null) && e > src) /* non empty match? */
+					src = e;  /* skip it */
+				else if (src < ms.src_end)
+				{
+					char c = src[0];
+					src = src.next();
+					LuaLAddChar(b, c);
+				}
+				else break;
+				if (anchor != 0) break;
+			}
+			LuaLAddLString(b, src, (uint)(ms.src_end - src));
+			LuaLPushResult(b);
+			LuaPushInteger(L, n);  /* number of substitutions */
+			return 2;
+		}
+
+		/* }====================================================== */
+
+
+		/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
+		public const int MAX_ITEM = 512;
+		/* valid flags in a format specification */
+		public const string FLAGS = "-+ #0";
+		/*
+		** maximum size of each format specification (such as '%-099.99d')
+		** (+10 accounts for %99.99x plus margin of error)
+		*/
+		public static readonly int MAX_FORMAT = (FLAGS.Length + 1) + (LUA_INTFRMLEN.Length + 1) + 10;
+
+
+		private static void addquoted(LuaState L, LuaLBuffer b, int arg)
+		{
+			uint l;
+			CharPtr s = LuaLCheckLString(L, arg, out l);
+			LuaLAddChar(b, '"');
+			while ((l--) != 0)
+			{
+				switch (s[0])
+				{
+					case '"':
+					case '\\':
+					case '\n':
+						{
+							LuaLAddChar(b, '\\');
+							LuaLAddChar(b, s[0]);
+							break;
+						}
+					case '\r':
+						{
+							LuaLAddLString(b, "\\r", 2);
+							break;
+						}
+					case '\0':
+						{
+							LuaLAddLString(b, "\\000", 4);
+							break;
+						}
+					default:
+						{
+							LuaLAddChar(b, s[0]);
+							break;
+						}
+				}
+				s = s.next();
+			}
+			LuaLAddChar(b, '"');
+		}
+
+		private static CharPtr scanformat(LuaState L, CharPtr strfrmt, CharPtr form)
+		{
+			CharPtr p = strfrmt;
+			while (p[0] != '\0' && strchr(FLAGS, p[0]) != null) p = p.next();  /* skip flags */
+			if ((uint)(p - strfrmt) >= (FLAGS.Length + 1))
+				LuaLError(L, "invalid format (repeated flags)");
+			if (isdigit((byte)(p[0]))) p = p.next();  /* skip width */
+			if (isdigit((byte)(p[0]))) p = p.next();  /* (2 digits at most) */
+			if (p[0] == '.')
+			{
+				p = p.next();
+				if (isdigit((byte)(p[0]))) p = p.next();  /* skip precision */
+				if (isdigit((byte)(p[0]))) p = p.next();  /* (2 digits at most) */
+			}
+			if (isdigit((byte)(p[0])))
+				LuaLError(L, "invalid format (width or precision too long)");
+			form[0] = '%';
+			form = form.next();
+			strncpy(form, strfrmt, p - strfrmt + 1);
+			form += p - strfrmt + 1;
+			form[0] = '\0';
+			return p;
+		}
+
+
+		private static void addintlen(CharPtr form)
+		{
+			uint l = (uint)strlen(form);
+			char spec = form[l - 1];
+			strcpy(form + l - 1, LUA_INTFRMLEN);
+			form[l + (LUA_INTFRMLEN.Length + 1) - 2] = spec;
+			form[l + (LUA_INTFRMLEN.Length + 1) - 1] = '\0';
+		}
+
+
+		private static int str_format(LuaState L)
+		{
+			int top = LuaGetTop(L);
+			int arg = 1;
+			uint sfl;
+			CharPtr strfrmt = LuaLCheckLString(L, arg, out sfl);
+			CharPtr strfrmt_end = strfrmt + sfl;
+			LuaLBuffer b = new LuaLBuffer(L);
+			LuaLBuffInit(L, b);
+			while (strfrmt < strfrmt_end)
+			{
+				if (strfrmt[0] != L_ESC)
+				{
+					LuaLAddChar(b, strfrmt[0]);
+					strfrmt = strfrmt.next();
+				}
+				else if (strfrmt[1] == L_ESC)
+				{
+					LuaLAddChar(b, strfrmt[0]);  /* %% */
+					strfrmt = strfrmt + 2;
+				}
+				else
+				{ /* format item */
+					strfrmt = strfrmt.next();
+					CharPtr form = new char[MAX_FORMAT];  /* to store the format (`%...') */
+					CharPtr buff = new char[MAX_ITEM];  /* to store the formatted item */
+					if (++arg > top)
+						LuaLArgError(L, arg, "no value");
+					strfrmt = scanformat(L, strfrmt, form);
+					char ch = strfrmt[0];
+					strfrmt = strfrmt.next();
+					switch (ch)
+					{
+						case 'c':
+							{
+								sprintf(buff, form, (int)LuaLCheckNumber(L, arg));
+								break;
+							}
+						case 'd':
+						case 'i':
+							{
+								addintlen(form);
+								sprintf(buff, form, (LUA_INTFRM_T)LuaLCheckNumber(L, arg));
+								break;
+							}
+						case 'o':
+						case 'u':
+						case 'x':
+						case 'X':
+							{
+								addintlen(form);
+								sprintf(buff, form, (UNSIGNED_LUA_INTFRM_T)LuaLCheckNumber(L, arg));
+								break;
+							}
+						case 'e':
+						case 'E':
+						case 'f':
+						case 'g':
+						case 'G':
+							{
+								sprintf(buff, form, (double)LuaLCheckNumber(L, arg));
+								break;
+							}
+						case 'q':
+							{
+								addquoted(L, b, arg);
+								continue;  /* skip the 'addsize' at the end */
+							}
+						case 's':
+							{
+								uint l;
+								CharPtr s = LuaLCheckLString(L, arg, out l);
+								if ((strchr(form, '.') == null) && l >= 100)
+								{
+									/* no precision and string is too long to be formatted;
+									   keep original string */
+									LuaPushValue(L, arg);
+									LuaLAddValue(b);
+									continue;  /* skip the `addsize' at the end */
+								}
+								else
+								{
+									sprintf(buff, form, s);
+									break;
+								}
+							}
+						default:
+							{  /* also treat cases `pnLlh' */
+								return LuaLError(L, "invalid option " + LUA_QL("%%%c") + " to " +
+													 LUA_QL("format"), strfrmt[-1]);
+							}
+					}
+					LuaLAddLString(b, buff, (uint)strlen(buff));
+				}
+			}
+			LuaLPushResult(b);
+			return 1;
+		}
+
+
+
+
+
+	}
+}
+#endif

+ 7 - 2
src/MoonSharp.Interpreter/CoreLib/Patterns/MatchState.cs → src/MoonSharp.Interpreter/CoreLib/StringLib/MatchState.cs

@@ -1,4 +1,6 @@
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
+#if true
+
+// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
 //
 //
 // Copyright (C) 2013 Sheng Lunan
 // Copyright (C) 2013 Sheng Lunan
 //
 //
@@ -19,7 +21,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
-namespace MoonSharp.Interpreter.CoreLib.Patterns
+namespace MoonSharp.Interpreter.CoreLib.StringLib
 {
 {
 	class MatchState
 	class MatchState
 	{
 	{
@@ -42,3 +44,6 @@ namespace MoonSharp.Interpreter.CoreLib.Patterns
 		}
 		}
 	}
 	}
 }
 }
+
+
+#endif

+ 18 - 10
src/MoonSharp.Interpreter/CoreLib/Patterns/PatternMatching.cs → src/MoonSharp.Interpreter/CoreLib/StringLib/PatternMatching.cs

@@ -1,4 +1,5 @@
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
+#if true
+// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
 //
 //
 // Copyright (C) 2013 Sheng Lunan
 // Copyright (C) 2013 Sheng Lunan
 //
 //
@@ -21,7 +22,7 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using MoonSharp.Interpreter.Execution;
 using MoonSharp.Interpreter.Execution;
 
 
-namespace MoonSharp.Interpreter.CoreLib.Patterns
+namespace MoonSharp.Interpreter.CoreLib.StringLib
 {
 {
 	static class PatternMatching
 	static class PatternMatching
 	{
 	{
@@ -492,9 +493,9 @@ namespace MoonSharp.Interpreter.CoreLib.Patterns
 
 
 		private static DynValue GmatchAux(ScriptExecutionContext executionContext, CallbackArguments args)
 		private static DynValue GmatchAux(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			DynValue v_idx = executionContext.Closure.Get("idx");
-			DynValue v_src = executionContext.Closure.Get("src");
-			DynValue v_pattern = executionContext.Closure.Get("pattern");
+			DynValue v_idx = GetClosure(executionContext).Get("idx");
+			DynValue v_src = GetClosure(executionContext).Get("src");
+			DynValue v_pattern = GetClosure(executionContext).Get("pattern");
 
 
 			MatchState ms = new MatchState();
 			MatchState ms = new MatchState();
 			string src = v_src.String;
 			string src = v_src.String;
@@ -512,7 +513,7 @@ namespace MoonSharp.Interpreter.CoreLib.Patterns
 				if (e != -1)
 				if (e != -1)
 				{
 				{
 					int newStart = (e == 0) ? e + 1 : e;
 					int newStart = (e == 0) ? e + 1 : e;
-					executionContext.Closure.Set("idx", DynValue.NewNumber(newStart));
+					GetClosure(executionContext).Set("idx", DynValue.NewNumber(newStart));
 					return PushCaptures(ms, s, e);
 					return PushCaptures(ms, s, e);
 				}
 				}
 			}
 			}
@@ -520,14 +521,20 @@ namespace MoonSharp.Interpreter.CoreLib.Patterns
 			return DynValue.Nil;
 			return DynValue.Nil;
 		}
 		}
 
 
+		private static Table GetClosure(ScriptExecutionContext executionContext)
+		{
+			return executionContext.AdditionalData as Table;
+		}
+
 		public static DynValue GMatch(Script script, string src, string pattern)
 		public static DynValue GMatch(Script script, string src, string pattern)
 		{
 		{
 			DynValue aux = DynValue.NewCallback(GmatchAux);
 			DynValue aux = DynValue.NewCallback(GmatchAux);
 
 
-			aux.Callback.Closure = new Table(script);
-			aux.Callback.Closure.Set("idx", DynValue.NewNumber(0));
-			aux.Callback.Closure.Set("src", DynValue.NewString(src));
-			aux.Callback.Closure.Set("pattern", DynValue.NewString(pattern));
+			var t = new Table(script);
+			t.Set("idx", DynValue.NewNumber(0));
+			t.Set("src", DynValue.NewString(src));
+			t.Set("pattern", DynValue.NewString(pattern));
+			aux.Callback.AdditionalData = t;
 
 
 			return aux;
 			return aux;
 		}
 		}
@@ -826,3 +833,4 @@ namespace MoonSharp.Interpreter.CoreLib.Patterns
 	}
 	}
 
 
 }
 }
+#endif

+ 1 - 1
src/MoonSharp.Interpreter/CoreLib/Patterns/StringRange.cs → src/MoonSharp.Interpreter/CoreLib/StringLib/StringRange.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
-namespace MoonSharp.Interpreter.CoreLib.Patterns
+namespace MoonSharp.Interpreter.CoreLib.StringLib
 {
 {
 	internal class StringRange
 	internal class StringRange
 	{
 	{

+ 0 - 0
src/MoonSharp.Interpreter/CoreLib/Patterns/Tools.cs → src/MoonSharp.Interpreter/CoreLib/StringLib/Tools.cs


+ 1 - 1
src/MoonSharp.Interpreter/CoreLib/StringModule.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
-using MoonSharp.Interpreter.CoreLib.Patterns;
+using MoonSharp.Interpreter.CoreLib.StringLib;
 using MoonSharp.Interpreter.Execution;
 using MoonSharp.Interpreter.Execution;
 
 
 namespace MoonSharp.Interpreter.CoreLib
 namespace MoonSharp.Interpreter.CoreLib

+ 2 - 2
src/MoonSharp.Interpreter/CoreLib/TableModule.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
-using MoonSharp.Interpreter.CoreLib.Patterns;
+using MoonSharp.Interpreter.CoreLib.StringLib;
 using MoonSharp.Interpreter.Execution;
 using MoonSharp.Interpreter.Execution;
 
 
 namespace MoonSharp.Interpreter.CoreLib
 namespace MoonSharp.Interpreter.CoreLib
@@ -51,7 +51,7 @@ namespace MoonSharp.Interpreter.CoreLib
 			DynValue vlist = args.AsType(0, "sort", DataType.Table, false);
 			DynValue vlist = args.AsType(0, "sort", DataType.Table, false);
 			DynValue lt = args[1];
 			DynValue lt = args[1];
 
 
-			if (lt.Type != DataType.Function && lt.Type != DataType.ClrFunction && lt.Type != DataType.Nil)
+			if (lt.Type != DataType.Function && lt.Type != DataType.ClrFunction && lt.IsNotNil())
 				args.AsType(1, "sort", DataType.Function, true); // this throws
 				args.AsType(1, "sort", DataType.Function, true); // this throws
 
 
 			int end = GetTableLength(executionContext, vlist);
 			int end = GetTableLength(executionContext, vlist);

+ 8 - 8
src/MoonSharp.Interpreter/DataStructs/FastStackDynamic.cs

@@ -1,20 +1,21 @@
-#if USE_DYNAMIC_STACKS
-
-using System;
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 
 
 namespace MoonSharp.Interpreter.DataStructs
 namespace MoonSharp.Interpreter.DataStructs
 {
 {
-	public class FastStack<T> : List<T>
+#if USE_DYNAMIC_STACKS
+	public class FastStack<T> : FastStackDynamic<T>
+#endif
+
+	public class FastStackDynamic<T> : List<T>
 	{
 	{
-		public FastStack(int maxCapacity)
-			: base(maxCapacity)
+			public FastStackDynamic(int startingCapacity)
+			: base(startingCapacity)
 		{
 		{
 		}
 		}
 
 
-
 		public T Push(T item)
 		public T Push(T item)
 		{
 		{
 			this.Add(item);
 			this.Add(item);
@@ -64,4 +65,3 @@ namespace MoonSharp.Interpreter.DataStructs
 }
 }
 
 
 
 
-#endif

+ 24 - 12
src/MoonSharp.Interpreter/DataTypes/CallbackArguments.cs

@@ -85,23 +85,17 @@ namespace MoonSharp.Interpreter
 		/// <returns></returns>
 		/// <returns></returns>
 		public DynValue AsType(int argNum, string funcName, DataType type, bool allowNil = false)
 		public DynValue AsType(int argNum, string funcName, DataType type, bool allowNil = false)
 		{
 		{
-			if (allowNil && this[argNum].Type == DataType.Nil)
-				return this[argNum];
-
-			if (argNum >= this.Count)
-				throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, type);
-
-			if (this[argNum].Type != type)
-				throw ScriptRuntimeException.BadArgument(argNum, funcName, type, this[argNum].Type, allowNil);
-
-			return this[argNum];
+			return this[argNum].CheckType(funcName, type, argNum, allowNil ? TypeValidationFlags.AllowNil | TypeValidationFlags.AutoConvert : TypeValidationFlags.AutoConvert);
 		}
 		}
 
 
 
 
+
 		public double AsDouble(int argNum, string funcName)
 		public double AsDouble(int argNum, string funcName)
 		{
 		{
-			if (this[argNum].Type == DataType.Nil)
-				throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, DataType.Number);
+			if (this[argNum].IsNil())
+			{
+					throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, DataType.Number);
+			}
 
 
 			if (this[argNum].Type != DataType.Number)
 			if (this[argNum].Type != DataType.Number)
 			{
 			{
@@ -120,6 +114,24 @@ namespace MoonSharp.Interpreter
 			return (int)d;
 			return (int)d;
 		}
 		}
 
 
+		public string AsString(ScriptExecutionContext executionContext, int argNum, string funcName, bool allowNil = false)
+		{
+			if (this[argNum].IsNil())
+			{
+				if (allowNil)
+					return null;
+				else
+					throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, DataType.String);
+			}
+
+			string str = this[argNum].CastToString();
+
+			if (str != null)
+				return str;
+
+			throw ScriptRuntimeException.BadArgument(argNum, funcName, DataType.String, this[argNum].Type, allowNil);
+		}
+
 		public string AsStringUsingMeta(ScriptExecutionContext executionContext, int i, string funcName)
 		public string AsStringUsingMeta(ScriptExecutionContext executionContext, int i, string funcName)
 		{
 		{
 			if ((this[i].Type == DataType.Table) && (this[i].Table.MetaTable != null) &&
 			if ((this[i].Type == DataType.Table) && (this[i].Table.MetaTable != null) &&

+ 3 - 2
src/MoonSharp.Interpreter/DataTypes/CallbackFunction.cs

@@ -29,6 +29,7 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		/// </summary>
 		/// <param name="executionContext">The execution context.</param>
 		/// <param name="executionContext">The execution context.</param>
 		/// <param name="args">The arguments.</param>
 		/// <param name="args">The arguments.</param>
+		/// <param name="isMethodCall">if set to <c>true</c> this is a method call.</param>
 		/// <returns></returns>
 		/// <returns></returns>
 		public DynValue Invoke(ScriptExecutionContext executionContext, IList<DynValue> args, bool isMethodCall = false)
 		public DynValue Invoke(ScriptExecutionContext executionContext, IList<DynValue> args, bool isMethodCall = false)
 		{
 		{
@@ -93,9 +94,9 @@ namespace MoonSharp.Interpreter
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Gets or sets a Table used as additional data to the callback function (available in the execution context).
+		/// Gets or sets an object used as additional data to the callback function (available in the execution context).
 		/// </summary>
 		/// </summary>
-		public Table Closure { get; set; }
+		public object AdditionalData { get; set; }
 
 
 	}
 	}
 }
 }

+ 7 - 0
src/MoonSharp.Interpreter/DataTypes/DataType.cs

@@ -16,6 +16,10 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		/// </summary>
 		Nil,
 		Nil,
 		/// <summary>
 		/// <summary>
+		/// A place holder for no value
+		/// </summary>
+		Void,
+		/// <summary>
 		/// A Lua boolean
 		/// A Lua boolean
 		/// </summary>
 		/// </summary>
 		Boolean,
 		Boolean,
@@ -90,6 +94,8 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			switch (type)
 			switch (type)
 			{
 			{
+				case DataType.Void:
+					return "no value";
 				case DataType.Nil:
 				case DataType.Nil:
 					return "nil";
 					return "nil";
 				case DataType.Boolean:
 				case DataType.Boolean:
@@ -127,6 +133,7 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			switch (type)
 			switch (type)
 			{
 			{
+				case DataType.Void:
 				case DataType.Nil:
 				case DataType.Nil:
 					return "nil";
 					return "nil";
 				case DataType.Boolean:
 				case DataType.Boolean:

+ 140 - 21
src/MoonSharp.Interpreter/DataTypes/DynValue.cs

@@ -361,6 +361,10 @@ namespace MoonSharp.Interpreter
 		}
 		}
 
 
 
 
+		/// <summary>
+		/// A preinitialized, readonly instance, equaling Void
+		/// </summary>
+		public static DynValue Void { get; private set; }
 		/// <summary>
 		/// <summary>
 		/// A preinitialized, readonly instance, equaling Nil
 		/// A preinitialized, readonly instance, equaling Nil
 		/// </summary>
 		/// </summary>
@@ -377,7 +381,8 @@ namespace MoonSharp.Interpreter
 
 
 		static DynValue()
 		static DynValue()
 		{
 		{
-			Nil = new DynValue().AsReadOnly();
+			Nil = new DynValue() { m_Type = DataType.Nil }.AsReadOnly();
+			Void = new DynValue() { m_Type = DataType.Void }.AsReadOnly();
 			True = DynValue.NewBoolean(true).AsReadOnly();
 			True = DynValue.NewBoolean(true).AsReadOnly();
 			False = DynValue.NewBoolean(false).AsReadOnly();
 			False = DynValue.NewBoolean(false).AsReadOnly();
 		}
 		}
@@ -419,6 +424,8 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			switch (Type)
 			switch (Type)
 			{
 			{
+				case DataType.Void:
+					return "void";
 				case DataType.Nil:
 				case DataType.Nil:
 					return "nil";
 					return "nil";
 				case DataType.Boolean:
 				case DataType.Boolean:
@@ -461,6 +468,7 @@ namespace MoonSharp.Interpreter
 
 
 			switch (Type)
 			switch (Type)
 			{
 			{
+				case DataType.Void:
 				case DataType.Nil:
 				case DataType.Nil:
 					m_HashCode = 0;
 					m_HashCode = 0;
 					break;
 					break;
@@ -508,11 +516,17 @@ namespace MoonSharp.Interpreter
 			DynValue other = obj as DynValue;
 			DynValue other = obj as DynValue;
 
 
 			if (other == null) return false;
 			if (other == null) return false;
+
+			if ((other.Type == DataType.Nil && this.Type == DataType.Void)
+				|| (other.Type == DataType.Void && this.Type == DataType.Nil))
+				return true;
+
 			if (other.Type != this.Type) return false;
 			if (other.Type != this.Type) return false;
 
 
 
 
 			switch (Type)
 			switch (Type)
 			{
 			{
+				case DataType.Void:
 				case DataType.Nil:
 				case DataType.Nil:
 					return true;
 					return true;
 				case DataType.Boolean:
 				case DataType.Boolean:
@@ -605,7 +619,7 @@ namespace MoonSharp.Interpreter
 			DynValue rv = ToScalar();
 			DynValue rv = ToScalar();
 			if (rv.Type == DataType.Boolean)
 			if (rv.Type == DataType.Boolean)
 				return rv.Boolean;
 				return rv.Boolean;
-			else return (rv.Type != DataType.Nil);
+			else return (rv.Type != DataType.Nil && rv.Type != DataType.Void);
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -617,7 +631,7 @@ namespace MoonSharp.Interpreter
 				return this;
 				return this;
 
 
 			if (Tuple.Length == 0)
 			if (Tuple.Length == 0)
-				return DynValue.Nil;
+				return DynValue.Void;
 
 
 			return Tuple[0].ToScalar();
 			return Tuple[0].ToScalar();
 		}
 		}
@@ -656,19 +670,43 @@ namespace MoonSharp.Interpreter
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Determines whether this instance is nil.
+		/// Determines whether this instance is nil or void
 		/// </summary>
 		/// </summary>
 		public bool IsNil()
 		public bool IsNil()
 		{
 		{
-			return this.Type == DataType.Nil;
+			return this.Type == DataType.Nil || this.Type == DataType.Void;
+		}
+
+		/// <summary>
+		/// Determines whether this instance is not nil or void
+		/// </summary>
+		public bool IsNotNil()
+		{
+			return this.Type != DataType.Nil && this.Type != DataType.Void;
+		}
+
+		/// <summary>
+		/// Determines whether this instance is void
+		/// </summary>
+		public bool IsVoid()
+		{
+			return this.Type == DataType.Void;
+		}
+
+		/// <summary>
+		/// Determines whether this instance is not void
+		/// </summary>
+		public bool IsNotVoid()
+		{
+			return this.Type != DataType.Void;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Determines whether is nil or NaN (and thus unsuitable for using as a table key).
+		/// Determines whether is nil, void or NaN (and thus unsuitable for using as a table key).
 		/// </summary>
 		/// </summary>
 		public bool IsNilOrNan()
 		public bool IsNilOrNan()
 		{
 		{
-			return (this.Type == DataType.Nil) || (this.Type == DataType.Number && double.IsNaN(this.Number));
+			return (this.Type == DataType.Nil) || (this.Type == DataType.Void) || (this.Type == DataType.Number && double.IsNaN(this.Number));
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -689,31 +727,64 @@ namespace MoonSharp.Interpreter
 		/// Expands tuples to a list using functiona arguments logic
 		/// Expands tuples to a list using functiona arguments logic
 		/// </summary>
 		/// </summary>
 		/// <param name="args">The arguments to expand.</param>
 		/// <param name="args">The arguments to expand.</param>
-		/// <param name="target">The target list (if null, a new list is created and returned).</param>
+		/// <param name="target">The target list (if null, a new list is created and returned, if needed).</param>
 		/// <returns></returns>
 		/// <returns></returns>
-		public static IList<DynValue> ExpandArgumentsToList(IList<DynValue> args, List<DynValue> target = null)
+		public static IList<DynValue> ExpandArgumentsToList(IList<DynValue> args, IList<DynValue> target = null)
 		{
 		{
-			target = target ?? new List<DynValue>();
+			int lastValueIndex = -1;
+			bool hasTuples = (target != null);
 
 
-			for(int i = 0; i < args.Count; i++)
+			if (target == null)
 			{
 			{
-				DynValue v = args[i];
+				for (int i = 0; i < args.Count; i++)
+				{
+					DynValue v = args[i];
 
 
-				if (v.Type == DataType.Tuple)
+					if (v.Type == DataType.Tuple)
+						hasTuples = true;
+
+					if (v.Type != DataType.Void)
+						lastValueIndex = i;
+				}
+
+				if (hasTuples)
+					target = new List<DynValue>();
+				else
+					target = args;
+			}
+
+			if (hasTuples)
+			{
+				for (int i = 0; i < args.Count; i++)
 				{
 				{
-					if (i == args.Count - 1)
+					DynValue v = args[i];
+
+					if (v.Type == DataType.Tuple)
 					{
 					{
-						ExpandArgumentsToList(v.Tuple, target);
+						if (i == args.Count - 1)
+						{
+							ExpandArgumentsToList(v.Tuple, target);
+						}
+						else if (v.Tuple.Length > 0)
+						{
+							target.Add(v.Tuple[0]);
+						}
 					}
 					}
-					else if (v.Tuple.Length > 0)
+					else
 					{
 					{
-						target.Add(v.Tuple[0]);
+						target.Add(v);
+						if (v.Type != DataType.Void)
+							lastValueIndex = i;
 					}
 					}
 				}
 				}
-				else
-				{
-					target.Add(v);
-				}
+			}
+
+
+			// all non-last voids become nils
+			for (int i = 0; i < lastValueIndex; i++)
+			{
+				if (target[i].Type == DataType.Void)
+					target[i] = DynValue.Nil;
 			}
 			}
 
 
 			return target;
 			return target;
@@ -746,6 +817,54 @@ namespace MoonSharp.Interpreter
 			return (T)MoonSharp.Interpreter.Interop.ConversionHelper.MoonSharpValueToObjectOfType(this, typeof(T), null);
 			return (T)MoonSharp.Interpreter.Interop.ConversionHelper.MoonSharpValueToObjectOfType(this, typeof(T), null);
 		}
 		}
 
 
+		/// <summary>
+		/// Checks the type of this value corresponds to the desired type.
+		/// </summary>
+		/// <param name="funcName">Name of the function.</param>
+		/// <param name="desiredType">Type of the desired.</param>
+		/// <param name="argNum">The argument number.</param>
+		/// <param name="flags">The flags.</param>
+		/// <returns></returns>
+		public DynValue CheckType(string funcName, DataType desiredType, int argNum = -1, TypeValidationFlags flags = TypeValidationFlags.Default)
+		{
+			if (this.Type == desiredType)
+				return this;
+
+			bool allowNil = ((int)(flags & TypeValidationFlags.AllowNil) != 0);
+
+			if (allowNil && this.IsNil())
+				return this;
+
+			bool autoConvert = ((int)(flags & TypeValidationFlags.AutoConvert) != 0);
+
+			if (autoConvert)
+			{
+				if (desiredType == DataType.Boolean)
+					return DynValue.NewBoolean(this.CastToBool());
+
+				if (desiredType == DataType.Number)
+				{
+					double? v = this.CastToNumber();
+					if (v.HasValue)
+						return DynValue.NewNumber(v.Value);
+				}
+
+				if (desiredType == DataType.String)
+				{
+					string v = this.CastToString();
+					if (v != null)
+						return DynValue.NewString(v);
+				}
+			}
+
+
+			if (this.IsNil())
+				throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, desiredType);
+
+			throw ScriptRuntimeException.BadArgument(argNum, funcName, desiredType, this.Type, allowNil);
+		}
+
+
 	}
 	}
 
 
 
 

+ 2 - 2
src/MoonSharp.Interpreter/DataTypes/Table.cs

@@ -242,7 +242,7 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			for (LinkedListNode<TablePair> node = m_Values.First; node != null; node = node.Next)
 			for (LinkedListNode<TablePair> node = m_Values.First; node != null; node = node.Next)
 			{
 			{
-				if (node.Value.Value.Type == DataType.Nil)
+				if (node.Value.Value.IsNil())
 				{
 				{
 					if (node.Value.Key.Type == DataType.Number)
 					if (node.Value.Key.Type == DataType.Number)
 					{
 					{
@@ -272,7 +272,7 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		/// </summary>
 		public TablePair? NextKey(DynValue v)
 		public TablePair? NextKey(DynValue v)
 		{
 		{
-			if (v.Type == DataType.Nil)
+			if (v.IsNil())
 			{
 			{
 				LinkedListNode<TablePair> node = m_Values.First;
 				LinkedListNode<TablePair> node = m_Values.First;
 
 

+ 1 - 1
src/MoonSharp.Interpreter/DataTypes/TablePair.cs

@@ -28,7 +28,7 @@ namespace MoonSharp.Interpreter
 		public DynValue Value
 		public DynValue Value
 		{
 		{
 			get { return value; }
 			get { return value; }
-			set { if (key.Type != DataType.Nil) Value = value; }
+			set { if (key.IsNotNil()) Value = value; }
 		}
 		}
 
 
 
 

+ 16 - 0
src/MoonSharp.Interpreter/DataTypes/TypeValidationFlags.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter
+{
+	[Flags]
+	public enum TypeValidationFlags
+	{
+		AllowNil = 0x1,
+		AutoConvert = 0x2,
+
+		Default = AutoConvert
+	}
+}

+ 49 - 32
src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs

@@ -3,9 +3,13 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using MoonSharp.Interpreter.Execution.VM;
 using MoonSharp.Interpreter.Execution.VM;
+using MoonSharp.Interpreter.Interop.LuaStateInterop;
 
 
 namespace MoonSharp.Interpreter.Execution
 namespace MoonSharp.Interpreter.Execution
 {
 {
+	/// <summary>
+	/// Class giving access to details of the environment where the script is executing
+	/// </summary>
 	public class ScriptExecutionContext
 	public class ScriptExecutionContext
 	{
 	{
 		Processor m_Processor;
 		Processor m_Processor;
@@ -17,41 +21,41 @@ namespace MoonSharp.Interpreter.Execution
 			m_Callback = callBackFunction;
 			m_Callback = callBackFunction;
 		}
 		}
 
 
-		public Table Closure 
-		{ 
-			get { return m_Callback.Closure; } 
-			set { m_Callback.Closure = value; } 
-		}
-
-
-		public DynValue GetVar(SymbolRef symref)
-		{
-			if (CheckUpValue(symref))
-				return m_Callback.Closure.Get(symref.Name);
-
-			return m_Processor.GetVar(symref);
-		}
-
-		public void SetVar(SymbolRef symref, DynValue value)
+		/// <summary>
+		/// Gets or sets the additional data associated to this CLR function call.
+		/// </summary>
+		public object AdditionalData 
 		{
 		{
-			if (CheckUpValue(symref))
-				m_Callback.Closure.Set(symref.Name, value);
-
-			m_Processor.SetVar(symref, value);
+			get { return m_Callback.AdditionalData; }
+			set { m_Callback.AdditionalData = value; } 
 		}
 		}
 
 
 
 
+		/// <summary>
+		/// Gets the metatable associated with the given value.
+		/// </summary>
+		/// <param name="value">The value.</param>
+		/// <returns></returns>
 		public Table GetMetatable(DynValue value)
 		public Table GetMetatable(DynValue value)
 		{
 		{
 			return m_Processor.GetMetatable(value);
 			return m_Processor.GetMetatable(value);
 		}
 		}
 
 
 
 
+		/// <summary>
+		/// Gets the specified metamethod associated with the given value.
+		/// </summary>
+		/// <param name="value">The value.</param>
+		/// <param name="metamethod">The metamethod name.</param>
+		/// <returns></returns>
 		public DynValue GetMetamethod(DynValue value, string metamethod)
 		public DynValue GetMetamethod(DynValue value, string metamethod)
 		{
 		{
 			return m_Processor.GetMetamethod(value, metamethod);
 			return m_Processor.GetMetamethod(value, metamethod);
 		}
 		}
 
 
+		/// <summary>
+		/// prepares a tail call request for the specified metamethod, or null if no metamethod is found.
+		/// </summary>
 		public DynValue GetMetamethodTailCall(DynValue value, string metamethod, params DynValue[] args)
 		public DynValue GetMetamethodTailCall(DynValue value, string metamethod, params DynValue[] args)
 		{
 		{
 			DynValue meta = this.GetMetamethod(value, metamethod);
 			DynValue meta = this.GetMetamethod(value, metamethod);
@@ -59,34 +63,47 @@ namespace MoonSharp.Interpreter.Execution
 			return DynValue.NewTailCallReq(meta, args);
 			return DynValue.NewTailCallReq(meta, args);
 		}
 		}
 
 
+		/// <summary>
+		/// Gets the metamethod to be used for a binary operation using op1 and op2.
+		/// </summary>
 		public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
 		public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
 		{
 		{
 			return m_Processor.GetBinaryMetamethod(op1, op2, eventName);
 			return m_Processor.GetBinaryMetamethod(op1, op2, eventName);
 		}
 		}
 
 
+		/// <summary>
+		/// Gets the script object associated with this request
+		/// </summary>
+		/// <returns></returns>
 		public Script GetScript()
 		public Script GetScript()
 		{
 		{
 			return m_Processor.GetScript();
 			return m_Processor.GetScript();
 		}
 		}
 
 
+		/// <summary>
+		/// Gets the coroutine which is performing the call
+		/// </summary>
 		public Coroutine GetCallingCoroutine()
 		public Coroutine GetCallingCoroutine()
 		{
 		{
 			return m_Processor.AssociatedCoroutine;
 			return m_Processor.AssociatedCoroutine;
 		}
 		}
 
 
-		private bool CheckUpValue(SymbolRef symref)
+		/// <summary>
+		/// Calls a callback function implemented in "classic way". 
+		/// Useful to port C code from Lua, or C# code from UniLua and KopiLua.
+		/// Lua : http://www.lua.org/
+		/// UniLua : http://github.com/xebecnan/UniLua
+		/// KopiLua : http://github.com/NLua/KopiLua
+		/// </summary>
+		/// <param name="args">The arguments.</param>
+		/// <param name="functionName">Name of the function - for error messages.</param>
+		/// <param name="callback">The callback.</param>
+		/// <returns></returns>
+		public DynValue EmulateClassicCall(CallbackArguments args, string functionName, Func<LuaState, int> callback)
 		{
 		{
-			if (symref.Type != SymbolRefType.Upvalue)
-				return false;
-
-			if (m_Callback.Closure == null)
-				throw new ArgumentException("symref.Type is Upvalue on null CLR Closure");
-
-			return true;
+			LuaState L = new LuaState(this, args, functionName);
+			int retvals = callback(L);
+			return L.GetReturnValue(retvals);
 		}
 		}
-
-
-
-
 	}
 	}
 }
 }

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

@@ -42,13 +42,13 @@ namespace MoonSharp.Interpreter.Execution.VM
 			if (op1_MetaTable != null)
 			if (op1_MetaTable != null)
 			{
 			{
 				DynValue meta1 = op1_MetaTable.RawGet(eventName);
 				DynValue meta1 = op1_MetaTable.RawGet(eventName);
-				if (meta1 != null && meta1.Type != DataType.Nil)
+				if (meta1 != null && meta1.IsNotNil())
 					return meta1;
 					return meta1;
 			}
 			}
 			if (op2_MetaTable != null)
 			if (op2_MetaTable != null)
 			{
 			{
 				DynValue meta2 = op2_MetaTable.RawGet(eventName);
 				DynValue meta2 = op2_MetaTable.RawGet(eventName);
-				if (meta2 != null && meta2.Type != DataType.Nil)
+				if (meta2 != null && meta2.IsNotNil())
 					return meta2;
 					return meta2;
 			}
 			}
 			return null;
 			return null;
@@ -63,7 +63,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 			var metameth = metatable.RawGet(metamethod);
 			var metameth = metatable.RawGet(metamethod);
 			
 			
-			if (metameth == null || metameth.Type == DataType.Nil)
+			if (metameth == null || metameth.IsNil())
 				return null;
 				return null;
 
 
 			return metameth;
 			return metameth;

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

@@ -120,7 +120,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 							{
 							{
 								DynValue v = m_ValueStack.Pop();
 								DynValue v = m_ValueStack.Pop();
 
 
-								if (v.Type == DataType.Nil)
+								if (v.Type == DataType.Nil || v.Type == DataType.Void)
 									instructionPtr = i.NumVal;
 									instructionPtr = i.NumVal;
 							}
 							}
 							if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
 							if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
@@ -566,10 +566,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
 				IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
 
 
 				// we expand tuples before callbacks
 				// we expand tuples before callbacks
-				if (args.Any(v => v.Type == DataType.Tuple))
-				{
-					args = DynValue.ExpandArgumentsToList(args);
-				}
+				args = DynValue.ExpandArgumentsToList(args);
 
 
 				var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback), args, isMethodCall:thisCall);
 				var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback), args, isMethodCall:thisCall);
 				m_ValueStack.RemoveLast(argsCount + 1);
 				m_ValueStack.RemoveLast(argsCount + 1);
@@ -599,7 +596,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				{
 				{
 					var m = metatable.RawGet("__call");
 					var m = metatable.RawGet("__call");
 
 
-					if (m != null && m.Type != DataType.Nil)
+					if (m != null && m.IsNotNil())
 					{
 					{
 						DynValue[] tmp = new DynValue[argsCount + 1];
 						DynValue[] tmp = new DynValue[argsCount + 1];
 						for (int i = 0; i < argsCount + 1; i++)
 						for (int i = 0; i < argsCount + 1; i++)
@@ -635,7 +632,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				retpoint = csi.ReturnAddress;
 				retpoint = csi.ReturnAddress;
 				var argscnt = (int)(m_ValueStack.Pop().Number);
 				var argscnt = (int)(m_ValueStack.Pop().Number);
 				m_ValueStack.RemoveLast(argscnt + 1);
 				m_ValueStack.RemoveLast(argscnt + 1);
-				m_ValueStack.Push(DynValue.Nil);
+				m_ValueStack.Push(DynValue.Void);
 			}
 			}
 			else if (i.NumVal == 1)
 			else if (i.NumVal == 1)
 			{
 			{
@@ -877,7 +874,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 			}
 			}
 			else if (r.Type != l.Type)
 			else if (r.Type != l.Type)
 			{
 			{
-				m_ValueStack.Push(DynValue.False);
+				if ((l.Type == DataType.Nil && r.Type == DataType.Void)
+					|| (l.Type == DataType.Void && r.Type == DataType.Nil))
+					m_ValueStack.Push(DynValue.True);
+				else
+					m_ValueStack.Push(DynValue.False);
 			}
 			}
 			else if ((l.Type == DataType.Table || l.Type == DataType.UserData) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
 			else if ((l.Type == DataType.Table || l.Type == DataType.UserData) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
 			{
 			{

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

@@ -59,7 +59,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 			if (op1_MetaTable != null)
 			if (op1_MetaTable != null)
 			{
 			{
 				DynValue meta1 = op1_MetaTable.RawGet(eventName);
 				DynValue meta1 = op1_MetaTable.RawGet(eventName);
-				if (meta1 != null && meta1.Type != DataType.Nil)
+				if (meta1 != null && meta1.IsNotNil())
 					m = meta1;
 					m = meta1;
 			}
 			}
 
 

+ 15 - 0
src/MoonSharp.Interpreter/Interop/ConversionHelper.cs

@@ -158,6 +158,7 @@ namespace MoonSharp.Interpreter.Interop
 		{
 		{
 			switch (value.Type)
 			switch (value.Type)
 			{
 			{
+				case DataType.Void:
 				case DataType.Nil:
 				case DataType.Nil:
 					return null;
 					return null;
 				case DataType.Boolean:
 				case DataType.Boolean:
@@ -219,6 +220,20 @@ namespace MoonSharp.Interpreter.Interop
 
 
 			switch (value.Type)
 			switch (value.Type)
 			{
 			{
+				case DataType.Void:
+					if (desiredType.IsValueType)
+					{
+						if (defaultValue != null)
+							return defaultValue;
+
+						if (nullableType != null)
+							return null;
+					}
+					else
+					{
+						return defaultValue;
+					}
+					break;
 				case DataType.Nil:
 				case DataType.Nil:
 					if (desiredType.IsValueType)
 					if (desiredType.IsValueType)
 					{
 					{

+ 221 - 0
src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs

@@ -0,0 +1,221 @@
+//
+// This part taken from KopiLua - https://github.com/NLua/KopiLua
+//
+// =========================================================================================================
+//
+// Kopi Lua License
+// ----------------
+// MIT License for KopiLua
+// Copyright (c) 2012 LoDC
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all copies or substantial
+// portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ===============================================================================
+// Lua License
+// -----------
+// Lua is licensed under the terms of the MIT license reproduced below.
+// This means that Lua is free software and can be used for both academic
+// and commercial purposes at absolutely no cost.
+// For details and rationale, see http://www.lua.org/license.html .
+// ===============================================================================
+// Copyright (C) 1994-2008 Lua.org, PUC-Rio.
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop.LuaStateInterop
+{
+	public class CharPtr
+	{
+		public char[] chars;
+		public int index;
+
+		public char this[int offset]
+		{
+			get { return chars[index + offset]; }
+			set { chars[index + offset] = value; }
+		}
+
+		[CLSCompliantAttribute(false)]
+		public char this[uint offset]
+		{
+			get { return chars[index + offset]; }
+			set { chars[index + offset] = value; }
+		}
+		public char this[long offset]
+		{
+			get { return chars[index + (int)offset]; }
+			set { chars[index + (int)offset] = value; }
+		}
+
+		public static implicit operator CharPtr(string str) { return new CharPtr(str); }
+		public static implicit operator CharPtr(char[] chars) { return new CharPtr(chars); }
+		public static implicit operator CharPtr(byte[] bytes) { return new CharPtr(bytes); }
+
+		public CharPtr()
+		{
+			this.chars = null;
+			this.index = 0;
+		}
+
+		public CharPtr(string str)
+		{
+			this.chars = (str + '\0').ToCharArray();
+			this.index = 0;
+		}
+
+		public CharPtr(CharPtr ptr)
+		{
+			this.chars = ptr.chars;
+			this.index = ptr.index;
+		}
+
+		public CharPtr(CharPtr ptr, int index)
+		{
+			this.chars = ptr.chars;
+			this.index = index;
+		}
+
+		public CharPtr(char[] chars)
+		{
+			this.chars = chars;
+			this.index = 0;
+		}
+
+		public CharPtr(char[] chars, int index)
+		{
+			this.chars = chars;
+			this.index = index;
+		}
+
+		public CharPtr(byte[] bytes)
+		{
+			this.chars = new char[bytes.Length];
+			for (int i = 0; i < bytes.Length; i++)
+			{
+				this.chars[i] = (char)bytes[i];
+			}
+
+			this.index = 0;
+		}
+
+		public CharPtr(IntPtr ptr)
+		{
+			this.chars = new char[0];
+			this.index = 0;
+		}
+
+		public static CharPtr operator +(CharPtr ptr, int offset) { return new CharPtr(ptr.chars, ptr.index + offset); }
+		public static CharPtr operator -(CharPtr ptr, int offset) { return new CharPtr(ptr.chars, ptr.index - offset); }
+		[CLSCompliantAttribute(false)]
+		public static CharPtr operator +(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index + (int)offset); }
+		[CLSCompliantAttribute(false)]
+		public static CharPtr operator -(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index - (int)offset); }
+
+		public void inc() { this.index++; }
+		public void dec() { this.index--; }
+		public CharPtr next() { return new CharPtr(this.chars, this.index + 1); }
+		public CharPtr prev() { return new CharPtr(this.chars, this.index - 1); }
+		public CharPtr add(int ofs) { return new CharPtr(this.chars, this.index + ofs); }
+		public CharPtr sub(int ofs) { return new CharPtr(this.chars, this.index - ofs); }
+
+		public static bool operator ==(CharPtr ptr, char ch) { return ptr[0] == ch; }
+		public static bool operator ==(char ch, CharPtr ptr) { return ptr[0] == ch; }
+		public static bool operator !=(CharPtr ptr, char ch) { return ptr[0] != ch; }
+		public static bool operator !=(char ch, CharPtr ptr) { return ptr[0] != ch; }
+
+		public static CharPtr operator +(CharPtr ptr1, CharPtr ptr2)
+		{
+			string result = "";
+			for (int i = 0; ptr1[i] != '\0'; i++)
+				result += ptr1[i];
+			for (int i = 0; ptr2[i] != '\0'; i++)
+				result += ptr2[i];
+			return new CharPtr(result);
+		}
+		public static int operator -(CharPtr ptr1, CharPtr ptr2)
+		{
+			Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index - ptr2.index;
+		}
+		public static bool operator <(CharPtr ptr1, CharPtr ptr2)
+		{
+			Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index < ptr2.index;
+		}
+		public static bool operator <=(CharPtr ptr1, CharPtr ptr2)
+		{
+			Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index <= ptr2.index;
+		}
+		public static bool operator >(CharPtr ptr1, CharPtr ptr2)
+		{
+			Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index > ptr2.index;
+		}
+		public static bool operator >=(CharPtr ptr1, CharPtr ptr2)
+		{
+			Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index >= ptr2.index;
+		}
+		public static bool operator ==(CharPtr ptr1, CharPtr ptr2)
+		{
+			object o1 = ptr1 as CharPtr;
+			object o2 = ptr2 as CharPtr;
+			if ((o1 == null) && (o2 == null)) return true;
+			if (o1 == null) return false;
+			if (o2 == null) return false;
+			return (ptr1.chars == ptr2.chars) && (ptr1.index == ptr2.index);
+		}
+		public static bool operator !=(CharPtr ptr1, CharPtr ptr2) { return !(ptr1 == ptr2); }
+
+		public override bool Equals(object o)
+		{
+			return this == (o as CharPtr);
+		}
+
+		public override int GetHashCode()
+		{
+			return 0;
+		}
+		public override string ToString()
+		{
+			System.Text.StringBuilder result = new System.Text.StringBuilder();
+			for (int i = index; (i < chars.Length) && (chars[i] != '\0'); i++)
+				result.Append(chars[i]);
+
+			return result.ToString();
+		}
+
+		public string ToString(int length)
+		{
+			System.Text.StringBuilder result = new System.Text.StringBuilder();
+			for (int i = index; (i < chars.Length) && i < length; i++)
+				result.Append(chars[i]);
+			return result.ToString();
+		}
+	}
+
+}

+ 218 - 0
src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs

@@ -0,0 +1,218 @@
+#if false
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using ptrdiff_t = System.Int32;
+using lua_Integer = System.Int32;
+using LUA_INTFRM_T = System.Int64;
+using UNSIGNED_LUA_INTFRM_T = System.UInt64;
+using LuaLBuffer = System.Text.StringBuilder;
+
+namespace MoonSharp.Interpreter.Interop.LuaStateInterop
+{
+	public class LuaBase
+	{
+		protected const int LUA_TNONE = -1;
+		protected const int LUA_TNIL = 0;
+		protected const int LUA_TBOOLEAN = 1;
+		protected const int LUA_TLIGHTUSERDATA = 2;
+		protected const int LUA_TNUMBER = 3;
+		protected const int LUA_TSTRING = 4;
+		protected const int LUA_TTABLE = 5;
+		protected const int LUA_TFUNCTION = 6;
+		protected const int LUA_TUSERDATA = 7;
+		protected const int LUA_TTHREAD = 8;
+
+
+		protected static lua_Integer LuaType(LuaState L, lua_Integer p)
+		{
+			if (p > L.Args.Count || p <= 0)
+				return LUA_TNONE;
+
+			switch (L.Args[p].Type)
+			{
+				case DataType.Nil:
+					return LUA_TNIL;
+				case DataType.Boolean:
+					return LUA_TNIL;
+				case DataType.Number:
+					return LUA_TNUMBER;
+				case DataType.String:
+					return LUA_TSTRING;
+				case DataType.Function:
+					return LUA_TFUNCTION;
+				case DataType.Table:
+					return LUA_TTABLE;
+				case DataType.UserData:
+					return LUA_TUSERDATA;
+				case DataType.Thread:
+					return LUA_TTHREAD;
+				case DataType.ClrFunction:
+					return LUA_TFUNCTION;
+				case DataType.TailCallRequest:
+				case DataType.YieldRequest:
+				case DataType.Tuple:
+				default:
+					throw new ScriptRuntimeException("Can't call LuaType on any type");
+			}
+		}
+
+		protected static string LuaLCheckLString(LuaState L, lua_Integer argNum, out uint l)
+		{
+			string str = L.Args.AsString(L.ExecutionContext, argNum, L.FunctionName);
+			l = (uint)str.Length;
+			return str;
+		}
+
+		protected static void LuaPushInteger(LuaState L, lua_Integer val)
+		{
+			L.Stack.Push(DynValue.NewNumber(val));
+		}
+
+		protected static lua_Integer LuaToBoolean(LuaState L, lua_Integer p)
+		{
+			return L.Args[p].CastToBool() ? 1 : 0;
+		}
+
+		protected static string LuaToLString(LuaState luaState, lua_Integer p, out uint l)
+		{
+			return LuaLCheckLString(luaState, p, out l);
+		}
+
+		protected static string LuaToString(LuaState luaState, lua_Integer p)
+		{
+			uint l;
+			return LuaLCheckLString(luaState, p, out l);
+		}
+
+		protected static void LuaLAddValue(LuaLBuffer b)
+		{
+			b.StringBuilder.Append(b.LuaState.Stack.Pop().ToPrintString());
+		}
+
+		protected static void LuaLAddLString(LuaLBuffer b, CharPtr s, uint p)
+		{
+			b.StringBuilder.Append(s.ToString((int)p));
+		}
+
+		protected static lua_Integer LuaLOptInteger(LuaState L, lua_Integer pos, lua_Integer def)
+		{
+			return L.Args.AsInt(pos, L.FunctionName, true) ?? def;
+		}
+
+		protected static lua_Integer LuaLCheckInteger(LuaState L, lua_Integer pos)
+		{
+			return L.Args.AsInt(pos, L.FunctionName).Value;
+		}
+
+		protected static void LuaLArgCheck(LuaState L, bool condition, lua_Integer argNum, string message)
+		{
+			if (!condition)
+				throw new ScriptRuntimeException(message);
+		}
+
+		protected static lua_Integer LuaLCheckInt(LuaState L, lua_Integer argNum)
+		{
+			return LuaLCheckInteger(L, argNum);
+		}
+
+		protected static lua_Integer LuaGetTop(LuaState L)
+		{
+			return L.Args.Count;
+		}
+
+		protected static lua_Integer LuaLError(LuaState luaState, string message, params object[] args)
+		{
+			throw new ScriptRuntimeException(message, args);
+		}
+
+		protected static void LuaLAddChar(LuaLBuffer b, char p)
+		{
+			b.StringBuilder.Append(p);
+		}
+
+		protected static void LuaLBuffInit(LuaState L, LuaLBuffer b)
+		{
+		}
+
+		protected static void LuaPushLiteral(LuaState L, string literalString)
+		{
+			L.Stack.Push(DynValue.NewString(literalString));
+		}
+
+		protected static void LuaLPushResult(LuaLBuffer b)
+		{
+			LuaPushLiteral(b.LuaState, b.StringBuilder.ToString());
+		}
+
+		protected static void LuaPushLString(LuaState L, CharPtr s, uint len)
+		{
+			throw new NotImplementedException();
+		}
+
+		protected static void LuaLCheckStack(LuaState L, lua_Integer n, string message)
+		{
+			//throw new NotImplementedException();
+		}
+
+
+		protected static string LUA_QL(string p)
+		{
+			return "'" + p + "'";
+		}
+
+
+		protected static lua_Integer memcmp(CharPtr ptr1, CharPtr ptr2, uint size)
+		{
+			return memcmp(ptr1, ptr2, (int)size);
+		}
+
+		protected static int memcmp(CharPtr ptr1, CharPtr ptr2, int size)
+		{
+			for (int i = 0; i < size; i++)
+				if (ptr1[i] != ptr2[i])
+				{
+					if (ptr1[i] < ptr2[i])
+						return -1;
+					else
+						return 1;
+				}
+			return 0;
+		}
+
+		protected static CharPtr memchr(CharPtr ptr, char c, uint count)
+		{
+			for (uint i = 0; i < count; i++)
+				if (ptr[i] == c)
+					return new CharPtr(ptr.chars, (int)(ptr.index + i));
+			return null;
+		}
+
+		protected static CharPtr strpbrk(CharPtr str, CharPtr charset)
+		{
+			for (int i = 0; str[i] != '\0'; i++)
+				for (int j = 0; charset[j] != '\0'; j++)
+					if (str[i] == charset[j])
+						return new CharPtr(str.chars, str.index + i);
+			return null;
+		}
+
+		protected static void LuaPushNil(LuaState L)
+		{
+			L.Stack.Push(DynValue.Nil);
+		}
+
+		protected static void LuaAssert(bool p)
+		{
+			if (!p)
+				throw new InternalErrorException("LuaAssert failed!");
+		}
+
+
+
+
+	}
+}
+
+#endif

+ 21 - 0
src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaLBuffer.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop.LuaStateInterop
+{
+	public class LuaLBuffer 
+	{
+		public StringBuilder StringBuilder { get; private set; }
+		public LuaState LuaState { get; private set; }
+
+		public LuaLBuffer(LuaState l)
+		{
+			StringBuilder = new StringBuilder();
+			LuaState = l;
+		}
+
+
+	}
+}

+ 51 - 0
src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.DataStructs;
+using MoonSharp.Interpreter.Execution;
+
+namespace MoonSharp.Interpreter.Interop.LuaStateInterop
+{
+	/// <summary>
+	/// 
+	/// </summary>
+	public class LuaState
+	{
+		public ScriptExecutionContext ExecutionContext { get; private set; }
+
+		public FastStackDynamic<DynValue> Stack { get; private set; }
+
+		public string FunctionName { get; private set; }
+
+		internal LuaState(ScriptExecutionContext executionContext, CallbackArguments args, string functionName)
+		{
+			ExecutionContext = executionContext;
+			Stack = new FastStackDynamic<DynValue>(16);
+
+			for (int i = 0; i < args.Count; i++)
+				Stack.Push(args[i]);
+
+			FunctionName = functionName;
+		}
+
+		public DynValue GetReturnValue(int retvals)
+		{
+			if (retvals == 0)
+				return DynValue.Nil;
+			else if (retvals == 1)
+				return Stack.Peek(0);
+			else
+			{
+				DynValue[] rets = new DynValue[retvals];
+
+				for (int i = 0; i < retvals; i++)
+					rets[retvals - i - 1] = Stack.Peek(i);
+
+				return DynValue.NewTupleNested(rets);
+			}
+		}
+
+
+	}
+}

+ 9 - 0
src/MoonSharp.Interpreter/Interop/UserDataMethodDescriptor.cs

@@ -21,6 +21,7 @@ namespace MoonSharp.Interpreter.Interop
 		private object[] m_Defaults;
 		private object[] m_Defaults;
 		private Func<object, object[], object> m_OptimizedFunc = null;
 		private Func<object, object[], object> m_OptimizedFunc = null;
 		private Action<object, object[]> m_OptimizedAction = null;
 		private Action<object, object[]> m_OptimizedAction = null;
+		private bool m_IsAction = false;
 
 
 		internal UserDataMethodDescriptor(MethodInfo mi, InteropAccessMode accessMode)
 		internal UserDataMethodDescriptor(MethodInfo mi, InteropAccessMode accessMode)
 		{
 		{
@@ -29,6 +30,8 @@ namespace MoonSharp.Interpreter.Interop
 			this.Name = mi.Name;
 			this.Name = mi.Name;
 			this.IsStatic = mi.IsStatic;
 			this.IsStatic = mi.IsStatic;
 
 
+			m_IsAction = mi.ReturnType == typeof(void);
+
 			m_Arguments = mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
 			m_Arguments = mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
 			m_Defaults = mi.GetParameters().Select(pi => pi.DefaultValue).ToArray(); 
 			m_Defaults = mi.GetParameters().Select(pi => pi.DefaultValue).ToArray(); 
 
 
@@ -78,6 +81,12 @@ namespace MoonSharp.Interpreter.Interop
 			else if (m_OptimizedAction != null)
 			else if (m_OptimizedAction != null)
 			{
 			{
 				m_OptimizedAction(obj, pars);
 				m_OptimizedAction(obj, pars);
+				retv = DynValue.Void;
+			}
+			else if (m_IsAction)
+			{
+				MethodInfo.Invoke(obj, pars);
+				retv = DynValue.Void;
 			}
 			}
 			else
 			else
 			{
 			{

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

@@ -86,17 +86,21 @@
     <Compile Include="CoreLib\MathModule.cs" />
     <Compile Include="CoreLib\MathModule.cs" />
     <Compile Include="CoreLib\MetaTableMethods.cs" />
     <Compile Include="CoreLib\MetaTableMethods.cs" />
     <Compile Include="CoreLib\OsMethods.cs" />
     <Compile Include="CoreLib\OsMethods.cs" />
-    <Compile Include="CoreLib\Patterns\CaptureInfo.cs">
+    <Compile Include="CoreLib\StringLib\CaptureInfo.cs">
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
-    <Compile Include="CoreLib\Patterns\MatchState.cs">
+    <Compile Include="CoreLib\StringLib\KopiLua_StrLib.cs" />
+    <Compile Include="DataTypes\TypeValidationFlags.cs" />
+    <Compile Include="Interop\LuaStateInterop\CharPtr.cs" />
+    <Compile Include="Interop\LuaStateInterop\LuaBase.cs" />
+    <Compile Include="CoreLib\StringLib\MatchState.cs">
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
-    <Compile Include="CoreLib\Patterns\PatternMatching.cs">
+    <Compile Include="CoreLib\StringLib\PatternMatching.cs">
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
-    <Compile Include="CoreLib\Patterns\StringRange.cs" />
-    <Compile Include="CoreLib\Patterns\Tools.cs" />
+    <Compile Include="CoreLib\StringLib\StringRange.cs" />
+    <Compile Include="CoreLib\StringLib\Tools.cs" />
     <Compile Include="CoreLib\StringModule.cs" />
     <Compile Include="CoreLib\StringModule.cs" />
     <Compile Include="CoreLib\TableIterators.cs" />
     <Compile Include="CoreLib\TableIterators.cs" />
     <Compile Include="CoreLib\TableModule.cs" />
     <Compile Include="CoreLib\TableModule.cs" />
@@ -158,6 +162,8 @@
     <Compile Include="Interop\ConversionHelper.cs" />
     <Compile Include="Interop\ConversionHelper.cs" />
     <Compile Include="Interop\EnumerableWrapper.cs" />
     <Compile Include="Interop\EnumerableWrapper.cs" />
     <Compile Include="Interop\LinqHelpers.cs" />
     <Compile Include="Interop\LinqHelpers.cs" />
+    <Compile Include="Interop\LuaStateInterop\LuaLBuffer.cs" />
+    <Compile Include="Interop\LuaStateInterop\LuaState.cs" />
     <Compile Include="Interop\MoonSharpUserDataAttribute.cs" />
     <Compile Include="Interop\MoonSharpUserDataAttribute.cs" />
     <Compile Include="Interop\MoonSharpVisibleAttribute.cs" />
     <Compile Include="Interop\MoonSharpVisibleAttribute.cs" />
     <Compile Include="Interop\UserDataDelegateDescriptor.cs" />
     <Compile Include="Interop\UserDataDelegateDescriptor.cs" />

+ 2 - 2
src/PerformanceComparison/CallbacksAndForthTests.cs

@@ -62,7 +62,7 @@ namespace PerformanceComparison
 
 
 			var championProperties = new ChampionPropertiesComponent();
 			var championProperties = new ChampionPropertiesComponent();
 			championProperties.SetFirstName("John");
 			championProperties.SetFirstName("John");
-			championProperties.SetLastName("Smith");
+			championProperties.SetLastName("Smith"); 
 
 
 			//var nLuaFunction = (LuaFunction)nLuaState["onUpdate"];
 			//var nLuaFunction = (LuaFunction)nLuaState["onUpdate"];
 			var moonSharpFunction = (Closure)moonSharpState.Globals["onUpdate"];
 			var moonSharpFunction = (Closure)moonSharpState.Globals["onUpdate"];
@@ -78,7 +78,7 @@ namespace PerformanceComparison
 			// Test MoonSharp
 			// Test MoonSharp
 			startTime = Environment.TickCount;
 			startTime = Environment.TickCount;
 			//DynValue v = DynValue.FromObject(moonSharpState, championProperties.ToInterface());
 			//DynValue v = DynValue.FromObject(moonSharpState, championProperties.ToInterface());
-			for (int i = 0; i < 100000; i++) moonSharpFunction.Call(championProperties.ToInterface());
+			for (int i = 0; i < 2000000; i++) moonSharpFunction.Call(championProperties.ToInterface());
 			endTime = Environment.TickCount;
 			endTime = Environment.TickCount;
 			Console.WriteLine("MoonSharp : {0}", endTime - startTime);
 			Console.WriteLine("MoonSharp : {0}", endTime - startTime);
 		}
 		}

+ 1 - 1
src/PerformanceComparison/PerformanceComparison.csproj

@@ -9,7 +9,7 @@
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>PerformanceComparison</RootNamespace>
     <RootNamespace>PerformanceComparison</RootNamespace>
     <AssemblyName>PerformanceComparison</AssemblyName>
     <AssemblyName>PerformanceComparison</AssemblyName>
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <FileAlignment>512</FileAlignment>
     <SccProjectName>
     <SccProjectName>
     </SccProjectName>
     </SccProjectName>

+ 1 - 1
src/PerformanceComparison/app.config

@@ -1,3 +1,3 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <configuration>
 <configuration>
-<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>