Browse Source

print, table.concat, __le

Xanathar 11 years ago
parent
commit
657484d2cd

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

@@ -162,12 +162,17 @@ namespace MoonSharp.Debugger
 		{
 		{
 			try
 			try
 			{
 			{
-				m_Script.Call(0, m_Script.GetMainChunk());
+				m_Script.Call(m_Script.GetMainChunk());
+			}
+			catch (ScriptRuntimeException ex)
+			{
+				timerFollow.Enabled = false;
+				Console_WriteLine("Guest raised unhandled CLR exception: {0} -@{3:X8} {2}\n{1}\n", ex.GetType(), ex.ToString(), ex.DecoratedMessage, ex.InstructionPtr);
 			}
 			}
 			catch (Exception ex)
 			catch (Exception ex)
 			{
 			{
 				timerFollow.Enabled = false;
 				timerFollow.Enabled = false;
-				Console_WriteLine("Guest raised unhandled CLR exception: {0}\n{1}\n", ex.GetType(), ex.ToString());
+				Console_WriteLine("Guest raised unhandled CLR exception: {0} \n{1}\n", ex.GetType(), ex.ToString());
 			}
 			}
 		}
 		}
 
 

+ 69 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/StringLibTests.cs

@@ -92,5 +92,74 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Utils.DynAssert(res, null);
 			Utils.DynAssert(res, null);
 		}
 		}
 
 
+
+		[Test]
+		public void PrintTest1()
+		{
+			string script = @"
+				print('ciao', 1);
+			";
+			string printed = null;
+
+			Script S = new Script();
+			DynValue main = S.LoadString(script);
+
+			S.DebugPrint = s =>
+			{
+				printed = s;
+			};
+
+			S.Call(main);
+
+			Assert.AreEqual("ciao\t1", printed);
+		}
+
+		[Test]
+		public void PrintTest2()
+		{
+			string script = @"
+				t = {};
+				m = {};
+
+				function m.__tostring()
+					return 'ciao';
+				end
+
+				setmetatable(t, m);
+
+				print(t, 1);
+			";
+			string printed = null;
+
+			Script S = new Script();
+			DynValue main = S.LoadString(script);
+
+			S.DebugPrint = s =>
+			{
+				printed = s;
+			};
+
+			S.Call(main);
+
+			Assert.AreEqual("ciao\t1", printed);
+		}
+
+		[Test]
+		public void ToStringTest()
+		{
+			string script = @"
+				t = {}
+				mt = {}
+				a = nil
+				function mt.__tostring () a = 'yup' end
+				setmetatable(t, mt)
+				return tostring(t), a;
+			";
+			DynValue res = Script.RunString(script);
+			Utils.DynAssert(res, null, "yup");
+
+		}
+
+
 	}
 	}
 }
 }

+ 12 - 93
src/MoonSharp.Interpreter/CoreLib/BasicMethods.cs

@@ -158,113 +158,32 @@ namespace MoonSharp.Interpreter.CoreLib
 		[MoonSharpMethod]
 		[MoonSharpMethod]
 		public static DynValue print(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue print(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			Table values = new Table(executionContext.GetOwnerScript());
-			bool hasmeta = false;
+			StringBuilder sb = new StringBuilder();
 
 
 			for (int i = 0; i < args.Count; i++)
 			for (int i = 0; i < args.Count; i++)
 			{
 			{
+				if (i != 0)
+					sb.Append('\t');
+
 				if ((args[i].Type == DataType.Table) && (args[i].Table.MetaTable != null) &&
 				if ((args[i].Type == DataType.Table) && (args[i].Table.MetaTable != null) &&
 					(args[i].Table.MetaTable.RawGet("__tostring") != null))
 					(args[i].Table.MetaTable.RawGet("__tostring") != null))
 				{
 				{
-					values[i] = args[i].CloneAsWritable();
-					hasmeta = true;
+					var v = executionContext.GetOwnerScript().Call(args[i].Table.MetaTable.RawGet("__tostring"), args[i]);
+
+					if (v.Type != DataType.String)
+						throw new ScriptRuntimeException("'tostring' must return a string to 'print'");
+
+					sb.Append(v.ToPrintString());
 				}
 				}
 				else
 				else
 				{
 				{
-					values[i] = DynValue.NewString(args[i].ToPrintString());
+					sb.Append(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;
-			}
+			executionContext.GetOwnerScript().DebugPrint(sb.ToString());
 
 
-			DoPrint(values);
 			return DynValue.Nil;
 			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());
-		}
-
-
-
 	}
 	}
 }
 }

+ 28 - 10
src/MoonSharp.Interpreter/CoreLib/TableModule.cs

@@ -54,24 +54,42 @@ namespace MoonSharp.Interpreter.CoreLib
 		[MoonSharpMethod()]
 		[MoonSharpMethod()]
 		public static DynValue concat(ScriptExecutionContext executionContext, CallbackArguments args)
 		public static DynValue concat(ScriptExecutionContext executionContext, CallbackArguments args)
 		{
 		{
-			// !INCOMPAT
-
-			// The theory says the method calls __len to get the len in case it's not forced as a param.
-			// But then it uses rawget to access. The only case where we differ if we take the shortcut
-			// of using rawlen is if the first param is passed to force a non-first index and the second 
-			// isn't, or if __len is used to limit the maximum length. Likely an acceptable divergence, 
-			// at least for now. [Note that this behaviour is actually undefined in Lua 5.1, and __len 
-			// usage is documented only for Lua 5.2]
-
 			DynValue vlist = args.AsType(0, "concat", DataType.Table, false);
 			DynValue vlist = args.AsType(0, "concat", DataType.Table, false);
 			DynValue vsep = args.AsType(1, "concat", DataType.String, true);
 			DynValue vsep = args.AsType(1, "concat", DataType.String, true);
 			DynValue vstart = args.AsType(2, "concat", DataType.Number, true);
 			DynValue vstart = args.AsType(2, "concat", DataType.Number, true);
 			DynValue vend = args.AsType(3, "concat", DataType.Number, true);
 			DynValue vend = args.AsType(3, "concat", DataType.Number, true);
 
 
+
+
 			Table list = vlist.Table;
 			Table list = vlist.Table;
 			string sep = vsep.IsNil() ? "" : vsep.String;
 			string sep = vsep.IsNil() ? "" : vsep.String;
 			int start = vstart.IsNilOrNan() ? 1 : (int)vstart.Number;
 			int start = vstart.IsNilOrNan() ? 1 : (int)vstart.Number;
-			int end = vend.IsNilOrNan() ? (int)list.Length : (int)vend.Number;
+			int end; 
+
+			if (vend.IsNilOrNan())
+			{
+				DynValue __len = executionContext.GetMetamethod(vlist, "__len");
+
+				if (__len != null)
+				{
+					DynValue lenv = executionContext.GetOwnerScript().Call(__len, vlist);
+
+					double? len = lenv.CastToNumber();
+
+					if (len == null)
+						throw new ScriptRuntimeException("object length is not a number");
+
+					end = (int)len;
+				}
+				else
+				{
+					end = (int)vlist.Table.Length;
+				}
+			}
+			else 
+			{
+				end = (int)vend.Number;
+			}
 
 
 			if (end < start)
 			if (end < start)
 				return DynValue.NewString(string.Empty);
 				return DynValue.NewString(string.Empty);

+ 4 - 2
src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs

@@ -99,7 +99,10 @@ namespace MoonSharp.Interpreter.Execution.VM
 		{
 		{
 			var i = AppendInstruction(new Instruction() { OpCode = opcode });
 			var i = AppendInstruction(new Instruction() { OpCode = opcode });
 
 
-			if (opcode == OpCode.Eq || opcode == OpCode.Less || opcode == OpCode.LessEq)
+			if (opcode == OpCode.LessEq)
+				AppendInstruction(new Instruction() { OpCode = OpCode.CNot });
+
+			if (opcode == OpCode.Eq || opcode == OpCode.Less)
 				AppendInstruction(new Instruction() { OpCode = OpCode.ToBool });
 				AppendInstruction(new Instruction() { OpCode = OpCode.ToBool });
 
 
 			return i;
 			return i;
@@ -147,7 +150,6 @@ namespace MoonSharp.Interpreter.Execution.VM
 			return AppendInstruction(new Instruction() { OpCode = OpCode.ToNum, NumVal = stage });
 			return AppendInstruction(new Instruction() { OpCode = OpCode.ToNum, NumVal = stage });
 		}
 		}
 
 
-
 		public Instruction Emit_Incr(int i)
 		public Instruction Emit_Incr(int i)
 		{
 		{
 			return AppendInstruction(new Instruction() { OpCode = OpCode.Incr, NumVal = i });
 			return AppendInstruction(new Instruction() { OpCode = OpCode.Incr, NumVal = i });

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

@@ -59,6 +59,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 		Len,		// Size operator of the topmost operand on the v-stack
 		Len,		// Size operator of the topmost operand on the v-stack
 		Neg,		// Negation (unary minus) operator of the topmost operand on the v-stack
 		Neg,		// Negation (unary minus) operator of the topmost operand on the v-stack
 		Power,		// Power of the two topmost operands on the v-stack
 		Power,		// Power of the two topmost operands on the v-stack
+		CNot,		// Conditional NOT - takes second operand from the v-stack (must be bool), if true execs a NOT otherwise execs a TOBOOL
+
 
 
 		// Type conversions and manipulations
 		// Type conversions and manipulations
 		MkTuple,	// Creates a tuple from the topmost n values
 		MkTuple,	// Creates a tuple from the topmost n values

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

@@ -44,6 +44,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 				BasePointer = m_ValueStack.Count,
 				BasePointer = m_ValueStack.Count,
 				Debug_EntryPoint = function.Function.ByteCodeLocation,
 				Debug_EntryPoint = function.Function.ByteCodeLocation,
 				ReturnAddress = -1,
 				ReturnAddress = -1,
+				ClosureScope = function.Function.ClosureContext,
 			});
 			});
 
 
 			return Processing_Loop(function.Function.ByteCodeLocation);
 			return Processing_Loop(function.Function.ByteCodeLocation);

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

@@ -88,6 +88,9 @@ namespace MoonSharp.Interpreter.Execution.VM
 						case OpCode.Not:
 						case OpCode.Not:
 							ExecNot(i);
 							ExecNot(i);
 							break;
 							break;
+						case OpCode.CNot:
+							ExecCNot(i);
+							break;
 						case OpCode.JfOrPop:
 						case OpCode.JfOrPop:
 						case OpCode.JtOrPop:
 						case OpCode.JtOrPop:
 							instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
 							instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
@@ -222,13 +225,12 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 		return_to_native_code:
 		return_to_native_code:
 
 
-			if (m_ValueStack.Count == 1)
+			//if (m_ValueStack.Count == 1)
 				return m_ValueStack.Pop();
 				return m_ValueStack.Pop();
-			else if (m_ValueStack.Count == 0)
-				return DynValue.Nil;
-			else
-				throw new InternalErrorException("Unexpected value stack count at program end : {0}", m_ValueStack.Count);
-
+			//else if (m_ValueStack.Count == 0)
+			//	return DynValue.Nil;
+			//else
+			//	throw new InternalErrorException("Unexpected value stack count at program end : {0}", m_ValueStack.Count);
 		}
 		}
 
 
 
 
@@ -412,6 +414,19 @@ namespace MoonSharp.Interpreter.Execution.VM
 		}
 		}
 
 
 
 
+		private void ExecCNot(Instruction i)
+		{
+			DynValue v = m_ValueStack.Pop();
+			DynValue not = m_ValueStack.Pop();
+
+			if (not.Type != DataType.Boolean)
+				throw new InternalErrorException("CNOT had non-bool arg");
+
+			if (not.CastToBool())
+				m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
+			else
+				m_ValueStack.Push(DynValue.NewBoolean(v.CastToBool()));
+		}
 
 
 		private void ExecNot(Instruction i)
 		private void ExecNot(Instruction i)
 		{
 		{
@@ -838,18 +853,20 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 			if (l.Type == DataType.Number && r.Type == DataType.Number)
 			if (l.Type == DataType.Number && r.Type == DataType.Number)
 			{
 			{
+				m_ValueStack.Push(DynValue.False);
 				m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
 				m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
 			}
 			}
 			else if (l.Type == DataType.String && r.Type == DataType.String)
 			else if (l.Type == DataType.String && r.Type == DataType.String)
 			{
 			{
+				m_ValueStack.Push(DynValue.False);
 				m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
 				m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
 			}
 			}
 			else
 			else
 			{
 			{
-				int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr);
+				int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
 				if (ip < 0)
 				if (ip < 0)
 				{
 				{
-					ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr);
+					ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
 
 
 					if (ip < 0)
 					if (ip < 0)
 						throw ScriptRuntimeException.CompareInvalidType(l, r);
 						throw ScriptRuntimeException.CompareInvalidType(l, r);

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

@@ -73,12 +73,15 @@ namespace MoonSharp.Interpreter.Execution.VM
 				return -1;
 				return -1;
 			}
 			}
 		}
 		}
-		private int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string eventName, int instructionPtr)
+		private int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string eventName, int instructionPtr, DynValue extraPush = null)
 		{
 		{
 			var m = Internal_GetBinHandler(l, r, eventName);
 			var m = Internal_GetBinHandler(l, r, eventName);
 
 
 			if (m != null)
 			if (m != null)
 			{
 			{
+				if (extraPush != null)
+					m_ValueStack.Push(extraPush);
+
 				m_ValueStack.Push(m);
 				m_ValueStack.Push(m);
 				m_ValueStack.Push(l);
 				m_ValueStack.Push(l);
 				m_ValueStack.Push(r);
 				m_ValueStack.Push(r);

+ 14 - 36
src/MoonSharp.Interpreter/Script.cs

@@ -21,6 +21,7 @@ namespace MoonSharp.Interpreter
 	/// </summary>
 	/// </summary>
 	public class Script
 	public class Script
 	{
 	{
+		Processor m_MainRoutine = null;
 		List<Processor> m_Coroutines = new List<Processor>();
 		List<Processor> m_Coroutines = new List<Processor>();
 		ByteCode m_ByteCode;
 		ByteCode m_ByteCode;
 		List<SourceCode> m_Sources = new List<SourceCode>();
 		List<SourceCode> m_Sources = new List<SourceCode>();
@@ -52,7 +53,7 @@ namespace MoonSharp.Interpreter
 			DebugPrint = s => { Console.WriteLine(s); };
 			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_MainRoutine = new Processor(this, m_GlobalTable, m_ByteCode);
 			ReseedRandomGenerator(DateTime.Now.Millisecond);
 			ReseedRandomGenerator(DateTime.Now.Millisecond);
 		}
 		}
 
 
@@ -173,12 +174,10 @@ namespace MoonSharp.Interpreter
 		/// <returns>
 		/// <returns>
 		/// A DynValue containing the result of the processing of the loaded chunk.
 		/// A DynValue containing the result of the processing of the loaded chunk.
 		/// </returns>
 		/// </returns>
-		public DynValue DoString(string code, Table globalContext = null, int coroutine = -1)
+		public DynValue DoString(string code, Table globalContext = null)
 		{
 		{
-			coroutine = FixCoroutineIndex(coroutine);
-
 			DynValue func = LoadString(code, globalContext);
 			DynValue func = LoadString(code, globalContext);
-			return Call(coroutine, func);
+			return Call(func);
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -190,12 +189,10 @@ namespace MoonSharp.Interpreter
 		/// <returns>
 		/// <returns>
 		/// A DynValue containing the result of the processing of the loaded chunk.
 		/// A DynValue containing the result of the processing of the loaded chunk.
 		/// </returns>
 		/// </returns>
-		public DynValue DoFile(string filename, Table globalContext = null, int coroutine = -1)
+		public DynValue DoFile(string filename, Table globalContext = null)
 		{
 		{
-			coroutine = FixCoroutineIndex(coroutine);
-
 			DynValue func = LoadFile(filename, globalContext);
 			DynValue func = LoadFile(filename, globalContext);
-			return Call(coroutine, func);
+			return Call(func);
 		}
 		}
 
 
 
 
@@ -235,17 +232,6 @@ namespace MoonSharp.Interpreter
 			return DynValue.NewClosure(c);
 			return DynValue.NewClosure(c);
 		}
 		}
 
 
-
-
-		/// <summary>
-		/// Fixes the index of a coroutine translating a -1 parameter.
-		/// </summary>
-		/// <param name="coroutine">The coroutine.</param>
-		private int FixCoroutineIndex(int coroutine)
-		{
-			return (coroutine >= 0) ? coroutine : 0;
-		}
-
 		/// <summary>
 		/// <summary>
 		/// Calls the specified function.
 		/// Calls the specified function.
 		/// </summary>
 		/// </summary>
@@ -253,9 +239,9 @@ namespace MoonSharp.Interpreter
 		/// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
 		/// <param name="function">The Lua/Moon# function to be called - callbacks are not supported.</param>
 		/// <param name="args">The arguments to pass to the function.</param>
 		/// <param name="args">The arguments to pass to the function.</param>
 		/// <returns></returns>
 		/// <returns></returns>
-		public DynValue Call(int coroutine, DynValue function, params DynValue[] args)
+		public DynValue Call(DynValue function, params DynValue[] args)
 		{
 		{
-			return m_Coroutines[coroutine].Call(function, args);
+			return m_MainRoutine.Call(function, args);
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -271,22 +257,14 @@ namespace MoonSharp.Interpreter
 		/// Attaches a debugger.
 		/// Attaches a debugger.
 		/// </summary>
 		/// </summary>
 		/// <param name="debugger">The debugger object.</param>
 		/// <param name="debugger">The debugger object.</param>
-		/// <param name="coroutine">
-		/// The coroutine to which the debugger attaches, or -1 to attach it to all coroutines. 
-		/// If -1 is specified, the debugger is also automatically attached to new coroutines.
 		/// </param>
 		/// </param>
-		public void AttachDebugger(IDebugger debugger, int coroutine = -1)
+		public void AttachDebugger(IDebugger debugger)
 		{
 		{
-			if (coroutine < 0)
-			{
-				m_Debugger = debugger;
-				foreach (var C in m_Coroutines)
-					C.AttachDebugger(debugger);
-			}
-			else
-			{
-				m_Coroutines[coroutine].AttachDebugger(debugger);
-			}
+			m_Debugger = debugger;
+			m_MainRoutine.AttachDebugger(debugger);
+
+			foreach (var C in m_Coroutines)
+				C.AttachDebugger(debugger);
 
 
 			m_Debugger.SetSourceCode(m_ByteCode, null);
 			m_Debugger.SetSourceCode(m_ByteCode, null);
 		}
 		}