Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions polymod/hscript/_internal/Parser.hx
Original file line number Diff line number Diff line change
Expand Up @@ -570,9 +570,17 @@ class Parser
{
while (true)
{
var id = getIdent();
var t = maybe(TDoubleDot) ? parseType() : null;
args.push({name: id, t: t});
var arg:Argument = {name: null};
if (maybe(TQuestion)) arg.opt = true;
arg.name = getIdent();

if (allowTypes)
{
if (maybe(TDoubleDot)) arg.t = parseType();
if (maybe(TOp("="))) arg.value = parseExpr();
}
args.push(arg);

var tk = token();
switch (tk)
{
Expand Down
123 changes: 74 additions & 49 deletions polymod/hscript/_internal/PolymodInterpEx.hx
Original file line number Diff line number Diff line change
Expand Up @@ -664,47 +664,55 @@ class PolymodInterpEx extends Interp
{
hasOpt = true;
}
else
if (!p.opt && p.value == null)
{
minParams++;
}
}

// This CREATES a new function in memory, that we call later.
var newFun:Dynamic = function(args:Array<Dynamic>) {
if (((args == null) ? 0 : args.length) != params.length)
// This CREATES a new function in memory, that we call later.
var newFun:Dynamic = function(args:Array<Dynamic>)
{
if (args == null) args = [];

if (args.length < minParams)
{
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
if (name != null)
str += " for function '" + name + "'";
errorEx(ECustom(str));
}

// make sure mandatory args are forced
var args2 = [];
var pos = 0;
for (p in params)
{
if (args.length < minParams)
if (pos < args.length)
{
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
if (name != null) str += " for function '" + name + "'";
errorEx(ECustom(str));
var arg = args[pos++];
if (arg == null && p.value != null)
{
args2.push(expr(p.value));
}
else
{
args2.push(arg);
}
}
// make sure mandatory args are forced
var args2 = [];
var extraParams = args.length - minParams;
var pos = 0;
for (p in params)
else
{
if (p.opt)
if (p.value != null)
{
if (extraParams > 0)
{
args2.push(args[pos++]);
extraParams--;
}
else
{
args2.push(null);
}
args2.push(expr(p.value));
}
else
{
args2.push(args[pos++]);
args2.push(null);
}
}
args = args2;
}
args = args2;

clone.depth++;

Expand Down Expand Up @@ -1657,31 +1665,9 @@ public function callScriptClassStaticFunction(clsName:String, fnName:String, arg
{
// Populate function arguments.

// previousValues is used to restore variables after they are shadowed in the local scope.
var previousClassDecl = _classDeclOverride;
var previousValues:Map<String, Dynamic> = [];
var i = 0;
for (a in fn.args)
{
var value:Dynamic = null;

if (args != null && i < args.length)
{
value = args[i];
}
else if (a.value != null)
{
value = this.expr(a.value);
}

// NOTE: We assign these as variables rather than locals because those get wiped when we enter the function.
if (this.variables.exists(a.name))
{
previousValues.set(a.name, this.variables.get(a.name));
}
this.variables.set(a.name, value);
i++;
}
// previousValues is used to restore variables after they are shadowed in the local scope.
var previousValues:Map<String, Dynamic> = setFunctionValues(fn, args);

this._classDeclOverride = cls;

Expand Down Expand Up @@ -1732,6 +1718,45 @@ public function callScriptClassStaticFunction(clsName:String, fnName:String, arg
}
}

/**
* Initializes function arguments within the interpreter scope.
*
* @param fn The function declaration to extract arguments from.
* @param args The arguments to pass to the function.
* @return The Map containing the variable values before they are shadowed in the local scope.
*/
public function setFunctionValues(fn:Null<FunctionDecl>, args:Array<Dynamic> = null):Map<String, Dynamic>
{
var previousValues:Map<String, Dynamic> = [];
if (fn == null) return previousValues;

var i = 0;
for (a in fn.args)
{
var value:Dynamic = null;

// Uses the passed value if provided and not null, if not fall back to the default value defined in the function argument.
if (args != null && i < args.length && args[i] != null)
{
value = args[i];
}
else if (a.value != null)
{
value = this.expr(a.value);
}

// NOTE: We assign these as variables rather than locals because those get wiped when we enter the function.
if (this.variables.exists(a.name))
{
previousValues.set(a.name, this.variables.get(a.name));
}
this.variables.set(a.name, value);
i++;
}

return previousValues;
}

public function hasScriptClassStaticFunction(clsName:String, fnName:String):Bool
{
var imports:Map<String, PolymodClassImport> = [];
Expand Down
24 changes: 1 addition & 23 deletions polymod/hscript/_internal/PolymodScriptClass.hx
Original file line number Diff line number Diff line change
Expand Up @@ -668,29 +668,7 @@ class PolymodScriptClass
if (fn != null)
{
// previousValues is used to restore variables after they are shadowed in the local scope.
var previousValues:Map<String, Dynamic> = [];
var i = 0;
for (a in fn.args)
{
var value:Dynamic = null;

if (args != null && i < args.length)
{
value = args[i];
}
else if (a.value != null)
{
value = _interp.expr(a.value);
}

// NOTE: We assign these as variables rather than locals because those get wiped when we enter the function.
if (_interp.variables.exists(a.name))
{
previousValues.set(a.name, _interp.variables.get(a.name));
}
_interp.variables.set(a.name, value);
i++;
}
var previousValues:Map<String, Dynamic> = _interp.setFunctionValues(fn, args);

// Polymod.debug('Calling scripted class function "${fullyQualifiedName}.${fnName}(${args})"', null);

Expand Down