regress: remove infrastructure needed for ES6 stuff, simplify loops

This commit is contained in:
TopchetoEU 2024-11-23 20:09:29 +02:00
parent 754648fbf6
commit 14e4aade35
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
12 changed files with 140 additions and 166 deletions

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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() {
var res = get();
if (res == null) return null;
else return i -> Instruction.jmp(res.getAsInt() - i);
public void flushAdders() {
for (var adder : deferredAdders.peek()) {
adder.run();
}
public IntFunction<Instruction> getJump(String name) {
deferredAdders.pop();
}
public boolean jump(CompileResult target) {
var res = get();
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 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) {

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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));
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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()));
}
}

View File

@ -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);

View File

@ -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));