Skip to content
This repository was archived by the owner on Dec 31, 2024. It is now read-only.
Merged
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
30 changes: 17 additions & 13 deletions src/main/java/me/topchetoeu/jscript/common/Instruction.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ public static enum Type {
STORE_MEMBER_STR(0x4B),

DEF_PROP(0x50),
KEYS(0x51),
TYPEOF(0x52),
OPERATION(0x53),
DEF_FIELD(0x51),
KEYS(0x52),
TYPEOF(0x53),
OPERATION(0x54),

GLOB_GET(0x60),
GLOB_SET(0x61),
Expand Down Expand Up @@ -341,8 +342,8 @@ public static Instruction globDef(String name) {
return new Instruction(Type.GLOB_DEF, name);
}

public static Instruction globGet(String name) {
return new Instruction(Type.GLOB_GET, name);
public static Instruction globGet(String name, boolean force) {
return new Instruction(Type.GLOB_GET, name, force);
}
public static Instruction globSet(String name, boolean keep, boolean define) {
return new Instruction(Type.GLOB_SET, name, keep, define);
Expand Down Expand Up @@ -404,10 +405,10 @@ public static Instruction loadArr(int count) {
return new Instruction(Type.LOAD_ARR, count);
}
public static Instruction dup() {
return new Instruction(Type.DUP, 1);
return new Instruction(Type.DUP, 1, 0);
}
public static Instruction dup(int count) {
return new Instruction(Type.DUP, count);
public static Instruction dup(int count, int offset) {
return new Instruction(Type.DUP, count, offset);
}

public static Instruction storeVar(int i) {
Expand Down Expand Up @@ -435,7 +436,7 @@ public static Instruction storeMember(int key) {
return new Instruction(Type.STORE_MEMBER_INT, key, false);
}
public static Instruction storeMember(int key, boolean keep) {
return new Instruction(Type.STORE_MEMBER_STR, key, keep);
return new Instruction(Type.STORE_MEMBER_INT, key, keep);
}

public static Instruction discard() {
Expand All @@ -449,12 +450,15 @@ public static Instruction typeof(String varName) {
return new Instruction(Type.TYPEOF, varName);
}

public static Instruction keys(boolean forInFormat) {
return new Instruction(Type.KEYS, forInFormat);
public static Instruction keys(boolean own, boolean onlyEnumerable) {
return new Instruction(Type.KEYS, own, onlyEnumerable);
}

public static Instruction defProp() {
return new Instruction(Type.DEF_PROP);
public static Instruction defProp(boolean setter) {
return new Instruction(Type.DEF_PROP, setter);
}
public static Instruction defField() {
return new Instruction(Type.DEF_FIELD);
}

public static Instruction operation(Operation op) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public static <T> ParseRes<T> failed() {
return new ParseRes<T>(State.FAILED, null, null, null, 0);
}
public static <T> ParseRes<T> error(Location loc, String error) {
// TODO: differentiate definitive and probable errors
return new ParseRes<>(State.ERROR, loc, error, null, 0);
}
public static <T> ParseRes<T> res(T val, int i) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

public class CompoundNode extends Node {
public final Node[] statements;
public final boolean hasScope;
public boolean hasScope;
public Location end;

@Override public void resolve(CompileResult target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import me.topchetoeu.jscript.common.parsing.Parsing;
import me.topchetoeu.jscript.common.parsing.Source;
import me.topchetoeu.jscript.compilation.control.ReturnNode;
import me.topchetoeu.jscript.compilation.patterns.Pattern;

public class FunctionArrowNode extends FunctionNode {
@Override public String name() { return null; }
Expand All @@ -34,22 +35,20 @@ public static ParseRes<FunctionArrowNode> parse(Source src, int i) {
Parameters params;

if (src.is(i + n, "(")) {
var paramsRes = JavaScript.parseParameters(src, i + n);
var paramsRes = Parameters.parseParameters(src, i + n);
if (!paramsRes.isSuccess()) return paramsRes.chainError();
n += paramsRes.n;
n += Parsing.skipEmpty(src, i + n);

params = paramsRes.result;
}
else {
var singleParam = Parsing.parseIdentifier(src, i + n);
var singleParam = Pattern.parse(src, i + n, true);
if (!singleParam.isSuccess()) return ParseRes.failed();

var paramLoc = src.loc(i + n);
n += singleParam.n;
n += Parsing.skipEmpty(src, i + n);

params = new Parameters(List.of(new Parameter(paramLoc, singleParam.result, null)));
params = new Parameters(List.of(singleParam.result));
}

if (!src.is(i + n, "=>")) return ParseRes.failed();
Expand Down
59 changes: 30 additions & 29 deletions src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package me.topchetoeu.jscript.compilation;

import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.common.parsing.Location;
import me.topchetoeu.jscript.common.parsing.ParseRes;
import me.topchetoeu.jscript.common.parsing.Parsing;
import me.topchetoeu.jscript.common.parsing.Source;
import me.topchetoeu.jscript.compilation.JavaScript.DeclarationType;
import me.topchetoeu.jscript.compilation.scope.FunctionScope;
import me.topchetoeu.jscript.compilation.scope.Variable;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;

public abstract class FunctionNode extends Node {
public final CompoundNode body;
Expand All @@ -33,40 +32,41 @@ public final CompileResult compileBody(Environment env, FunctionScope scope, boo
return new CompileResult(env, scope, params.params.size(), target -> {
if (params.params.size() > 0) {
target.add(Instruction.loadArgs(true));
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, 0));
var i = 0;

for (var param : params.params) {
if (scope.has(param.name, false)) throw new SyntaxException(param.loc, "Duplicate parameter name not allowed");
if (!JavaScript.checkVarName(param.name)) {
throw new SyntaxException(param.loc, String.format("Unexpected identifier '%s'", param.name));
}
var varI = scope.define(new Variable(param.name, false), param.loc);

target.add(Instruction.loadMember(i++));

if (param.node != null) {
var end = new DeferredIntSupplier();

target.add(Instruction.dup());
target.add(Instruction.pushUndefined());
target.add(Instruction.operation(Operation.EQUALS));
target.add(Instruction.jmpIfNot(end));
target.add(Instruction.discard());
param.node.compile(target, true);

end.set(target.size());
}

target.add(_i -> varI.index().toSet(false));
param.destruct(target, DeclarationType.VAR, true);
// if (scope.has(param.name, false)) throw new SyntaxException(param.loc, "Duplicate parameter name not allowed");
// if (!JavaScript.checkVarName(param.name)) {
// throw new SyntaxException(param.loc, String.format("Unexpected identifier '%s'", param.name));
// }
// var varI = scope.define(new Variable(param.name, false), param.loc);

// if (param.node != null) {
// var end = new DeferredIntSupplier();

// target.add(Instruction.dup());
// target.add(Instruction.pushUndefined());
// target.add(Instruction.operation(Operation.EQUALS));
// target.add(Instruction.jmpIfNot(end));
// target.add(Instruction.discard());
// param.node.compile(target, true);

// end.set(target.size());
// }

// target.add(_i -> varI.index().toSet(false));
}
}

if (params.restName != null) {
if (scope.has(params.restName, false)) throw new SyntaxException(params.restLocation, "Duplicate parameter name not allowed");
var restVar = scope.define(new Variable(params.restName, false), params.restLocation);
if (params.rest != null) {
target.add(Instruction.loadRestArgs(params.params.size()));
target.add(_i -> restVar.index().toSet(false));
params.rest.destruct(target, DeclarationType.VAR, true);
// if (scope.has(params.restName, false)) throw new SyntaxException(params.restLocation, "Duplicate parameter name not allowed");
// var restVar = scope.define(new Variable(params.restName, false), params.restLocation);
// target.add(_i -> restVar.index().toSet(false));
}

if (selfName != null && !scope.has(name, false)) {
Expand Down Expand Up @@ -107,6 +107,7 @@ public FunctionNode(Location loc, Location end, Parameters params, CompoundNode
this.end = end;
this.params = params;
this.body = body;
this.body.hasScope = false;
}

public static void compileWithName(Node stm, CompileResult target, boolean pollute, String name) {
Expand All @@ -130,7 +131,7 @@ public static ParseRes<FunctionNode> parseFunction(Source src, int i, boolean st
n += name.n;
n += Parsing.skipEmpty(src, i + n);

var params = JavaScript.parseParameters(src, i + n);
var params = Parameters.parseParameters(src, i + n);
if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected a parameter list");
n += params.n;

Expand Down
70 changes: 3 additions & 67 deletions src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import me.topchetoeu.jscript.compilation.values.operations.DiscardNode;
import me.topchetoeu.jscript.compilation.values.operations.IndexNode;
import me.topchetoeu.jscript.compilation.values.operations.OperationNode;
import me.topchetoeu.jscript.compilation.values.operations.PostfixNode;
import me.topchetoeu.jscript.compilation.values.operations.TypeofNode;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;

Expand Down Expand Up @@ -140,8 +141,8 @@ public static ParseRes<? extends Node> parseExpression(Source src, int i, int pr
ParseRes<Node> res = ParseRes.first(src, i + n,
(s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence),
(s, j) -> OperationNode.parseIn(s, j, _prev, precedence),
(s, j) -> ChangeNode.parsePostfixIncrease(s, j, _prev, precedence),
(s, j) -> ChangeNode.parsePostfixDecrease(s, j, _prev, precedence),
(s, j) -> PostfixNode.parsePostfixIncrease(s, j, _prev, precedence),
(s, j) -> PostfixNode.parsePostfixDecrease(s, j, _prev, precedence),
(s, j) -> OperationNode.parseOperator(s, j, _prev, precedence),
(s, j) -> IfNode.parseTernary(s, j, _prev, precedence),
(s, j) -> IndexNode.parseMember(s, j, _prev, precedence),
Expand Down Expand Up @@ -221,71 +222,6 @@ public static ParseRes<Boolean> parseStatementEnd(Source src, int i) {
return ParseRes.failed();
}

public static ParseRes<Parameters> parseParameters(Source src, int i) {
var n = Parsing.skipEmpty(src, i);

var openParen = Parsing.parseOperator(src, i + n, "(");
if (!openParen.isSuccess()) return openParen.chainError(src.loc(i + n), "Expected a parameter list");
n += openParen.n;

var params = new ArrayList<Parameter>();

var closeParen = Parsing.parseOperator(src, i + n, ")");
n += closeParen.n;

if (!closeParen.isSuccess()) {
while (true) {
n += Parsing.skipEmpty(src, i + n);

if (src.is(i + n, "...")) {
n += 3;
var restLoc = src.loc(i);

var restName = Parsing.parseIdentifier(src, i + n);
if (!restName.isSuccess()) return ParseRes.error(src.loc(i + n), "Expected a rest parameter");
n += restName.n;
n += Parsing.skipEmpty(src, i + n);

if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected an end of parameters list after rest parameter");
n++;

return ParseRes.res(new Parameters(params, restName.result, restLoc), n);
}

var paramLoc = src.loc(i);

var name = Parsing.parseIdentifier(src, i + n);
if (!name.isSuccess()) return ParseRes.error(src.loc(i + n), "Expected a parameter or a closing brace");
n += name.n;
n += Parsing.skipEmpty(src, i + n);

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 parameter 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;
}
}
}

return ParseRes.res(new Parameters(params), n);
}

public static ParseRes<DeclarationType> parseDeclarationType(Source src, int i) {
var res = Parsing.parseIdentifier(src, i);
if (!res.isSuccess()) return res.chainError();
Expand Down
Loading