Add first test #23

Merged
marregui merged 25 commits from ma/add-first-tests into master 2024-09-04 12:29:17 +00:00
19 changed files with 166 additions and 83 deletions
Showing only changes of commit 412edc0ebc - Show all commits

View File

@ -3,10 +3,11 @@ package me.topchetoeu.jscript.common;
public class FunctionBody { public class FunctionBody {
public final FunctionBody[] children; public final FunctionBody[] children;
public final Instruction[] instructions; public final Instruction[] instructions;
public final int localsN, capturesN, argsN; public final int localsN, capturesN, argsN, length;
public FunctionBody(int localsN, int capturesN, int argsN, Instruction[] instructions, FunctionBody[] children) { public FunctionBody(int localsN, int capturesN, int length, int argsN, Instruction[] instructions, FunctionBody[] children) {
this.children = children; this.children = children;
this.length = length;
this.argsN = argsN; this.argsN = argsN;
this.localsN = localsN; this.localsN = localsN;
this.capturesN = capturesN; this.capturesN = capturesN;

View File

@ -3,7 +3,7 @@ package me.topchetoeu.jscript.compilation;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.function.Supplier; import java.util.function.IntFunction;
import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
@ -16,11 +16,11 @@ import me.topchetoeu.jscript.compilation.scope.LocalScope;
import me.topchetoeu.jscript.compilation.scope.Scope; import me.topchetoeu.jscript.compilation.scope.Scope;
public final class CompileResult { public final class CompileResult {
public final List<Supplier<Instruction>> instructions; public final List<IntFunction<Instruction>> instructions;
public final List<CompileResult> children; public final List<CompileResult> children;
public final FunctionMapBuilder map; public final FunctionMapBuilder map;
public final Environment env; public final Environment env;
public int length = 0; public int length, assignN;
public final Scope scope; public final Scope scope;
public int temp() { public int temp() {
@ -29,18 +29,18 @@ public final class CompileResult {
} }
public CompileResult add(Instruction instr) { public CompileResult add(Instruction instr) {
instructions.add(() -> instr); instructions.add(i -> instr);
return this; return this;
} }
public CompileResult add(Supplier<Instruction> instr) { public CompileResult add(IntFunction<Instruction> instr) {
instructions.add(instr); instructions.add(instr);
return this; return this;
} }
public CompileResult set(int i, Instruction instr) { public CompileResult set(int i, Instruction instr) {
instructions.set(i, () -> instr); instructions.set(i, _i -> instr);
return this; return this;
} }
public CompileResult set(int i, Supplier<Instruction>instr) { public CompileResult set(int i, IntFunction<Instruction>instr) {
instructions.set(i, instr); instructions.set(i, instr);
return this; return this;
} }
@ -76,7 +76,10 @@ public final class CompileResult {
public Instruction[] instructions() { public Instruction[] instructions() {
var res = new Instruction[instructions.size()]; var res = new Instruction[instructions.size()];
var i = 0; var i = 0;
for (var suppl : instructions) res[i++] = suppl.get(); for (var suppl : instructions) {
res[i] = suppl.apply(i);
i++;
}
return res; return res;
} }
@ -90,10 +93,15 @@ public final class CompileResult {
var instrRes = new Instruction[instructions.size()]; var instrRes = new Instruction[instructions.size()];
var i = 0; var i = 0;
for (var suppl : instructions) instrRes[i++] = suppl.get();
for (var suppl : instructions) {
instrRes[i] = suppl.apply(i);
i++;
}
return new FunctionBody( return new FunctionBody(
scope.localsCount() + scope.allocCount(), scope.capturesCount(), length, scope.localsCount() + scope.allocCount(), scope.capturesCount(),
length, assignN,
instrRes, builtChildren instrRes, builtChildren
); );
} }

View File

@ -19,11 +19,11 @@ public class CompoundNode extends Node {
for (var stm : statements) stm.resolve(target); for (var stm : statements) stm.resolve(target);
} }
@Override public void compile(CompileResult target, boolean pollute, BreakpointType type) { public void compile(CompileResult target, boolean pollute, boolean alloc, BreakpointType type) {
List<Node> statements = new ArrayList<Node>(); List<Node> statements = new ArrayList<Node>();
var subtarget = target.subtarget(); var subtarget = target.subtarget();
subtarget.add(() -> Instruction.stackAlloc(subtarget.scope.allocCount())); if (alloc) subtarget.add(i -> Instruction.stackAlloc(subtarget.scope.allocCount()));
for (var stm : this.statements) { for (var stm : this.statements) {
if (stm instanceof FunctionStatementNode func) { if (stm instanceof FunctionStatementNode func) {
@ -42,13 +42,17 @@ public class CompoundNode extends Node {
} }
subtarget.scope.end(); subtarget.scope.end();
subtarget.add(Instruction.stackFree(subtarget.scope.allocCount())); if (alloc) subtarget.add(Instruction.stackFree(subtarget.scope.allocCount()));
if (!polluted && pollute) { if (!polluted && pollute) {
target.add(Instruction.pushUndefined()); target.add(Instruction.pushUndefined());
} }
} }
@Override public void compile(CompileResult target, boolean pollute, BreakpointType type) {
compile(target, pollute, true, type);
}
public CompoundNode setEnd(Location loc) { public CompoundNode setEnd(Location loc) {
this.end = loc; this.end = loc;
return this; return this;

View File

@ -1,6 +1,7 @@
package me.topchetoeu.jscript.compilation; package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType; import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.parsing.Location; import me.topchetoeu.jscript.common.parsing.Location;
import me.topchetoeu.jscript.common.parsing.ParseRes; import me.topchetoeu.jscript.common.parsing.ParseRes;
@ -12,7 +13,7 @@ import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public abstract class FunctionNode extends Node { public abstract class FunctionNode extends Node {
public final CompoundNode body; public final CompoundNode body;
public final String[] args; public final Parameters params;
public final Location end; public final Location end;
public abstract String name(); public abstract String name();
@ -39,14 +40,6 @@ public abstract class FunctionNode extends Node {
} }
private CompileResult compileBody(CompileResult target, String name, boolean storeSelf, boolean pollute, BreakpointType bp) { private CompileResult compileBody(CompileResult target, String name, boolean storeSelf, boolean pollute, BreakpointType bp) {
for (var i = 0; i < args.length; i++) {
for (var j = 0; j < i; j++) {
if (args[i].equals(args[j])) {
throw new SyntaxException(loc(), "Duplicate parameter '" + args[i] + "'.");
}
}
}
var env = target.env.child() var env = target.env.child()
.remove(LabelContext.BREAK_CTX) .remove(LabelContext.BREAK_CTX)
.remove(LabelContext.CONTINUE_CTX); .remove(LabelContext.CONTINUE_CTX);
@ -54,16 +47,31 @@ public abstract class FunctionNode extends Node {
var funcScope = new FunctionScope(target.scope); var funcScope = new FunctionScope(target.scope);
var subtarget = new CompileResult(env, new LocalScope(funcScope)); var subtarget = new CompileResult(env, new LocalScope(funcScope));
for (var arg : args) { for (var param : params.params) {
// TODO: Implement default values // TODO: Implement default values
// TODO: Implement argument location // TODO: Implement argument location
funcScope.defineArg(arg, loc()); if (funcScope.hasArg(param.name)) throw new SyntaxException(param.loc, "Duplicate parameter name not allowed");
var i = funcScope.defineParam(param.name, param.loc);
if (param.node != null) {
var end = new DeferredIntSupplier();
subtarget.add(_i -> Instruction.loadVar(i.index()));
subtarget.add(Instruction.pushUndefined());
subtarget.add(Instruction.operation(Operation.EQUALS));
subtarget.add(_i -> Instruction.jmpIfNot(end.getAsInt() - _i));
param.node.compile(subtarget, pollute);
subtarget.add(_i -> Instruction.storeVar(i.index()));
end.set(subtarget.size());
}
} }
body.resolve(subtarget); body.resolve(subtarget);
body.compile(subtarget, false); body.compile(subtarget, false, false, BreakpointType.NONE);
subtarget.length = args.length; subtarget.length = params.length;
subtarget.assignN = params.params.size();
subtarget.scope.end(); subtarget.scope.end();
funcScope.end(); funcScope.end();
@ -88,11 +96,11 @@ public abstract class FunctionNode extends Node {
compile(target, pollute, (String)null, BreakpointType.NONE); compile(target, pollute, (String)null, BreakpointType.NONE);
} }
public FunctionNode(Location loc, Location end, String[] args, CompoundNode body) { public FunctionNode(Location loc, Location end, Parameters params, CompoundNode body) {
super(loc); super(loc);
this.end = end; this.end = end;
this.args = args; this.params = params;
this.body = body; this.body = body;
} }
@ -117,21 +125,21 @@ public abstract class FunctionNode extends Node {
n += name.n; n += name.n;
n += Parsing.skipEmpty(src, i + n); n += Parsing.skipEmpty(src, i + n);
var args = JavaScript.parseParamList(src, i + n); var params = JavaScript.parseParameters(src, i + n);
if (!args.isSuccess()) return args.chainError(src.loc(i + n), "Expected a parameter list"); if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected a parameter list");
n += args.n; n += params.n;
var body = CompoundNode.parse(src, i + n); var body = CompoundNode.parse(src, i + n);
if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for function."); if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for function");
n += body.n; n += body.n;
if (statement) return ParseRes.res(new FunctionStatementNode( if (statement) return ParseRes.res(new FunctionStatementNode(
loc, src.loc(i + n - 1), loc, src.loc(i + n - 1),
args.result.toArray(String[]::new), body.result, name.result params.result, body.result, name.result
), n); ), n);
else return ParseRes.res(new FunctionValueNode( else return ParseRes.res(new FunctionValueNode(
loc, src.loc(i + n - 1), loc, src.loc(i + n - 1),
args.result.toArray(String[]::new), body.result, name.result params.result, body.result, name.result
), n); ), n);
} }
} }

View File

@ -18,8 +18,8 @@ public class FunctionStatementNode extends FunctionNode {
target.add(VariableNode.toSet(target, end, this.name, pollute, true)); target.add(VariableNode.toSet(target, end, this.name, pollute, true));
} }
public FunctionStatementNode(Location loc, Location end, String[] args, CompoundNode body, String name) { public FunctionStatementNode(Location loc, Location end, Parameters params, CompoundNode body, String name) {
super(loc, end, args, body); super(loc, end, params, body);
this.name = name; this.name = name;
} }
} }

View File

@ -12,8 +12,8 @@ public class FunctionValueNode extends FunctionNode {
compile(target, pollute, true, name, bp); compile(target, pollute, true, name, bp);
} }
public FunctionValueNode(Location loc, Location end, String[] args, CompoundNode body, String name) { public FunctionValueNode(Location loc, Location end, Parameters params, CompoundNode body, String name) {
super(loc, end, args, body); super(loc, end, params, body);
this.name = name; this.name = name;
} }
} }

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation; package me.topchetoeu.jscript.compilation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Set; import java.util.Set;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.common.parsing.Filename; import me.topchetoeu.jscript.common.parsing.Filename;
import me.topchetoeu.jscript.common.parsing.ParseRes; import me.topchetoeu.jscript.common.parsing.ParseRes;
@ -212,40 +212,53 @@ public class JavaScript {
return ParseRes.failed(); return ParseRes.failed();
} }
public static ParseRes<List<String>> parseParamList(Source src, int i) { public static ParseRes<Parameters> parseParameters(Source src, int i) {
var n = Parsing.skipEmpty(src, i); var n = Parsing.skipEmpty(src, i);
var openParen = Parsing.parseOperator(src, i + n, "("); var openParen = Parsing.parseOperator(src, i + n, "(");
if (!openParen.isSuccess()) return openParen.chainError(src.loc(i + n), "Expected a parameter list."); if (!openParen.isSuccess()) return openParen.chainError(src.loc(i + n), "Expected a parameter list");
n += openParen.n; n += openParen.n;
var args = new ArrayList<String>(); var params = new ArrayList<Parameter>();
var closeParen = Parsing.parseOperator(src, i + n, ")"); var closeParen = Parsing.parseOperator(src, i + n, ")");
n += closeParen.n; n += closeParen.n;
if (!closeParen.isSuccess()) { if (!closeParen.isSuccess()) {
while (true) { while (true) {
var argRes = Parsing.parseIdentifier(src, i + n); n += Parsing.skipEmpty(src, i + n);
if (argRes.isSuccess()) {
args.add(argRes.result);
n += argRes.n;
n += Parsing.skipEmpty(src, i);
if (src.is(i + n, ",")) { var paramLoc = src.loc(i);
n++;
n += Parsing.skipEmpty(src, i + n); var name = Parsing.parseIdentifier(src, i + n);
} if (!name.isSuccess()) return ParseRes.error(src.loc(i + n), "Expected an argument or a closing brace");
if (src.is(i + n, ")")) { n += name.n;
n++; n += Parsing.skipEmpty(src, i + n);
break;
} if (src.is(i + n, "=")) {
n++;
var val = parseExpression(src, i + n, 2);
if (!val.isSuccess()) return openParen.chainError(src.loc(i + n), "Expected a default value");
n += val.n;
n += Parsing.skipEmpty(src, i + n);
params.add(new Parameter(paramLoc, name.result, val.result));
}
else params.add(new Parameter(paramLoc, name.result, null));
if (src.is(i + n, ",")) {
n++;
n += Parsing.skipEmpty(src, i + n);
}
if (src.is(i + n, ")")) {
n++;
break;
} }
else return ParseRes.error(src.loc(i + n), "Expected an argument, or a closing brace.");
} }
} }
return ParseRes.res(args, n); return ParseRes.res(new Parameters(params), n);
} }
public static Node[] parse(Environment env, Filename filename, String raw) { public static Node[] parse(Environment env, Filename filename, String raw) {
@ -279,7 +292,7 @@ public class JavaScript {
try { try {
stm.resolve(target); stm.resolve(target);
stm.compile(target, true); stm.compile(target, true, false, BreakpointType.NONE);
// FunctionNode.checkBreakAndCont(target, 0); // FunctionNode.checkBreakAndCont(target, 0);
} }
catch (SyntaxException e) { catch (SyntaxException e) {

View File

@ -2,8 +2,8 @@ package me.topchetoeu.jscript.compilation;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.function.IntFunction;
import java.util.function.IntSupplier; import java.util.function.IntSupplier;
import java.util.function.Supplier;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.common.environment.Environment;
@ -25,15 +25,15 @@ public class LabelContext {
return map.get(name); return map.get(name);
} }
public Supplier<Instruction> getJump(int offset) { public IntFunction<Instruction> getJump() {
var res = get(); var res = get();
if (res == null) return null; if (res == null) return null;
else return () -> Instruction.jmp(res.getAsInt() - offset); else return i -> Instruction.jmp(res.getAsInt() - i);
} }
public Supplier<Instruction> getJump(int offset, String name) { public IntFunction<Instruction> getJump(String name) {
var res = get(name); var res = get(name);
if (res == null) return null; if (res == null) return null;
else return () -> Instruction.jmp(res.getAsInt() - offset); else return i -> Instruction.jmp(res.getAsInt() - i);
} }
public void push(IntSupplier jumpTarget) { public void push(IntSupplier jumpTarget) {

View File

@ -0,0 +1,15 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.parsing.Location;
public final class Parameter {
public final Location loc;
public final String name;
public final Node node;
public Parameter(Location loc, String name, Node node) {
this.name = name;
this.node = node;
this.loc = loc;
}
}

View File

@ -0,0 +1,28 @@
package me.topchetoeu.jscript.compilation;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public final class Parameters {
public final int length;
public final List<Parameter> params;
public final Set<String> names;
public Parameters(List<Parameter> params) {
this.names = new HashSet<>();
var len = params.size();
for (var i = params.size() - 1; i >= 0; i--) {
if (params.get(i).node == null) break;
len--;
}
for (var param : params) {
this.names.add(param.name);
}
this.params = params;
this.length = len;
}
}

View File

@ -40,7 +40,7 @@ public class VariableDeclareNode extends Node {
target.add(VariableNode.toSet(target, entry.location, entry.name, false, true)); target.add(VariableNode.toSet(target, entry.location, entry.name, false, true));
} }
else { else {
target.add(() -> { target.add(_i -> {
var i = target.scope.get(entry.name, true); var i = target.scope.get(entry.name, true);
if (i == null) return Instruction.globDef(entry.name); if (i == null) return Instruction.globDef(entry.name);

View File

@ -15,7 +15,7 @@ public class BreakNode extends Node {
public final String label; public final String label;
@Override public void compile(CompileResult target, boolean pollute) { @Override public void compile(CompileResult target, boolean pollute) {
var res = LabelContext.getBreak(target.env).getJump(target.size()); var res = LabelContext.getBreak(target.env).getJump();
if (res == null) { if (res == null) {
if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label));
else throw new SyntaxException(loc(), "Illegal break statement"); else throw new SyntaxException(loc(), "Illegal break statement");

View File

@ -15,7 +15,7 @@ public class ContinueNode extends Node {
public final String label; public final String label;
@Override public void compile(CompileResult target, boolean pollute) { @Override public void compile(CompileResult target, boolean pollute) {
var res = LabelContext.getCont(target.env).getJump(target.size()); var res = LabelContext.getCont(target.env).getJump();
if (res == null) { if (res == null) {
if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label));
else throw new SyntaxException(loc(), "Illegal continue statement"); else throw new SyntaxException(loc(), "Illegal continue statement");

View File

@ -44,7 +44,7 @@ public class SwitchNode extends Node {
value.compile(target, true, BreakpointType.STEP_OVER); value.compile(target, true, BreakpointType.STEP_OVER);
var subtarget = target.subtarget(); var subtarget = target.subtarget();
subtarget.add(() -> Instruction.stackAlloc(subtarget.scope.allocCount())); subtarget.add(_i -> Instruction.stackAlloc(subtarget.scope.allocCount()));
// TODO: create a jump map // TODO: create a jump map
for (var ccase : cases) { for (var ccase : cases) {

View File

@ -27,7 +27,7 @@ public class FunctionScope extends Scope {
else if (parent == null) throw new RuntimeException("Strict variables may be defined only in local scopes"); else if (parent == null) throw new RuntimeException("Strict variables may be defined only in local scopes");
else return parent.defineStrict(name, readonly, loc); else return parent.defineStrict(name, readonly, loc);
} }
public VariableDescriptor defineArg(String name, Location loc) { public VariableDescriptor defineParam(String name, Location loc) {
return specials.add(name, false); return specials.add(name, false);
} }
public boolean hasArg(String name) { public boolean hasArg(String name) {

View File

@ -97,7 +97,7 @@ public class ObjectNode extends Node {
if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a property name after '" + access + "'"); if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a property name after '" + access + "'");
n += name.n; n += name.n;
var params = JavaScript.parseParamList(src, i + n); var params = JavaScript.parseParameters(src, i + n);
if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected an argument list"); if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected an argument list");
n += params.n; n += params.n;
@ -109,7 +109,7 @@ public class ObjectNode extends Node {
return ParseRes.res(new ObjProp( return ParseRes.res(new ObjProp(
name.result, access.result, name.result, access.result,
new FunctionValueNode(loc, end, params.result.toArray(String[]::new), body.result, access + " " + name.result.toString()) new FunctionValueNode(loc, end, params.result, body.result, access + " " + name.result.toString())
), n); ), n);
} }

View File

@ -1,5 +1,6 @@
package me.topchetoeu.jscript.compilation.values; package me.topchetoeu.jscript.compilation.values;
import java.util.function.IntFunction;
import java.util.function.Supplier; import java.util.function.Supplier;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
@ -33,7 +34,7 @@ public class VariableNode extends Node implements AssignableNode {
var i = target.scope.get(name, true); var i = target.scope.get(name, true);
if (i == null) { if (i == null) {
target.add((Supplier<Instruction>)() -> { target.add(_i -> {
if (target.scope.has(name)) throw new SyntaxException(loc(), String.format("Cannot access '%s' before initialization", name)); if (target.scope.has(name)) throw new SyntaxException(loc(), String.format("Cannot access '%s' before initialization", name));
return Instruction.globGet(name); return Instruction.globGet(name);
}); });
@ -45,28 +46,28 @@ public class VariableNode extends Node implements AssignableNode {
} }
} }
public static Supplier<Instruction> toGet(CompileResult target, Location loc, String name, Supplier<Instruction> onGlobal) { public static IntFunction<Instruction> toGet(CompileResult target, Location loc, String name, Supplier<Instruction> onGlobal) {
var i = target.scope.get(name, true); var i = target.scope.get(name, true);
if (i == null) return () -> { if (i == null) return _i -> {
if (target.scope.has(name)) throw new SyntaxException(loc, String.format("Cannot access '%s' before initialization", name)); if (target.scope.has(name)) throw new SyntaxException(loc, String.format("Cannot access '%s' before initialization", name));
else return onGlobal.get(); else return onGlobal.get();
}; };
else return () -> Instruction.loadVar(i.index()); else return _i -> Instruction.loadVar(i.index());
} }
public static Supplier<Instruction> toGet(CompileResult target, Location loc, String name) { public static IntFunction<Instruction> toGet(CompileResult target, Location loc, String name) {
return toGet(target, loc, name, () -> Instruction.globGet(name)); return toGet(target, loc, name, () -> Instruction.globGet(name));
} }
public static Supplier<Instruction> toSet(CompileResult target, Location loc, String name, boolean keep, boolean define) { public static IntFunction<Instruction> toSet(CompileResult target, Location loc, String name, boolean keep, boolean define) {
var i = target.scope.get(name, true); var i = target.scope.get(name, true);
if (i == null) return () -> { if (i == null) return _i -> {
if (target.scope.has(name)) throw new SyntaxException(loc, String.format("Cannot access '%s' before initialization", name)); if (target.scope.has(name)) throw new SyntaxException(loc, String.format("Cannot access '%s' before initialization", name));
else return Instruction.globSet(name, keep, define); else return Instruction.globSet(name, keep, define);
}; };
else return () -> Instruction.storeVar(i.index(), keep); else return _i -> Instruction.storeVar(i.index(), keep);
} }

View File

@ -420,11 +420,16 @@ public final class Frame {
this.argsVal = new ArgumentsValue(this, args); this.argsVal = new ArgumentsValue(this, args);
this.captures = func.captures; this.captures = func.captures;
for (var i = 0; i < func.body.argsN; i++) { var i = 0;
for (; i < func.body.argsN && i < args.length; i++) {
this.locals.add(new Value[] { args[i] }); this.locals.add(new Value[] { args[i] });
} }
for (; i < args.length; i++) {
this.locals.add(new Value[] { Value.UNDEFINED });
}
for (var i = 0; i < func.body.localsN; i++) { for (i = 0; i < func.body.localsN; i++) {
this.locals.add(new Value[] { Value.UNDEFINED }); this.locals.add(new Value[] { Value.UNDEFINED });
} }

View File

@ -30,7 +30,7 @@ public final class CodeFunction extends FunctionValue {
} }
public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) { public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) {
super(name, body.argsN); super(name, body.length);
this.captures = captures; this.captures = captures;
this.env = env; this.env = env;
this.body = body; this.body = body;