Pārlūkot izejas kodu

fixed nestes closures

Xanathar 11 gadi atpakaļ
vecāks
revīzija
954618acb3

+ 39 - 3
src/MoonSharp.Interpreter.Tests/EndToEnd/ClosureTests.cs

@@ -158,6 +158,8 @@ namespace MoonSharp.Interpreter.Tests
 				function container()
 					local x = 20
 
+					local ztmp = { }
+
 					for i=1,5 do
 						local y = 0
 		
@@ -195,18 +197,18 @@ namespace MoonSharp.Interpreter.Tests
 
 
 		[Test]
-		public void NestedUpvaluesNotQuiteWorking()
+		public void NestedUpvalues()
 		{
 			string script = @"
 	local y = y;
 
-	local x = x;
+	local x = 0;
 	local m = { };
 
 	function m:a()
 		self.t = {
 			dojob = function() 
-				if (x == nil) then return 1; else return 0; end
+				if (x == 0) then return 1; else return 0; end
 			end,
 		};
 	end
@@ -222,6 +224,40 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(10, res.Number);
 		}
 
+		[Test]
+		public void NestedOutOfScopeUpvalues()
+		{
+			string script = @"
+
+	function X()
+		local y = y;
+
+		local x = 0;
+		local m = { };
+
+		function m:a()
+			self.t = {
+				dojob = function() 
+					if (x == 0) then return 1; else return 0; end
+				end,
+			};
+		end
+
+		return m;
+	end
+
+	Q = X();
+
+	Q:a();
+
+	return 10 * Q.t.dojob();
+								";
+
+			DynValue res = new Script(CoreModules.Preset_HardSandbox).DoString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(10, res.Number);
+		}
 
 	}
 }

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

@@ -21,14 +21,14 @@ namespace MoonSharp.Interpreter
 		private static ClosureContext emptyClosure = new ClosureContext();
 
 
-		internal Closure(Script script, int idx, SymbolRef[] symbols, DynValue[] localscope)
+		internal Closure(Script script, int idx, SymbolRef[] symbols, IEnumerable<DynValue> resolvedLocals)
 		{
 			OwnerScript = script;
 
 			ByteCodeLocation = idx;
 
 			if (symbols.Length > 0)
-				ClosureContext = new ClosureContext(symbols, symbols.Select(s => localscope[s.i_Index]));
+				ClosureContext = new ClosureContext(symbols, resolvedLocals);
 			else
 				ClosureContext = emptyClosure;
 		}

+ 12 - 18
src/MoonSharp.Interpreter/DataTypes/SymbolRef.cs

@@ -22,7 +22,7 @@ namespace MoonSharp.Interpreter
 		public int Index { get { return i_Index; } }
 		public string Name { get { return i_Name; } }
 		public DynValue TableRefObject { get { return i_TableRefObject; } }
-		public DynValue TableRefIndex { get { return i_TableRefIndex; } } 
+		public DynValue TableRefIndex { get { return i_TableRefIndex; } }
 
 
 
@@ -40,34 +40,28 @@ namespace MoonSharp.Interpreter
 		{
 			return new SymbolRef() { i_Index = index, i_Type = SymbolRefType.Upvalue, i_Name = name };
 		}
-		public static SymbolRef Argument(string name, int index)
-		{
-			return new SymbolRef() { i_Index = index, i_Type = SymbolRefType.Argument, i_Name = name };
-		}
-
-		public static SymbolRef Invalid()
-		{
-			return new SymbolRef() { i_Index = -1, i_Type = SymbolRefType.Invalid, i_Name = "!INV!" };
-		}
 
 		public static SymbolRef ObjIndex(DynValue baseObject, DynValue indexObject)
 		{
 			return new SymbolRef() { i_TableRefObject = baseObject, i_TableRefIndex = indexObject, i_Type = SymbolRefType.Index };
 		}
 
-		public bool IsValid()
-		{
-			return i_Type !=  SymbolRefType.Invalid;
-		}
-
-
 		public override string ToString()
 		{
 			return string.Format("{0}[{1}] : {2}", i_Type, i_Index, i_Name);
 		}
 
-
-
+		public SymbolRef Clone()
+		{
+			return new SymbolRef()
+			{
+				i_Index = this.i_Index,
+				i_Name = this.i_Name,
+				i_TableRefIndex = this.i_TableRefIndex,
+				i_TableRefObject = this.i_TableRefObject,
+				i_Type = this.i_Type,
+			};
+		}
 
 	}
 }

+ 27 - 28
src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs

@@ -11,13 +11,14 @@ namespace MoonSharp.Interpreter.Execution
 		List<BuildTimeScopeFrame> m_Frames = new List<BuildTimeScopeFrame>();
 		List<IClosureBuilder> m_ClosureBuilders = new List<IClosureBuilder>();
 
-		public BuildTimeScope()
-		{
-			//PushFunction();
-		}
 
-		public void PushFunction()
+		public void PushFunction(IClosureBuilder closureBuilder)
 		{
+			m_ClosureBuilders.Add(closureBuilder);
+
+			if (closureBuilder != null)
+				closureBuilder.UpvalueCreationTag = (m_Frames.Count - 1);
+
 			m_Frames.Add(new BuildTimeScopeFrame());
 		}
 
@@ -36,7 +37,9 @@ namespace MoonSharp.Interpreter.Execution
 			var last = m_Frames.Last();
 			last.ResolveLRefs();
 			m_Frames.RemoveAt(m_Frames.Count - 1);
-			
+
+			m_ClosureBuilders.RemoveAt(m_ClosureBuilders.Count - 1);
+
 			return last.GetRuntimeFrameData();
 		}
 
@@ -48,26 +51,33 @@ namespace MoonSharp.Interpreter.Execution
 			if (local != null)
 				return local;
 
-			IClosureBuilder closure = m_ClosureBuilders.LastOrDefault();
-
-			if (closure != null)
+			for (int i = m_Frames.Count - 2; i >= 0; i--)
 			{
-				int closureLocalBlockIdx = (int)closure.UpvalueCreationTag;
+				SymbolRef symb = m_Frames[i].Find(name);
 
-				if (closureLocalBlockIdx >= 0)
+				if (symb != null)
 				{
-					for (int i = closureLocalBlockIdx; i >= 0; i--)
-					{
-						SymbolRef symb = m_Frames[i].Find(name);
-						if (symb != null)
-							return closure.CreateUpvalue(this, symb);
-					}
+					symb = CreateUpValue(this, symb, i, m_Frames.Count - 2);
+						
+					if (symb != null)
+						return symb;
 				}
 			}
 
 			return SymbolRef.Global(name);
 		}
 
+		private SymbolRef CreateUpValue(BuildTimeScope buildTimeScope, SymbolRef symb, int closuredFrame, int currentFrame)
+		{
+			// it's a 0-level upvalue. Just create it and we're done.
+			if (closuredFrame == currentFrame)
+				return m_ClosureBuilders[currentFrame + 1].CreateUpvalue(this, symb);
+
+			SymbolRef upvalue = CreateUpValue(buildTimeScope, symb, closuredFrame, currentFrame - 1);
+
+			return m_ClosureBuilders[currentFrame + 1].CreateUpvalue(this, upvalue);
+		}
+
 		public SymbolRef DefineLocal(string name)
 		{
 			return m_Frames.Last().DefineLocal(name);
@@ -79,17 +89,6 @@ namespace MoonSharp.Interpreter.Execution
 		}
 
 
-		public void EnterClosure(IClosureBuilder closureBuilder)
-		{
-			m_ClosureBuilders.Add(closureBuilder);
-			closureBuilder.UpvalueCreationTag = (m_Frames.Count - 1);
-		}
-
-		public void LeaveClosure()
-		{
-			m_ClosureBuilders.RemoveAt(m_ClosureBuilders.Count - 1);
-		}
-
 
 	}
 }

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

@@ -122,7 +122,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 						ClearBlockData(i.Block, i.OpCode == OpCode.Exit);
 						break;
 					case OpCode.Closure:
-						m_ValueStack.Push(DynValue.NewClosure(new Closure(this.m_Script, i.NumVal, i.SymbolList, m_ExecutionStack.Peek().LocalScope)));
+						ExecClosure(i);
 						break;
 					case OpCode.BeginFn:
 						ExecBeginFn(i);
@@ -192,6 +192,24 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 		}
 
+		private void ExecClosure(Instruction i)
+		{
+			Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
+				i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
+
+			m_ValueStack.Push(DynValue.NewClosure(c));
+		}
+
+		private DynValue GetUpvalueSymbol(SymbolRef s)
+		{
+			if (s.Type == SymbolRefType.Local)
+				return m_ExecutionStack.Peek().LocalScope[s.i_Index];
+			else if (s.Type == SymbolRefType.Upvalue)
+				return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
+			else
+				throw new Exception("unsupported symbol type");
+		}
+
 		private void ExecMkTuple(Instruction i)
 		{
 			Slice<DynValue> slice = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);

+ 14 - 5
src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs

@@ -15,6 +15,8 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 		RuntimeScopeFrame m_StackFrame;
 		List<SymbolRef> m_Closure = new List<SymbolRef>();
 		bool m_HasVarArgs = false;
+		Instruction m_ClosureInstruction = null;
+
 		public object UpvalueCreationTag { get; set; }
 
 		public FunctionDefinitionExpression(LuaParser.AnonfunctiondefContext context, ScriptLoadingContext lcontext, bool pushSelfParam = false)
@@ -33,6 +35,12 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 			}
 
 			m_Closure.Add(symbol);
+
+			if (m_ClosureInstruction != null)
+			{
+				m_ClosureInstruction.SymbolList = m_Closure.ToArray();
+			}
+
 			return SymbolRef.Upvalue(symbol.i_Name, m_Closure.Count - 1);
 		}
 
@@ -64,9 +72,7 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 			if (m_HasVarArgs)
 				paramnames.Add("...");
 
-			lcontext.Scope.EnterClosure(this);
-
-			lcontext.Scope.PushFunction();
+			lcontext.Scope.PushFunction(this);
 
 			m_ParamNames = DefineArguments(paramnames, lcontext);
 
@@ -74,7 +80,6 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 
 			m_StackFrame = lcontext.Scope.PopFunction();
 
-			lcontext.Scope.LeaveClosure();
 		}
 
 		private SymbolRef[] DefineArguments(List<string> paramnames, ScriptLoadingContext lcontext)
@@ -109,7 +114,11 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 
 		public int Compile(ByteCode bc, Action afterDecl, string friendlyName)
 		{
-			bc.Emit_Closure(m_Closure.ToArray(), bc.GetJumpPointForNextInstruction() + 3);
+			SymbolRef[] symbs = m_Closure
+				//.Select((s, idx) => s.CloneLocalAndSetFrame(m_ClosureFrames[idx]))
+				.ToArray();
+
+			m_ClosureInstruction = bc.Emit_Closure(symbs, bc.GetJumpPointForNextInstruction() + 3);
 			afterDecl();
 			return CompileBody(bc, friendlyName);
 		}

+ 12 - 2
src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs

@@ -12,7 +12,7 @@ using MoonSharp.Interpreter.Tree.Statements;
 
 namespace MoonSharp.Interpreter.Tree.Statements
 {
-	class ChunkStatement : Statement
+	class ChunkStatement : Statement, IClosureBuilder
 	{
 		Statement m_Block;
 		RuntimeScopeFrame m_StackFrame;
@@ -20,7 +20,7 @@ namespace MoonSharp.Interpreter.Tree.Statements
 		public ChunkStatement(LuaParser.ChunkContext context, ScriptLoadingContext lcontext)
 			: base(context, lcontext)
 		{
-			lcontext.Scope.PushFunction();
+			lcontext.Scope.PushFunction(this);
 			m_Block = NodeFactory.CreateStatement(context.block(), lcontext);
 			m_StackFrame = lcontext.Scope.PopFunction();
 		}
@@ -32,5 +32,15 @@ namespace MoonSharp.Interpreter.Tree.Statements
 			bc.Emit_Ret(0);
 			//bc.Leave(m_StackFrame);
 		}
+
+		public object UpvalueCreationTag
+		{
+			get; set;
+		}
+
+		public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol)
+		{
+			return null;
+		}
 	}
 }