Skip to content

Commit f9eb0f0

Browse files
authored
Merge pull request #18 from Librelancer/feat-default-param-fix
Default params
2 parents 4e4b5dd + a4847ff commit f9eb0f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+333
-59
lines changed

src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
7070
case OpCode.Swap:
7171
case OpCode.Clean:
7272
case OpCode.CopyValue:
73+
case OpCode.JLclInit:
7374
return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
7475
case OpCode.Local:
7576
case OpCode.Upvalue:

src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections.Generic;
22
using System.Linq;
33
using MoonSharp.Interpreter.Execution.Scopes;
4+
using MoonSharp.Interpreter.Tree;
45
using MoonSharp.Interpreter.Tree.Statements;
56

67
namespace MoonSharp.Interpreter.Execution
@@ -10,11 +11,15 @@ internal class BuildTimeScope
1011
List<BuildTimeScopeFrame> m_Frames = new List<BuildTimeScopeFrame>();
1112
List<IClosureBuilder> m_ClosureBuilders = new List<IClosureBuilder>();
1213

13-
14-
public void PushFunction(IClosureBuilder closureBuilder, bool hasVarArgs)
14+
public void PushFunction(IClosureBuilder closureBuilder)
1515
{
1616
m_ClosureBuilders.Add(closureBuilder);
17-
m_Frames.Add(new BuildTimeScopeFrame(hasVarArgs));
17+
m_Frames.Add(new BuildTimeScopeFrame());
18+
}
19+
20+
public void SetHasVarArgs()
21+
{
22+
m_Frames.Last().HasVarArgs = true;
1823
}
1924

2025
public void PushBlock()

src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeBlock.cs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using MoonSharp.Interpreter.Tree.Statements;
45

56
namespace MoonSharp.Interpreter.Execution.Scopes
@@ -8,13 +9,9 @@ internal class BuildTimeScopeBlock
89
{
910
internal BuildTimeScopeBlock Parent { get; private set; }
1011
internal List<BuildTimeScopeBlock> ChildNodes { get; private set; }
11-
1212
internal RuntimeScopeBlock ScopeBlock { get; private set; }
13-
1413
Dictionary<string, SymbolRef> m_DefinedNames = new Dictionary<string, SymbolRef>();
15-
16-
17-
14+
1815
internal void Rename(string name)
1916
{
2017
SymbolRef sref = m_DefinedNames[name];

src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScopeFrame.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using MoonSharp.Interpreter.Tree.Statements;
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using MoonSharp.Interpreter.Tree.Statements;
24

35
namespace MoonSharp.Interpreter.Execution.Scopes
46
{
@@ -8,11 +10,10 @@ internal class BuildTimeScopeFrame
810
BuildTimeScopeBlock m_ScopeTreeHead;
911
RuntimeScopeFrame m_ScopeFrame = new RuntimeScopeFrame();
1012

11-
public bool HasVarArgs { get; private set;}
13+
public bool HasVarArgs { get; set;}
1214

13-
internal BuildTimeScopeFrame(bool hasVarArgs)
15+
internal BuildTimeScopeFrame()
1416
{
15-
HasVarArgs = hasVarArgs;
1617
m_ScopeTreeHead = m_ScopeTreeRoot = new BuildTimeScopeBlock(null);
1718
}
1819

src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs

+5
Original file line numberDiff line numberDiff line change
@@ -356,5 +356,10 @@ public int Emit_Swap(int p1, int p2)
356356
return AppendInstruction(new Instruction() { OpCode = OpCode.Swap, NumVal = p1, NumVal2 = p2 });
357357
}
358358

359+
public int Emit_JLclInit(SymbolRef sym, int target)
360+
{
361+
if(sym.Type != SymbolRefType.Local) throw new InternalErrorException("Unexpected symbol type : {0}", sym);
362+
return AppendInstruction(new Instruction() { OpCode = OpCode.JLclInit, NumVal = target, NumVal2 = sym.Index });
363+
}
359364
}
360365
}

src/MoonSharp.Interpreter/Execution/VM/OpCode.cs

+3
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ internal enum OpCode
9090
IterPrep, // Prepares an iterator for execution
9191
IterUpd, // Updates the var part of an iterator
9292

93+
// Nil coalescing
9394
NilCoalescing,
9495
NilCoalescingInverse,
9596

97+
JLclInit, // Inits a param value if a default one is specified and not provided at callsite.
98+
9699
// Meta
97100
Invalid, // Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum
98101
}

src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs

+4
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false)
306306
instructionPtr = ExecNilCoalescingAssignmentInverse(i, instructionPtr);
307307
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
308308
break;
309+
case OpCode.JLclInit:
310+
if(m_ValueStack[m_ExecutionStack.Peek().BasePointer + i.NumVal2].IsNotNil())
311+
instructionPtr = i.NumVal;
312+
break;
309313
case OpCode.Invalid:
310314
throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.String));
311315
default:

src/MoonSharp.Interpreter/Tree/Expression_.cs

+5-7
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ internal static List<Expression> ExprListAfterFirstExpr(ScriptLoadingContext lco
5252

5353
return exps;
5454
}
55-
56-
55+
5756
internal static List<Expression> ExprList(ScriptLoadingContext lcontext)
5857
{
5958
List<Expression> exps = new List<Expression>();
@@ -78,8 +77,7 @@ internal static Expression Expr(ScriptLoadingContext lcontext)
7877

7978
internal static Expression SubExpr(ScriptLoadingContext lcontext, bool isPrimary, bool binaryChainInProgress = false)
8079
{
81-
Expression e = null;
82-
80+
Expression e;
8381
Token T = lcontext.Lexer.Current;
8482

8583
if (T.IsUnaryOperator())
@@ -202,7 +200,7 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext)
202200
lcontext.Lexer.Next();
203201
}
204202
lcontext.Lexer.Next();
205-
bool arrowLambda = lcontext.Lexer.Current.Type == TokenType.Arrow;
203+
bool arrowLambda = lcontext.Lexer.Current.Type == TokenType.Arrow || lcontext.Lexer.PeekNext().Type == TokenType.Arrow;
206204
lcontext.Lexer.RestorePos();
207205
if (arrowLambda)
208206
return new FunctionDefinitionExpression(lcontext, false, true);
@@ -222,11 +220,11 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext)
222220
/// <returns></returns>
223221
internal static Expression PrimaryExp(ScriptLoadingContext lcontext)
224222
{
225-
if (lcontext.Lexer.PeekNext().Type == TokenType.Arrow &&
226-
lcontext.Lexer.Current.Type == TokenType.Name)
223+
if (lcontext.Lexer.PeekNext().Type == TokenType.Arrow && lcontext.Lexer.Current.Type == TokenType.Name)
227224
{
228225
return new FunctionDefinitionExpression(lcontext, false, true);
229226
}
227+
230228
Expression e = PrefixExp(lcontext);
231229

232230
while (true)

src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs

-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ class FunctionCallExpression : Expression
1111
Expression m_Function;
1212
string m_Name;
1313
string m_DebugErr;
14-
1514
internal SourceRef SourceRef { get; private set; }
1615

17-
1816
public FunctionCallExpression(ScriptLoadingContext lcontext, Expression function, Token thisCallName)
1917
: base(lcontext)
2018
{

src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs

+82-26
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class FunctionDefinitionExpression : Expression, IClosureBuilder
2424
SymbolRef m_Env;
2525

2626
SourceRef m_Begin, m_End;
27-
27+
private ScriptLoadingContext lcontext;
28+
List<FunctionDefinitionStatement.FunctionParamRef> paramnames;
2829

2930
public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlobalEnv)
3031
: this(lcontext, false, usesGlobalEnv, false)
@@ -33,26 +34,43 @@ public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlob
3334
public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool isLambda)
3435
: this(lcontext, pushSelfParam, false, isLambda)
3536
{ }
36-
37-
37+
3838
private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool usesGlobalEnv, bool isLambda)
3939
: base(lcontext)
4040
{
41+
this.lcontext = lcontext;
42+
4143
if (m_UsesGlobalEnv = usesGlobalEnv)
4244
CheckTokenType(lcontext, TokenType.Function);
4345

46+
47+
// create scope
48+
// This needs to be up here to allow for arguments to correctly close over ENV
49+
// Arguments, however, must come before any other local definitions to avoid closing
50+
// over uninitialised variables. (Note for hoisting).
51+
lcontext.Scope.PushFunction(this);
52+
53+
if (m_UsesGlobalEnv)
54+
{
55+
m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV);
56+
}
57+
else
58+
{
59+
lcontext.Scope.ForceEnvUpValue();
60+
}
61+
62+
// Parse arguments
4463
// here lexer should be at the '(' or at the '|'
4564
//Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round);
4665

4766
Token openRound;
48-
List<string> paramnames;
4967
bool openCurly = false;
5068
if (isLambda)
5169
{
5270
openRound = lcontext.Lexer.Current;
5371
lcontext.Lexer.Next();
5472
if (openRound.Type == TokenType.Name)
55-
paramnames = new List<string>(new[] {openRound.Text});
73+
paramnames = new List<FunctionDefinitionStatement.FunctionParamRef>(new FunctionDefinitionStatement.FunctionParamRef[] {new FunctionDefinitionStatement.FunctionParamRef(openRound.Text)});
5674
else
5775
paramnames = BuildParamList(lcontext, pushSelfParam, openRound);
5876
}
@@ -77,19 +95,10 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel
7795

7896
m_Begin = openRound.GetSourceRefUpTo(lcontext.Lexer.Current);
7997

80-
// create scope
81-
lcontext.Scope.PushFunction(this, m_HasVarArgs);
82-
83-
if (m_UsesGlobalEnv)
84-
{
85-
m_Env = lcontext.Scope.DefineLocal(WellKnownSymbols.ENV);
86-
}
87-
else
88-
{
89-
lcontext.Scope.ForceEnvUpValue();
90-
}
9198

9299
m_ParamNames = DefineArguments(paramnames, lcontext);
100+
101+
if(m_HasVarArgs) lcontext.Scope.SetHasVarArgs(); //Moved here
93102

94103
if(isLambda)
95104
m_Statement = CreateLambdaBody(lcontext, arrowFunc);
@@ -150,33 +159,61 @@ private Statement CreateBody(ScriptLoadingContext lcontext, bool openCurly)
150159
return s;
151160
}
152161

153-
private List<string> BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken)
162+
private List<FunctionDefinitionStatement.FunctionParamRef> BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken)
154163
{
155164
TokenType closeToken = openBracketToken.Type == TokenType.Lambda ? TokenType.Lambda : TokenType.Brk_Close_Round;
156165

157-
List<string> paramnames = new List<string>();
166+
List<FunctionDefinitionStatement.FunctionParamRef> paramnames = new List<FunctionDefinitionStatement.FunctionParamRef>();
158167

159168
// method decls with ':' must push an implicit 'self' param
160169
if (pushSelfParam)
161-
paramnames.Add(lcontext.Syntax == ScriptSyntax.CLike ? "this" : "self");
170+
paramnames.Add(lcontext.Syntax == ScriptSyntax.CLike ? new FunctionDefinitionStatement.FunctionParamRef("this") : new FunctionDefinitionStatement.FunctionParamRef("self"));
162171

172+
bool parsingDefaultParams = false;
163173
while (lcontext.Lexer.Current.Type != closeToken)
164174
{
165175
Token t = lcontext.Lexer.Current;
176+
bool nextAfterParamDeclr = true;
166177

167178
if (t.Type == TokenType.Name)
168179
{
169-
paramnames.Add(t.Text);
180+
string paramName = t.Text;
181+
182+
if (lcontext.Lexer.PeekNext().Type == TokenType.Op_Assignment)
183+
{
184+
parsingDefaultParams = true;
185+
lcontext.Lexer.Next();
186+
lcontext.Lexer.Next();
187+
Expression defaultVal = Expr(lcontext);
188+
nextAfterParamDeclr = false;
189+
190+
paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(paramName, defaultVal));
191+
}
192+
else
193+
{
194+
if (parsingDefaultParams)
195+
{
196+
throw new SyntaxErrorException(t, "after first parameter with default value a parameter without default value cannot be declared", t.Text)
197+
{
198+
IsPrematureStreamTermination = (t.Type == TokenType.Eof)
199+
};
200+
}
201+
202+
paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(paramName));
203+
}
170204
}
171205
else if (t.Type == TokenType.VarArgs)
172206
{
173207
m_HasVarArgs = true;
174-
paramnames.Add(WellKnownSymbols.VARARGS);
208+
paramnames.Add(new FunctionDefinitionStatement.FunctionParamRef(WellKnownSymbols.VARARGS));
175209
}
176210
else
177211
UnexpectedTokenType(t);
178212

179-
lcontext.Lexer.Next();
213+
if (nextAfterParamDeclr)
214+
{
215+
lcontext.Lexer.Next();
216+
}
180217

181218
t = lcontext.Lexer.Current;
182219

@@ -197,18 +234,18 @@ private List<string> BuildParamList(ScriptLoadingContext lcontext, bool pushSelf
197234
return paramnames;
198235
}
199236

200-
private SymbolRef[] DefineArguments(List<string> paramnames, ScriptLoadingContext lcontext)
237+
private SymbolRef[] DefineArguments(List<FunctionDefinitionStatement.FunctionParamRef> paramnames, ScriptLoadingContext lcontext)
201238
{
202239
HashSet<string> names = new HashSet<string>();
203240

204241
SymbolRef[] ret = new SymbolRef[paramnames.Count];
205242

206243
for (int i = paramnames.Count - 1; i >= 0; i--)
207244
{
208-
if (!names.Add(paramnames[i]))
209-
paramnames[i] = paramnames[i] + "@" + i.ToString();
245+
if (!names.Add(paramnames[i].Name))
246+
paramnames[i].Name = paramnames[i].Name + "@" + i.ToString();
210247

211-
ret[i] = lcontext.Scope.DefineLocal(paramnames[i]);
248+
ret[i] = lcontext.Scope.DefineLocal(paramnames[i].Name);
212249
}
213250

214251
return ret;
@@ -243,6 +280,8 @@ public override DynValue Eval(ScriptExecutionContext context)
243280

244281
public int CompileBody(ByteCode bc, string friendlyName)
245282
{
283+
//LoadingContext.Scope.PopFunction()
284+
246285
string funcName = friendlyName ?? ("<" + this.m_Begin.FormatLocation(bc.Script, true) + ">");
247286

248287
bc.PushSourceRef(m_Begin);
@@ -265,8 +304,25 @@ public int CompileBody(ByteCode bc, string friendlyName)
265304
}
266305

267306
if (m_ParamNames.Length > 0)
307+
{
268308
bc.Emit_Args(m_ParamNames);
269309

310+
for (int i = 0; i < m_ParamNames.Length; i++)
311+
{
312+
FunctionDefinitionStatement.FunctionParamRef fr = paramnames[i];
313+
SymbolRef sr = m_ParamNames[i];
314+
315+
if (fr.DefaultValue != null)
316+
{
317+
var jp = bc.Emit_JLclInit(sr, -1);
318+
fr.DefaultValue.CompilePossibleLiteral(bc);
319+
new SymbolRefExpression(lcontext, sr).CompileAssignment(bc, Operator.NotAnOperator, 0, 0);
320+
bc.Emit_Pop();
321+
bc.SetNumVal(jp, bc.GetJumpPointForNextInstruction());
322+
}
323+
}
324+
}
325+
270326
m_Statement.Compile(bc);
271327

272328
bc.PopSourceRef();

src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ class IndexExpression : Expression, IVariable
1010
Expression m_BaseExp;
1111
Expression m_IndexExp;
1212
string m_Name;
13-
private Token nameToken;
1413
private bool inc;
1514
private bool dec;
1615
private bool nilCheck;
@@ -125,7 +124,7 @@ public void CompileAssignment(ByteCode bc, Operator op, int stackofs, int tuplei
125124
{
126125
if (isLength)
127126
{
128-
throw new SyntaxErrorException(nameToken, "Cannot assign to readonly property .length");
127+
throw new SyntaxErrorException(null, "Cannot assign to readonly property .length");
129128
}
130129
if (op != Operator.NotAnOperator)
131130
{

0 commit comments

Comments
 (0)