From 479bbe113b8fe0a3d05a6f19f3c32c007f2d561b Mon Sep 17 00:00:00 2001 From: lofcz Date: Thu, 7 Apr 2022 00:26:12 +0200 Subject: [PATCH 1/2] Draft default params Add support for arrow functions Refactor Mark default params test n14 as flaky Initial implementation of default parameters --- .../Execution/InstructionFieldUsage.cs | 1 + .../Execution/Scopes/BuildTimeScope.cs | 2 +- .../Execution/Scopes/BuildTimeScopeBlock.cs | 7 +- .../Execution/Scopes/BuildTimeScopeFrame.cs | 4 +- .../Execution/VM/ByteCode.cs | 5 ++ .../Execution/VM/OpCode.cs | 3 + .../VM/Processor/Processor_InstructionLoop.cs | 4 + src/MoonSharp.Interpreter/Tree/Expression_.cs | 12 ++- .../Expressions/FunctionCallExpression.cs | 2 - .../FunctionDefinitionExpression.cs | 78 +++++++++++++++---- .../Tree/Expressions/IndexExpression.cs | 3 +- src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs | 5 +- .../Tree/Statements/AssignmentStatement.cs | 2 + .../Statements/FunctionDefinitionStatement.cs | 28 ++++++- .../CLike/SyntaxCLike/Functions/1-call.lua | 3 + .../CLike/SyntaxCLike/Functions/1-call.txt | 0 .../10-call-default-scope-local-3.lua | 16 ++++ .../10-call-default-scope-local-3.txt | 3 + .../Functions/11-call-default-scope-arrow.lua | 5 ++ .../Functions/11-call-default-scope-arrow.txt | 1 + .../12-call-default-scope-arrow-invalid.lua | 5 ++ .../12-call-default-scope-arrow-invalid.txt | 0 .../13-call-default-scope-arrow-arrow.lua | 7 ++ .../13-call-default-scope-arrow-arrow.txt | 1 + ...efault-scope-arrow-arrow-default-flaky.lua | 5 ++ ...efault-scope-arrow-arrow-default-flaky.txt | 1 + ...ll-default-scope-arrow-arrow-default-2.lua | 7 ++ ...ll-default-scope-arrow-arrow-default-2.txt | 1 + .../SyntaxCLike/Functions/2-call-default.lua | 7 ++ .../SyntaxCLike/Functions/2-call-default.txt | 3 + .../Functions/3-call-default-invalid.lua | 7 ++ .../Functions/3-call-default-invalid.txt | 0 .../Functions/4-call-default-2.lua | 5 ++ .../Functions/4-call-default-2.txt | 1 + .../Functions/5-call-default-3.lua | 5 ++ .../Functions/5-call-default-3.txt | 1 + .../Functions/6-call-default-local.lua | 5 ++ .../Functions/6-call-default-local.txt | 1 + .../Functions/7-call-default-scope.lua | 7 ++ .../Functions/7-call-default-scope.txt | 1 + .../Functions/8-call-default-scope-local.lua | 7 ++ .../Functions/8-call-default-scope-local.txt | 1 + .../9-call-default-scope-local-2.lua | 14 ++++ .../9-call-default-scope-local-2.txt | 2 + .../EndToEnd/CLikeTestRunner.cs | 34 +++++++- 45 files changed, 270 insertions(+), 42 deletions(-) create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.txt diff --git a/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs b/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs index 5ef6bf69..7636b231 100644 --- a/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs +++ b/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs @@ -70,6 +70,7 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op) case OpCode.Swap: case OpCode.Clean: case OpCode.CopyValue: + case OpCode.JLclInit: return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; case OpCode.Local: case OpCode.Upvalue: diff --git a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs index 63a83282..9c259265 100644 --- a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs +++ b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using MoonSharp.Interpreter.Execution.Scopes; +using MoonSharp.Interpreter.Tree; using MoonSharp.Interpreter.Tree.Statements; namespace MoonSharp.Interpreter.Execution @@ -10,7 +11,6 @@ internal class BuildTimeScope List m_Frames = new List(); List m_ClosureBuilders = new List(); - public void PushFunction(IClosureBuilder closureBuilder, bool hasVarArgs) { m_ClosureBuilders.Add(closureBuilder); diff --git a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeBlock.cs b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeBlock.cs index 78987b41..630635f2 100644 --- a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeBlock.cs +++ b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeBlock.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using MoonSharp.Interpreter.Tree.Statements; namespace MoonSharp.Interpreter.Execution.Scopes @@ -8,13 +9,9 @@ internal class BuildTimeScopeBlock { internal BuildTimeScopeBlock Parent { get; private set; } internal List ChildNodes { get; private set; } - internal RuntimeScopeBlock ScopeBlock { get; private set; } - Dictionary m_DefinedNames = new Dictionary(); - - - + internal void Rename(string name) { SymbolRef sref = m_DefinedNames[name]; diff --git a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs index 7d22709f..57dff639 100644 --- a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs +++ b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs @@ -1,4 +1,6 @@ -using MoonSharp.Interpreter.Tree.Statements; +using System.Collections.Generic; +using System.Linq; +using MoonSharp.Interpreter.Tree.Statements; namespace MoonSharp.Interpreter.Execution.Scopes { diff --git a/src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs b/src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs index 003e788a..1ef0757f 100755 --- a/src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs @@ -356,5 +356,10 @@ public int Emit_Swap(int p1, int p2) return AppendInstruction(new Instruction() { OpCode = OpCode.Swap, NumVal = p1, NumVal2 = p2 }); } + public int Emit_JLclInit(SymbolRef sym, int target) + { + if(sym.Type != SymbolRefType.Local) throw new InternalErrorException("Unexpected symbol type : {0}", sym); + return AppendInstruction(new Instruction() { OpCode = OpCode.JLclInit, NumVal = target, NumVal2 = sym.Index }); + } } } diff --git a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs index 4c2d1acf..f38306be 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs @@ -90,9 +90,12 @@ internal enum OpCode IterPrep, // Prepares an iterator for execution IterUpd, // Updates the var part of an iterator + // Nil coalescing NilCoalescing, NilCoalescingInverse, + JLclInit, // Inits a param value if a default one is specified and not provided at callsite. + // Meta Invalid, // Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum } diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs index ccb91c71..cad32abf 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs @@ -306,6 +306,10 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false) instructionPtr = ExecNilCoalescingAssignmentInverse(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; break; + case OpCode.JLclInit: + if(m_ValueStack[m_ExecutionStack.Peek().BasePointer + i.NumVal2].IsNotNil()) + instructionPtr = i.NumVal; + break; case OpCode.Invalid: throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.String)); default: diff --git a/src/MoonSharp.Interpreter/Tree/Expression_.cs b/src/MoonSharp.Interpreter/Tree/Expression_.cs index 95af9da5..5d70f469 100644 --- a/src/MoonSharp.Interpreter/Tree/Expression_.cs +++ b/src/MoonSharp.Interpreter/Tree/Expression_.cs @@ -52,8 +52,7 @@ internal static List ExprListAfterFirstExpr(ScriptLoadingContext lco return exps; } - - + internal static List ExprList(ScriptLoadingContext lcontext) { List exps = new List(); @@ -78,8 +77,7 @@ internal static Expression Expr(ScriptLoadingContext lcontext) internal static Expression SubExpr(ScriptLoadingContext lcontext, bool isPrimary, bool binaryChainInProgress = false) { - Expression e = null; - + Expression e; Token T = lcontext.Lexer.Current; if (T.IsUnaryOperator()) @@ -202,7 +200,7 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext) lcontext.Lexer.Next(); } lcontext.Lexer.Next(); - bool arrowLambda = lcontext.Lexer.Current.Type == TokenType.Arrow; + bool arrowLambda = lcontext.Lexer.Current.Type == TokenType.Arrow || lcontext.Lexer.PeekNext().Type == TokenType.Arrow; lcontext.Lexer.RestorePos(); if (arrowLambda) return new FunctionDefinitionExpression(lcontext, false, true); @@ -222,11 +220,11 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext) /// internal static Expression PrimaryExp(ScriptLoadingContext lcontext) { - if (lcontext.Lexer.PeekNext().Type == TokenType.Arrow && - lcontext.Lexer.Current.Type == TokenType.Name) + if (lcontext.Lexer.PeekNext().Type == TokenType.Arrow && lcontext.Lexer.Current.Type == TokenType.Name) { return new FunctionDefinitionExpression(lcontext, false, true); } + Expression e = PrefixExp(lcontext); while (true) diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs index 4aae7c89..52e81715 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs @@ -11,10 +11,8 @@ class FunctionCallExpression : Expression Expression m_Function; string m_Name; string m_DebugErr; - internal SourceRef SourceRef { get; private set; } - public FunctionCallExpression(ScriptLoadingContext lcontext, Expression function, Token thisCallName) : base(lcontext) { diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs index 78766bb1..7b80e29a 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs @@ -24,7 +24,8 @@ class FunctionDefinitionExpression : Expression, IClosureBuilder SymbolRef m_Env; SourceRef m_Begin, m_End; - + private ScriptLoadingContext lcontext; + List paramnames; public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlobalEnv) : this(lcontext, false, usesGlobalEnv, false) @@ -33,11 +34,12 @@ public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlob public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool isLambda) : this(lcontext, pushSelfParam, false, isLambda) { } - - + private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool usesGlobalEnv, bool isLambda) : base(lcontext) { + this.lcontext = lcontext; + if (m_UsesGlobalEnv = usesGlobalEnv) CheckTokenType(lcontext, TokenType.Function); @@ -45,14 +47,13 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel //Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round); Token openRound; - List paramnames; bool openCurly = false; if (isLambda) { openRound = lcontext.Lexer.Current; lcontext.Lexer.Next(); if (openRound.Type == TokenType.Name) - paramnames = new List(new[] {openRound.Text}); + paramnames = new List(new FunctionDefinitionStatement.FunctionParamRef[] {new FunctionDefinitionStatement.FunctionParamRef(openRound.Text)}); else paramnames = BuildParamList(lcontext, pushSelfParam, openRound); } @@ -150,33 +151,61 @@ private Statement CreateBody(ScriptLoadingContext lcontext, bool openCurly) return s; } - private List BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken) + private List BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken) { TokenType closeToken = openBracketToken.Type == TokenType.Lambda ? TokenType.Lambda : TokenType.Brk_Close_Round; - List paramnames = new List(); + List paramnames = new List(); // method decls with ':' must push an implicit 'self' param if (pushSelfParam) - paramnames.Add(lcontext.Syntax == ScriptSyntax.CLike ? "this" : "self"); + paramnames.Add(lcontext.Syntax == ScriptSyntax.CLike ? new FunctionDefinitionStatement.FunctionParamRef("this") : new FunctionDefinitionStatement.FunctionParamRef("self")); + bool parsingDefaultParams = false; while (lcontext.Lexer.Current.Type != closeToken) { Token t = lcontext.Lexer.Current; + bool nextAfterParamDeclr = true; if (t.Type == TokenType.Name) { - paramnames.Add(t.Text); + string paramName = t.Text; + + if (lcontext.Lexer.PeekNext().Type == TokenType.Op_Assignment) + { + parsingDefaultParams = true; + lcontext.Lexer.Next(); + lcontext.Lexer.Next(); + Expression defaultVal = Expr(lcontext); + nextAfterParamDeclr = false; + + paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(paramName, defaultVal)); + } + else + { + if (parsingDefaultParams) + { + throw new SyntaxErrorException(t, "after first parameter with default value a parameter without default value cannot be declared", t.Text) + { + IsPrematureStreamTermination = (t.Type == TokenType.Eof) + }; + } + + paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(paramName)); + } } else if (t.Type == TokenType.VarArgs) { m_HasVarArgs = true; - paramnames.Add(WellKnownSymbols.VARARGS); + paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(WellKnownSymbols.VARARGS)); } else UnexpectedTokenType(t); - lcontext.Lexer.Next(); + if (nextAfterParamDeclr) + { + lcontext.Lexer.Next(); + } t = lcontext.Lexer.Current; @@ -197,7 +226,7 @@ private List BuildParamList(ScriptLoadingContext lcontext, bool pushSelf return paramnames; } - private SymbolRef[] DefineArguments(List paramnames, ScriptLoadingContext lcontext) + private SymbolRef[] DefineArguments(List paramnames, ScriptLoadingContext lcontext) { HashSet names = new HashSet(); @@ -205,10 +234,10 @@ private SymbolRef[] DefineArguments(List paramnames, ScriptLoadingContex for (int i = paramnames.Count - 1; i >= 0; i--) { - if (!names.Add(paramnames[i])) - paramnames[i] = paramnames[i] + "@" + i.ToString(); + if (!names.Add(paramnames[i].Name)) + paramnames[i].Name = paramnames[i].Name + "@" + i.ToString(); - ret[i] = lcontext.Scope.DefineLocal(paramnames[i]); + ret[i] = lcontext.Scope.DefineLocal(paramnames[i].Name); } return ret; @@ -243,6 +272,8 @@ public override DynValue Eval(ScriptExecutionContext context) public int CompileBody(ByteCode bc, string friendlyName) { + //LoadingContext.Scope.PopFunction() + string funcName = friendlyName ?? ("<" + this.m_Begin.FormatLocation(bc.Script, true) + ">"); bc.PushSourceRef(m_Begin); @@ -265,8 +296,25 @@ public int CompileBody(ByteCode bc, string friendlyName) } if (m_ParamNames.Length > 0) + { bc.Emit_Args(m_ParamNames); + for (int i = 0; i < m_ParamNames.Length; i++) + { + FunctionDefinitionStatement.FunctionParamRef fr = paramnames[i]; + SymbolRef sr = m_ParamNames[i]; + + if (fr.DefaultValue != null) + { + var jp = bc.Emit_JLclInit(sr, -1); + fr.DefaultValue.CompilePossibleLiteral(bc); + new SymbolRefExpression(lcontext, sr).CompileAssignment(bc, Operator.NotAnOperator, 0, 0); + bc.Emit_Pop(); + bc.SetNumVal(jp, bc.GetJumpPointForNextInstruction()); + } + } + } + m_Statement.Compile(bc); bc.PopSourceRef(); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs index 07b26a9e..ff337eee 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs @@ -10,7 +10,6 @@ class IndexExpression : Expression, IVariable Expression m_BaseExp; Expression m_IndexExp; string m_Name; - private Token nameToken; private bool inc; private bool dec; private bool nilCheck; @@ -125,7 +124,7 @@ public void CompileAssignment(ByteCode bc, Operator op, int stackofs, int tuplei { if (isLength) { - throw new SyntaxErrorException(nameToken, "Cannot assign to readonly property .length"); + throw new SyntaxErrorException(null, "Cannot assign to readonly property .length"); } if (op != Operator.NotAnOperator) { diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs index 85776255..67ffb58d 100755 --- a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs @@ -851,9 +851,7 @@ private Token ReadHashBang(int fromLine, int fromCol) private Token ReadCMultilineComment(int fromLine, int fromCol) { StringBuilder text = new StringBuilder(32); - - bool extraneousFound = false; - + for (char c = CursorChar(); ; c = CursorCharNext()) { if (c == '\r') continue; @@ -894,7 +892,6 @@ private Token ReadComment(int fromLine, int fromCol) } else if (c == '\n') { - extraneousFound = true; CursorCharNext(); return CreateToken(TokenType.Comment, fromLine, fromCol, text.ToString()); } diff --git a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs index 43d1f067..3e2ebf52 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using MoonSharp.Interpreter.Debugging; using MoonSharp.Interpreter.Execution; @@ -145,6 +146,7 @@ public AssignmentStatement(ScriptLoadingContext lcontext, Expression firstExpres else { CheckTokenType(lcontext, TokenType.Op_Assignment); } + m_RValues = Expression.ExprList(lcontext); } diff --git a/src/MoonSharp.Interpreter/Tree/Statements/FunctionDefinitionStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/FunctionDefinitionStatement.cs index 02fc23ed..27e2ace3 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/FunctionDefinitionStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/FunctionDefinitionStatement.cs @@ -8,6 +8,29 @@ namespace MoonSharp.Interpreter.Tree.Statements { class FunctionDefinitionStatement : Statement { + internal class FunctionParamRef + { + public string Name { get; set; } + public Expression DefaultValue { get; set; } + + public FunctionParamRef(string name) + { + Name = name; + } + + public FunctionParamRef(string name, Expression defaultValue) + { + Name = name; + DefaultValue = defaultValue; + } + } + + internal class FunctionRef + { + public string Name { get; set; } + public List Params { get; set; } + } + SymbolRef m_FuncSymbol; SourceRef m_SourceRef; @@ -27,17 +50,16 @@ public FunctionDefinitionStatement(ScriptLoadingContext lcontext, bool local, To funcKeyword = localToken ?? funcKeyword; // for debugger purposes m_Local = local; - + Token name = CheckTokenType(lcontext, TokenType.Name); + if (m_Local) { - Token name = CheckTokenType(lcontext, TokenType.Name); m_FuncSymbol = lcontext.Scope.TryDefineLocal(name.Text); m_FriendlyName = string.Format("{0} (local)", name.Text); m_SourceRef = funcKeyword.GetSourceRef(name); } else { - Token name = CheckTokenType(lcontext, TokenType.Name); string firstName = name.Text; m_SourceRef = funcKeyword.GetSourceRef(name); diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.lua new file mode 100644 index 00000000..607debe1 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.lua @@ -0,0 +1,3 @@ +function f1(a, b, c) {} + +f1(10, 20); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/1-call.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.lua new file mode 100644 index 00000000..7a382330 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.lua @@ -0,0 +1,16 @@ +local function f1(a = 500) { + print("a: " + a) +} + +f1() + +if (2 > 1) { + + local function f1(a = 600) { + print("a: " + a) + } + + f1() +} + +f1() \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.txt new file mode 100644 index 00000000..008e233a --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/10-call-default-scope-local-3.txt @@ -0,0 +1,3 @@ +a: 500 +a: 600 +a: 500 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.lua new file mode 100644 index 00000000..b702773f --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.lua @@ -0,0 +1,5 @@ +f = (x = 500) => { + print(x) +} + +f(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.txt new file mode 100644 index 00000000..eb1f4948 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/11-call-default-scope-arrow.txt @@ -0,0 +1 @@ +500 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.lua new file mode 100644 index 00000000..95234de9 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.lua @@ -0,0 +1,5 @@ +f = (x = 500, x2) => { + print(x) +} + +f(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/12-call-default-scope-arrow-invalid.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.lua new file mode 100644 index 00000000..db33eae7 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.lua @@ -0,0 +1,7 @@ +f = (x) => { + x() +} + +f(() => { + print("yes") +}); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.txt new file mode 100644 index 00000000..396a0ba2 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/13-call-default-scope-arrow-arrow.txt @@ -0,0 +1 @@ +yes \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua new file mode 100644 index 00000000..0644c6dc --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua @@ -0,0 +1,5 @@ +f = (x = () => {print("yes")}) => { + x() +} + +f(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt new file mode 100644 index 00000000..396a0ba2 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt @@ -0,0 +1 @@ +yes \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.lua new file mode 100644 index 00000000..f4a649fe --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.lua @@ -0,0 +1,7 @@ +f = (x = () => {print("yes")}) => { + x() +} + +f(() => { + print("no") +}); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.txt new file mode 100644 index 00000000..54299a48 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/15-call-default-scope-arrow-arrow-default-2.txt @@ -0,0 +1 @@ +no \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.lua new file mode 100644 index 00000000..379b00ca --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.lua @@ -0,0 +1,7 @@ +function f1(a, b, c = 100) { + print("a: " + a) + print("b: " + b) + print("c: " + c) +} + +f1(10, 20); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.txt new file mode 100644 index 00000000..84e69f2b --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/2-call-default.txt @@ -0,0 +1,3 @@ +a: 10 +b: 20 +c: 100 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.lua new file mode 100644 index 00000000..27b1fdb8 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.lua @@ -0,0 +1,7 @@ +function f1(a = 50, b, c = 100) { + print("a: " + a) + print("b: " + b) + print("c: " + c) +} + +f1(10, 20); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/3-call-default-invalid.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.lua new file mode 100644 index 00000000..059f5357 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.lua @@ -0,0 +1,5 @@ +function f1(a = 80) { + print("a: " + a) +} + +f1(10); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.txt new file mode 100644 index 00000000..fe38f180 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/4-call-default-2.txt @@ -0,0 +1 @@ +a: 10 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.lua new file mode 100644 index 00000000..33ff9ee1 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.lua @@ -0,0 +1,5 @@ +function f1(a = 80) { + print("a: " + a) +} + +f1(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.txt new file mode 100644 index 00000000..7bda620c --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/5-call-default-3.txt @@ -0,0 +1 @@ +a: 80 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.lua new file mode 100644 index 00000000..71585da4 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.lua @@ -0,0 +1,5 @@ +local function f1(a = 80) { + print("a: " + a) +} + +f1(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.txt new file mode 100644 index 00000000..7bda620c --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/6-call-default-local.txt @@ -0,0 +1 @@ +a: 80 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.lua new file mode 100644 index 00000000..bb6699e1 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.lua @@ -0,0 +1,7 @@ +function f1(a = 500) { + print("global a: " + a) +} + +if (2 > 1) { + f1() +} \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.txt new file mode 100644 index 00000000..ec2ec889 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/7-call-default-scope.txt @@ -0,0 +1 @@ +global a: 500 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.lua new file mode 100644 index 00000000..96e0270c --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.lua @@ -0,0 +1,7 @@ +local function f1(a = 500) { + print("a: " + a) +} + +if (2 > 1) { + f1() +} \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.txt new file mode 100644 index 00000000..4020fea7 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/8-call-default-scope-local.txt @@ -0,0 +1 @@ +a: 500 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.lua new file mode 100644 index 00000000..3a238975 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.lua @@ -0,0 +1,14 @@ +local function f1(a = 500) { + print("a: " + a) +} + +f1() + +if (2 > 1) { + + function f1(a = 600) { + print("a: " + a) + } + + f1() +} \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.txt new file mode 100644 index 00000000..a9db8281 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/9-call-default-scope-local-2.txt @@ -0,0 +1,2 @@ +a: 500 +a: 600 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLikeTestRunner.cs b/src/MoonSharp.Tests/EndToEnd/CLikeTestRunner.cs index 47090ff1..988ca721 100644 --- a/src/MoonSharp.Tests/EndToEnd/CLikeTestRunner.cs +++ b/src/MoonSharp.Tests/EndToEnd/CLikeTestRunner.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using System.Threading.Tasks; @@ -40,8 +41,37 @@ public async Task Run(string path) script.Options.Syntax = ScriptSyntax.CLike; } - await script.DoStringAsync(code); + if (path.Contains("flaky")) + { + Assert.Inconclusive($"Test {path} marked as flaky"); + return; + } + + try + { + await script.DoStringAsync(code); + Assert.AreEqual(output.Trim(), stdOut.ToString().Trim(), $"Test {path} did not pass."); - Assert.AreEqual(output.Trim(), stdOut.ToString().Trim(), $"Test {path} did not pass."); + if (path.Contains("invalid")) + { + Assert.Fail("Expected to crash but 'passed'"); + } + } + catch (Exception e) + { + if (e is AssertionException ae) + { + Assert.Fail($"Test {path} did not pass.\nMessage: {ae.Message}\n{ae.StackTrace}"); + return; + } + + if (path.Contains("invalid")) + { + Assert.Pass($"Crashed as expected: {e.Message}"); + return; + } + + Assert.Fail($"Test {path} did not pass.\nMessage: {e.Message}\n{e.StackTrace}"); + } } } \ No newline at end of file From a4847ffd1377db544d86a18800fda7f0e146f255 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Thu, 7 Apr 2022 15:12:57 +0930 Subject: [PATCH 2/2] Fix scoping issues with default function parameters --- .../Execution/Scopes/BuildTimeScope.cs | 9 ++++-- .../Execution/Scopes/BuildTimeScopeFrame.cs | 5 ++-- .../FunctionDefinitionExpression.cs | 30 ++++++++++++------- .../Tree/Statements/ChunkStatement.cs | 3 +- ...all-default-scope-arrow-arrow-default.lua} | 0 ...all-default-scope-arrow-arrow-default.txt} | 0 .../Functions/16-default-call-closure.lua | 21 +++++++++++++ .../Functions/16-default-call-closure.txt | 2 ++ src/MoonSharp.Tests/EndToEnd/CSyntaxTests.cs | 10 +++++++ 9 files changed, 63 insertions(+), 17 deletions(-) rename src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/{14-call-default-scope-arrow-arrow-default-flaky.lua => 14-call-default-scope-arrow-arrow-default.lua} (100%) rename src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/{14-call-default-scope-arrow-arrow-default-flaky.txt => 14-call-default-scope-arrow-arrow-default.txt} (100%) create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.txt diff --git a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs index 9c259265..9b30517d 100644 --- a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs +++ b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs @@ -11,10 +11,15 @@ internal class BuildTimeScope List m_Frames = new List(); List m_ClosureBuilders = new List(); - public void PushFunction(IClosureBuilder closureBuilder, bool hasVarArgs) + public void PushFunction(IClosureBuilder closureBuilder) { m_ClosureBuilders.Add(closureBuilder); - m_Frames.Add(new BuildTimeScopeFrame(hasVarArgs)); + m_Frames.Add(new BuildTimeScopeFrame()); + } + + public void SetHasVarArgs() + { + m_Frames.Last().HasVarArgs = true; } public void PushBlock() diff --git a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs index 57dff639..73d0a763 100644 --- a/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs +++ b/src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs @@ -10,11 +10,10 @@ internal class BuildTimeScopeFrame BuildTimeScopeBlock m_ScopeTreeHead; RuntimeScopeFrame m_ScopeFrame = new RuntimeScopeFrame(); - public bool HasVarArgs { get; private set;} + public bool HasVarArgs { get; set;} - internal BuildTimeScopeFrame(bool hasVarArgs) + internal BuildTimeScopeFrame() { - HasVarArgs = hasVarArgs; m_ScopeTreeHead = m_ScopeTreeRoot = new BuildTimeScopeBlock(null); } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs index 7b80e29a..c7d32c13 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs @@ -43,6 +43,23 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel if (m_UsesGlobalEnv = usesGlobalEnv) CheckTokenType(lcontext, TokenType.Function); + + // create scope + // This needs to be up here to allow for arguments to correctly close over ENV + // Arguments, however, must come before any other local definitions to avoid closing + // over uninitialised variables. (Note for hoisting). + lcontext.Scope.PushFunction(this); + + if (m_UsesGlobalEnv) + { + m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV); + } + else + { + lcontext.Scope.ForceEnvUpValue(); + } + + // Parse arguments // here lexer should be at the '(' or at the '|' //Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round); @@ -78,19 +95,10 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel m_Begin = openRound.GetSourceRefUpTo(lcontext.Lexer.Current); - // create scope - lcontext.Scope.PushFunction(this, m_HasVarArgs); - - if (m_UsesGlobalEnv) - { - m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV); - } - else - { - lcontext.Scope.ForceEnvUpValue(); - } m_ParamNames = DefineArguments(paramnames, lcontext); + + if(m_HasVarArgs) lcontext.Scope.SetHasVarArgs(); //Moved here if(isLambda) m_Statement = CreateLambdaBody(lcontext, arrowFunc); diff --git a/src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs index 6bcbcd84..a72751c6 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs @@ -13,7 +13,8 @@ class ChunkStatement : Statement, IClosureBuilder public ChunkStatement(ScriptLoadingContext lcontext) : base(lcontext) { - lcontext.Scope.PushFunction(this, true); + lcontext.Scope.PushFunction(this); + lcontext.Scope.SetHasVarArgs(); m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV); m_VarArgs = lcontext.Scope.DefineLocal(WellKnownSymbols.VARARGS); diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default.lua similarity index 100% rename from src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.lua rename to src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default.lua diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default.txt similarity index 100% rename from src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default-flaky.txt rename to src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/14-call-default-scope-arrow-arrow-default.txt diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.lua new file mode 100644 index 00000000..672626cc --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.lua @@ -0,0 +1,21 @@ +local z = 2 + +f = (x = () => {print(z)}) => { + x() +} + +z = 3 + +f(); + +function test2() { + local z = 2 + f = (x = () => {print(z)}) => { + x() + } + z = 7; + return f; +} + +local f2 = test2(); +f2(); \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.txt new file mode 100644 index 00000000..2108f32f --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Functions/16-default-call-closure.txt @@ -0,0 +1,2 @@ +3 +7 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CSyntaxTests.cs b/src/MoonSharp.Tests/EndToEnd/CSyntaxTests.cs index c65d8131..db2b39fd 100644 --- a/src/MoonSharp.Tests/EndToEnd/CSyntaxTests.cs +++ b/src/MoonSharp.Tests/EndToEnd/CSyntaxTests.cs @@ -183,6 +183,16 @@ public void CFor_Closure() ", s => s.Options.Syntax = ScriptSyntax.CLike); } + [Test] + public void CallDefaultFunc() + { + TestScript.Run(@" + f = (x = () => {print('yes')}) => { + x() + } + f();", s => s.Options.Syntax = ScriptSyntax.CLike); + } + [Test] public void AddConcat() {