regress: remove infrastructure needed for ES6 stuff, simplify loops
This commit is contained in:
parent
754648fbf6
commit
14e4aade35
@ -3,8 +3,6 @@ package me.topchetoeu.jscript.compilation;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import me.topchetoeu.jscript.common.FunctionBody;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
@ -14,7 +12,7 @@ import me.topchetoeu.jscript.common.environment.Key;
|
||||
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
||||
import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder;
|
||||
import me.topchetoeu.jscript.common.parsing.Location;
|
||||
import me.topchetoeu.jscript.compilation.scope.Scope;
|
||||
import me.topchetoeu.jscript.compilation.scope.FunctionScope;
|
||||
|
||||
public final class CompileResult {
|
||||
public static final class ChildData {
|
||||
@ -27,15 +25,12 @@ public final class CompileResult {
|
||||
}
|
||||
}
|
||||
|
||||
public final List<IntFunction<Instruction>> instructions;
|
||||
public final List<Instruction> instructions;
|
||||
public final List<CompileResult> children;
|
||||
public final FunctionMapBuilder map;
|
||||
public final Environment env;
|
||||
public int length;
|
||||
public Runnable buildTask = () -> {
|
||||
throw new IllegalStateException("Compile result is not ready to be built");
|
||||
};
|
||||
public final Scope scope;
|
||||
public final FunctionScope scope;
|
||||
|
||||
public int temp() {
|
||||
instructions.add(null);
|
||||
@ -43,21 +38,14 @@ public final class CompileResult {
|
||||
}
|
||||
|
||||
public CompileResult add(Instruction instr) {
|
||||
instructions.add(i -> instr);
|
||||
return this;
|
||||
}
|
||||
public CompileResult add(IntFunction<Instruction> instr) {
|
||||
instructions.add(instr);
|
||||
return this;
|
||||
}
|
||||
public CompileResult set(int i, Instruction instr) {
|
||||
instructions.set(i, _i -> instr);
|
||||
return this;
|
||||
}
|
||||
public CompileResult set(int i, IntFunction<Instruction>instr) {
|
||||
instructions.set(i, instr);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int size() { return instructions.size(); }
|
||||
|
||||
public void setDebug(Location loc, BreakpointType type) {
|
||||
@ -79,62 +67,25 @@ public final class CompileResult {
|
||||
setLocationAndDebug(instructions.size() - 1, loc, type);
|
||||
}
|
||||
|
||||
public void beginScope() {
|
||||
// for (var cap : scope.capturables()) {
|
||||
// add(_i -> Instruction.capInit(cap.index().index));
|
||||
// }
|
||||
}
|
||||
public void reallocScope() {
|
||||
for (var cap : scope.capturables()) {
|
||||
add(_i -> cap.index().toGet());
|
||||
add(_i -> Instruction.capFree(cap.index().index));
|
||||
add(_i -> cap.index().toInit());
|
||||
}
|
||||
|
||||
scope.end();
|
||||
}
|
||||
public void endScope() {
|
||||
for (var cap : scope.capturables()) {
|
||||
add(_i -> Instruction.capFree(cap.index().index));
|
||||
}
|
||||
for (var var : scope.locals()) {
|
||||
add(_i -> Instruction.varFree(var.index().index));
|
||||
}
|
||||
|
||||
scope.end();
|
||||
}
|
||||
|
||||
public int addChild(CompileResult res) {
|
||||
this.children.add(res);
|
||||
return this.children.size() - 1;
|
||||
}
|
||||
|
||||
public Instruction[] instructions() {
|
||||
var res = new Instruction[instructions.size()];
|
||||
var i = 0;
|
||||
for (var suppl : instructions) {
|
||||
res[i] = suppl.apply(i);
|
||||
i++;
|
||||
}
|
||||
return res;
|
||||
return instructions.toArray(new Instruction[0]);
|
||||
}
|
||||
|
||||
public FunctionMap map() {
|
||||
return map.build(scope);
|
||||
return map.build(scope.localNames(), scope.captureNames());
|
||||
}
|
||||
public FunctionBody body() {
|
||||
var builtChildren = new FunctionBody[children.size()];
|
||||
|
||||
for (var i = 0; i < children.size(); i++) builtChildren[i] = children.get(i).body();
|
||||
|
||||
var instrRes = new Instruction[instructions.size()];
|
||||
var i = 0;
|
||||
var instrRes = instructions();
|
||||
|
||||
for (var suppl : instructions) {
|
||||
instrRes[i] = suppl.apply(i);
|
||||
// System.out.println(instrRes[i]);
|
||||
i++;
|
||||
}
|
||||
for (var instr : instrRes) System.out.println(instr);
|
||||
|
||||
return new FunctionBody(
|
||||
scope.localsCount(), scope.capturablesCount(), scope.capturesCount(),
|
||||
@ -143,7 +94,7 @@ public final class CompileResult {
|
||||
}
|
||||
|
||||
public CompileResult subtarget() {
|
||||
return new CompileResult(env, new Scope(scope), this);
|
||||
return new CompileResult(env, new FunctionScope(scope), this);
|
||||
}
|
||||
|
||||
public CompileResult setEnvironment(Environment env) {
|
||||
@ -160,16 +111,15 @@ public final class CompileResult {
|
||||
return new CompileResult(env.child(), scope, this);
|
||||
}
|
||||
|
||||
public CompileResult(Environment env, Scope scope, int length, Consumer<CompileResult> task) {
|
||||
public CompileResult(Environment env, FunctionScope scope, int length) {
|
||||
this.scope = scope;
|
||||
this.instructions = new ArrayList<>();
|
||||
this.children = new LinkedList<>();
|
||||
this.map = FunctionMap.builder();
|
||||
this.env = env;
|
||||
this.length = length;
|
||||
this.buildTask = () -> task.accept(this);
|
||||
}
|
||||
private CompileResult(Environment env, Scope scope, CompileResult parent) {
|
||||
private CompileResult(Environment env, FunctionScope scope, CompileResult parent) {
|
||||
this.scope = scope;
|
||||
this.instructions = parent.instructions;
|
||||
this.children = parent.children;
|
||||
|
@ -14,7 +14,6 @@ import me.topchetoeu.jscript.common.parsing.Source;
|
||||
|
||||
public class CompoundNode extends Node {
|
||||
public final Node[] statements;
|
||||
public boolean hasScope;
|
||||
public Location end;
|
||||
|
||||
@Override public void resolve(CompileResult target) {
|
||||
@ -24,12 +23,9 @@ public class CompoundNode extends Node {
|
||||
public void compile(CompileResult target, boolean pollute, boolean singleEntry, BreakpointType type) {
|
||||
List<Node> statements = new ArrayList<Node>();
|
||||
|
||||
var subtarget = hasScope ? target.subtarget() : target;
|
||||
if (hasScope) subtarget.beginScope();
|
||||
|
||||
for (var stm : this.statements) {
|
||||
if (stm instanceof FunctionStatementNode func) {
|
||||
func.compile(subtarget, false);
|
||||
func.compile(target, false);
|
||||
}
|
||||
else statements.add(stm);
|
||||
}
|
||||
@ -39,12 +35,10 @@ public class CompoundNode extends Node {
|
||||
for (var i = 0; i < statements.size(); i++) {
|
||||
var stm = statements.get(i);
|
||||
|
||||
if (i != statements.size() - 1) stm.compile(subtarget, false, BreakpointType.STEP_OVER);
|
||||
else stm.compile(subtarget, polluted = pollute, BreakpointType.STEP_OVER);
|
||||
if (i != statements.size() - 1) stm.compile(target, false, BreakpointType.STEP_OVER);
|
||||
else stm.compile(target, polluted = pollute, BreakpointType.STEP_OVER);
|
||||
}
|
||||
|
||||
if (hasScope) subtarget.endScope();
|
||||
|
||||
if (!polluted && pollute) {
|
||||
target.add(Instruction.pushUndefined());
|
||||
}
|
||||
@ -59,9 +53,8 @@ public class CompoundNode extends Node {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompoundNode(Location loc, boolean hasScope, Node ...statements) {
|
||||
public CompoundNode(Location loc, Node ...statements) {
|
||||
super(loc);
|
||||
this.hasScope = hasScope;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
@ -92,9 +85,9 @@ public class CompoundNode extends Node {
|
||||
children.addAll(Arrays.asList(comp.statements));
|
||||
children.add(curr.result);
|
||||
|
||||
return ParseRes.res(new CompoundNode(loc, comp.hasScope, children.toArray(new Node[0])), n);
|
||||
return ParseRes.res(new CompoundNode(loc, children.toArray(new Node[0])), n);
|
||||
}
|
||||
else return ParseRes.res(new CompoundNode(loc, false, prev, curr.result), n);
|
||||
else return ParseRes.res(new CompoundNode(loc, prev, curr.result), n);
|
||||
}
|
||||
public static ParseRes<CompoundNode> parse(Source src, int i) {
|
||||
var n = Parsing.skipEmpty(src, i);
|
||||
@ -124,6 +117,6 @@ public class CompoundNode extends Node {
|
||||
statements.add(res.result);
|
||||
}
|
||||
|
||||
return ParseRes.res(new CompoundNode(loc, true, statements.toArray(new Node[0])).setEnd(src.loc(i + n - 1)), n);
|
||||
return ParseRes.res(new CompoundNode(loc, statements.toArray(new Node[0])).setEnd(src.loc(i + n - 1)), n);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package me.topchetoeu.jscript.compilation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import me.topchetoeu.jscript.common.SyntaxException;
|
||||
@ -17,9 +18,7 @@ import me.topchetoeu.jscript.compilation.control.ContinueNode;
|
||||
import me.topchetoeu.jscript.compilation.control.DebugNode;
|
||||
import me.topchetoeu.jscript.compilation.control.DeleteNode;
|
||||
import me.topchetoeu.jscript.compilation.control.DoWhileNode;
|
||||
import me.topchetoeu.jscript.compilation.control.ForInNode;
|
||||
import me.topchetoeu.jscript.compilation.control.ForNode;
|
||||
import me.topchetoeu.jscript.compilation.control.ForOfNode;
|
||||
import me.topchetoeu.jscript.compilation.control.IfNode;
|
||||
import me.topchetoeu.jscript.compilation.control.ReturnNode;
|
||||
import me.topchetoeu.jscript.compilation.control.SwitchNode;
|
||||
@ -29,7 +28,6 @@ import me.topchetoeu.jscript.compilation.control.WhileNode;
|
||||
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.ClassValueNode;
|
||||
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
||||
import me.topchetoeu.jscript.compilation.values.RegexNode;
|
||||
import me.topchetoeu.jscript.compilation.values.SuperNode;
|
||||
@ -49,16 +47,8 @@ import me.topchetoeu.jscript.compilation.values.operations.TypeofNode;
|
||||
|
||||
public final class JavaScript {
|
||||
public static enum DeclarationType {
|
||||
VAR(false, false),
|
||||
CONST(true, true),
|
||||
LET(true, false);
|
||||
|
||||
public final boolean strict, readonly;
|
||||
|
||||
private DeclarationType(boolean strict, boolean readonly) {
|
||||
this.strict = strict;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
@Deprecated
|
||||
VAR;
|
||||
}
|
||||
|
||||
public static final Key<Environment> COMPILE_ROOT = Key.of();
|
||||
@ -93,7 +83,6 @@ public final class JavaScript {
|
||||
return ParseRes.first(src, i,
|
||||
(s, j) -> statement ? ParseRes.failed() : ObjectNode.parse(s, j),
|
||||
(s, j) -> statement ? ParseRes.failed() : FunctionNode.parseFunction(s, j, false),
|
||||
(s, j) -> statement ? ParseRes.failed() : ClassValueNode.parse(s, j),
|
||||
JavaScript::parseLiteral,
|
||||
StringNode::parse,
|
||||
RegexNode::parse,
|
||||
@ -102,7 +91,6 @@ public final class JavaScript {
|
||||
ChangeNode::parsePrefixIncrease,
|
||||
OperationNode::parsePrefix,
|
||||
ArrayNode::parse,
|
||||
(s, j) -> statement ? ParseRes.failed() : FunctionArrowNode.parse(s, j),
|
||||
JavaScript::parseParens,
|
||||
CallNode::parseNew,
|
||||
TypeofNode::parse,
|
||||
@ -188,14 +176,13 @@ public final class JavaScript {
|
||||
return res.addN(end.n);
|
||||
}
|
||||
|
||||
public static ParseRes<? extends Node> parseStatement(Source src, int i) {
|
||||
public static ParseRes<Node> parseStatement(Source src, int i) {
|
||||
var n = Parsing.skipEmpty(src, i);
|
||||
|
||||
if (src.is(i + n, ";")) return ParseRes.res(new DiscardNode(src.loc(i+ n), null), n + 1);
|
||||
if (Parsing.isIdentifier(src, i + n, "with")) return ParseRes.error(src.loc(i + n), "'with' statements are not allowed.");
|
||||
|
||||
ParseRes<? extends Node> res = ParseRes.first(src, i + n,
|
||||
ClassStatementNode::parse,
|
||||
ParseRes<Node> res = ParseRes.first(src, i + n,
|
||||
VariableDeclareNode::parse,
|
||||
ReturnNode::parse,
|
||||
ThrowNode::parse,
|
||||
@ -206,8 +193,6 @@ public final class JavaScript {
|
||||
WhileNode::parse,
|
||||
SwitchNode::parse,
|
||||
ForNode::parse,
|
||||
ForInNode::parse,
|
||||
ForOfNode::parse,
|
||||
DoWhileNode::parse,
|
||||
TryNode::parse,
|
||||
CompoundNode::parse,
|
||||
@ -231,13 +216,11 @@ public final class JavaScript {
|
||||
return ParseRes.failed();
|
||||
}
|
||||
|
||||
public static ParseRes<DeclarationType> parseDeclarationType(Source src, int i) {
|
||||
public static ParseRes<Boolean> parseDeclarationType(Source src, int i) {
|
||||
var res = Parsing.parseIdentifier(src, i);
|
||||
if (!res.isSuccess()) return res.chainError();
|
||||
|
||||
if (res.result.equals("var")) return ParseRes.res(DeclarationType.VAR, res.n);
|
||||
if (res.result.equals("let")) return ParseRes.res(DeclarationType.LET, res.n);
|
||||
if (res.result.equals("const")) return ParseRes.res(DeclarationType.CONST, res.n);
|
||||
if (res.result.equals("var")) return ParseRes.res(true, res.n);
|
||||
|
||||
return ParseRes.failed();
|
||||
}
|
||||
@ -272,9 +255,8 @@ public final class JavaScript {
|
||||
env = env.child();
|
||||
env.add(COMPILE_ROOT, env);
|
||||
|
||||
var func = new FunctionValueNode(null, null, new Parameters(Arrays.asList()), new CompoundNode(null, true, statements), null);
|
||||
var func = new FunctionValueNode(null, null, Arrays.asList(), new CompoundNode(null, statements), null);
|
||||
var res = func.compileBody(env, new FunctionScope(true), true, null, null);
|
||||
res.buildTask.run();
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -299,4 +281,42 @@ public final class JavaScript {
|
||||
|
||||
return ParseRes.res(nameRes.result, n);
|
||||
}
|
||||
|
||||
public static ParseRes<List<VariableNode>> 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<VariableNode>();
|
||||
|
||||
var closeParen = Parsing.parseOperator(src, i + n, ")");
|
||||
n += closeParen.n;
|
||||
|
||||
if (!closeParen.isSuccess()) {
|
||||
while (true) {
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
|
||||
var param = VariableNode.parse(src, i + n);
|
||||
if (!param.isSuccess()) return ParseRes.error(src.loc(i + n), "Expected a parameter or a closing brace");
|
||||
n += param.n;
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
|
||||
params.add(param.result);
|
||||
|
||||
if (src.is(i + n, ",")) {
|
||||
n++;
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
}
|
||||
|
||||
if (src.is(i + n, ")")) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ParseRes.res(params, n);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package me.topchetoeu.jscript.compilation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.Stack;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
@ -18,6 +19,8 @@ public class LabelContext {
|
||||
private final LinkedList<IntSupplier> list = new LinkedList<>();
|
||||
private final HashMap<String, IntSupplier> map = new HashMap<>();
|
||||
|
||||
private final Stack<ArrayList<Runnable>> deferredAdders = new Stack<>();
|
||||
|
||||
public IntSupplier get() {
|
||||
return list.peekLast();
|
||||
}
|
||||
@ -25,15 +28,31 @@ public class LabelContext {
|
||||
return map.get(name);
|
||||
}
|
||||
|
||||
public IntFunction<Instruction> getJump() {
|
||||
public void flushAdders() {
|
||||
for (var adder : deferredAdders.peek()) {
|
||||
adder.run();
|
||||
}
|
||||
|
||||
deferredAdders.pop();
|
||||
}
|
||||
|
||||
public boolean jump(CompileResult target) {
|
||||
var res = get();
|
||||
if (res == null) return null;
|
||||
else return i -> Instruction.jmp(res.getAsInt() - i);
|
||||
if (res != null) {
|
||||
var tmp = target.temp();
|
||||
this.deferredAdders.peek().add(() -> target.set(tmp, Instruction.jmp(res.getAsInt() - tmp)));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
public IntFunction<Instruction> getJump(String name) {
|
||||
public boolean jump(CompileResult target, String name) {
|
||||
var res = get(name);
|
||||
if (res == null) return null;
|
||||
else return i -> Instruction.jmp(res.getAsInt() - i);
|
||||
if (res != null) {
|
||||
var tmp = target.temp();
|
||||
this.deferredAdders.peek().add(() -> target.set(tmp, Instruction.jmp(res.getAsInt() - tmp)));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
public void push(IntSupplier jumpTarget) {
|
||||
@ -48,6 +67,7 @@ public class LabelContext {
|
||||
public void pushLoop(Location loc, String name, IntSupplier jumpTarget) {
|
||||
push(jumpTarget);
|
||||
push(loc, name, jumpTarget);
|
||||
deferredAdders.push(new ArrayList<>());
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
@ -61,6 +81,7 @@ public class LabelContext {
|
||||
public void popLoop(String name) {
|
||||
pop();
|
||||
pop(name);
|
||||
flushAdders();
|
||||
}
|
||||
|
||||
public static LabelContext getBreak(Environment env) {
|
||||
|
@ -15,12 +15,10 @@ public class BreakNode extends Node {
|
||||
public final String label;
|
||||
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
var res = LabelContext.getBreak(target.env).getJump();
|
||||
if (res == null) {
|
||||
if (!LabelContext.getBreak(target.env).jump(target)) {
|
||||
if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label));
|
||||
else throw new SyntaxException(loc(), "Illegal break statement");
|
||||
}
|
||||
target.add(res);
|
||||
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
|
@ -15,12 +15,10 @@ public class ContinueNode extends Node {
|
||||
public final String label;
|
||||
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
var res = LabelContext.getCont(target.env).getJump();
|
||||
if (res == null) {
|
||||
if (!LabelContext.getCont(target.env).jump(target)) {
|
||||
if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label));
|
||||
else throw new SyntaxException(loc(), "Illegal continue statement");
|
||||
}
|
||||
target.add(res);
|
||||
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
|
@ -27,13 +27,14 @@ public class DoWhileNode extends Node {
|
||||
|
||||
LabelContext.pushLoop(target.env, loc(), label, end, start);
|
||||
body.compile(target, false, BreakpointType.STEP_OVER);
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
mid.set(target.size());
|
||||
condition.compile(target, true, BreakpointType.STEP_OVER);
|
||||
int endI = target.size();
|
||||
end.set(endI + 1);
|
||||
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
target.add(Instruction.jmpIf(start - endI));
|
||||
}
|
||||
|
||||
|
@ -8,14 +8,15 @@ import me.topchetoeu.jscript.common.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.common.parsing.Source;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.CompoundNode;
|
||||
import me.topchetoeu.jscript.compilation.DeferredIntSupplier;
|
||||
import me.topchetoeu.jscript.compilation.JavaScript;
|
||||
import me.topchetoeu.jscript.compilation.LabelContext;
|
||||
import me.topchetoeu.jscript.compilation.DeferredIntSupplier;
|
||||
import me.topchetoeu.jscript.compilation.Node;
|
||||
import me.topchetoeu.jscript.compilation.patterns.Binding;
|
||||
import me.topchetoeu.jscript.compilation.values.VariableNode;
|
||||
|
||||
public class ForInNode extends Node {
|
||||
public final Binding binding;
|
||||
public final boolean isDecl;
|
||||
public final VariableNode binding;
|
||||
public final Node object, body;
|
||||
public final String label;
|
||||
|
||||
@ -25,8 +26,6 @@ public class ForInNode extends Node {
|
||||
}
|
||||
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
binding.declareLateInit(target);
|
||||
|
||||
object.compile(target, true, BreakpointType.STEP_OVER);
|
||||
target.add(Instruction.keys(false, true));
|
||||
|
||||
@ -35,27 +34,32 @@ public class ForInNode extends Node {
|
||||
int mid = target.temp();
|
||||
|
||||
target.add(Instruction.loadMember("value")).setLocation(binding.loc());
|
||||
binding.assign(target, false);
|
||||
target.add(VariableNode.toInit(target, loc(), binding.name));
|
||||
|
||||
target.setLocationAndDebug(object.loc(), BreakpointType.STEP_OVER);
|
||||
|
||||
var end = new DeferredIntSupplier();
|
||||
|
||||
LabelContext.pushLoop(target.env, loc(), label, end, start);
|
||||
CompoundNode.compileMultiEntry(body, target, false, BreakpointType.STEP_OVER);
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
int endI = target.size();
|
||||
|
||||
target.add(Instruction.jmp(start - endI));
|
||||
target.add(Instruction.discard());
|
||||
target.set(mid, Instruction.jmpIfNot(endI - mid + 1));
|
||||
|
||||
end.set(endI);
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
|
||||
public ForInNode(Location loc, String label, Binding binding, Node object, Node body) {
|
||||
public ForInNode(Location loc, String label, VariableNode binding, boolean isDecl, Node object, Node body) {
|
||||
super(loc);
|
||||
this.label = label;
|
||||
this.binding = binding;
|
||||
this.isDecl = isDecl;
|
||||
this.object = object;
|
||||
this.body = body;
|
||||
}
|
||||
@ -76,9 +80,15 @@ public class ForInNode extends Node {
|
||||
n++;
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
|
||||
var binding = Binding.parse(src, i + n);
|
||||
if (!binding.isSuccess()) return ParseRes.error(src.loc(i + n), "Expected a binding in for-in loop");
|
||||
n += binding.n;
|
||||
var varKw = JavaScript.parseDeclarationType(src, i + n);
|
||||
n += varKw.n;
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
|
||||
var bindingLoc = src.loc(i + n);
|
||||
|
||||
var name = Parsing.parseIdentifier(src, i + n);
|
||||
if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a variable name");
|
||||
n += name.n;
|
||||
n += Parsing.skipEmpty(src, i + n);
|
||||
|
||||
if (!Parsing.isIdentifier(src, i + n, "in")) return ParseRes.error(src.loc(i + n), "Expected 'in' keyword after variable declaration");
|
||||
@ -96,6 +106,6 @@ public class ForInNode extends Node {
|
||||
if (!bodyRes.isSuccess()) return bodyRes.chainError(src.loc(i + n), "Expected a for-in body");
|
||||
n += bodyRes.n;
|
||||
|
||||
return ParseRes.res(new ForInNode(loc, label.result, binding.result, obj.result, bodyRes.result), n);
|
||||
return ParseRes.res(new ForInNode(loc, label.result, new VariableNode(bindingLoc, name.result), varKw.isSuccess(), obj.result, bodyRes.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,6 @@ public class ForNode extends Node {
|
||||
}
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
var subtarget = target.subtarget();
|
||||
subtarget.scope.singleEntry = false;
|
||||
subtarget.beginScope();
|
||||
|
||||
declaration.compile(subtarget, false, BreakpointType.STEP_OVER);
|
||||
|
||||
@ -38,20 +36,16 @@ public class ForNode extends Node {
|
||||
|
||||
LabelContext.pushLoop(subtarget.env, loc(), label, end, start);
|
||||
CompoundNode.compileMultiEntry(body, subtarget, false, BreakpointType.STEP_OVER);
|
||||
LabelContext.popLoop(subtarget.env, label);
|
||||
|
||||
subtarget.reallocScope();
|
||||
|
||||
CompoundNode.compileMultiEntry(assignment, subtarget, false, BreakpointType.STEP_OVER);
|
||||
int endI = subtarget.size();
|
||||
|
||||
end.set(endI);
|
||||
LabelContext.popLoop(subtarget.env, label);
|
||||
|
||||
subtarget.add(Instruction.jmp(start - endI));
|
||||
subtarget.set(mid, Instruction.jmpIfNot(endI - mid + 1));
|
||||
if (pollute) subtarget.add(Instruction.pushUndefined());
|
||||
|
||||
subtarget.endScope();
|
||||
}
|
||||
|
||||
public ForNode(Location loc, String label, Node declaration, Node condition, Node assignment, Node body) {
|
||||
|
@ -43,41 +43,37 @@ public class SwitchNode extends Node {
|
||||
|
||||
value.compile(target, true, BreakpointType.STEP_OVER);
|
||||
|
||||
var subtarget = target.subtarget();
|
||||
subtarget.beginScope();
|
||||
|
||||
// TODO: create a jump map
|
||||
for (var ccase : cases) {
|
||||
subtarget.add(Instruction.dup());
|
||||
ccase.value.compile(subtarget, true);
|
||||
subtarget.add(Instruction.operation(Operation.EQUALS));
|
||||
caseToStatement.put(subtarget.temp(), ccase.statementI);
|
||||
target.add(Instruction.dup());
|
||||
ccase.value.compile(target, true);
|
||||
target.add(Instruction.operation(Operation.EQUALS));
|
||||
caseToStatement.put(target.temp(), ccase.statementI);
|
||||
}
|
||||
|
||||
int start = subtarget.temp();
|
||||
int start = target.temp();
|
||||
var end = new DeferredIntSupplier();
|
||||
|
||||
LabelContext.getBreak(target.env).push(loc(), label, end);
|
||||
for (var stm : body) {
|
||||
statementToIndex.put(statementToIndex.size(), subtarget.size());
|
||||
stm.compile(subtarget, false, BreakpointType.STEP_OVER);
|
||||
statementToIndex.put(statementToIndex.size(), target.size());
|
||||
stm.compile(target, false, BreakpointType.STEP_OVER);
|
||||
}
|
||||
|
||||
int endI = target.size();
|
||||
end.set(endI);
|
||||
LabelContext.getBreak(target.env).pop(label);
|
||||
|
||||
subtarget.endScope();
|
||||
target.add(Instruction.discard());
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
|
||||
int endI = subtarget.size();
|
||||
end.set(endI);
|
||||
subtarget.add(Instruction.discard());
|
||||
if (pollute) subtarget.add(Instruction.pushUndefined());
|
||||
|
||||
if (defaultI < 0 || defaultI >= body.length) subtarget.set(start, Instruction.jmp(endI - start));
|
||||
else subtarget.set(start, Instruction.jmp(statementToIndex.get(defaultI) - start));
|
||||
if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(endI - start));
|
||||
else target.set(start, Instruction.jmp(statementToIndex.get(defaultI) - start));
|
||||
|
||||
for (var el : caseToStatement.entrySet()) {
|
||||
var i = statementToIndex.get(el.getValue());
|
||||
if (i == null) i = endI;
|
||||
subtarget.set(el.getKey(), Instruction.jmpIf(i - el.getKey()));
|
||||
target.set(el.getKey(), Instruction.jmpIf(i - el.getKey()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import me.topchetoeu.jscript.compilation.DeferredIntSupplier;
|
||||
import me.topchetoeu.jscript.compilation.JavaScript;
|
||||
import me.topchetoeu.jscript.compilation.LabelContext;
|
||||
import me.topchetoeu.jscript.compilation.Node;
|
||||
import me.topchetoeu.jscript.compilation.scope.Variable;
|
||||
|
||||
public class TryNode extends Node {
|
||||
public final CompoundNode tryBody;
|
||||
@ -42,17 +41,11 @@ public class TryNode extends Node {
|
||||
catchStart = target.size() - start;
|
||||
|
||||
if (captureName != null) {
|
||||
var subtarget = target.subtarget();
|
||||
subtarget.beginScope();
|
||||
subtarget.scope.singleEntry = true;
|
||||
|
||||
var catchVar = subtarget.scope.defineStrict(new Variable(captureName, false), catchBody.loc());
|
||||
subtarget.add(Instruction.loadError());
|
||||
subtarget.add(catchVar.index().toInit());
|
||||
catchBody.compile(subtarget, false);
|
||||
subtarget.endScope();
|
||||
|
||||
subtarget.scope.end();
|
||||
var catchVar = target.scope.defineCatch(captureName);
|
||||
target.add(Instruction.loadError());
|
||||
target.add(catchVar.index().toInit());
|
||||
catchBody.compile(target, false);
|
||||
target.scope.undefineCatch();
|
||||
}
|
||||
else catchBody.compile(target, false);
|
||||
|
||||
|
@ -30,10 +30,10 @@ public class WhileNode extends Node {
|
||||
|
||||
LabelContext.pushLoop(target.env, loc(), label, end, start);
|
||||
CompoundNode.compileMultiEntry(body, target, false, BreakpointType.STEP_OVER);
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
var endI = target.size();
|
||||
end.set(endI + 1);
|
||||
LabelContext.popLoop(target.env, label);
|
||||
|
||||
target.add(Instruction.jmp(start - end.getAsInt()));
|
||||
target.set(mid, Instruction.jmpIfNot(end.getAsInt() - mid + 1));
|
||||
|
Loading…
Reference in New Issue
Block a user