fix: treat "arguments" as a keyword (as per strict soecifications)

This commit is contained in:
TopchetoEU 2024-09-05 13:18:53 +03:00
parent e509edc459
commit d7353e19ed
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
9 changed files with 59 additions and 24 deletions

View File

@ -352,8 +352,8 @@ public class Instruction {
public static Instruction loadThis() { public static Instruction loadThis() {
return new Instruction(Type.LOAD_THIS); return new Instruction(Type.LOAD_THIS);
} }
public static Instruction loadArgs() { public static Instruction loadArgs(boolean real) {
return new Instruction(Type.LOAD_ARGS); return new Instruction(Type.LOAD_ARGS, real);
} }
public static Instruction loadRestArgs(int offset) { public static Instruction loadRestArgs(int offset) {
return new Instruction(Type.LOAD_REST_ARGS, offset); return new Instruction(Type.LOAD_REST_ARGS, offset);

View File

@ -54,17 +54,21 @@ public class FunctionArrowNode extends FunctionNode {
if (!src.is(i + n, "=>")) return ParseRes.failed(); if (!src.is(i + n, "=>")) return ParseRes.failed();
n += 2; n += 2;
n += Parsing.skipEmpty(src, i + n);
ParseRes<Node> body = ParseRes.first(src, i + n, if (src.is(i + n, "{")) {
(s, j) -> JavaScript.parseExpression(s, j, 2), var body = CompoundNode.parse(src, i + n);
CompoundNode::parse if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compount statement after '=>'");
); n += body.n;
if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected an expression or a compount statement after '=>'");
n += body.n;
return ParseRes.res(new FunctionArrowNode( return ParseRes.res(new FunctionArrowNode(loc, src.loc(i + n - 1), params, body.result), n);
loc, src.loc(i + n - 1), }
params, body.result else {
), n); var body = JavaScript.parseExpression(src, i + n, 2);
if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compount statement after '=>'");
n += body.n;
return ParseRes.res(new FunctionArrowNode(loc, src.loc(i + n - 1), params, body.result), n);
}
} }
} }

View File

@ -31,12 +31,12 @@ public abstract class FunctionNode extends Node {
.remove(LabelContext.CONTINUE_CTX); .remove(LabelContext.CONTINUE_CTX);
return new CompileResult(env, scope, params.params.size(), target -> { return new CompileResult(env, scope, params.params.size(), target -> {
if (hasArgs || params.params.size() > 0) target.add(Instruction.loadArgs()); if (hasArgs || params.params.size() > 0) target.add(Instruction.loadArgs(true));
if (hasArgs) { // if (hasArgs) {
var argsVar = scope.defineStrict(new Variable("arguments", true), loc()); // var argsVar = scope.defineStrict(new Variable("arguments", true), loc());
target.add(_i -> Instruction.storeVar(argsVar.index(), params.params.size() > 0)); // target.add(_i -> Instruction.storeVar(argsVar.index(), params.params.size() > 0));
} // }
if (params.params.size() > 0) { if (params.params.size() > 0) {
if (params.params.size() > 1) target.add(Instruction.dup(params.params.size() - 1)); if (params.params.size() > 1) target.add(Instruction.dup(params.params.size() - 1));

View File

@ -24,6 +24,7 @@ import me.topchetoeu.jscript.compilation.control.ThrowNode;
import me.topchetoeu.jscript.compilation.control.TryNode; import me.topchetoeu.jscript.compilation.control.TryNode;
import me.topchetoeu.jscript.compilation.control.WhileNode; import me.topchetoeu.jscript.compilation.control.WhileNode;
import me.topchetoeu.jscript.compilation.scope.FunctionScope; import me.topchetoeu.jscript.compilation.scope.FunctionScope;
import me.topchetoeu.jscript.compilation.values.ArgumentsNode;
import me.topchetoeu.jscript.compilation.values.ArrayNode; import me.topchetoeu.jscript.compilation.values.ArrayNode;
import me.topchetoeu.jscript.compilation.values.ObjectNode; import me.topchetoeu.jscript.compilation.values.ObjectNode;
import me.topchetoeu.jscript.compilation.values.RegexNode; import me.topchetoeu.jscript.compilation.values.RegexNode;
@ -60,7 +61,7 @@ public final class JavaScript {
"finally", "for", "do", "while", "switch", "case", "default", "new", "finally", "for", "do", "while", "switch", "case", "default", "new",
"function", "var", "return", "throw", "typeof", "delete", "break", "function", "var", "return", "throw", "typeof", "delete", "break",
"continue", "debugger", "implements", "interface", "package", "private", "continue", "debugger", "implements", "interface", "package", "private",
"protected", "public", "static" "protected", "public", "static", "arguments"
); );
public static ParseRes<? extends Node> parseParens(Source src, int i) { public static ParseRes<? extends Node> parseParens(Source src, int i) {
@ -115,7 +116,7 @@ public final class JavaScript {
if (id.result.equals("false")) return ParseRes.res(new BoolNode(loc, false), n); if (id.result.equals("false")) return ParseRes.res(new BoolNode(loc, false), n);
if (id.result.equals("null")) return ParseRes.res(new NullNode(loc), n); if (id.result.equals("null")) return ParseRes.res(new NullNode(loc), n);
if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n); if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n);
// if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n); if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n);
return ParseRes.failed(); return ParseRes.failed();
} }

View File

@ -0,0 +1,17 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.parsing.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Node;
public class ArgumentsNode extends Node {
@Override public void compile(CompileResult target, boolean pollute) {
if (pollute) target.add(Instruction.loadArgs(false));
}
public ArgumentsNode(Location loc) {
super(loc);
}
}

View File

@ -13,6 +13,7 @@ import me.topchetoeu.jscript.common.parsing.Source;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.JavaScript;
import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.Node;
import me.topchetoeu.jscript.compilation.values.ArgumentsNode;
import me.topchetoeu.jscript.compilation.values.ArrayNode; import me.topchetoeu.jscript.compilation.values.ArrayNode;
import me.topchetoeu.jscript.compilation.values.ObjectNode; import me.topchetoeu.jscript.compilation.values.ObjectNode;
import me.topchetoeu.jscript.compilation.values.ThisNode; import me.topchetoeu.jscript.compilation.values.ThisNode;
@ -55,6 +56,9 @@ public class CallNode extends Node {
else if (func instanceof ThisNode) { else if (func instanceof ThisNode) {
res = "this"; res = "this";
} }
else if (func instanceof ArgumentsNode) {
res = "arguments";
}
else if (func instanceof ArrayNode) { else if (func instanceof ArrayNode) {
var els = new ArrayList<String>(); var els = new ArrayList<String>();

View File

@ -101,8 +101,9 @@ public final class Frame {
*/ */
public final Value[][] captures; public final Value[][] captures;
public final List<Value[]> locals = new ArrayList<>(); public final List<Value[]> locals = new ArrayList<>();
public final Value self;
public final Value argsVal; public final Value argsVal;
public Value self;
public Value fakeArgs;
public final Value[] args; public final Value[] args;
public final boolean isNew; public final boolean isNew;
public final Stack<TryCtx> tryStack = new Stack<>(); public final Stack<TryCtx> tryStack = new Stack<>();

View File

@ -185,7 +185,10 @@ public class InstructionRunner {
var func = new CodeFunction(env, name, frame.function.body.children[id], captures); var func = new CodeFunction(env, name, frame.function.body.children[id], captures);
if (!callable) func.enableCall = false; if (!callable) func.enableCall = false;
if (!constructible) func.enableNew = false; if (!constructible) func.enableNew = false;
if (captureThis) func.self = frame.self; if (captureThis) {
func.self = frame.self;
func.argsVal = frame.argsVal;
}
frame.push(func); frame.push(func);
frame.codePtr++; frame.codePtr++;
@ -472,7 +475,8 @@ public class InstructionRunner {
} }
private static Value execLoadArgs(Environment env, Instruction instr, Frame frame) { private static Value execLoadArgs(Environment env, Instruction instr, Frame frame) {
frame.push(frame.argsVal); if ((boolean)instr.get(0) || frame.fakeArgs == null) frame.push(frame.argsVal);
else frame.push(frame.fakeArgs);
frame.codePtr++; frame.codePtr++;
return null; return null;
} }

View File

@ -9,6 +9,7 @@ public final class CodeFunction extends FunctionValue {
public final FunctionBody body; public final FunctionBody body;
public final Value[][] captures; public final Value[][] captures;
public Value self; public Value self;
public Value argsVal;
public Environment env; public Environment env;
private Value onCall(Frame frame) { private Value onCall(Frame frame) {
@ -26,8 +27,11 @@ public final class CodeFunction extends FunctionValue {
} }
@Override public Value onCall(Environment env, boolean isNew, String name, Value thisArg, Value ...args) { @Override public Value onCall(Environment env, boolean isNew, String name, Value thisArg, Value ...args) {
if (self != null) return onCall(new Frame(env, isNew, self, args, this)); var frame = new Frame(env, isNew, thisArg, args, this);
else return onCall(new Frame(env, isNew, thisArg, args, this)); if (argsVal != null) frame.fakeArgs = argsVal;
if (self != null) frame.self = self;
return onCall(frame);
} }
public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) { public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) {