浏览代码

tostring and print

Xanathar 11 年之前
父节点
当前提交
aa34b89d14

+ 1 - 7
src/MoonSharp.Debugger/MainForm.cs

@@ -50,12 +50,6 @@ namespace MoonSharp.Debugger
 		Script m_Script;
 		Script m_Script;
 		SynchronizationContext m_Ctx;
 		SynchronizationContext m_Ctx;
 
 
-		DynValue Print(ScriptExecutionContext executionContext, CallbackArguments values)
-		{
-			string prn = string.Join(" ", values.List.Select(v => v.ToPrintString()).ToArray());
-			Console_WriteLine("{0}", prn);
-			return DynValue.Nil;
-		}
 
 
 		DynValue Assert(ScriptExecutionContext executionContext, CallbackArguments values)
 		DynValue Assert(ScriptExecutionContext executionContext, CallbackArguments values)
 		{
 		{
@@ -91,7 +85,7 @@ namespace MoonSharp.Debugger
 		{
 		{
 			m_Script = new Script(CoreModules.Preset_Complete);
 			m_Script = new Script(CoreModules.Preset_Complete);
 
 
-			m_Script.Globals["print"] = DynValue.NewCallback(Print);
+			m_Script.DebugPrint = s => { Console_WriteLine("{0}", s); };
 			m_Script.Globals["assert"] = DynValue.NewCallback(Assert);
 			m_Script.Globals["assert"] = DynValue.NewCallback(Assert);
 			m_Script.Globals["xassert"] = DynValue.NewCallback(XAssert);
 			m_Script.Globals["xassert"] = DynValue.NewCallback(XAssert);
 
 

+ 54 - 18
src/MoonSharp.Interpreter.Tests/EndToEnd/TailCallTests.cs

@@ -11,33 +11,69 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 	public class TailCallTests
 	public class TailCallTests
 	{
 	{
 		[Test]
 		[Test]
-		[Ignore]
 		public void TailCallFromCLR()
 		public void TailCallFromCLR()
 		{
 		{
-//			string script = @"
-//				function getResult(x)
-//					return 156*x;  
-//				end
-//
-//				return clrtail(9)";
+			string script = @"
+				function getResult(x)
+					return 156*x;  
+				end
 
 
+				return clrtail(9)";
 
 
-//			Script S = new Script();
 
 
-//			S.Globals["clrtail"] = DynValue.NewCallback((xc, a) =>
-//			{
-//				SymbolRef lref = SymbolRef.Global("getResult");
-//				DynValue fn = xc.GetVar(lref);
-//				DynValue k3 = DynValue.NewNumber(a[0].Number / 3);
+			Script S = new Script();
 
 
-//				return DynValue.NewTailCallReq(fn, k3);
-//			});
+			S.Globals["clrtail"] = DynValue.NewCallback((xc, a) =>
+			{
+				DynValue fn = S.Globals["getResult"];
+				DynValue k3 = DynValue.NewNumber(a[0].Number / 3);
 
 
-//			var res = S.DoString(script);
+				return DynValue.NewTailCallReq(fn, k3);
+			});
 
 
-//			Assert.AreEqual(DataType.Number, res.Type);
-//			Assert.AreEqual(468, res.Number);
+			var res = S.DoString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(468, res.Number);
+		}
+
+
+		[Test]
+		public void CheckToString()
+		{
+			string script = @"
+				return tostring(9)";
+
+
+			Script S = new Script();
+			var res = S.DoString(script);
+
+			Assert.AreEqual(DataType.String, res.Type);
+			Assert.AreEqual("9", res.String);
 		}
 		}
 
 
+		[Test]
+		public void CheckToStringMeta()
+		{
+			string script = @"
+				t = {}
+				m = {
+					__tostring = function(v)
+						return 'ciao';
+					end
+				}
+
+				setmetatable(t, m);
+				s = tostring(t);
+
+				return (s);";
+
+
+			Script S = new Script();
+			var res = S.DoString(script);
+
+			Assert.AreEqual(DataType.String, res.Type);
+			Assert.AreEqual("ciao", res.String);
+		}
 	}
 	}
 }
 }

+ 1 - 1
src/MoonSharp.Interpreter.Tests/TestMore/231-metatable.t

@@ -38,7 +38,7 @@ is(setmetatable(t, t1), t)
 is(getmetatable(t), t1)
 is(getmetatable(t), t1)
 is(setmetatable(t, nil), t)
 is(setmetatable(t, nil), t)
 error_like(function () setmetatable(t, true) end,
 error_like(function () setmetatable(t, true) end,
-           "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected%)")
+           "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected.+%)")
 
 
 mt = {}
 mt = {}
 mt.__metatable = "not your business"
 mt.__metatable = "not your business"

+ 3 - 4
src/MoonSharp.Interpreter.Tests/TestMore/TapRunner.cs

@@ -14,11 +14,9 @@ namespace MoonSharp.Interpreter.Tests
 	{
 	{
 		string m_File;
 		string m_File;
 
 
-		public DynValue Print(ScriptExecutionContext exctx, CallbackArguments values)
+		public void Print(string str)
 		{
 		{
-			string str = string.Join(" ", values.List.Select(s => s.ToPrintString()).ToArray());
 			Assert.IsFalse(str.Trim().StartsWith("not ok"), string.Format("TAP fail ({0}) : {1}", m_File, str));
 			Assert.IsFalse(str.Trim().StartsWith("not ok"), string.Format("TAP fail ({0}) : {1}", m_File, str));
-			return DynValue.Nil;
 		}
 		}
 
 
 		public TapRunner(string filename)
 		public TapRunner(string filename)
@@ -30,7 +28,8 @@ namespace MoonSharp.Interpreter.Tests
 		{
 		{
 			Script S = new Script();
 			Script S = new Script();
 
 
-			S.Globals["print"] = DynValue.NewCallback(Print);
+			//S.Globals["print"] = DynValue.NewCallback(Print);
+			S.DebugPrint = Print;
 			S.Globals["arg"] = DynValue.NewTable(S);
 			S.Globals["arg"] = DynValue.NewTable(S);
 
 
 			var L = new ClassicLuaScriptLoader();
 			var L = new ClassicLuaScriptLoader();

+ 0 - 2
src/MoonSharp.Interpreter.Tests/TestMore/TestMoreTests.cs

@@ -198,7 +198,6 @@ namespace MoonSharp.Interpreter.Tests
 
 
 
 
 		[Test]
 		[Test]
-		[Ignore]
 		public void TestMore_231_metatable()
 		public void TestMore_231_metatable()
 		{
 		{
 			TapRunner.Run(@"TestMore\231-metatable.t");
 			TapRunner.Run(@"TestMore\231-metatable.t");
@@ -206,7 +205,6 @@ namespace MoonSharp.Interpreter.Tests
 
 
 
 
 		[Test]
 		[Test]
-		[Ignore]
 		public void TestMore_232_object()
 		public void TestMore_232_object()
 		{
 		{
 			TapRunner.Run(@"TestMore\232-object.t");
 			TapRunner.Run(@"TestMore\232-object.t");

+ 137 - 1
src/MoonSharp.Interpreter/CoreLib/BasicMethods.cs

@@ -76,11 +76,39 @@ namespace MoonSharp.Interpreter.CoreLib
 		}
 		}
 
 
 
 
+		// tostring (v)
+		// ----------------------------------------------------------------------------------------------------------------
+		// Receives a value of any type and converts it to a string in a reasonable format. (For complete control of how 
+		// numbers are converted, use string.format.)
+		// 
+		// If the metatable of v has a "__tostring" field, then tostring calls the corresponding value with v as argument, 
+		// and uses the result of the call as its result. 
 		[MoonSharpMethod]
 		[MoonSharpMethod]
 		public static DynValue tostring(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue tostring(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
 			DynValue v = args[0];
 			DynValue v = args[0];
-			return DynValue.NewString(v.ToPrintString());
+			DynValue tail = executionContext.GetMetamethodTailCall(v, "__tostring", v);
+			
+			if (tail == null || tail.IsNil())
+				return DynValue.NewString(v.ToPrintString());
+
+			tail.TailCallData.Continuation = new CallbackFunction(__tostring_continuation);
+
+			return tail;
+		}
+
+		private static DynValue __tostring_continuation(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			DynValue b = args[0].ToScalar();
+
+			if (b.IsNil())
+				return b;
+
+			if (b.Type != DataType.String)
+				throw new ScriptRuntimeException("'tostring' must return a string");
+
+
+			return b;
 		}
 		}
 
 
 
 
@@ -127,6 +155,114 @@ namespace MoonSharp.Interpreter.CoreLib
 			}
 			}
 		}
 		}
 
 
+		[MoonSharpMethod]
+		public static DynValue print(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			Table values = new Table(executionContext.GetOwnerScript());
+			bool hasmeta = false;
+
+			for (int i = 0; i < args.Count; i++)
+			{
+				if ((args[i].Type == DataType.Table) && (args[i].Table.MetaTable != null) &&
+					(args[i].Table.MetaTable.RawGet("__tostring") != null))
+				{
+					values[i] = args[i].CloneAsWritable();
+					hasmeta = true;
+				}
+				else
+				{
+					values[i] = DynValue.NewString(args[i].ToPrintString());
+				}
+			}
+
+			values["i"] = DynValue.NewNumber(-1);
+			values["l"] = DynValue.NewNumber(args.Count);
+
+			if (!hasmeta)
+			{
+				DoPrint(values);
+				return DynValue.Nil;
+			}
+
+			executionContext.Closure = values;
+
+			return __print_to_string_loop(executionContext, args);
+		}
+
+		public static DynValue __print_to_string_loop(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			Table values = executionContext.Closure;
+			int idx = (int)values["i"].Number;
+			int len = (int)values["l"].Number;
+
+			while(idx < len)
+			{
+				idx++;
+
+				DynValue v = values[idx];
+
+				if (v.Type == DataType.String)
+					continue;
+				else if (v.Type == DataType.Nil)
+					continue;
+
+				values["i"].AssignNumber(idx);
+
+
+				DynValue tail = executionContext.GetMetamethodTailCall(v, "__tostring", v);
+
+				if (tail == null || tail.IsNil())
+					return DynValue.Nil;
+
+				tail.TailCallData.Continuation = new CallbackFunction(__print_tostring_continuation);
+				tail.TailCallData.Continuation.Closure = values;
+
+				return tail;
+			}
+
+			DoPrint(values);
+			return DynValue.Nil;
+		}
+
+		private static DynValue __print_tostring_continuation(ScriptExecutionContext executionContext, CallbackArguments args)
+		{
+			DynValue b = args[0].ToScalar();
+			Table values = executionContext.Closure;
+			int idx = (int)values["i"].Number;
+
+			if (!b.IsNil())
+			{
+				if (b.Type != DataType.String)
+					throw new ScriptRuntimeException("'tostring' must return a string to 'print'");
+			}
+
+			values[idx] = b;
+
+			return __print_to_string_loop(executionContext, args);
+		}
+
+
+		
+		private static void DoPrint(Table t)
+		{
+			StringBuilder sb = new StringBuilder();
+			int len = (int)t["l"].Number;
+
+			for (int i = 0; i < len; i++)
+			{
+				DynValue v = t[i];
+
+				if (v.IsNil())
+					continue;
+
+				if (i != 0)
+					sb.Append('\t');
+
+				sb.Append(v.String);
+			}
+
+			t.OwnerScript.DebugPrint(sb.ToString());
+		}
 
 
 
 
 
 

+ 15 - 11
src/MoonSharp.Interpreter/CoreLib/MetaTableMethods.cs

@@ -40,21 +40,25 @@ namespace MoonSharp.Interpreter.CoreLib
 		public static DynValue getmetatable(ScriptExecutionContext executionContext, CallbackArguments args)  
 		public static DynValue getmetatable(ScriptExecutionContext executionContext, CallbackArguments args)  
 		{
 		{
 			DynValue obj = args[0];
 			DynValue obj = args[0];
+			Table meta = null;
 
 
-			if (obj.Type == DataType.Nil)
-				return DynValue.Nil;
-
-			DynValue curmeta = executionContext.GetMetamethod(obj, "__metatable");
-
-			if (curmeta != null)
+			if (obj.Type.CanHaveTypeMetatables())
 			{
 			{
-				return curmeta;
+				meta = executionContext.GetOwnerScript().GetTypeMetatable(obj.Type);
+			}
+			
+			
+			if (obj.Type == DataType.Table)
+			{
+				meta = obj.Table.MetaTable;
 			}
 			}
 
 
-			if (obj.Table.MetaTable != null)
-				return DynValue.NewTable(obj.Table.MetaTable);
-
-			return DynValue.Nil;
+			if (meta == null)
+				return DynValue.Nil;
+			else if (meta.RawGet("__metatable") != null)
+				return meta["__metatable"];
+			else
+				return DynValue.NewTable(meta);
 		}
 		}
 
 
 		// rawget (table, index)
 		// rawget (table, index)

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

@@ -10,7 +10,16 @@ namespace MoonSharp.Interpreter.CoreLib
 	[MoonSharpModule(Namespace="string")]
 	[MoonSharpModule(Namespace="string")]
 	public class StringModule
 	public class StringModule
 	{
 	{
-		[MoonSharpMethod()]
+		public static void MoonSharpInit(Table globalTable, Table stringTable)
+		{
+			Table stringMetatable = new Table(globalTable.OwnerScript);
+			stringMetatable["__index"] = DynValue.NewTable(stringTable);
+			globalTable.OwnerScript.SetTypeMetatable(DataType.String, stringMetatable);
+		}
+
+
+
+		[MoonSharpMethod]
 		public static DynValue match(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue match(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
 			DynValue s = args.AsType(0, "match", DataType.String, false);
 			DynValue s = args.AsType(0, "match", DataType.String, false);

+ 4 - 4
src/MoonSharp.Interpreter/DataTypes/CallbackArguments.cs

@@ -37,11 +37,11 @@ namespace MoonSharp.Interpreter
 			return List.ToArray();
 			return List.ToArray();
 		}
 		}
 
 
-		public void ThrowBadArgument(int argNum, string funcName, object expected, object got)
+		public void ThrowBadArgument(int argNum, string funcName, object expected, object got, bool allowNil)
 		{
 		{
 			// bad argument #1 to 'next' (table expected, got number)
 			// bad argument #1 to 'next' (table expected, got number)
-			throw new ScriptRuntimeException("bad argument #{0} to '{1}' ({2} expected, got {3}",
-				argNum + 1, funcName, expected, got);
+			throw new ScriptRuntimeException("bad argument #{0} to '{1}' ({2}{3} expected, got {4})",
+				argNum + 1, funcName, allowNil ? "nil or " : "", expected.ToString().ToLowerInvariant(), got.ToString().ToLowerInvariant());
 		}
 		}
 
 
 		public DynValue AsType(int argNum, string funcName, DataType type, bool allowNil = false)
 		public DynValue AsType(int argNum, string funcName, DataType type, bool allowNil = false)
@@ -50,7 +50,7 @@ namespace MoonSharp.Interpreter
 				return this[argNum];
 				return this[argNum];
 
 
 			if (this[argNum].Type != type)
 			if (this[argNum].Type != type)
-				ThrowBadArgument(argNum, funcName, type, this[argNum].Type);
+				ThrowBadArgument(argNum, funcName, type, this[argNum].Type, allowNil);
 
 
 			return this[argNum];
 			return this[argNum];
 		}
 		}

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

@@ -14,6 +14,7 @@ namespace MoonSharp.Interpreter
 		Number,
 		Number,
 		String,
 		String,
 		Function,
 		Function,
+
 		Table,
 		Table,
 		Tuple,
 		Tuple,
 		UserData,
 		UserData,
@@ -21,10 +22,18 @@ namespace MoonSharp.Interpreter
 
 
 		ClrFunction,
 		ClrFunction,
 		TailCallRequest,
 		TailCallRequest,
+
+		MaxMetaTypes = Table
 	}
 	}
 
 
 	public static class LuaTypeExtensions
 	public static class LuaTypeExtensions
 	{
 	{
+		public static bool CanHaveTypeMetatables(this DataType type)
+		{
+			return (int)type < (int)DataType.MaxMetaTypes;
+		}
+
+
 		public static string ToLuaTypeString(this DataType type)
 		public static string ToLuaTypeString(this DataType type)
 		{
 		{
 			switch (type)
 			switch (type)

+ 6 - 0
src/MoonSharp.Interpreter/DataTypes/DynValue.cs

@@ -62,6 +62,10 @@ namespace MoonSharp.Interpreter
 		/// Gets or sets the user object, if this value is userdata
 		/// Gets or sets the user object, if this value is userdata
 		/// </summary>
 		/// </summary>
 		public object UserObject { get; set; }
 		public object UserObject { get; set; }
+		/// <summary>
+		/// Gets the tail call data.
+		/// </summary>
+		public TailCallData TailCallData { get { return UserObject as TailCallData; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// Returns true if this instance is write protected.
 		/// Returns true if this instance is write protected.
@@ -69,6 +73,8 @@ namespace MoonSharp.Interpreter
 		public bool ReadOnly { get; internal set; }
 		public bool ReadOnly { get; internal set; }
 
 
 
 
+
+
 		/// <summary>
 		/// <summary>
 		/// Creates a new writable value initialized to Nil.
 		/// Creates a new writable value initialized to Nil.
 		/// </summary>
 		/// </summary>

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

@@ -260,5 +260,8 @@ namespace MoonSharp.Interpreter
 		/// Gets the meta-table associated with this instance.
 		/// Gets the meta-table associated with this instance.
 		/// </summary>
 		/// </summary>
 		public Table MetaTable { get; set; }
 		public Table MetaTable { get; set; }
+
+
+
 	}
 	}
 }
 }

+ 5 - 1
src/MoonSharp.Interpreter/Execution/ExecutionContext.cs

@@ -17,7 +17,11 @@ namespace MoonSharp.Interpreter.Execution
 			m_Callback = callBackFunction;
 			m_Callback = callBackFunction;
 		}
 		}
 
 
-		public Table Closure { get { return m_Callback.Closure; } }
+		public Table Closure 
+		{ 
+			get { return m_Callback.Closure; } 
+			set { m_Callback.Closure = value; } 
+		}
 
 
 
 
 		public DynValue GetVar(SymbolRef symref)
 		public DynValue GetVar(SymbolRef symref)

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

@@ -24,6 +24,10 @@ namespace MoonSharp.Interpreter.Execution.VM
 			{
 			{
 				return value.Table.MetaTable;
 				return value.Table.MetaTable;
 			}
 			}
+			else if (value.Type.CanHaveTypeMetatables())
+			{
+				return m_Script.GetTypeMetatable(value.Type);
+			}
 			else
 			else
 			{
 			{
 				return null;
 				return null;

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

@@ -583,7 +583,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 			{
 			{
 				m_ValueStack.Pop(); // discard tail call request
 				m_ValueStack.Pop(); // discard tail call request
 
 
-				TailCallData tcd = (TailCallData)tail.UserObject;
+				TailCallData tcd = tail.TailCallData;
 
 
 				m_ValueStack.Push(tcd.Function);
 				m_ValueStack.Push(tcd.Function);
 
 
@@ -1019,16 +1019,6 @@ namespace MoonSharp.Interpreter.Execution.VM
 						return instructionPtr;
 						return instructionPtr;
 					}
 					}
 				}
 				}
-				else if (obj.Type == DataType.String)
-				{
-					h = GetMetamethod(obj, "__index");
-
-					if (h == null || h.IsNil())
-					{
-						// by default, bounce to the string table
-						h = m_GlobalTable["string"];
-					}
-				}
 				else
 				else
 				{
 				{
 					h = GetMetamethod(obj, "__index");
 					h = GetMetamethod(obj, "__index");

+ 19 - 11
src/MoonSharp.Interpreter/Modules/ModuleRegister.cs

@@ -45,23 +45,31 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			Table table = CreateModuleNamespace(gtable, t);
 			Table table = CreateModuleNamespace(gtable, t);
 
 
-			foreach (MethodInfo mi in t.GetMethods(BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic).Where(_mi => _mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0))
+			foreach (MethodInfo mi in t.GetMethods(BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic))
 			{
 			{
-				MoonSharpMethodAttribute attr = (MoonSharpMethodAttribute)mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).First();
+				if (mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0)
+				{
+					MoonSharpMethodAttribute attr = (MoonSharpMethodAttribute)mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).First();
 
 
-				ParameterInfo[] pi = mi.GetParameters();
+					ParameterInfo[] pi = mi.GetParameters();
 
 
-				if (pi.Length != 2 || pi[0].ParameterType != typeof(ScriptExecutionContext)
-					|| pi[1].ParameterType != typeof(CallbackArguments) || mi.ReturnType != typeof(DynValue))
-				{
-					throw new ArgumentException(string.Format("Method {0} does not have the right signature.", mi.Name));
-				}
+					if (pi.Length != 2 || pi[0].ParameterType != typeof(ScriptExecutionContext)
+						|| pi[1].ParameterType != typeof(CallbackArguments) || mi.ReturnType != typeof(DynValue))
+					{
+						throw new ArgumentException(string.Format("Method {0} does not have the right signature.", mi.Name));
+					}
 
 
-				Func<ScriptExecutionContext, CallbackArguments, DynValue> func = (Func<ScriptExecutionContext, CallbackArguments, DynValue>)Delegate.CreateDelegate(typeof(Func<ScriptExecutionContext, CallbackArguments, DynValue>), mi);
+					Func<ScriptExecutionContext, CallbackArguments, DynValue> func = (Func<ScriptExecutionContext, CallbackArguments, DynValue>)Delegate.CreateDelegate(typeof(Func<ScriptExecutionContext, CallbackArguments, DynValue>), mi);
 
 
-				string name = (!string.IsNullOrEmpty(attr.Name)) ? attr.Name : mi.Name;
+					string name = (!string.IsNullOrEmpty(attr.Name)) ? attr.Name : mi.Name;
 
 
-				table[name] = DynValue.NewCallback(func);
+					table[name] = DynValue.NewCallback(func);
+				}
+				else if (mi.Name == "MoonSharpInit")
+				{
+					object[] args = new object[2] { gtable, table };
+					mi.Invoke(null, args);
+				}
 			}
 			}
 
 
 			foreach (FieldInfo fi in t.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic).Where(_mi => _mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0))
 			foreach (FieldInfo fi in t.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic).Where(_mi => _mi.GetCustomAttributes(typeof(MoonSharpMethodAttribute), false).Length > 0))

+ 40 - 0
src/MoonSharp.Interpreter/Script.cs

@@ -27,6 +27,7 @@ namespace MoonSharp.Interpreter
 		Table m_GlobalTable;
 		Table m_GlobalTable;
 		IDebugger m_Debugger;
 		IDebugger m_Debugger;
 		IScriptLoader m_ScriptLoader = DefaultScriptLoader;
 		IScriptLoader m_ScriptLoader = DefaultScriptLoader;
+		Table[] m_TypeMetatables = new Table[(int)DataType.MaxMetaTypes];
 
 
 		static Script()
 		static Script()
 		{
 		{
@@ -48,6 +49,7 @@ namespace MoonSharp.Interpreter
 		/// <param name="coreModules">The core modules to be pre-registered in the default global table.</param>
 		/// <param name="coreModules">The core modules to be pre-registered in the default global table.</param>
 		public Script(CoreModules coreModules)
 		public Script(CoreModules coreModules)
 		{
 		{
+			DebugPrint = s => { Console.WriteLine(s); };
 			m_ByteCode = new ByteCode();
 			m_ByteCode = new ByteCode();
 			m_GlobalTable = new Table(this).RegisterCoreModules(coreModules);
 			m_GlobalTable = new Table(this).RegisterCoreModules(coreModules);
 			m_Coroutines.Add(new Processor(this, m_GlobalTable, m_ByteCode));
 			m_Coroutines.Add(new Processor(this, m_GlobalTable, m_ByteCode));
@@ -321,5 +323,43 @@ namespace MoonSharp.Interpreter
 		{
 		{
 			RandomGenerator = new Random();
 			RandomGenerator = new Random();
 		}
 		}
+
+
+		/// <summary>
+		/// Gets a type metatable.
+		/// </summary>
+		/// <param name="type">The type.</param>
+		/// <returns></returns>
+		public Table GetTypeMetatable(DataType type)
+		{
+			int t = (int)type;
+
+			if (t >= 0 && t < m_TypeMetatables.Length)
+				return m_TypeMetatables[t];
+
+			return null;
+		}
+
+		/// <summary>
+		/// Sets a type metatable.
+		/// </summary>
+		/// <param name="type">The type. Must be Nil, Boolean, Number, String or Function</param>
+		/// <param name="metatable">The metatable.</param>
+		/// <exception cref="System.ArgumentException">Specified type not supported :  + type.ToString()</exception>
+		public void SetTypeMetatable(DataType type, Table metatable)
+		{
+			int t = (int)type;
+
+			if (t >= 0 && t < m_TypeMetatables.Length)
+				m_TypeMetatables[t] = metatable;
+			else
+				throw new ArgumentException("Specified type not supported : " + type.ToString());
+		}
+
+		/// <summary>
+		/// Gets or sets the debug print handler
+		/// </summary>
+		public Action<string> DebugPrint { get; set; }
+
 	}
 	}
 }
 }