Browse Source

User data fixes and bug fixes

Xanathar 11 years ago
parent
commit
757e5b6e22
43 changed files with 865 additions and 1186 deletions
  1. 30 0
      src/MoonSharp.Interpreter.Tests/EndToEnd/ErrorHandlingTests.cs
  2. 45 0
      src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs
  3. 181 1
      src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs
  4. 1 0
      src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.csproj
  5. 4 4
      src/MoonSharp.Interpreter.Tests/TestMore/314-regex.t
  6. 14 2
      src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs
  7. 0 37
      src/MoonSharp.Interpreter/CoreLib/StringLib/CaptureInfo.cs
  8. 8 4
      src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs
  9. 0 49
      src/MoonSharp.Interpreter/CoreLib/StringLib/MatchState.cs
  10. 0 836
      src/MoonSharp.Interpreter/CoreLib/StringLib/PatternMatching.cs
  11. 3 3
      src/MoonSharp.Interpreter/DataTypes/DynValue.cs
  12. 96 66
      src/MoonSharp.Interpreter/DataTypes/UserData.cs
  13. 5 0
      src/MoonSharp.Interpreter/Errors/DynamicExpressionException.cs
  14. 6 0
      src/MoonSharp.Interpreter/Errors/InternalErrorException.cs
  15. 12 0
      src/MoonSharp.Interpreter/Errors/InterpreterException.cs
  16. 6 0
      src/MoonSharp.Interpreter/Errors/ScriptRuntimeException.cs
  17. 12 0
      src/MoonSharp.Interpreter/Errors/SyntaxErrorException.cs
  18. 1 1
      src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs
  19. 2 1
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
  20. 8 6
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
  21. 0 0
      src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpUserDataAttribute.cs
  22. 0 0
      src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpVisibleAttribute.cs
  23. 0 0
      src/MoonSharp.Interpreter/Interop/Converters/ConversionHelper.cs
  24. 0 0
      src/MoonSharp.Interpreter/Interop/Converters/LinqHelpers.cs
  25. 17 0
      src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs
  26. 14 0
      src/MoonSharp.Interpreter/Interop/IUserDataType.cs
  27. 2 1
      src/MoonSharp.Interpreter/Interop/InteropAccessMode.cs
  28. 23 0
      src/MoonSharp.Interpreter/Interop/InteropRegistrationPolicy.cs
  29. 6 0
      src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs
  30. 0 11
      src/MoonSharp.Interpreter/Interop/Portable.cs
  31. 0 0
      src/MoonSharp.Interpreter/Interop/PredefinedUserData/AnonWrapper.cs
  32. 0 0
      src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs
  33. 68 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs
  34. 69 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs
  35. 194 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataDescriptor.cs
  36. 0 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataMethodDescriptor.cs
  37. 0 0
      src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataPropertyDescriptor.cs
  38. 0 18
      src/MoonSharp.Interpreter/Interop/UserDataDelegateDescriptor.cs
  39. 0 123
      src/MoonSharp.Interpreter/Interop/UserDataDescriptor.cs
  40. 19 21
      src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj
  41. 2 1
      src/MoonSharp.Interpreter/Script.cs
  42. 13 0
      src/MoonSharp.Interpreter/ScriptOptions.cs
  43. 4 1
      src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs

+ 30 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/ErrorHandlingTests.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace MoonSharp.Interpreter.Tests.EndToEnd
+{
+	[TestFixture]
+	public class ErrorHandlingTests
+	{
+		[Test]
+		public void PCallMultipleReturns()
+		{
+			string script = @"return pcall(function() return 1,2,3 end)";
+
+			Script S = new Script();
+			var res = S.DoString(script);
+
+			Assert.AreEqual(DataType.Tuple, res.Type);
+			Assert.AreEqual(4, res.Tuple.Length);
+			Assert.AreEqual(true, res.Tuple[0].Boolean);
+			Assert.AreEqual(1, res.Tuple[1].Number);
+			Assert.AreEqual(2, res.Tuple[2].Number);
+			Assert.AreEqual(3, res.Tuple[3].Number);
+		}
+
+
+	}
+}

+ 45 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs

@@ -1239,6 +1239,51 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(3, res.Number);
 			Assert.AreEqual(3, res.Number);
 		}
 		}
 
 
+		[Test]
+		public void VarArgsSumMainChunk()
+		{
+			string script = @"
+					local t = pack(...);
+					local sum = 0;
+
+					for i = 1, #t do
+						sum = sum + t[i];
+					end
+	
+					return sum;
+								";
+
+			DynValue fn = new Script().LoadString(script);
+
+			DynValue res = fn.Function.Call(1, 2, 3, 4);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(10, res.Number);
+		}
+
+		[Test]
+		[ExpectedException(ExpectedException = typeof(SyntaxErrorException))]
+		public void VarArgsInNoVarArgsReturnsError()
+		{
+			string script = @"
+					function x()
+						local t = {...};
+						local sum = 0;
+
+						for i = 1, #t do
+							sum = sum + t[i];
+						end
+	
+						return sum;
+					end
+
+					return x(1,2,3,4);
+								";
+
+			DynValue res = Script.RunString(script);
+		}
+
+
 
 
 	}
 	}
 }
 }

+ 181 - 1
src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs

@@ -2,6 +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.Interop;
 using NUnit.Framework;
 using NUnit.Framework;
 
 
 namespace MoonSharp.Interpreter.Tests.EndToEnd
 namespace MoonSharp.Interpreter.Tests.EndToEnd
@@ -16,8 +17,13 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 				return string.Format("{0}%{1}", p1, p2);
 				return string.Format("{0}%{1}", p1, p2);
 			}
 			}
 
 
+			public int SomeMethodWithLongName(int i)
+			{
+				return i * 2;
+			}
 
 
-			public static StringBuilder ConcatS(int p1, string p2, IComparable p3, bool p4, List<object> p5, IEnumerable<object> p6, 
+
+			public static StringBuilder ConcatS(int p1, string p2, IComparable p3, bool p4, List<object> p5, IEnumerable<object> p6,
 				StringBuilder p7, Dictionary<object, object> p8, SomeClass p9, int p10 = 1994)
 				StringBuilder p7, Dictionary<object, object> p8, SomeClass p9, int p10 = 1994)
 			{
 			{
 				p7.Append(p1);
 				p7.Append(p1);
@@ -68,9 +74,66 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			}
 			}
 		}
 		}
 
 
+		public interface Interface1
+		{
+			string Test1();
+		}
+
+		public interface Interface2
+		{
+			string Test2();
+		}
+
+		public class SomeOtherClass
+		{
+			public string Test1()
+			{
+				return "Test1";
+			}
+
+			public string Test2()
+			{
+				return "Test2";
+			}
+		}
+
+		public class SelfDescribingClass : IUserDataType
+		{
+			public DynValue Index(Script script, DynValue index)
+			{
+				return DynValue.NewNumber(index.Number * 3);
+			}
+
+			public bool SetIndex(Script script, DynValue index, DynValue value)
+			{
+				throw new NotImplementedException();
+			}
+
+			public DynValue MetaIndex(Script script, string metaname)
+			{
+				throw new NotImplementedException();
+			}
+		}
+
+		public class SomeOtherClassWithDualInterfaces : Interface1, Interface2
+		{
+			public string Test1()
+			{
+				return "Test1";
+			}
+
+			public string Test2()
+			{
+				return "Test2";
+			}
+		}
+
+
 
 
 		public void Test_ConcatMethodStatic(InteropAccessMode opt)
 		public void Test_ConcatMethodStatic(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				x = static.ConcatS(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
 				x = static.ConcatS(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
@@ -90,8 +153,11 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Assert.AreEqual(DataType.String, res.Type);
 			Assert.AreEqual(DataType.String, res.Type);
 			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1994", res.String);
 			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1994", res.String);
 		}
 		}
+
 		public void Test_ConcatMethod(InteropAccessMode opt)
 		public void Test_ConcatMethod(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				x = myobj.ConcatI(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
 				x = myobj.ConcatI(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
@@ -110,8 +176,11 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Assert.AreEqual(DataType.String, res.Type);
 			Assert.AreEqual(DataType.String, res.Type);
 			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1912", res.String);
 			Assert.AreEqual("eheh1ciao!SOMECLASS!True|asdqwezxc|asdqwezxc|123xy|asdqweXYzxc|!SOMECLASS!1912", res.String);
 		}
 		}
+
 		public void Test_ConcatMethodSemicolon(InteropAccessMode opt)
 		public void Test_ConcatMethodSemicolon(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				x = myobj:ConcatI(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
 				x = myobj:ConcatI(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
@@ -133,6 +202,8 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 
 
 		public void Test_ConcatMethodStaticSimplifiedSyntax(InteropAccessMode opt)
 		public void Test_ConcatMethodStaticSimplifiedSyntax(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				t = { 'asd', 'qwe', 'zxc', ['x'] = 'X', ['y'] = 'Y' };
 				x = static.ConcatS(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
 				x = static.ConcatS(1, 'ciao', myobj, true, t, t, 'eheh', t, myobj);
@@ -155,6 +226,8 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 
 
 		public void Test_DelegateMethod(InteropAccessMode opt)
 		public void Test_DelegateMethod(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				x = concat(1, 2);
 				x = concat(1, 2);
 				return x;";
 				return x;";
@@ -173,6 +246,8 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 
 
 		public void Test_ListMethod(InteropAccessMode opt)
 		public void Test_ListMethod(InteropAccessMode opt)
 		{
 		{
+			UserData.UnregisterType<SomeClass>();
+
 			string script = @"    
 			string script = @"    
 				x = mklist(1, 4);
 				x = mklist(1, 4);
 				sum = 0;				
 				sum = 0;				
@@ -305,5 +380,110 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 		{
 		{
 			Test_ListMethod(InteropAccessMode.Preoptimized);
 			Test_ListMethod(InteropAccessMode.Preoptimized);
 		}
 		}
+
+		[Test]
+		public void Interop_TestAutoregisterPolicy()
+		{
+			try
+			{
+				string script = @"return myobj:Test1()";
+
+				UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic;
+
+				Script S = new Script();
+
+				SomeOtherClass obj = new SomeOtherClass();
+
+				S.Globals.Set("myobj", UserData.Create(obj));
+
+				DynValue res = S.DoString(script);
+
+				Assert.AreEqual(DataType.String, res.Type);
+				Assert.AreEqual("Test1", res.String);
+			}
+			finally
+			{
+				UserData.RegistrationPolicy = InteropRegistrationPolicy.Explicit;
+			}
+		}
+
+		[Test]
+		public void Interop_TestAutoregisterPolicyWithDualInterfaces()
+		{
+			string script = @"return myobj:Test1() .. myobj:Test2()";
+
+			Script S = new Script();
+
+			UserData.RegisterType<Interface1>();
+			UserData.RegisterType<Interface2>();
+
+			SomeOtherClassWithDualInterfaces obj = new SomeOtherClassWithDualInterfaces();
+
+			S.Globals.Set("myobj", UserData.Create(obj));
+
+			DynValue res = S.DoString(script);
+
+			Assert.AreEqual(DataType.String, res.Type);
+			Assert.AreEqual("Test1Test2", res.String);
+		}
+
+		[Test]
+		public void Interop_TestNamesCamelized()
+		{
+			UserData.UnregisterType<SomeClass>();
+
+			string script = @"    
+				a = myobj:SomeMethodWithLongName(1);
+				b = myobj:someMethodWithLongName(2);
+				c = myobj:some_method_with_long_name(3);
+				d = myobj:Some_method_withLong_name(4);
+				
+				return a + b + c + d;
+			";
+
+			Script S = new Script();
+
+			SomeClass obj = new SomeClass();
+
+			UserData.RegisterType<SomeClass>();
+
+			S.Globals.Set("myobj", UserData.Create(obj));
+
+			DynValue res = S.DoString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(20, res.Number);
+
+		}
+
+		[Test]
+		public void Interop_TestSelfDescribingType()
+		{
+			UserData.UnregisterType<SelfDescribingClass>();
+
+			string script = @"    
+				a = myobj[1];
+				b = myobj[2];
+				c = myobj[3];
+				
+				return a + b + c;
+			";
+
+			Script S = new Script();
+
+			SelfDescribingClass obj = new SelfDescribingClass();
+
+			UserData.RegisterType<SelfDescribingClass>();
+
+			S.Globals.Set("myobj", UserData.Create(obj));
+
+			DynValue res = S.DoString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(18, res.Number);
+
+		}
+
+
 	}
 	}
 }
 }

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

@@ -80,6 +80,7 @@
     <Compile Include="EndToEnd\ClosureTests.cs" />
     <Compile Include="EndToEnd\ClosureTests.cs" />
     <Compile Include="EndToEnd\CoroutineTests.cs" />
     <Compile Include="EndToEnd\CoroutineTests.cs" />
     <Compile Include="EndToEnd\DynamicTests.cs" />
     <Compile Include="EndToEnd\DynamicTests.cs" />
+    <Compile Include="EndToEnd\ErrorHandlingTests.cs" />
     <Compile Include="EndToEnd\LuaTestSuiteExtract.cs" />
     <Compile Include="EndToEnd\LuaTestSuiteExtract.cs" />
     <Compile Include="EndToEnd\MetatableTests.cs">
     <Compile Include="EndToEnd\MetatableTests.cs">
       <SubType>Code</SubType>
       <SubType>Code</SubType>

+ 4 - 4
src/MoonSharp.Interpreter.Tests/TestMore/314-regex.t

@@ -196,13 +196,13 @@ local test_patterns = {
 	[===[a%X+f			abcdef		nil		not hexadecimal]===], 
 	[===[a%X+f			abcdef		nil		not hexadecimal]===], 
 	[===[a%X+f			axy;Zf		axy;Zf		not hexadecimal]===], 
 	[===[a%X+f			axy;Zf		axy;Zf		not hexadecimal]===], 
 	[===[a%z+f			abcdef		nil		zero (deprecated)]===], 
 	[===[a%z+f			abcdef		nil		zero (deprecated)]===], 
---	[===[a\0+f			abcdef		nil		zero]===], 
+	[===[a\0+f			abcdef		nil		zero]===], 
 	[===[a%z+f			a\0f		a\0f		zero (deprecated)]===], 
 	[===[a%z+f			a\0f		a\0f		zero (deprecated)]===], 
---	[===[a\0+f			a\0f		a\0f		zero]===], 
+	[===[a\0+f			a\0f		a\0f		zero]===], 
 	[===[a%Z+f			abcdef		abcdef		not zero (deprecated)]===], 
 	[===[a%Z+f			abcdef		abcdef		not zero (deprecated)]===], 
---	[===[a[^\0]+f		abcdef		abcdef		not zero]===], 
+	[===[a[^\0]+f		abcdef		abcdef		not zero]===], 
 	[===[a%Z+f			abc\0ef		nil		not zero (deprecated)]===], 
 	[===[a%Z+f			abc\0ef		nil		not zero (deprecated)]===], 
---	[===[a[^\0]+f		abc\0ef		nil		not zero]===], 
+	[===[a[^\0]+f		abc\0ef		nil		not zero]===], 
 	[===[a%b()f			a(bcde)f	a(bcde)f	balanced]===], 
 	[===[a%b()f			a(bcde)f	a(bcde)f	balanced]===], 
 	[===[a%b()f			a(b(de)f	nil		balanced]===], 
 	[===[a%b()f			a(b(de)f	nil		balanced]===], 
 	[===[a%b()f			a(b(d)e)f	a(b(d)e)f	balanced]===], 
 	[===[a%b()f			a(b(d)e)f	a(b(d)e)f	balanced]===], 

+ 14 - 2
src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs

@@ -79,15 +79,27 @@ namespace MoonSharp.Interpreter.CoreLib
 			}
 			}
 		}
 		}
 
 
+		private static DynValue MakeReturnTuple(bool retstatus, CallbackArguments args)
+		{
+			DynValue[] rets = new DynValue[args.Count + 1];
+
+			for (int i = 0; i < args.Count; i++)
+				rets[i + 1] = args[i];
+
+			rets[0] = DynValue.NewBoolean(retstatus);
+
+			return DynValue.NewTuple(rets);
+		}
+
 
 
 		public static DynValue pcall_continuation(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue pcall_continuation(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			return DynValue.NewTupleNested(DynValue.True, args[0]);
+			return MakeReturnTuple(true, args);			
 		}
 		}
 
 
 		public static DynValue pcall_onerror(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue pcall_onerror(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			return DynValue.NewTupleNested(DynValue.False, args[0]);
+			return MakeReturnTuple(false, args);
 		}
 		}
 
 
 
 

+ 0 - 37
src/MoonSharp.Interpreter/CoreLib/StringLib/CaptureInfo.cs

@@ -1,37 +0,0 @@
-#if true
-
-
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
-//
-// Copyright (C) 2013 Sheng Lunan
-//
-// 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.Linq;
-using System.Text;
-
-namespace MoonSharp.Interpreter.CoreLib.StringLib
-{
-	class CaptureInfo
-	{
-
-		public int Len;
-		public int Init;
-	}
-
-}
-
-
-#endif

+ 8 - 4
src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs

@@ -521,7 +521,8 @@ namespace MoonSharp.Interpreter.CoreLib.StringLib
 		{
 		{
 			uint l1, l2;
 			uint l1, l2;
 			CharPtr s = LuaLCheckLString(L, 1, out l1);
 			CharPtr s = LuaLCheckLString(L, 1, out l1);
-			CharPtr p = LuaLCheckLString(L, 2, out l2);
+			CharPtr p = PatchPattern(LuaLCheckLString(L, 2, out l2));
+
 			ptrdiff_t init = posrelat(LuaLOptInteger(L, 3, 1), l1) - 1;
 			ptrdiff_t init = posrelat(LuaLOptInteger(L, 3, 1), l1) - 1;
 			if (init < 0) init = 0;
 			if (init < 0) init = 0;
 			else if ((uint)(init) > l1) init = (ptrdiff_t)l1;
 			else if ((uint)(init) > l1) init = (ptrdiff_t)l1;
@@ -638,7 +639,7 @@ namespace MoonSharp.Interpreter.CoreLib.StringLib
 		{
 		{
 			CallbackFunction C = new CallbackFunction(gmatch_aux_2, "gmatch");
 			CallbackFunction C = new CallbackFunction(gmatch_aux_2, "gmatch");
 			string s = ArgAsType(L, 1, DataType.String, false).String;
 			string s = ArgAsType(L, 1, DataType.String, false).String;
-			string p = ArgAsType(L, 2, DataType.String, false).String;
+			string p = PatchPattern(ArgAsType(L, 2, DataType.String, false).String);
 
 
 
 
 			C.AdditionalData = new GMatchAuxData()
 			C.AdditionalData = new GMatchAuxData()
@@ -739,7 +740,7 @@ namespace MoonSharp.Interpreter.CoreLib.StringLib
 		{
 		{
 			uint srcl;
 			uint srcl;
 			CharPtr src = LuaLCheckLString(L, 1, out srcl);
 			CharPtr src = LuaLCheckLString(L, 1, out srcl);
-			CharPtr p = LuaLCheckString(L, 2);
+			CharPtr p = PatchPattern(LuaLCheckStringStr(L, 2));
 			int tr = LuaType(L, 3);
 			int tr = LuaType(L, 3);
 			int max_s = LuaLOptInt(L, 4, (int)(srcl + 1));
 			int max_s = LuaLOptInt(L, 4, (int)(srcl + 1));
 			int anchor = 0;
 			int anchor = 0;
@@ -990,7 +991,10 @@ namespace MoonSharp.Interpreter.CoreLib.StringLib
 		}
 		}
 
 
 
 
-
+		private static string PatchPattern(string charPtr)
+		{
+			return charPtr.Replace("\0", "%z");
+		}
 
 
 
 
 	}
 	}

+ 0 - 49
src/MoonSharp.Interpreter/CoreLib/StringLib/MatchState.cs

@@ -1,49 +0,0 @@
-#if true
-
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
-//
-// Copyright (C) 2013 Sheng Lunan
-//
-// 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.Linq;
-using System.Text;
-
-namespace MoonSharp.Interpreter.CoreLib.StringLib
-{
-	class MatchState
-	{
-		public int Level;
-		public string Src;
-		public int SrcInit;
-		public int SrcEnd;
-		public string Pattern;
-		public int PatternEnd;
-		public CaptureInfo[] Capture;
-
-		public MatchState()
-		{
-			Capture = new CaptureInfo[PatternMatching.LUA_MAXCAPTURES];
-
-			for (int i = 0; i < PatternMatching.LUA_MAXCAPTURES; ++i)
-			{
-				Capture[i] = new CaptureInfo();
-			}
-		}
-	}
-}
-
-
-#endif

+ 0 - 836
src/MoonSharp.Interpreter/CoreLib/StringLib/PatternMatching.cs

@@ -1,836 +0,0 @@
-#if true
-// This portion of code is taken from UniLua: https://github.com/xebecnan/UniLua
-//
-// Copyright (C) 2013 Sheng Lunan
-//
-// 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.Globalization;
-using System.Linq;
-using System.Text;
-using MoonSharp.Interpreter.Execution;
-
-namespace MoonSharp.Interpreter.CoreLib.StringLib
-{
-	static class PatternMatching
-	{
-		private const int CAP_UNFINISHED = -1;
-		private const int CAP_POSITION = -2;
-		public const int LUA_MAXCAPTURES = 32;
-		private const char L_ESC = '%';
-		private const string FLAGS = "-+ #0";
-		private static readonly char[] SPECIALS;
-
-		static PatternMatching()
-		{
-			SPECIALS = "^$*+?.([%-".ToCharArray();
-		}
-
-		private static int PosRelative(int pos, int len)
-		{
-			if (pos == int.MinValue) return 1;
-			else if (pos >= 0) return pos;
-			else if (0 - pos > len) return 0;
-			else return len - (-pos) + 1;
-		}
-
-		private static int ClassEnd(MatchState ms, int p)
-		{
-			switch (ms.Pattern[p++])
-			{
-				case L_ESC:
-					{
-						if (p == ms.PatternEnd)
-							throw new ScriptRuntimeException("malformed pattern (ends with '%')");
-						return p + 1;
-					}
-				case '[':
-					{
-						if (ms.Pattern[p] == '^') p++;
-						do
-						{
-							if (p == ms.PatternEnd)
-								throw new ScriptRuntimeException("malformed pattern (missing ']')");
-							if (ms.Pattern[p++] == L_ESC && p < ms.PatternEnd)
-								p++; // skip escapes (e.g. `%]')
-						} while (ms.Pattern[p] != ']');
-						return p + 1;
-					}
-				default: return p;
-			}
-		}
-
-		private static bool IsXDigit(char c)
-		{
-			switch (c)
-			{
-				case '0':
-				case '1':
-				case '2':
-				case '3':
-				case '4':
-				case '5':
-				case '6':
-				case '7':
-				case '8':
-				case '9':
-				case 'a':
-				case 'b':
-				case 'c':
-				case 'd':
-				case 'e':
-				case 'f':
-				case 'A':
-				case 'B':
-				case 'C':
-				case 'D':
-				case 'E':
-				case 'F':
-					return true;
-				default:
-					return false;
-			}
-		}
-
-		private static bool MatchClass(char c, char cl)
-		{
-			bool res;
-			bool reverse = false;
-
-			if (char.IsUpper(cl))
-			{
-				cl = char.ToLower(cl);
-				reverse = true;
-			}
-
-			switch (cl)
-			{
-				case 'a': res = Char.IsLetter(c); break;
-				case 'c': res = Char.IsControl(c); break;
-				case 'd': res = Char.IsDigit(c); break;
-				case 'g': throw new System.NotImplementedException();
-				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(c); break;
-				case 'z': res = (c == '\0'); break;  /* deprecated option */
-				default: return (cl == c);
-			}
-
-			if (reverse) return !res;
-			else return res;
-		}
-
-		private static bool MatchBreaketClass(MatchState ms, char c, int p, int ec)
-		{
-			bool sig = true;
-			if (ms.Pattern[p + 1] == '^')
-			{
-				sig = false;
-				p++; // skip the `^'
-			}
-			while (++p < ec)
-			{
-				if (ms.Pattern[p] == L_ESC)
-				{
-					p++;
-					if (MatchClass(c, ms.Pattern[p]))
-						return sig;
-				}
-				else if (ms.Pattern[p + 1] == '-' && (p + 2 < ec))
-				{
-					p += 2;
-					if (ms.Pattern[p - 2] <= c && c <= ms.Pattern[p])
-						return sig;
-				}
-				else if (ms.Pattern[p] == c) return sig;
-			}
-			return !sig;
-		}
-
-		private static bool SingleMatch(MatchState ms, char c, int p, int ep)
-		{
-			switch (ms.Pattern[p])
-			{
-				case '.': return true; // matches any char
-				case L_ESC: return MatchClass(c, ms.Pattern[p + 1]);
-				case '[': return MatchBreaketClass(ms, c, p, ep - 1);
-				default: return ms.Pattern[p] == c;
-			}
-		}
-
-		private static int MatchBalance(MatchState ms, int s, int p)
-		{
-			if (p >= ms.PatternEnd - 1)
-				throw new ScriptRuntimeException("malformed pattern (missing arguments to '%b')");
-			if (ms.Src[s] != ms.Pattern[p]) return -1;
-			else
-			{
-				char b = ms.Pattern[p];
-				char e = ms.Pattern[p + 1];
-				int count = 1;
-				while (++s < ms.SrcEnd)
-				{
-					if (ms.Src[s] == e)
-					{
-						if (--count == 0) return s + 1;
-					}
-					else if (ms.Src[s] == b) count++;
-				}
-			}
-			return -1; //string ends out of balance
-		}
-
-		private static int MaxExpand(MatchState ms, int s, int p, int ep)
-		{
-			int i = 0; // counts maximum expand for item
-			while ((s + i) < ms.SrcEnd && SingleMatch(ms, ms.Src[s + i], p, ep))
-				i++;
-			// keeps trying to match with the maximum repetitions
-			while (i >= 0)
-			{
-				int res = Match(ms, (s + i), (ep + 1));
-				if (res >= 0) return res;
-				i--; // else didn't match; reduce 1 repetition to try again
-			}
-			return -1;
-		}
-
-		private static int MinExpand(MatchState ms, int s, int p, int ep)
-		{
-			for (; ; )
-			{
-				int res = Match(ms, s, ep + 1);
-				if (res >= 0)
-					return res;
-				else if (s < ms.SrcEnd && SingleMatch(ms, ms.Src[s], p, ep))
-					s++; // try with one more repetition
-				else return -1;
-			}
-		}
-
-		private static int CaptureToClose(MatchState ms)
-		{
-			int level = ms.Level;
-			for (level--; level >= 0; level--)
-			{
-				if (ms.Capture[level].Len == CAP_UNFINISHED)
-					return level;
-			}
-
-			throw new ScriptRuntimeException("invalid pattern capture");
-		}
-
-		private static int StartCapture(MatchState ms, int s, int p, int what)
-		{
-			int level = ms.Level;
-			if (level >= LUA_MAXCAPTURES)
-				throw new ScriptRuntimeException("too many captures");
-
-			ms.Capture[level].Init = s;
-			ms.Capture[level].Len = what;
-			ms.Level = level + 1;
-			int res = Match(ms, s, p);
-			if (res == -1) // match failed?
-				ms.Level--;
-			return res;
-		}
-
-		private static int EndCapture(MatchState ms, int s, int p)
-		{
-			int l = CaptureToClose(ms);
-			ms.Capture[l].Len = s - ms.Capture[l].Init; // close capture
-			int res = Match(ms, s, p);
-			if (res == -1) // match failed?
-				ms.Capture[l].Len = CAP_UNFINISHED; // undo capture
-			return res;
-		}
-
-		private static int CheckCapture(MatchState ms, char l)
-		{
-			int i = (int)(l - '1');
-			if (i < 0 || i >= ms.Level || ms.Capture[i].Len == CAP_UNFINISHED)
-				throw new ScriptRuntimeException("invalid capture index {0}", i + 1);
-
-			return i;
-		}
-
-		private static int MatchCapture(MatchState ms, int s, char l)
-		{
-			int i = CheckCapture(ms, l);
-			int len = ms.Capture[i].Len;
-			if (ms.SrcEnd - s >= len &&
-				string.Compare(ms.Src, ms.Capture[i].Init, ms.Src, s, len) == 0)
-				return s + len;
-			else
-				return -1;
-		}
-
-		private static int Match(MatchState ms, int s, int p)
-		{
-		init: // using goto's to optimize tail recursion
-			if (p == ms.PatternEnd)
-				return s;
-			switch (ms.Pattern[p])
-			{
-				case '(': // start capture
-					{
-						if (ms.Pattern[p + 1] == ')') // position capture?
-							return StartCapture(ms, s, p + 2, CAP_POSITION);
-						else
-							return StartCapture(ms, s, p + 1, CAP_UNFINISHED);
-					}
-				case ')': // end capture
-					{
-						return EndCapture(ms, s, p + 1);
-					}
-				case '$':
-					{
-						if (p + 1 == ms.PatternEnd) // is the `$' the last char in pattern?
-							return (s == ms.SrcEnd) ? s : -1; // check end of string
-						else goto dflt;
-					}
-				case L_ESC: // escaped sequences not in the format class[*+?-]?
-					{
-						switch (ms.Pattern[p + 1])
-						{
-							case 'b': // balanced string?
-								{
-									s = MatchBalance(ms, s, p + 2);
-									if (s == -1) return -1;
-									p += 4; goto init; // else return match(ms, s, p+4);
-								}
-							case 'f': // frontier?
-								{
-									p += 2;
-									if (p >= ms.Pattern.Length || ms.Pattern[p] != '[')
-										throw new ScriptRuntimeException("missing '[' after '%f' in pattern");
-									int ep = ClassEnd(ms, p); //points to what is next
-									char previous = (s == ms.SrcInit) ? '\0' : ms.Src[s - 1];
-									if (MatchBreaketClass(ms, previous, p, ep - 1) ||
-										(s < ms.Src.Length && !MatchBreaketClass(ms, ms.Src[s], p, ep - 1))) return -1;
-									p = ep; goto init; // else return match( ms, s, ep );
-								}
-							case '0':
-							case '1':
-							case '2':
-							case '3':
-							case '4':
-							case '5':
-							case '6':
-							case '7':
-							case '8':
-							case '9': // capture results (%0-%9)?
-								{
-									s = MatchCapture(ms, s, ms.Pattern[p + 1]);
-									if (s == -1) return -1;
-									p += 2; goto init; // else return match(ms, s, p+2);
-								}
-							default: goto dflt;
-						}
-					}
-				default:
-				dflt: // pattern class plus optional suffix
-					{
-						int ep = ClassEnd(ms, p);
-						bool m = s < ms.SrcEnd && SingleMatch(ms, ms.Src[s], p, ep);
-						if (ep < ms.PatternEnd)
-						{
-							switch (ms.Pattern[ep]) //fix gmatch bug patten is [^a]
-							{
-								case '?': // optional
-									{
-										if (m)
-										{
-											int res = Match(ms, s + 1, ep + 1);
-											if (res != -1)
-												return res;
-										}
-										p = ep + 1; goto init; // else return match(ms, s, ep+1);
-									}
-								case '*': // 0 or more repetitions
-									{
-										return MaxExpand(ms, s, p, ep);
-									}
-								case '+': // 1 or more repetitions
-									{
-										return (m ? MaxExpand(ms, s + 1, p, ep) : -1);
-									}
-								case '-': // 0 or more repetitions (minimum)
-									{
-										return MinExpand(ms, s, p, ep);
-									}
-							}
-						}
-						if (!m) return -1;
-						s++; p = ep; goto init; // else return match(ms, s+1, ep);
-					}
-			}
-		}
-
-
-
-
-
-		private static DynValue PushOneCapture(MatchState ms, int i, int start, int end)
-		{
-			if (i >= ms.Level)
-			{
-				if (i == 0) // ms.Level == 0, too
-					return DynValue.NewString(ms.Src.Substring(start, end - start));
-				else
-					throw new ScriptRuntimeException("invalid capture index");
-			}
-			else
-			{
-				int l = ms.Capture[i].Len;
-				if (l == CAP_UNFINISHED)
-					throw new ScriptRuntimeException("unfinished capture");
-				if (l == CAP_POSITION)
-					return DynValue.NewNumber(ms.Capture[i].Init - ms.SrcInit + 1);
-				else
-					return DynValue.NewString(ms.Src.Substring(ms.Capture[i].Init, l));
-			}
-		}
-
-		private static DynValue PushCaptures(MatchState ms, int spos, int epos)
-		{
-			int nLevels = (ms.Level == 0 && spos >= 0) ? 1 : ms.Level;
-
-			DynValue[] captures = new DynValue[nLevels];
-
-			for (int i = 0; i < nLevels; ++i)
-				captures[i] = PushOneCapture(ms, i, spos, epos);
-
-			return DynValue.NewTuple(captures);
-		}
-
-		private static bool NoSpecials(string pattern)
-		{
-			return pattern.IndexOfAny(SPECIALS) == -1;
-		}
-
-		private static DynValue StrFindAux(string s, string p, int init, bool plain, bool find)
-		{
-			init = PosRelative(init, s.Length);
-
-			if (init < 1)
-			{
-				init = 1;
-			}
-			else if (init > s.Length + 1) // start after string's end?
-			{
-				return DynValue.Nil;
-			}
-			
-			// explicit request or no special characters?
-			if (find && (plain || NoSpecials(p)))
-			{
-				// do a plain search
-				int pos = s.IndexOf(p, init - 1);
-				if (pos >= 0)
-				{
-					return DynValue.NewTuple(
-						DynValue.NewNumber(pos + 1),
-						DynValue.NewNumber(pos + p.Length));
-				}
-			}
-			else
-			{
-				int s1 = init - 1;
-				int ppos = 0;
-				bool anchor = p[ppos] == '^';
-				if (anchor)
-					ppos++; // skip anchor character
-
-				MatchState ms = new MatchState();
-				ms.Src = s;
-				ms.SrcInit = s1;
-				ms.SrcEnd = s.Length;
-				ms.Pattern = p;
-				ms.PatternEnd = p.Length;
-
-				do
-				{
-					ms.Level = 0;
-					int res = Match(ms, s1, ppos);
-					if (res != -1)
-					{
-						if (find)
-						{
-							return DynValue.NewTupleNested(
-								DynValue.NewNumber(s1 + 1),
-								DynValue.NewNumber(res),
-								PushCaptures(ms, -1, 0));
-						}
-						else return PushCaptures(ms, s1, res);
-					}
-				} while (s1++ < ms.SrcEnd && !anchor);
-			}
-
-			return DynValue.Nil;
-		}
-
-		public static DynValue Str_Find(string s, string p, int init, bool plain)
-		{
-			return StrFindAux(s, p, init, plain, true);
-		}
-
-
-		private static DynValue GmatchAux(ScriptExecutionContext executionContext, CallbackArguments args)
-		{
-			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();
-			string src = v_src.String;
-			string pattern = v_pattern.String;
-			ms.Src = src;
-			ms.SrcInit = 0;
-			ms.SrcEnd = src.Length;
-			ms.Pattern = pattern;
-			ms.PatternEnd = pattern.Length;
-
-			for (int s = (int)v_idx.Number; s <= ms.SrcEnd; s++)
-			{
-				ms.Level = 0;
-				int e = Match(ms, s, 0);
-				if (e != -1)
-				{
-					int newStart = (e == 0) ? e + 1 : e;
-					GetClosure(executionContext).Set("idx", DynValue.NewNumber(newStart));
-					return PushCaptures(ms, s, e);
-				}
-			}
-
-			return DynValue.Nil;
-		}
-
-		private static Table GetClosure(ScriptExecutionContext executionContext)
-		{
-			return executionContext.AdditionalData as Table;
-		}
-
-		public static DynValue GMatch(Script script, string src, string pattern)
-		{
-			DynValue aux = DynValue.NewCallback(GmatchAux);
-
-			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;
-		}
-		public static DynValue Match(string s, string p, int init)
-		{
-			return StrFindAux(s, p, init, false, false);
-		}
-
-		private static void Add_S(MatchState ms, StringBuilder b, int s, int e, DynValue repl)
-		{
-			string news = repl.CastToString();
-			for (int i = 0; i < news.Length; i++)
-			{
-				if (news[i] != L_ESC)
-					b.Append(news[i]);
-				else
-				{
-					i++;  /* skip ESC */
-					if (!Char.IsDigit((news[i])))
-						b.Append(news[i]);
-					else if (news[i] == '0')
-						b.Append(ms.Src.Substring(s, (e - s)));
-					else
-					{
-						var v = PushOneCapture(ms, news[i] - '1', s, e);
-						b.Append(v.CastToString());  /* add capture to accumulated result */
-					}
-				}
-			}
-		}
-
-
-		private static void Add_Value(ScriptExecutionContext executionContext, MatchState ms, StringBuilder b, int s, int e, DynValue repl)
-		{
-			var result = DynValue.Nil;
-
-			switch (repl.Type)
-			{
-				case DataType.Number:
-				case DataType.String:
-					{
-						Add_S(ms, b, s, e, repl);
-						return;
-					}
-				case DataType.Function:
-					{
-						DynValue tuple = PushCaptures(ms, s, e);
-						result = repl.Function.Call(tuple.Tuple);
-						break;
-					}
-				case DataType.ClrFunction:
-					{
-						DynValue tuple = PushCaptures(ms, s, e);
-						result = repl.Callback.Invoke(executionContext, tuple.Tuple);
-
-						if (result.Type == DataType.TailCallRequest || result.Type == DataType.YieldRequest)
-							throw new ScriptRuntimeException("the function passed cannot be called directly as it contains a tail or yield request. wrap in a script function instead.");
-
-						break;
-					}
-				case DataType.Table:
-					{
-						var v = PushOneCapture(ms, 0, s, e);
-						result = repl.Table.Get(v);
-						break;
-					}
-			}
-			if (result.CastToBool() == false)
-			{  
-				b.Append(ms.Src.Substring(s, (e - s)));  /* keep original text */
-			}
-			else if (result.Type != DataType.String && result.Type != DataType.Number)
-				throw new ScriptRuntimeException("invalid replacement value (a %s)", result.Type.ToLuaTypeString());
-			else
-				b.Append(result.CastToString());
-		}
-
-		public static DynValue Str_Gsub(ScriptExecutionContext executionContext, string src, string p, DynValue repl, int? max_s_n)
-		{
-			int srcl = src.Length;
-			DataType tr = repl.Type;
-			int max_s = max_s_n ?? srcl + 1;
-
-			int anchor = 0;
-			if (p[0] == '^')
-			{
-				p = p.Substring(1);
-				anchor = 1;
-			}
-			int n = 0;
-			MatchState ms = new MatchState();
-			StringBuilder b = new StringBuilder(srcl);
-
-			if (tr != DataType.Number && tr != DataType.String && tr != DataType.Function && tr != DataType.Table && tr != DataType.ClrFunction)
-				throw new ScriptRuntimeException("string/function/table expected");
-
-			ms.Src = src;
-			ms.SrcInit = 0;
-			ms.SrcEnd = srcl;
-			ms.Pattern = p;
-			ms.PatternEnd = p.Length;
-			int s = 0;
-			while (n < max_s)
-			{
-				ms.Level = 0;
-				int e = Match(ms, s, 0);
-				if (e != -1)
-				{
-					n++;
-					Add_Value(executionContext, ms, b, s, e, repl);
-				}
-				if ((e != -1) && e > s) /* non empty match? */
-					s = e;  /* skip it */
-				else if (s < ms.SrcEnd)
-				{
-					char c = src[s];
-					++s;
-					b.Append(c);
-				}
-				else break;
-				if (anchor != 0) break;
-			}
-			b.Append(src.Substring(s, ms.SrcEnd - s));
-
-			return DynValue.NewTuple(
-				DynValue.NewString(b.ToString()),
-				DynValue.NewNumber(n)
-				);
-		}
-
-		private static int ScanFormat(string format, int s, out string form)
-		{
-			int p = s;
-			// skip flags
-			while (p < format.Length && format[p] != '\0' && FLAGS.IndexOf(format[p]) != -1)
-				p++;
-			if (p - s > FLAGS.Length)
-				throw new ScriptRuntimeException("invalid format (repeat flags)");
-			if (Char.IsDigit(format[p])) p++; // skip width
-			if (Char.IsDigit(format[p])) p++; // (2 digits at most)
-			if (format[p] == '.')
-			{
-				p++;
-				if (Char.IsDigit(format[p])) p++; // skip precision
-				if (Char.IsDigit(format[p])) p++; // (2 digits at most)
-			}
-			if (Char.IsDigit(format[p]))
-				throw new ScriptRuntimeException("invalid format (width of precision too long)");
-			form = "%" + format.Substring(s, (p - s + 1));
-			return p;
-		}
-
-		internal static string Str_Format(ScriptExecutionContext executionContext, CallbackArguments args)
-		{
-			const string FUNCNAME = "format";
-			string format = args.AsType(0, FUNCNAME, DataType.String, false).String;
-
-			StringBuilder sb = new StringBuilder();
-			int argidx = 0;
-			int top = args.Count;
-			int s = 0;
-			int e = format.Length;
-			while (s < e)
-			{
-				if (format[s] != L_ESC)
-				{
-					sb.Append(format[s++]);
-					continue;
-				}
-
-				if (format[++s] == L_ESC)
-				{
-					sb.Append(format[s++]);
-					continue;
-				}
-
-				++argidx;
-
-				string form;
-				s = ScanFormat(format, s, out form);
-				switch (format[s++]) // TODO: properly handle form
-				{
-					case 'c':
-						{
-							sb.Append((char)args.AsInt(argidx, FUNCNAME));
-							break;
-						}
-					case 'd':
-					case 'i':
-						{
-							int n = args.AsInt(argidx, FUNCNAME);
-							sb.Append(n.ToString(CultureInfo.InvariantCulture));
-							break;
-						}
-					case 'u':
-						{
-							int n = args.AsInt(argidx, FUNCNAME);
-							if (n < 0) throw ScriptRuntimeException.BadArgumentNoNegativeNumbers(argidx, FUNCNAME);
-							sb.Append(n.ToString(CultureInfo.InvariantCulture));
-							break;
-						}
-					case 'o':
-						{
-							int n = args.AsInt(argidx, FUNCNAME);
-							if (n < 0) throw ScriptRuntimeException.BadArgumentNoNegativeNumbers(argidx, FUNCNAME);
-							sb.Append(Convert.ToString(n, 8));
-							break;
-						}
-					case 'x':
-						{
-							int n = args.AsInt(argidx, FUNCNAME);
-							if (n < 0) throw ScriptRuntimeException.BadArgumentNoNegativeNumbers(argidx, FUNCNAME);
-							// sb.Append( string.Format("{0:x}", n) );
-							sb.AppendFormat("{0:x}", n);
-							break;
-						}
-					case 'X':
-						{
-							int n = args.AsInt(argidx, FUNCNAME);
-							if (n < 0) throw ScriptRuntimeException.BadArgumentNoNegativeNumbers(argidx, FUNCNAME);
-							// sb.Append( string.Format("{0:X}", n) );
-							sb.AppendFormat("{0:X}", n);
-							break;
-						}
-					case 'e':
-					case 'E':
-						{
-							sb.AppendFormat("{0:E}", args.AsType(argidx, FUNCNAME, DataType.Number).Number);
-							break;
-						}
-					case 'f':
-						{
-							sb.AppendFormat("{0:F}", args.AsType(argidx, FUNCNAME, DataType.Number).Number);
-							break;
-						}
-#if LUA_USE_AFORMAT
-					case 'a': case 'A':
-#endif
-					case 'g':
-					case 'G':
-						{
-							sb.AppendFormat("{0:G}", args.AsType(argidx, FUNCNAME, DataType.Number).Number);
-							break;
-						}
-					case 'q':
-						{
-							AddQuoted(sb, args.AsStringUsingMeta(executionContext, argidx, FUNCNAME));
-							break;
-						}
-					case 's':
-						{
-							sb.Append(args.AsStringUsingMeta(executionContext, argidx, FUNCNAME));
-							break;
-						}
-					default: // also treat cases `pnLlh'
-						{
-							throw new ScriptRuntimeException("invalid option '{0}' to 'format'",
-								format[s - 1]);
-						}
-				}
-			}
-			
-			return sb.ToString();
-		}
-
-		private static void AddQuoted(StringBuilder sb, string s)
-		{
-			sb.Append('"');
-			for (var i = 0; i < s.Length; ++i)
-			{
-				var c = s[i];
-				if (c == '"' || c == '\\' || c == '\n' || c == '\r')
-				{
-					sb.Append('\\').Append(c);
-				}
-				else if (c == '\0' || Char.IsControl(c))
-				{
-					if (i + 1 >= s.Length || !Char.IsDigit(s[i + 1]))
-					{
-						sb.AppendFormat("\\{0:D}", (int)c);
-					}
-					else
-					{
-						sb.AppendFormat("\\{0:D3}", (int)c);
-					}
-				}
-				else
-				{
-					sb.Append(c);
-				}
-			}
-			sb.Append('"');
-		}
-
-
-	}
-
-}
-#endif

+ 3 - 3
src/MoonSharp.Interpreter/DataTypes/DynValue.cs

@@ -426,9 +426,9 @@ namespace MoonSharp.Interpreter
 				if (m_Object is UserData)
 				if (m_Object is UserData)
 				{
 				{
 					UserData ud = (UserData)m_Object;
 					UserData ud = (UserData)m_Object;
-
-					if (ud.Object != null)
-						return ud.Object.ToString();
+					string str = ud.Descriptor.AsString(ud.Object);
+					if (str != null)
+						return str;
 				}
 				}
 
 
 				return refid.FormatTypeString(typeString);
 				return refid.FormatTypeString(typeString);

+ 96 - 66
src/MoonSharp.Interpreter/DataTypes/UserData.cs

@@ -18,31 +18,27 @@ namespace MoonSharp.Interpreter
 		public DynValue UserValue { get; set; }
 		public DynValue UserValue { get; set; }
 
 
 		public object Object { get; set; }
 		public object Object { get; set; }
-		internal UserDataDescriptor Descriptor { get; set; }
+		internal IUserDataDescriptor Descriptor { get; set; }
 
 
-#if USE_RW_LOCK
-		private static ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
-#else
-		private static object m_Lock = new object();
-#endif
-		private static Dictionary<Type, UserDataDescriptor> s_Registry = new Dictionary<Type, UserDataDescriptor>();
-		private static InteropAccessMode m_DefaultAccessMode;
+		private static object s_Lock = new object();
+		private static Dictionary<Type, IUserDataDescriptor> s_Registry = new Dictionary<Type, IUserDataDescriptor>();
+		private static InteropAccessMode s_DefaultAccessMode;
 
 
 		static UserData()
 		static UserData()
 		{
 		{
 			RegisterType<AnonWrapper>(InteropAccessMode.HideMembers);
 			RegisterType<AnonWrapper>(InteropAccessMode.HideMembers);
 			RegisterType<EnumerableWrapper>(InteropAccessMode.HideMembers);
 			RegisterType<EnumerableWrapper>(InteropAccessMode.HideMembers);
-			m_DefaultAccessMode = InteropAccessMode.LazyOptimized;
+			s_DefaultAccessMode = InteropAccessMode.LazyOptimized;
 		}
 		}
 
 
 		public static void RegisterType<T>(InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
 		public static void RegisterType<T>(InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
 		{
 		{
-			RegisterType_Impl(typeof(T), accessMode, friendlyName);
+			RegisterType_Impl(typeof(T), accessMode, friendlyName, null);
 		}
 		}
 
 
 		public static void RegisterType(Type type, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
 		public static void RegisterType(Type type, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null)
 		{
 		{
-			RegisterType_Impl(type, accessMode, friendlyName);
+			RegisterType_Impl(type, accessMode, friendlyName, null);
 		}
 		}
 
 
 		public static void RegisterAssembly(Assembly asm = null)
 		public static void RegisterAssembly(Assembly asm = null)
@@ -63,6 +59,17 @@ namespace MoonSharp.Interpreter
 			}
 			}
 		}
 		}
 
 
+		public static void UnregisterType<T>()
+		{
+			UnregisterType(typeof(T));
+		}
+
+		public static void UnregisterType(Type t)
+		{
+			lock (s_Lock)
+				if (s_Registry.ContainsKey(t))
+					s_Registry.Remove(t);
+		}
 
 
 		public static DynValue Create(object o)
 		public static DynValue Create(object o)
 		{
 		{
@@ -93,21 +100,23 @@ namespace MoonSharp.Interpreter
 			return CreateStatic(typeof(T));
 			return CreateStatic(typeof(T));
 		}
 		}
 
 
+		public static InteropRegistrationPolicy RegistrationPolicy { get; set; }
+
 		public static InteropAccessMode DefaultAccessMode
 		public static InteropAccessMode DefaultAccessMode
 		{
 		{
-			get { return m_DefaultAccessMode; }
+			get { return s_DefaultAccessMode; }
 			set
 			set
 			{
 			{
 				if (value == InteropAccessMode.Default)
 				if (value == InteropAccessMode.Default)
 					throw new ArgumentException("DefaultAccessMode");
 					throw new ArgumentException("DefaultAccessMode");
 
 
-				m_DefaultAccessMode = value;
+				s_DefaultAccessMode = value;
 			}
 			}
 		}
 		}
 
 
 
 
 
 
-		private static void RegisterType_Impl(Type type, InteropAccessMode accessMode, string friendlyName)
+		private static IUserDataDescriptor RegisterType_Impl(Type type, InteropAccessMode accessMode, string friendlyName, IUserDataDescriptor descriptor)
 		{
 		{
 			if (accessMode == InteropAccessMode.Default)
 			if (accessMode == InteropAccessMode.Default)
 			{
 			{
@@ -120,86 +129,107 @@ namespace MoonSharp.Interpreter
 
 
 
 
 			if (accessMode == InteropAccessMode.Default)
 			if (accessMode == InteropAccessMode.Default)
-				accessMode = m_DefaultAccessMode;
+				accessMode = s_DefaultAccessMode;
 
 
-#if USE_RW_LOCK
-			m_Lock.EnterWriteLock();
-#else
-			Monitor.Enter(m_Lock);
-#endif
-
-			try
+			lock(s_Lock)
 			{
 			{
 				if (!s_Registry.ContainsKey(type))
 				if (!s_Registry.ContainsKey(type))
 				{
 				{
-					UserDataDescriptor udd = new UserDataDescriptor(type, accessMode, friendlyName);
-					s_Registry.Add(udd.Type, udd);
-
-					if (accessMode == InteropAccessMode.BackgroundOptimized)
+					if (descriptor == null)
 					{
 					{
-						ThreadPool.QueueUserWorkItem(o => udd.Optimize());
+						if (type.GetInterfaces().Any(ii => ii == typeof(IUserDataType)))
+						{
+							AutoDescribingUserDataDescriptor audd = new AutoDescribingUserDataDescriptor(type, friendlyName);
+							s_Registry.Add(audd.Type, audd);
+							return audd;
+						}
+						else
+						{
+							StandardUserDataDescriptor udd = new StandardUserDataDescriptor(type, accessMode, friendlyName);
+							s_Registry.Add(udd.Type, udd);
+
+							if (accessMode == InteropAccessMode.BackgroundOptimized)
+							{
+								ThreadPool.QueueUserWorkItem(o => udd.Optimize());
+							}
+
+							return udd;
+						}
+					}
+					else
+					{
+						s_Registry.Add(descriptor.Type, descriptor);
+						return descriptor;
 					}
 					}
 				}
 				}
-			}
-			finally
-			{
-#if USE_RW_LOCK
-				m_Lock.ExitWriteLock();
-#else
-				Monitor.Exit(m_Lock);
-#endif
+				else return s_Registry[type];
 			}
 			}
 		}
 		}
 
 
-		private static UserDataDescriptor GetDescriptorForType<T>(bool deepSearch = true)
+		private static IUserDataDescriptor GetDescriptorForType<T>(bool searchInterfaces)
 		{
 		{
-			return GetDescriptorForType(typeof(T), deepSearch);
+			return GetDescriptorForType(typeof(T), searchInterfaces);
 		}
 		}
 
 
-		private static UserDataDescriptor GetDescriptorForType(Type type, bool deepSearch = true)
+		private static IUserDataDescriptor GetDescriptorForType(Type type, bool searchInterfaces)
 		{
 		{
-#if USE_RW_LOCK
-			m_Lock.EnterReadLock();
-#else
-			Monitor.Enter(m_Lock);
-#endif
-
-			try
+			lock(s_Lock)
 			{
 			{
-				if (!deepSearch)
-					return s_Registry.ContainsKey(type) ? s_Registry[type] : null;
+				IUserDataDescriptor typeDescriptor = null;
+
+				// if the type has been explicitly registered, return its descriptor as it's complete
+				if (s_Registry.ContainsKey(type))
+					return s_Registry[type];
 
 
-				for (Type t = type; t != typeof(object); t = t.BaseType)
+				if (RegistrationPolicy == InteropRegistrationPolicy.Automatic)
 				{
 				{
-					UserDataDescriptor u;
+					return RegisterType_Impl(type, DefaultAccessMode, type.FullName, null);
+				}
+
+				// search for the base object descriptors
+				for (Type t = type; t != null; t = t.BaseType)
+				{
+					IUserDataDescriptor u;
 
 
 					if (s_Registry.TryGetValue(t, out u))
 					if (s_Registry.TryGetValue(t, out u))
-						return u;
+					{
+						typeDescriptor = u;
+						break;
+					}
 				}
 				}
 
 
-				foreach (Type t in type.GetInterfaces())
+				// we should not search interfaces (for example, it's just for statics..), no need to look further
+				if (!searchInterfaces)
+					return typeDescriptor;
+
+				List<IUserDataDescriptor> descriptors = new List<IUserDataDescriptor>();
+
+				if (typeDescriptor != null)
+					descriptors.Add(typeDescriptor);
+
+
+				if (searchInterfaces)
 				{
 				{
-					if (s_Registry.ContainsKey(t))
-						return s_Registry[t];
+					foreach (Type t in type.GetInterfaces())
+					{
+						IUserDataDescriptor u;
+
+						if (s_Registry.TryGetValue(t, out u))
+							descriptors.Add(u);
+					}
 				}
 				}
 
 
-				if (s_Registry.ContainsKey(typeof(object)))
-					return s_Registry[type];
+				if (descriptors.Count == 1)
+					return descriptors[0];
+				else if (descriptors.Count == 0)
+					return null;
+				else
+					return new CompositeUserDataDescriptor(descriptors, type);
 			}
 			}
-			finally
-			{
-#if USE_RW_LOCK
-				m_Lock.ExitReadLock();
-#else
-				Monitor.Exit(m_Lock);
-#endif
-			}
-
-			return null;
 		}
 		}
 
 
 
 
-		private static UserDataDescriptor GetDescriptorForObject(object o)
+		private static IUserDataDescriptor GetDescriptorForObject(object o)
 		{
 		{
 			return GetDescriptorForType(o.GetType(), true);
 			return GetDescriptorForType(o.GetType(), true);
 		}
 		}

+ 5 - 0
src/MoonSharp.Interpreter/Errors/DynamicExpressionException.cs

@@ -11,6 +11,11 @@ namespace MoonSharp.Interpreter
 			: base("<dynamic>: " + format, args)
 			: base("<dynamic>: " + format, args)
 		{
 		{
 
 
+		}
+		public DynamicExpressionException(string message)
+			: base("<dynamic>: " + message)
+		{
+
 		}
 		}
 	}
 	}
 }
 }

+ 6 - 0
src/MoonSharp.Interpreter/Errors/InternalErrorException.cs

@@ -9,6 +9,12 @@ namespace MoonSharp.Interpreter
 	[Serializable]
 	[Serializable]
 	public class InternalErrorException : InterpreterException
 	public class InternalErrorException : InterpreterException
 	{
 	{
+		internal InternalErrorException(string message)
+			: base(message)
+		{
+
+		}
+
 		internal InternalErrorException(string format, params object[] args)
 		internal InternalErrorException(string format, params object[] args)
 			: base(format, args)
 			: base(format, args)
 		{
 		{

+ 12 - 0
src/MoonSharp.Interpreter/Errors/InterpreterException.cs

@@ -14,12 +14,24 @@ namespace MoonSharp.Interpreter
 
 
 		}
 		}
 
 
+		protected InterpreterException(string message)
+			: base(message)
+		{
+
+		}
+
 		protected InterpreterException(string format, params object[] args)
 		protected InterpreterException(string format, params object[] args)
 			: base(string.Format(format, args))
 			: base(string.Format(format, args))
 		{
 		{
 
 
 		}
 		}
 
 
+		protected InterpreterException(IParseTree tree, string message)
+			: base(message + FormatTree(tree))
+		{
+
+		}
+
 		protected InterpreterException(IParseTree tree, string format, params object[] args)
 		protected InterpreterException(IParseTree tree, string format, params object[] args)
 			: base(string.Format(format, args) + FormatTree(tree))
 			: base(string.Format(format, args) + FormatTree(tree))
 		{
 		{

+ 6 - 0
src/MoonSharp.Interpreter/Errors/ScriptRuntimeException.cs

@@ -16,6 +16,12 @@ namespace MoonSharp.Interpreter
 		{
 		{
 		}
 		}
 
 
+		public ScriptRuntimeException(string message)
+			: base(message)
+		{
+
+		}
+
 		public ScriptRuntimeException(string format, params object[] args)
 		public ScriptRuntimeException(string format, params object[] args)
 			: base(format, args)
 			: base(format, args)
 		{
 		{

+ 12 - 0
src/MoonSharp.Interpreter/Errors/SyntaxErrorException.cs

@@ -21,5 +21,17 @@ namespace MoonSharp.Interpreter
 		{
 		{
 
 
 		}
 		}
+
+		internal SyntaxErrorException(string message)
+			: base(message)
+		{
+
+		}
+
+		internal SyntaxErrorException(IParseTree tree, string message)
+			: base(tree, message)
+		{
+
+		}
 	}
 	}
 }
 }

+ 1 - 1
src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs

@@ -180,7 +180,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 			return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Closure, SymbolList = symbols, NumVal = jmpnum });
 			return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Closure, SymbolList = symbols, NumVal = jmpnum });
 		}
 		}
 
 
-		public Instruction Emit_Args(SymbolRef[] symbols)
+		public Instruction Emit_Args(params SymbolRef[] symbols)
 		{
 		{
 			return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Args, SymbolList = symbols });
 			return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Args, SymbolList = symbols });
 		}
 		}

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

@@ -118,6 +118,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		private void LeaveProcessor()
 		private void LeaveProcessor()
 		{
 		{
 			m_ExecutionNesting -= 1;
 			m_ExecutionNesting -= 1;
+			m_OwningThreadID = -1;
 
 
 			if (m_Parent != null)
 			if (m_Parent != null)
 			{
 			{
@@ -134,7 +135,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 		{
 		{
 			int threadID = Thread.CurrentThread.ManagedThreadId;
 			int threadID = Thread.CurrentThread.ManagedThreadId;
 
 
-			if (m_OwningThreadID >= 0 && m_OwningThreadID != threadID)
+			if (m_OwningThreadID >= 0 && m_OwningThreadID != threadID && m_Script.Options.CheckThreadAccess)
 			{
 			{
 				string msg = string.Format("Cannot enter the same MoonSharp processor from two different threads : {0} and {1}", m_OwningThreadID, threadID);
 				string msg = string.Format("Cannot enter the same MoonSharp processor from two different threads : {0} and {1}", m_OwningThreadID, threadID);
 				throw new InvalidOperationException(msg);
 				throw new InvalidOperationException(msg);

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

@@ -1130,10 +1130,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 				{
 				{
 					UserData ud = obj.UserData;
 					UserData ud = obj.UserData;
 
 
-					if (idx.Type != DataType.String)
-						throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__newindex", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
+					if (!ud.Descriptor.SetIndex(this.GetScript(), ud.Object, idx, value))
+					{
+						throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
+					}
 
 
-					ud.Descriptor.SetIndex(this.GetScript(), ud.Object, idx.String, value);
 					return instructionPtr;
 					return instructionPtr;
 				}
 				}
 				else
 				else
@@ -1197,10 +1198,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 				{
 				{
 					UserData ud = obj.UserData;
 					UserData ud = obj.UserData;
 
 
-					if (idx.Type != DataType.String)
-						throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__index", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
+					var v = ud.Descriptor.Index(this.GetScript(), ud.Object, idx);
+
+					if (v == null)
+						throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
 
 
-					var v = ud.Descriptor.Index(this.GetScript(), ud.Object, idx.String);
 					m_ValueStack.Push(v.AsReadOnly());
 					m_ValueStack.Push(v.AsReadOnly());
 					return instructionPtr;
 					return instructionPtr;
 				}
 				}

+ 0 - 0
src/MoonSharp.Interpreter/Interop/MoonSharpUserDataAttribute.cs → src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpUserDataAttribute.cs


+ 0 - 0
src/MoonSharp.Interpreter/Interop/MoonSharpVisibleAttribute.cs → src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpVisibleAttribute.cs


+ 0 - 0
src/MoonSharp.Interpreter/Interop/ConversionHelper.cs → src/MoonSharp.Interpreter/Interop/Converters/ConversionHelper.cs


+ 0 - 0
src/MoonSharp.Interpreter/Interop/LinqHelpers.cs → src/MoonSharp.Interpreter/Interop/Converters/LinqHelpers.cs


+ 17 - 0
src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	public interface IUserDataDescriptor
+	{
+		string Name { get; }
+		Type Type { get; }
+		DynValue Index(Script script, object obj, DynValue index);
+		bool SetIndex(Script script, object obj, DynValue index, DynValue value);
+		string AsString(object obj);
+		DynValue MetaIndex(Script script, object obj, string metaname);
+	}
+}

+ 14 - 0
src/MoonSharp.Interpreter/Interop/IUserDataType.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	public interface IUserDataType
+	{
+		DynValue Index(Script script, DynValue index);
+		bool SetIndex(Script script, DynValue index, DynValue value);
+		DynValue MetaIndex(Script script, string metaname);
+	}
+}

+ 2 - 1
src/MoonSharp.Interpreter/DataTypes/InteropAccessMode.cs → src/MoonSharp.Interpreter/Interop/InteropAccessMode.cs

@@ -6,7 +6,8 @@ using System.Text;
 namespace MoonSharp.Interpreter
 namespace MoonSharp.Interpreter
 {
 {
 	/// <summary>
 	/// <summary>
-	/// Enumerations of the possible strategies to marshal CLR objects to MoonSharp userdata and functions.
+	/// Enumerations of the possible strategies to marshal CLR objects to MoonSharp userdata and functions
+	/// when using automatic descriptors.
 	/// See also : <seealso cref="CallbackFunction"/> and <seealso cref="UserData"/> .
 	/// See also : <seealso cref="CallbackFunction"/> and <seealso cref="UserData"/> .
 	/// </summary>
 	/// </summary>
 	public enum InteropAccessMode
 	public enum InteropAccessMode

+ 23 - 0
src/MoonSharp.Interpreter/Interop/InteropRegistrationPolicy.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	/// <summary>
+	/// Enumerations of the possible policies to handle UserData type registrations
+	/// See also : <seealso cref="UserData"/> .
+	/// </summary>
+	public enum InteropRegistrationPolicy
+	{
+		/// <summary>
+		/// Types must be explicitly registered. If a base type or interface is registered, that is used.
+		/// </summary>
+		Explicit,
+		/// <summary>
+		/// Types are automatically registered if not found in the registry. This is easier to use but potentially unsafe.
+		/// </summary>
+		Automatic,
+	}
+}

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

@@ -251,6 +251,12 @@ namespace MoonSharp.Interpreter.Interop.LuaStateInterop
 			return LuaLCheckLString(L, p, out dummy);
 			return LuaLCheckLString(L, p, out dummy);
 		}
 		}
 
 
+		protected static string LuaLCheckStringStr(LuaState L, lua_Integer p)
+		{
+			uint dummy;
+			return LuaLCheckLString(L, p, out dummy);
+		}
+
 		protected static void LuaLArgError(LuaState L, lua_Integer arg, string p)
 		protected static void LuaLArgError(LuaState L, lua_Integer arg, string p)
 		{
 		{
 			throw ScriptRuntimeException.BadArgument(arg - 1, L.FunctionName, p);
 			throw ScriptRuntimeException.BadArgument(arg - 1, L.FunctionName, p);

+ 0 - 11
src/MoonSharp.Interpreter/Interop/Portable.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace MoonSharp.Interpreter.Interop
-{
-	public class Portable
-	{
-	}
-}

+ 0 - 0
src/MoonSharp.Interpreter/Interop/AnonWrapper.cs → src/MoonSharp.Interpreter/Interop/PredefinedUserData/AnonWrapper.cs


+ 0 - 0
src/MoonSharp.Interpreter/Interop/EnumerableWrapper.cs → src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs


+ 68 - 0
src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Interop;
+
+namespace MoonSharp.Interpreter
+{
+	internal class AutoDescribingUserDataDescriptor : IUserDataDescriptor
+	{
+		private string m_FriendlyName;
+		private Type m_Type;
+
+		public AutoDescribingUserDataDescriptor(Type type, string friendlyName)
+		{
+			m_FriendlyName = friendlyName;
+			m_Type = type;
+		}
+
+		public string Name
+		{
+			get { return m_FriendlyName; }
+		}
+
+		public Type Type
+		{
+			get { return m_Type; }
+		}
+
+		public DynValue Index(Script script, object obj, DynValue index)
+		{
+			IUserDataType u = obj as IUserDataType;
+
+			if (u != null)
+				return u.Index(script, index);
+
+			return null;
+		}
+
+		public bool SetIndex(Script script, object obj, DynValue index, DynValue value)
+		{
+			IUserDataType u = obj as IUserDataType;
+
+			if (u != null)
+				return u.SetIndex(script, index, value);
+
+			return false;
+		}
+
+		public string AsString(object obj)
+		{
+			if (obj != null)
+				return obj.ToString();
+			else
+				return null;
+		}
+
+		public DynValue MetaIndex(Script script, object obj, string metaname)
+		{
+			IUserDataType u = obj as IUserDataType;
+
+			if (u != null)
+				return u.MetaIndex(script, metaname);
+
+			return null;
+		}
+	}
+}

+ 69 - 0
src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	internal class CompositeUserDataDescriptor : IUserDataDescriptor
+	{
+		private List<IUserDataDescriptor> m_Descriptors;
+		private Type m_Type;
+
+		public CompositeUserDataDescriptor(List<IUserDataDescriptor> descriptors, Type type)
+		{
+			m_Descriptors = descriptors;
+			m_Type = type;
+		}
+
+		public string Name
+		{
+			get { return "^" + m_Type.FullName; }
+		}
+
+		public Type Type
+		{
+			get { return m_Type; }
+		}
+
+		public DynValue Index(Script script, object obj, DynValue index)
+		{
+			foreach (IUserDataDescriptor dd in m_Descriptors)
+			{
+				DynValue v = dd.Index(script, obj, index);
+
+				if (v != null)
+					return v;
+			}
+			return null;
+		}
+
+		public bool SetIndex(Script script, object obj, DynValue index, DynValue value)
+		{
+			foreach (IUserDataDescriptor dd in m_Descriptors)
+			{
+				if (dd.SetIndex(script, obj, index, value))
+					return true;
+			}
+			return false;
+		}
+
+		public string AsString(object obj)
+		{
+			return (obj != null) ? obj.ToString() : null;
+		}
+
+
+		public DynValue MetaIndex(Script script, object obj, string metaname)
+		{
+			foreach (IUserDataDescriptor dd in m_Descriptors)
+			{
+				DynValue v = dd.MetaIndex(script, obj, metaname);
+
+				if (v != null)
+					return v;
+			}
+			return null;
+		}
+	}
+}

+ 194 - 0
src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataDescriptor.cs

@@ -0,0 +1,194 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using MoonSharp.Interpreter.Execution;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	public class StandardUserDataDescriptor : IUserDataDescriptor
+	{
+		public string Name { get; private set; }
+		public Type Type { get; private set; }
+		public InteropAccessMode AccessMode { get; private set; }
+		public string FriendlyName { get; private set; }
+
+		private Dictionary<string, UserDataMethodDescriptor> m_Methods = new Dictionary<string, UserDataMethodDescriptor>();
+		private Dictionary<string, UserDataPropertyDescriptor> m_Properties = new Dictionary<string, UserDataPropertyDescriptor>();
+
+		protected internal StandardUserDataDescriptor(Type type, InteropAccessMode accessMode, string friendlyName)
+		{
+			Type = type;
+			Name = type.FullName;
+			AccessMode = accessMode;
+			FriendlyName = friendlyName;
+
+			if (AccessMode != InteropAccessMode.HideMembers)
+			{
+				foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Static))
+				{
+					if (CheckVisibility(mi.GetCustomAttributes(true), mi.IsPublic))
+					{
+						if (mi.IsSpecialName)
+							continue;
+
+						var md = new UserDataMethodDescriptor(mi, this.AccessMode);
+
+						if (m_Methods.ContainsKey(md.Name))
+							continue;
+						//throw new ArgumentException(string.Format("{0}.{1} has overloads", Name, md.Name));
+
+						m_Methods.Add(md.Name, md);
+					}
+				}
+
+				foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
+				{
+					if (CheckVisibility(pi.GetCustomAttributes(true), IsPropertyInfoPublic(pi)))
+					{
+						var pd = new UserDataPropertyDescriptor(pi, this.AccessMode);
+						m_Properties.Add(pd.Name, pd);
+					}
+				}
+			}
+		}
+
+		private bool IsPropertyInfoPublic(PropertyInfo pi)
+		{
+			MethodInfo getter = pi.GetGetMethod();
+			MethodInfo setter = pi.GetSetMethod();
+
+			return (getter != null && getter.IsPublic) || (setter != null && setter.IsPublic);
+		}
+
+		private bool CheckVisibility(object[] attributes, bool isPublic)
+		{
+			MoonSharpVisibleAttribute va = attributes.OfType<MoonSharpVisibleAttribute>().SingleOrDefault();
+
+			if (va != null)
+				return va.Visible;
+			else
+				return isPublic;
+		}
+
+
+		public DynValue Index(Script script, object obj, DynValue index)
+		{
+			if (index.Type != DataType.String)
+				throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__index", this.Name), "string", index.Type.ToLuaTypeString(), false);
+
+			DynValue v = TryIndex(script, obj, index.String);
+			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(index.String));
+			if (v == null) v = TryIndex(script, obj, Camelify(index.String));
+			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
+
+			return v;
+		}
+
+		protected virtual DynValue TryIndex(Script script, object obj, string indexName)
+		{
+			UserDataMethodDescriptor mdesc;
+
+			if (m_Methods.TryGetValue(indexName, out mdesc))
+				return DynValue.NewCallback(mdesc.GetCallback(script, obj));
+
+			UserDataPropertyDescriptor pdesc;
+
+			if (m_Properties.TryGetValue(indexName, out pdesc))
+			{
+				object o = pdesc.GetValue(obj);
+				return ConversionHelper.ClrObjectToComplexMoonSharpValue(script, o);
+			}
+
+			return null;
+		}
+
+		public bool SetIndex(Script script, object obj, DynValue index, DynValue value)
+		{
+			if (index.Type != DataType.String)
+				throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__setindex", this.Name), "string", index.Type.ToLuaTypeString(), false);
+
+			bool v = TrySetIndex(script, obj, index.String, value);
+			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
+			if (!v) v = TrySetIndex(script, obj, Camelify(index.String), value);
+			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
+
+			return v;
+		}
+
+		protected virtual bool TrySetIndex(Script script, object obj, string indexName, DynValue value)
+		{
+			UserDataPropertyDescriptor pdesc;
+
+			if (m_Properties.TryGetValue(indexName, out pdesc))
+			{
+				object o = ConversionHelper.MoonSharpValueToObjectOfType(value, pdesc.PropertyInfo.PropertyType, null);
+				pdesc.SetValue(obj, o, value.Type);
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		internal void Optimize()
+		{
+			foreach (var m in this.m_Methods.Values)
+				m.Optimize();
+
+			foreach (var m in this.m_Properties.Values)
+			{
+				m.OptimizeGetter();
+				m.OptimizeSetter();
+			}
+
+		}
+
+		protected static string Camelify(string name)
+		{
+			StringBuilder sb = new StringBuilder(name.Length);
+
+			bool lastWasUnderscore = false;
+			for (int i = 0; i < name.Length; i++)
+			{
+				if (name[i] == '_' && i != 0)
+				{
+					lastWasUnderscore = true;
+				}
+				else
+				{
+					if (lastWasUnderscore)
+						sb.Append(char.ToUpperInvariant(name[i]));
+					else
+						sb.Append(name[i]);
+
+					lastWasUnderscore = false;
+				}
+			}
+
+			return sb.ToString();
+		}
+
+		protected static  string UpperFirstLetter(string name)
+		{
+			if (!string.IsNullOrEmpty(name))
+				return char.ToUpperInvariant(name[0]) + name.Substring(1);
+
+			return name;
+		}
+
+		public string AsString(object obj)
+		{
+			return (obj != null) ? obj.ToString() : null;
+		}
+
+		public DynValue MetaIndex(Script script, object obj, string metaname)
+		{
+			// TODO: meta access to overloaded operators ?
+			return null;
+		}
+	}
+}

+ 0 - 0
src/MoonSharp.Interpreter/Interop/UserDataMethodDescriptor.cs → src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataMethodDescriptor.cs


+ 0 - 0
src/MoonSharp.Interpreter/Interop/UserDataPropertyDescriptor.cs → src/MoonSharp.Interpreter/Interop/StandardDescriptors/UserDataPropertyDescriptor.cs


+ 0 - 18
src/MoonSharp.Interpreter/Interop/UserDataDelegateDescriptor.cs

@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace MoonSharp.Interpreter.Interop
-{
-	class UserDataDelegateDescriptor
-	{
-
-		//void X(Delegate D)
-		//{
-		//	D.
-		//}
-
-
-	}
-}

+ 0 - 123
src/MoonSharp.Interpreter/Interop/UserDataDescriptor.cs

@@ -1,123 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using MoonSharp.Interpreter.Execution;
-
-namespace MoonSharp.Interpreter.Interop
-{
-	internal class UserDataDescriptor
-	{
-		internal string Name { get; private set; }
-		internal Type Type { get; private set; }
-		internal InteropAccessMode AccessMode { get; private set; }
-		internal string FriendlyName { get; private set; }
-
-		private Dictionary<string, UserDataMethodDescriptor> m_Methods = new Dictionary<string, UserDataMethodDescriptor>();
-		private Dictionary<string, UserDataPropertyDescriptor> m_Properties = new Dictionary<string, UserDataPropertyDescriptor>();
-
-		internal UserDataDescriptor(Type type, InteropAccessMode accessMode, string friendlyName)
-		{
-			Type = type;
-			Name = type.FullName;
-			AccessMode = accessMode;
-			FriendlyName = friendlyName;
-
-			if (AccessMode != InteropAccessMode.HideMembers)
-			{
-				foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Static))
-				{
-					if (CheckVisibility(mi.GetCustomAttributes(true), mi.IsPublic))
-					{
-						if (mi.IsSpecialName)
-							continue;
-
-						var md = new UserDataMethodDescriptor(mi, this.AccessMode);
-
-						if (m_Methods.ContainsKey(md.Name))
-							throw new ArgumentException(string.Format("{0}.{1} has overloads", Name, md.Name));
-
-						m_Methods.Add(md.Name, md);
-					}
-				}
-
-				foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
-				{
-					if (CheckVisibility(pi.GetCustomAttributes(true), IsPropertyInfoPublic(pi)))
-					{
-						var pd = new UserDataPropertyDescriptor(pi, this.AccessMode);
-						m_Properties.Add(pd.Name, pd);
-					}
-				}
-			}
-		}
-
-		private bool IsPropertyInfoPublic(PropertyInfo pi)
-		{
-			MethodInfo getter = pi.GetGetMethod();
-			MethodInfo setter = pi.GetSetMethod();
-
-			return (getter != null && getter.IsPublic) || (setter != null && setter.IsPublic);
-		}
-
-		private bool CheckVisibility(object[] attributes, bool isPublic)
-		{
-			MoonSharpVisibleAttribute va = attributes.OfType<MoonSharpVisibleAttribute>().SingleOrDefault();
-
-			if (va != null)
-				return va.Visible;
-			else
-				return isPublic;
-		}
-
-
-
-		internal DynValue Index(Script script, object obj, string idxname)
-		{
-			UserDataMethodDescriptor mdesc;
-
-			if (m_Methods.TryGetValue(idxname, out mdesc))
-				return DynValue.NewCallback(mdesc.GetCallback(script, obj));
-
-			UserDataPropertyDescriptor pdesc;
-
-			if (m_Properties.TryGetValue(idxname, out pdesc))
-			{
-				object o = pdesc.GetValue(obj);
-				return ConversionHelper.ClrObjectToComplexMoonSharpValue(script, o);
-			}
-
-			throw ScriptRuntimeException.UserDataMissingField(this.Name, idxname);
-		}
-
-		internal void SetIndex(Script script, object obj, string idxname, DynValue value)
-		{
-			UserDataPropertyDescriptor pdesc;
-
-			if (m_Properties.TryGetValue(idxname, out pdesc))
-			{
-				object o = ConversionHelper.MoonSharpValueToObjectOfType(value, pdesc.PropertyInfo.PropertyType, null);
-				pdesc.SetValue(obj, o, value.Type);
-			}
-			else
-			{
-				throw ScriptRuntimeException.UserDataMissingField(this.Name, idxname);
-			}
-		}
-
-		internal void Optimize()
-		{
-			foreach (var m in this.m_Methods.Values)
-				m.Optimize();
-			
-			foreach (var m in this.m_Properties.Values)
-			{
-				m.OptimizeGetter();
-				m.OptimizeSetter();
-			}
-
-		}
-	}
-}

+ 19 - 21
src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj

@@ -95,24 +95,18 @@
     <Compile Include="CoreLib\MetaTableModule.cs" />
     <Compile Include="CoreLib\MetaTableModule.cs" />
     <Compile Include="CoreLib\OsSystemModule.cs" />
     <Compile Include="CoreLib\OsSystemModule.cs" />
     <Compile Include="CoreLib\OsTimeModule.cs" />
     <Compile Include="CoreLib\OsTimeModule.cs" />
-    <Compile Include="CoreLib\StringLib\CaptureInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
     <Compile Include="CoreLib\StringLib\KopiLua_StrLib.cs" />
     <Compile Include="CoreLib\StringLib\KopiLua_StrLib.cs" />
+    <Compile Include="Interop\InteropRegistrationPolicy.cs" />
+    <Compile Include="Interop\IUserDataType.cs" />
     <Compile Include="DataTypes\ScriptFunctionDelegate.cs" />
     <Compile Include="DataTypes\ScriptFunctionDelegate.cs" />
     <Compile Include="DataTypes\TypeValidationFlags.cs" />
     <Compile Include="DataTypes\TypeValidationFlags.cs" />
     <Compile Include="Errors\DynamicExpressionException.cs" />
     <Compile Include="Errors\DynamicExpressionException.cs" />
     <Compile Include="Execution\DynamicExpression.cs" />
     <Compile Include="Execution\DynamicExpression.cs" />
     <Compile Include="Execution\VM\CallStackItemFlags.cs" />
     <Compile Include="Execution\VM\CallStackItemFlags.cs" />
-    <Compile Include="Interop\AnonWrapper.cs" />
+    <Compile Include="Interop\PredefinedUserData\AnonWrapper.cs" />
+    <Compile Include="Interop\IUserDataDescriptor.cs" />
     <Compile Include="Interop\LuaStateInterop\CharPtr.cs" />
     <Compile Include="Interop\LuaStateInterop\CharPtr.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase.cs" />
-    <Compile Include="CoreLib\StringLib\MatchState.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="CoreLib\StringLib\PatternMatching.cs">
-      <SubType>Code</SubType>
-    </Compile>
     <Compile Include="CoreLib\StringLib\StringRange.cs" />
     <Compile Include="CoreLib\StringLib\StringRange.cs" />
     <Compile Include="Interop\LuaStateInterop\Tools.cs" />
     <Compile Include="Interop\LuaStateInterop\Tools.cs" />
     <Compile Include="CoreLib\StringModule.cs" />
     <Compile Include="CoreLib\StringModule.cs" />
@@ -171,20 +165,24 @@
     <Compile Include="Execution\VM\Processor\Processor_Coroutines.cs" />
     <Compile Include="Execution\VM\Processor\Processor_Coroutines.cs" />
     <Compile Include="Execution\VM\Processor\Processor_Errors.cs" />
     <Compile Include="Execution\VM\Processor\Processor_Errors.cs" />
     <Compile Include="Interface\IteratorHelper.cs" />
     <Compile Include="Interface\IteratorHelper.cs" />
-    <Compile Include="Interop\ConversionHelper.cs" />
-    <Compile Include="Interop\EnumerableWrapper.cs" />
-    <Compile Include="Interop\LinqHelpers.cs" />
+    <Compile Include="Interop\Converters\ConversionHelper.cs" />
+    <Compile Include="Interop\PredefinedUserData\EnumerableWrapper.cs" />
+    <Compile Include="Interop\Converters\LinqHelpers.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase_CLib.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase_CLib.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaLBuffer.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaLBuffer.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaState.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaState.cs" />
-    <Compile Include="Interop\MoonSharpUserDataAttribute.cs" />
-    <Compile Include="Interop\MoonSharpVisibleAttribute.cs" />
-    <Compile Include="Interop\Portable.cs" />
-    <Compile Include="Interop\UserDataDelegateDescriptor.cs" />
-    <Compile Include="Interop\UserDataDescriptor.cs" />
-    <Compile Include="DataTypes\InteropAccessMode.cs" />
-    <Compile Include="Interop\UserDataMethodDescriptor.cs" />
-    <Compile Include="Interop\UserDataPropertyDescriptor.cs">
+    <Compile Include="Interop\Attributes\MoonSharpUserDataAttribute.cs" />
+    <Compile Include="Interop\Attributes\MoonSharpVisibleAttribute.cs" />
+    <Compile Include="Interop\StandardDescriptors\AutoDescribingUserDataDescriptor.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interop\StandardDescriptors\CompositeUserDataDescriptor.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interop\StandardDescriptors\UserDataDescriptor.cs" />
+    <Compile Include="Interop\InteropAccessMode.cs" />
+    <Compile Include="Interop\StandardDescriptors\UserDataMethodDescriptor.cs" />
+    <Compile Include="Interop\StandardDescriptors\UserDataPropertyDescriptor.cs">
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
     <Compile Include="Loaders\ClassicLuaScriptLoader.cs" />
     <Compile Include="Loaders\ClassicLuaScriptLoader.cs" />

+ 2 - 1
src/MoonSharp.Interpreter/Script.cs

@@ -26,7 +26,7 @@ namespace MoonSharp.Interpreter
 		/// <summary>
 		/// <summary>
 		/// The version of the MoonSharp engine
 		/// The version of the MoonSharp engine
 		/// </summary>
 		/// </summary>
-		public const string VERSION = "0.8.1.0";
+		public const string VERSION = "0.8.5.0"; 
 
 
 		/// <summary>
 		/// <summary>
 		/// The Lua version being supported
 		/// The Lua version being supported
@@ -47,6 +47,7 @@ namespace MoonSharp.Interpreter
 				ScriptLoader = new ClassicLuaScriptLoader(),
 				ScriptLoader = new ClassicLuaScriptLoader(),
 				DebugPrint = s => { Console.WriteLine(s); },
 				DebugPrint = s => { Console.WriteLine(s); },
 				DebugInput = () => { return Console.ReadLine(); },
 				DebugInput = () => { return Console.ReadLine(); },
+				CheckThreadAccess = true,
 			};
 			};
 		}
 		}
 
 

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

@@ -52,5 +52,18 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		/// </summary>
 		public bool UseLuaErrorLocations { get; set; }
 		public bool UseLuaErrorLocations { get; set; }
 
 
+
+		/// <summary>
+		/// Gets or sets a value indicating whether the thread check is enabled.
+		/// A "lazy" thread check is performed everytime execution is entered to ensure that no two threads
+		/// calls MoonSharp execution concurrently. However 1) the check is performed best effort (thus, it might
+		/// not detect all issues) and 2) it might trigger in very odd legal situations (like, switching threads 
+		/// inside a CLR-callback without actually having concurrency.
+		/// 
+		/// Disable this option if the thread check is giving problems in your scenario, but please check that
+		/// you are not calling MoonSharp execution concurrently as it is not supported.
+		/// </summary>
+		public bool CheckThreadAccess { get; set; }
+
 	}
 	}
 }
 }

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

@@ -19,12 +19,14 @@ namespace MoonSharp.Interpreter.Tree.Statements
 		RuntimeScopeFrame m_StackFrame;
 		RuntimeScopeFrame m_StackFrame;
 		Table m_GlobalEnv;
 		Table m_GlobalEnv;
 		SymbolRef m_Env;
 		SymbolRef m_Env;
+		SymbolRef m_VarArgs;
 
 
 		public ChunkStatement(LuaParser.ChunkContext context, ScriptLoadingContext lcontext, Table globalEnv)
 		public ChunkStatement(LuaParser.ChunkContext context, ScriptLoadingContext lcontext, Table globalEnv)
 			: base(context, lcontext)
 			: base(context, lcontext)
 		{
 		{
-			lcontext.Scope.PushFunction(this, false);
+			lcontext.Scope.PushFunction(this, true);
 			m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV);
 			m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV);
+			m_VarArgs = lcontext.Scope.DefineLocal(WellKnownSymbols.VARARGS);
 			
 			
 			m_GlobalEnv = globalEnv;
 			m_GlobalEnv = globalEnv;
 
 
@@ -35,6 +37,7 @@ namespace MoonSharp.Interpreter.Tree.Statements
 		public override void Compile(Execution.VM.ByteCode bc)
 		public override void Compile(Execution.VM.ByteCode bc)
 		{
 		{
 			bc.Emit_BeginFn(m_StackFrame, "<chunk-root>");
 			bc.Emit_BeginFn(m_StackFrame, "<chunk-root>");
+			bc.Emit_Args(m_VarArgs);
 
 
 			bc.Emit_Literal(DynValue.NewTable(m_GlobalEnv));
 			bc.Emit_Literal(DynValue.NewTable(m_GlobalEnv));
 			bc.Emit_Store(m_Env, 0, 0);
 			bc.Emit_Store(m_Env, 0, 0);