Skip to content

Commit

Permalink
Merge pull request #18 from Librelancer/feat-default-param-fix
Browse files Browse the repository at this point in the history
Default params
  • Loading branch information
CallumDev authored Apr 7, 2022
2 parents 4e4b5dd + a4847ff commit f9eb0f0
Show file tree
Hide file tree
Showing 49 changed files with 333 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 8 additions & 3 deletions src/MoonSharp.Interpreter/Execution/Scopes/BuildTimeScope.cs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,11 +11,15 @@ internal class BuildTimeScope
List<BuildTimeScopeFrame> m_Frames = new List<BuildTimeScopeFrame>();
List<IClosureBuilder> m_ClosureBuilders = new List<IClosureBuilder>();


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()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MoonSharp.Interpreter.Tree.Statements;

namespace MoonSharp.Interpreter.Execution.Scopes
Expand All @@ -8,13 +9,9 @@ internal class BuildTimeScopeBlock
{
internal BuildTimeScopeBlock Parent { get; private set; }
internal List<BuildTimeScopeBlock> ChildNodes { get; private set; }

internal RuntimeScopeBlock ScopeBlock { get; private set; }

Dictionary<string, SymbolRef> m_DefinedNames = new Dictionary<string, SymbolRef>();




internal void Rename(string name)
{
SymbolRef sref = m_DefinedNames[name];
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -8,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);
}

Expand Down
5 changes: 5 additions & 0 deletions src/MoonSharp.Interpreter/Execution/VM/ByteCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}
}
}
3 changes: 3 additions & 0 deletions src/MoonSharp.Interpreter/Execution/VM/OpCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
12 changes: 5 additions & 7 deletions src/MoonSharp.Interpreter/Tree/Expression_.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ internal static List<Expression> ExprListAfterFirstExpr(ScriptLoadingContext lco

return exps;
}



internal static List<Expression> ExprList(ScriptLoadingContext lcontext)
{
List<Expression> exps = new List<Expression>();
Expand All @@ -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())
Expand Down Expand Up @@ -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);
Expand All @@ -222,11 +220,11 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext)
/// <returns></returns>
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class FunctionDefinitionExpression : Expression, IClosureBuilder
SymbolRef m_Env;

SourceRef m_Begin, m_End;

private ScriptLoadingContext lcontext;
List<FunctionDefinitionStatement.FunctionParamRef> paramnames;

public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlobalEnv)
: this(lcontext, false, usesGlobalEnv, false)
Expand All @@ -33,26 +34,43 @@ 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);


// 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);

Token openRound;
List<string> paramnames;
bool openCurly = false;
if (isLambda)
{
openRound = lcontext.Lexer.Current;
lcontext.Lexer.Next();
if (openRound.Type == TokenType.Name)
paramnames = new List<string>(new[] {openRound.Text});
paramnames = new List<FunctionDefinitionStatement.FunctionParamRef>(new FunctionDefinitionStatement.FunctionParamRef[] {new FunctionDefinitionStatement.FunctionParamRef(openRound.Text)});
else
paramnames = BuildParamList(lcontext, pushSelfParam, openRound);
}
Expand All @@ -77,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);
Expand Down Expand Up @@ -150,33 +159,61 @@ private Statement CreateBody(ScriptLoadingContext lcontext, bool openCurly)
return s;
}

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

List<string> paramnames = new List<string>();
List<FunctionDefinitionStatement.FunctionParamRef> paramnames = new List<FunctionDefinitionStatement.FunctionParamRef>();

// 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;

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

private SymbolRef[] DefineArguments(List<string> paramnames, ScriptLoadingContext lcontext)
private SymbolRef[] DefineArguments(List<FunctionDefinitionStatement.FunctionParamRef> paramnames, ScriptLoadingContext lcontext)
{
HashSet<string> names = new HashSet<string>();

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

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;
Expand Down Expand Up @@ -243,6 +280,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);
Expand All @@ -265,8 +304,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
Loading

0 comments on commit f9eb0f0

Please sign in to comment.