refactor: some code cleanup, emit better bytecode
This commit is contained in:
parent
4d1846f082
commit
21a6d20ac5
@ -1,19 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|
||||||
|
|
||||||
public abstract class AssignStatement extends Statement {
|
|
||||||
public abstract void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
compile(target, scope, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AssignStatement(Location loc) {
|
|
||||||
super(loc);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
|
|
||||||
public abstract class AssignableStatement extends Statement {
|
public abstract class AssignableStatement extends Statement {
|
||||||
public abstract AssignStatement toAssign(Statement val, Operation operation);
|
public abstract Statement toAssign(Statement val, Operation operation);
|
||||||
|
|
||||||
protected AssignableStatement(Location loc) {
|
protected AssignableStatement(Location loc) {
|
||||||
super(loc);
|
super(loc);
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
|
||||||
|
|
||||||
public class CompileOptions {
|
|
||||||
public final boolean emitBpMap;
|
|
||||||
public final boolean emitVarNames;
|
|
||||||
|
|
||||||
public CompileOptions(boolean emitBpMap, boolean emitVarNames) {
|
|
||||||
this.emitBpMap = emitBpMap;
|
|
||||||
this.emitVarNames = emitVarNames;
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,16 +13,6 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public class CompoundStatement extends Statement {
|
public class CompoundStatement extends Statement {
|
||||||
public final Statement[] statements;
|
public final Statement[] statements;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() {
|
|
||||||
for (var stm : statements) {
|
|
||||||
if (stm instanceof FunctionStatement) continue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord varsScope) {
|
public void declare(ScopeRecord varsScope) {
|
||||||
for (var stm : statements) {
|
for (var stm : statements) {
|
||||||
@ -31,7 +21,7 @@ public class CompoundStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
for (var stm : statements) {
|
for (var stm : statements) {
|
||||||
if (stm instanceof FunctionStatement) {
|
if (stm instanceof FunctionStatement) {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
@ -45,8 +35,8 @@ public class CompoundStatement extends Statement {
|
|||||||
var stm = statements[i];
|
var stm = statements[i];
|
||||||
|
|
||||||
if (stm instanceof FunctionStatement) continue;
|
if (stm instanceof FunctionStatement) continue;
|
||||||
if (i != statements.length - 1) stm.compileNoPollution(target, scope, true);
|
if (i != statements.length - 1) stm.compileWithDebug(target, scope, false);
|
||||||
else stm.compileWithPollution(target, scope);
|
else stm.compileWithDebug(target, scope, pollute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,9 @@ public class DiscardStatement extends Statement {
|
|||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
value.compile(target, scope, false);
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
if (value == null) return;
|
|
||||||
value.compile(target, scope);
|
|
||||||
if (value.pollutesStack()) target.add(Instruction.discard());
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Statement optimize() {
|
public Statement optimize() {
|
||||||
|
@ -7,7 +7,6 @@ import me.topchetoeu.jscript.exceptions.SyntaxException;
|
|||||||
public class Instruction {
|
public class Instruction {
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
RETURN,
|
RETURN,
|
||||||
SIGNAL,
|
|
||||||
THROW,
|
THROW,
|
||||||
THROW_SYNTAX,
|
THROW_SYNTAX,
|
||||||
DELETE,
|
DELETE,
|
||||||
@ -162,12 +161,6 @@ public class Instruction {
|
|||||||
return new Instruction(null, Type.NOP, args);
|
return new Instruction(null, Type.NOP, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ATTENTION: Usage outside of try/catch is broken af
|
|
||||||
*/
|
|
||||||
public static Instruction signal(String name) {
|
|
||||||
return new Instruction(null, Type.SIGNAL, name);
|
|
||||||
}
|
|
||||||
public static Instruction nop(Object ...params) {
|
public static Instruction nop(Object ...params) {
|
||||||
for (var param : params) {
|
for (var param : params) {
|
||||||
if (param instanceof String) continue;
|
if (param instanceof String) continue;
|
||||||
|
@ -8,29 +8,15 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public abstract class Statement {
|
public abstract class Statement {
|
||||||
private Location _loc;
|
private Location _loc;
|
||||||
|
|
||||||
public abstract boolean pollutesStack();
|
|
||||||
public boolean pure() { return false; }
|
public boolean pure() { return false; }
|
||||||
public abstract void compile(List<Instruction> target, ScopeRecord scope);
|
public abstract void compile(List<Instruction> target, ScopeRecord scope, boolean pollute);
|
||||||
public void declare(ScopeRecord varsScope) { }
|
public void declare(ScopeRecord varsScope) { }
|
||||||
public Statement optimize() { return this; }
|
public Statement optimize() { return this; }
|
||||||
|
|
||||||
public void compileNoPollution(List<Instruction> target, ScopeRecord scope, boolean debug) {
|
public void compileWithDebug(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
compile(target, scope);
|
compile(target, scope, pollute);
|
||||||
if (debug && target.size() != start) target.get(start).setDebug(true);
|
if (target.size() != start) target.get(start).setDebug(true);
|
||||||
if (pollutesStack()) target.add(Instruction.discard().locate(loc()));
|
|
||||||
}
|
|
||||||
public void compileWithPollution(List<Instruction> target, ScopeRecord scope, boolean debug) {
|
|
||||||
int start = target.size();
|
|
||||||
compile(target, scope);
|
|
||||||
if (debug && target.size() != start) target.get(start).setDebug(true);
|
|
||||||
if (!pollutesStack()) target.add(Instruction.loadValue(null).locate(loc()));
|
|
||||||
}
|
|
||||||
public void compileNoPollution(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
compileNoPollution(target, scope, false);
|
|
||||||
}
|
|
||||||
public void compileWithPollution(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
compileWithPollution(target, scope, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location loc() { return _loc; }
|
public Location loc() { return _loc; }
|
||||||
|
@ -19,8 +19,6 @@ public class VariableDeclareStatement extends Statement {
|
|||||||
|
|
||||||
public final List<Pair> values;
|
public final List<Pair> values;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord varsScope) {
|
public void declare(ScopeRecord varsScope) {
|
||||||
for (var key : values) {
|
for (var key : values) {
|
||||||
@ -28,7 +26,7 @@ public class VariableDeclareStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
for (var entry : values) {
|
for (var entry : values) {
|
||||||
if (entry.name == null) continue;
|
if (entry.name == null) continue;
|
||||||
var key = scope.getKey(entry.name);
|
var key = scope.getKey(entry.name);
|
||||||
@ -39,10 +37,12 @@ public class VariableDeclareStatement extends Statement {
|
|||||||
target.add(Instruction.storeVar(key).locate(loc()));
|
target.add(Instruction.storeVar(key).locate(loc()));
|
||||||
}
|
}
|
||||||
else if (entry.value != null) {
|
else if (entry.value != null) {
|
||||||
entry.value.compileWithPollution(target, scope);
|
entry.value.compile(target, scope, true);
|
||||||
target.add(Instruction.storeVar(key).locate(loc()));
|
target.add(Instruction.storeVar(key).locate(loc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableDeclareStatement(Location loc, List<Pair> values) {
|
public VariableDeclareStatement(Location loc, List<Pair> values) {
|
||||||
|
@ -1,37 +1,36 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.compilation.control;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ArrayStatement extends Statement {
|
public class ArrayStatement extends Statement {
|
||||||
public final Statement[] statements;
|
public final Statement[] statements;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public boolean pure() { return true; }
|
||||||
@Override
|
|
||||||
public boolean pure() { return true; }
|
@Override
|
||||||
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
@Override
|
target.add(Instruction.loadArr(statements.length).locate(loc()));
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
var i = 0;
|
||||||
target.add(Instruction.loadArr(statements.length).locate(loc()));
|
for (var el : statements) {
|
||||||
var i = 0;
|
if (el != null) {
|
||||||
for (var el : statements) {
|
target.add(Instruction.dup().locate(loc()));
|
||||||
if (el != null) {
|
target.add(Instruction.loadValue(i).locate(loc()));
|
||||||
target.add(Instruction.dup().locate(loc()));
|
el.compile(target, scope, true);
|
||||||
target.add(Instruction.loadValue(i).locate(loc()));
|
target.add(Instruction.storeMember().locate(loc()));
|
||||||
el.compileWithPollution(target, scope);
|
}
|
||||||
target.add(Instruction.storeMember().locate(loc()));
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public ArrayStatement(Location loc, Statement[] statements) {
|
||||||
public ArrayStatement(Location loc, Statement[] statements) {
|
super(loc);
|
||||||
super(loc);
|
this.statements = statements;
|
||||||
this.statements = statements;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
@ -11,11 +11,9 @@ public class BreakStatement extends Statement {
|
|||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
target.add(Instruction.nop("break", label).locate(loc()));
|
target.add(Instruction.nop("break", label).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BreakStatement(Location loc, String label) {
|
public BreakStatement(Location loc, String label) {
|
||||||
|
@ -11,11 +11,9 @@ public class ContinueStatement extends Statement {
|
|||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
target.add(Instruction.nop("cont", label).locate(loc()));
|
target.add(Instruction.nop("cont", label).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContinueStatement(Location loc, String label) {
|
public ContinueStatement(Location loc, String label) {
|
||||||
|
@ -9,11 +9,9 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
|
|
||||||
public class DebugStatement extends Statement {
|
public class DebugStatement extends Statement {
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
target.add(Instruction.debug().locate(loc()));
|
target.add(Instruction.debug().locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DebugStatement(Location loc) {
|
public DebugStatement(Location loc) {
|
||||||
|
@ -12,13 +12,12 @@ public class DeleteStatement extends Statement {
|
|||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
value.compile(target, scope, true);
|
||||||
|
key.compile(target, scope, true);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
value.compile(target, scope);
|
|
||||||
key.compile(target, scope);
|
|
||||||
target.add(Instruction.delete().locate(loc()));
|
target.add(Instruction.delete().locate(loc()));
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteStatement(Location loc, Statement key, Statement value) {
|
public DeleteStatement(Location loc, Statement key, Statement value) {
|
||||||
|
@ -14,19 +14,16 @@ public class DoWhileStatement extends Statement {
|
|||||||
public final Statement condition, body;
|
public final Statement condition, body;
|
||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
body.declare(globScope);
|
body.declare(globScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (condition instanceof ConstantStatement) {
|
if (condition instanceof ConstantStatement) {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
body.compileNoPollution(target, scope);
|
body.compile(target, scope, false);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
||||||
WhileStatement.replaceBreaks(target, label, start, end, end + 1, end + 1);
|
WhileStatement.replaceBreaks(target, label, start, end, end + 1, end + 1);
|
||||||
@ -35,13 +32,14 @@ public class DoWhileStatement extends Statement {
|
|||||||
target.add(Instruction.jmp(start - end).locate(loc()));
|
target.add(Instruction.jmp(start - end).locate(loc()));
|
||||||
WhileStatement.replaceBreaks(target, label, start, end, start, end + 1);
|
WhileStatement.replaceBreaks(target, label, start, end, start, end + 1);
|
||||||
}
|
}
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
body.compileNoPollution(target, scope, true);
|
body.compileWithDebug(target, scope, false);
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
condition.compileWithPollution(target, scope);
|
condition.compile(target, scope, true);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
|
|
||||||
WhileStatement.replaceBreaks(target, label, start, mid - 1, mid, end + 1);
|
WhileStatement.replaceBreaks(target, label, start, mid - 1, mid, end + 1);
|
||||||
|
@ -14,9 +14,6 @@ public class ForInStatement extends Statement {
|
|||||||
public final Statement varValue, object, body;
|
public final Statement varValue, object, body;
|
||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
body.declare(globScope);
|
body.declare(globScope);
|
||||||
@ -24,16 +21,16 @@ public class ForInStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
var key = scope.getKey(varName);
|
var key = scope.getKey(varName);
|
||||||
if (key instanceof String) target.add(Instruction.makeVar((String)key));
|
if (key instanceof String) target.add(Instruction.makeVar((String)key));
|
||||||
|
|
||||||
if (varValue != null) {
|
if (varValue != null) {
|
||||||
varValue.compileWithPollution(target, scope);
|
varValue.compile(target, scope, true);
|
||||||
target.add(Instruction.storeVar(scope.getKey(varName)));
|
target.add(Instruction.storeVar(scope.getKey(varName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
object.compileWithPollution(target, scope);
|
object.compile(target, scope, true);
|
||||||
target.add(Instruction.keys());
|
target.add(Instruction.keys());
|
||||||
|
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
@ -58,8 +55,7 @@ public class ForInStatement extends Statement {
|
|||||||
|
|
||||||
for (var i = start; i < target.size(); i++) target.get(i).locate(loc());
|
for (var i = start; i < target.size(); i++) target.get(i).locate(loc());
|
||||||
|
|
||||||
body.compileNoPollution(target, scope, true);
|
body.compileWithDebug(target, scope, false);
|
||||||
|
|
||||||
|
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
|
|
||||||
@ -68,6 +64,7 @@ public class ForInStatement extends Statement {
|
|||||||
target.add(Instruction.jmp(start - end).locate(loc()));
|
target.add(Instruction.jmp(start - end).locate(loc()));
|
||||||
target.add(Instruction.discard().locate(loc()));
|
target.add(Instruction.discard().locate(loc()));
|
||||||
target.set(mid, Instruction.jmpIf(end - mid + 1).locate(loc()));
|
target.set(mid, Instruction.jmpIf(end - mid + 1).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ForInStatement(Location loc, String label, boolean isDecl, String varName, Statement varValue, Statement object, Statement body) {
|
public ForInStatement(Location loc, String label, boolean isDecl, String varName, Statement varValue, Statement object, Statement body) {
|
||||||
|
@ -14,44 +14,43 @@ public class ForStatement extends Statement {
|
|||||||
public final Statement declaration, assignment, condition, body;
|
public final Statement declaration, assignment, condition, body;
|
||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
declaration.declare(globScope);
|
declaration.declare(globScope);
|
||||||
body.declare(globScope);
|
body.declare(globScope);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
declaration.compile(target, scope);
|
declaration.compile(target, scope, false);
|
||||||
|
|
||||||
if (condition instanceof ConstantStatement) {
|
if (condition instanceof ConstantStatement) {
|
||||||
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
body.compileNoPollution(target, scope);
|
body.compile(target, scope, false);
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
assignment.compileNoPollution(target, scope, true);
|
assignment.compileWithDebug(target, scope, false);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
WhileStatement.replaceBreaks(target, label, start, mid, mid, end + 1);
|
WhileStatement.replaceBreaks(target, label, start, mid, mid, end + 1);
|
||||||
target.add(Instruction.jmp(start - target.size()).locate(loc()));
|
target.add(Instruction.jmp(start - target.size()).locate(loc()));
|
||||||
return;
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
condition.compileWithPollution(target, scope);
|
condition.compile(target, scope, true);
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
body.compileNoPollution(target, scope);
|
body.compile(target, scope, false);
|
||||||
int beforeAssign = target.size();
|
int beforeAssign = target.size();
|
||||||
assignment.compile(target, scope);
|
assignment.compileWithDebug(target, scope, false);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
|
|
||||||
WhileStatement.replaceBreaks(target, label, mid + 1, end, beforeAssign, end + 1);
|
WhileStatement.replaceBreaks(target, label, mid + 1, end, beforeAssign, end + 1);
|
||||||
|
|
||||||
target.add(Instruction.jmp(start - end).locate(loc()));
|
target.add(Instruction.jmp(start - end).locate(loc()));
|
||||||
target.set(mid, Instruction.jmpIfNot(end - mid + 1).locate(loc()));
|
target.set(mid, Instruction.jmpIfNot(end - mid + 1).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Statement optimize() {
|
public Statement optimize() {
|
||||||
|
@ -14,9 +14,6 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
public class IfStatement extends Statement {
|
public class IfStatement extends Statement {
|
||||||
public final Statement condition, body, elseBody;
|
public final Statement condition, body, elseBody;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
body.declare(globScope);
|
body.declare(globScope);
|
||||||
@ -24,33 +21,34 @@ public class IfStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (condition instanceof ConstantStatement) {
|
if (condition instanceof ConstantStatement) {
|
||||||
if (Values.not(((ConstantStatement)condition).value)) {
|
if (Values.not(((ConstantStatement)condition).value)) {
|
||||||
if (elseBody != null) elseBody.compileNoPollution(target, scope, true);
|
if (elseBody != null) elseBody.compileWithDebug(target, scope, pollute);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
body.compileNoPollution(target, scope, true);
|
body.compileWithDebug(target, scope, pollute);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
condition.compileWithPollution(target, scope);
|
condition.compile(target, scope, true);
|
||||||
|
|
||||||
if (elseBody == null) {
|
if (elseBody == null) {
|
||||||
int i = target.size();
|
int i = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
body.compileNoPollution(target, scope, true);
|
body.compileWithDebug(target, scope, pollute);
|
||||||
int endI = target.size();
|
int endI = target.size();
|
||||||
target.set(i, Instruction.jmpIfNot(endI - i).locate(loc()));
|
target.set(i, Instruction.jmpIfNot(endI - i).locate(loc()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
body.compileNoPollution(target, scope, true);
|
body.compileWithDebug(target, scope, pollute);
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
elseBody.compileNoPollution(target, scope, true);
|
elseBody.compileWithDebug(target, scope, pollute);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
|
|
||||||
target.set(start, Instruction.jmpIfNot(mid - start).locate(loc()));
|
target.set(start, Instruction.jmpIfNot(mid - start).locate(loc()));
|
||||||
|
@ -11,12 +11,9 @@ public class ReturnStatement extends Statement {
|
|||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
if (value == null) target.add(Instruction.loadValue(null).locate(loc()));
|
if (value == null) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
else value.compileWithPollution(target, scope);
|
else value.compile(target, scope, true);
|
||||||
target.add(Instruction.ret().locate(loc()));
|
target.add(Instruction.ret().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,6 @@ public class SwitchStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
public final SwitchCase[] cases;
|
public final SwitchCase[] cases;
|
||||||
public final Statement[] body;
|
public final Statement[] body;
|
||||||
@ -35,15 +32,15 @@ public class SwitchStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
var caseMap = new HashMap<Integer, Integer>();
|
var caseMap = new HashMap<Integer, Integer>();
|
||||||
var stmIndexMap = new HashMap<Integer, Integer>();
|
var stmIndexMap = new HashMap<Integer, Integer>();
|
||||||
|
|
||||||
value.compile(target, scope);
|
value.compile(target, scope, true);
|
||||||
|
|
||||||
for (var ccase : cases) {
|
for (var ccase : cases) {
|
||||||
target.add(Instruction.dup().locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
ccase.value.compileWithPollution(target, scope);
|
ccase.value.compile(target, scope, true);
|
||||||
target.add(Instruction.operation(Operation.EQUALS).locate(loc()));
|
target.add(Instruction.operation(Operation.EQUALS).locate(loc()));
|
||||||
caseMap.put(target.size(), ccase.statementI);
|
caseMap.put(target.size(), ccase.statementI);
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
@ -55,7 +52,7 @@ public class SwitchStatement extends Statement {
|
|||||||
|
|
||||||
for (var stm : body) {
|
for (var stm : body) {
|
||||||
stmIndexMap.put(stmIndexMap.size(), target.size());
|
stmIndexMap.put(stmIndexMap.size(), target.size());
|
||||||
stm.compileNoPollution(target, scope, true);
|
stm.compileWithDebug(target, scope, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(target.size() - start).locate(loc()));
|
if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(target.size() - start).locate(loc()));
|
||||||
|
@ -11,11 +11,8 @@ public class ThrowStatement extends Statement {
|
|||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return false; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
value.compile(target, scope, true);
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
value.compileWithPollution(target, scope);
|
|
||||||
target.add(Instruction.throwInstr().locate(loc()));
|
target.add(Instruction.throwInstr().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@ public class TryStatement extends Statement {
|
|||||||
public final Statement finallyBody;
|
public final Statement finallyBody;
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
tryBody.declare(globScope);
|
tryBody.declare(globScope);
|
||||||
@ -26,30 +23,31 @@ public class TryStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
|
|
||||||
int start = target.size(), tryN, catchN = -1, finN = -1;
|
int start = target.size(), tryN, catchN = -1, finN = -1;
|
||||||
|
|
||||||
tryBody.compileNoPollution(target, scope);
|
tryBody.compile(target, scope, false);
|
||||||
tryN = target.size() - start;
|
tryN = target.size() - start;
|
||||||
|
|
||||||
if (catchBody != null) {
|
if (catchBody != null) {
|
||||||
int tmp = target.size();
|
int tmp = target.size();
|
||||||
var local = scope instanceof GlobalScope ? scope.child() : (LocalScopeRecord)scope;
|
var local = scope instanceof GlobalScope ? scope.child() : (LocalScopeRecord)scope;
|
||||||
local.define(name, true);
|
local.define(name, true);
|
||||||
catchBody.compileNoPollution(target, scope);
|
catchBody.compile(target, scope, false);
|
||||||
local.undefine();
|
local.undefine();
|
||||||
catchN = target.size() - tmp;
|
catchN = target.size() - tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finallyBody != null) {
|
if (finallyBody != null) {
|
||||||
int tmp = target.size();
|
int tmp = target.size();
|
||||||
finallyBody.compileNoPollution(target, scope);
|
finallyBody.compile(target, scope, false);
|
||||||
finN = target.size() - tmp;
|
finN = target.size() - tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
target.set(start - 1, Instruction.tryInstr(tryN, catchN, finN).locate(loc()));
|
target.set(start - 1, Instruction.tryInstr(tryN, catchN, finN).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TryStatement(Location loc, Statement tryBody, Statement catchBody, Statement finallyBody, String name) {
|
public TryStatement(Location loc, Statement tryBody, Statement catchBody, Statement finallyBody, String name) {
|
||||||
|
@ -16,19 +16,16 @@ public class WhileStatement extends Statement {
|
|||||||
public final Statement condition, body;
|
public final Statement condition, body;
|
||||||
public final String label;
|
public final String label;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return false; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord globScope) {
|
public void declare(ScopeRecord globScope) {
|
||||||
body.declare(globScope);
|
body.declare(globScope);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (condition instanceof ConstantStatement) {
|
if (condition instanceof ConstantStatement) {
|
||||||
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
if (Values.toBoolean(((ConstantStatement)condition).value)) {
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
body.compileNoPollution(target, scope);
|
body.compile(target, scope, false);
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
replaceBreaks(target, label, start, end, start, end + 1);
|
replaceBreaks(target, label, start, end, start, end + 1);
|
||||||
target.add(Instruction.jmp(start - target.size()).locate(loc()));
|
target.add(Instruction.jmp(start - target.size()).locate(loc()));
|
||||||
@ -37,10 +34,10 @@ public class WhileStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
condition.compileWithPollution(target, scope);
|
condition.compile(target, scope, true);
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
body.compileNoPollution(target, scope);
|
body.compile(target, scope, false);
|
||||||
|
|
||||||
int end = target.size();
|
int end = target.size();
|
||||||
|
|
||||||
@ -48,6 +45,7 @@ public class WhileStatement extends Statement {
|
|||||||
|
|
||||||
target.add(Instruction.jmp(start - end).locate(loc()));
|
target.add(Instruction.jmp(start - end).locate(loc()));
|
||||||
target.set(mid, Instruction.jmpIfNot(end - mid + 1).locate(loc()));
|
target.set(mid, Instruction.jmpIfNot(end - mid + 1).locate(loc()));
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Statement optimize() {
|
public Statement optimize() {
|
||||||
|
@ -12,23 +12,19 @@ public class CallStatement extends Statement {
|
|||||||
public final Statement[] args;
|
public final Statement[] args;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
if (func instanceof IndexStatement) {
|
if (func instanceof IndexStatement) {
|
||||||
((IndexStatement)func).compile(target, scope, true);
|
((IndexStatement)func).compile(target, scope, true, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
target.add(Instruction.loadValue(null).locate(loc()));
|
target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
func.compileWithPollution(target, scope);
|
func.compile(target, scope, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var arg : args) {
|
for (var arg : args) arg.compile(target, scope, true);
|
||||||
arg.compileWithPollution(target, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
target.add(Instruction.call(args.length).locate(loc()).setDebug(true));
|
target.add(Instruction.call(args.length).locate(loc()).setDebug(true));
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CallStatement(Location loc, Statement func, Statement ...args) {
|
public CallStatement(Location loc, Statement func, Statement ...args) {
|
||||||
|
@ -15,11 +15,9 @@ public class ChangeStatement extends Statement {
|
|||||||
public final boolean postfix;
|
public final boolean postfix;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, postfix);
|
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, postfix);
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {
|
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|
||||||
|
|
||||||
public class CommaStatement extends Statement {
|
|
||||||
public final Statement first;
|
|
||||||
public final Statement second;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
|
||||||
public boolean pure() { return first.pure() && second.pure(); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
first.compileNoPollution(target, scope);
|
|
||||||
second.compileWithPollution(target, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Statement optimize() {
|
|
||||||
var f = first.optimize();
|
|
||||||
var s = second.optimize();
|
|
||||||
if (f.pure()) return s;
|
|
||||||
else return new CommaStatement(loc(), f, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommaStatement(Location loc, Statement first, Statement second) {
|
|
||||||
super(loc);
|
|
||||||
this.first = first;
|
|
||||||
this.second = second;
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,14 +10,12 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public class ConstantStatement extends Statement {
|
public class ConstantStatement extends Statement {
|
||||||
public final Object value;
|
public final Object value;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
target.add(Instruction.loadValue(value).locate(loc()));
|
if (pollute) target.add(Instruction.loadValue(value).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstantStatement(Location loc, Object val) {
|
public ConstantStatement(Location loc, Object val) {
|
||||||
|
@ -17,8 +17,6 @@ public class FunctionStatement extends Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return name == null; }
|
public boolean pure() { return name == null; }
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declare(ScopeRecord scope) {
|
public void declare(ScopeRecord scope) {
|
||||||
@ -69,7 +67,7 @@ public class FunctionStatement extends Statement {
|
|||||||
|
|
||||||
body.declare(subscope);
|
body.declare(subscope);
|
||||||
target.add(Instruction.debugVarNames(subscope.locals()));
|
target.add(Instruction.debugVarNames(subscope.locals()));
|
||||||
body.compile(target, subscope);
|
body.compile(target, subscope, false);
|
||||||
|
|
||||||
checkBreakAndCont(target, start);
|
checkBreakAndCont(target, start);
|
||||||
|
|
||||||
@ -90,12 +88,13 @@ public class FunctionStatement extends Statement {
|
|||||||
var key = scope.getKey(this.name);
|
var key = scope.getKey(this.name);
|
||||||
|
|
||||||
if (key instanceof String) target.add(Instruction.makeVar((String)key).locate(loc()));
|
if (key instanceof String) target.add(Instruction.makeVar((String)key).locate(loc()));
|
||||||
target.add(Instruction.storeVar(scope.getKey(this.name), true).locate(loc()));
|
target.add(Instruction.storeVar(scope.getKey(this.name), false).locate(loc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
compile(target, scope, null, false);
|
compile(target, scope, null, false);
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionStatement(Location loc, String name, String[] args, CompoundStatement body) {
|
public FunctionStatement(Location loc, String name, String[] args, CompoundStatement body) {
|
||||||
|
@ -8,14 +8,12 @@ import me.topchetoeu.jscript.compilation.Instruction;
|
|||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class GlobalThisStatement extends Statement {
|
public class GlobalThisStatement extends Statement {
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
target.add(Instruction.loadGlob().locate(loc()));
|
if (pollute) target.add(Instruction.loadGlob().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalThisStatement(Location loc) {
|
public GlobalThisStatement(Location loc) {
|
||||||
|
@ -3,49 +3,37 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignStatement;
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IndexAssignStatement extends AssignStatement {
|
public class IndexAssignStatement extends Statement {
|
||||||
public final Statement object;
|
public final Statement object;
|
||||||
public final Statement index;
|
public final Statement index;
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
public final Operation operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
|
|
||||||
int start = 0;
|
|
||||||
|
|
||||||
if (operation != null) {
|
if (operation != null) {
|
||||||
object.compileWithPollution(target, scope);
|
object.compile(target, scope, true);
|
||||||
index.compileWithPollution(target, scope);
|
index.compile(target, scope, true);
|
||||||
target.add(Instruction.dup(2, 0).locate(loc()));
|
target.add(Instruction.dup(2, 0).locate(loc()));
|
||||||
|
|
||||||
target.add(Instruction.loadMember().locate(loc()));
|
target.add(Instruction.loadMember().locate(loc()));
|
||||||
if (retPrevValue) {
|
value.compile(target, scope, true);
|
||||||
target.add(Instruction.dup().locate(loc()));
|
|
||||||
target.add(Instruction.move(3, 1).locate(loc()));
|
|
||||||
}
|
|
||||||
value.compileWithPollution(target, scope);
|
|
||||||
target.add(Instruction.operation(operation).locate(loc()));
|
target.add(Instruction.operation(operation).locate(loc()));
|
||||||
|
|
||||||
target.add(Instruction.storeMember(!retPrevValue).locate(loc()).setDebug(true));
|
target.add(Instruction.storeMember(pollute).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
object.compileWithPollution(target, scope);
|
object.compile(target, scope, true);
|
||||||
if (retPrevValue) target.add(Instruction.dup().locate(loc()));
|
index.compile(target, scope, true);
|
||||||
index.compileWithPollution(target, scope);
|
value.compile(target, scope, true);
|
||||||
value.compileWithPollution(target, scope);
|
|
||||||
|
|
||||||
target.add(Instruction.storeMember(!retPrevValue).locate(loc()).setDebug(true));
|
target.add(Instruction.storeMember(pollute).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
target.get(start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexAssignStatement(Location loc, Statement object, Statement index, Statement value, Operation operation) {
|
public IndexAssignStatement(Location loc, Statement object, Statement index, Statement value, Operation operation) {
|
||||||
|
@ -3,7 +3,6 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignStatement;
|
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
@ -14,31 +13,30 @@ public class IndexStatement extends AssignableStatement {
|
|||||||
public final Statement object;
|
public final Statement object;
|
||||||
public final Statement index;
|
public final Statement index;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssignStatement toAssign(Statement val, Operation operation) {
|
public Statement toAssign(Statement val, Operation operation) {
|
||||||
return new IndexAssignStatement(loc(), object, index, val, operation);
|
return new IndexAssignStatement(loc(), object, index, val, operation);
|
||||||
}
|
}
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope, boolean dupObj) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean dupObj, boolean pollute) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
object.compileWithPollution(target, scope);
|
object.compile(target, scope, true);
|
||||||
if (dupObj) target.add(Instruction.dup().locate(loc()));
|
if (dupObj) target.add(Instruction.dup().locate(loc()));
|
||||||
if (index instanceof ConstantStatement) {
|
if (index instanceof ConstantStatement) {
|
||||||
target.add(Instruction.loadMember(((ConstantStatement)index).value).locate(loc()));
|
target.add(Instruction.loadMember(((ConstantStatement)index).value).locate(loc()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
index.compileWithPollution(target, scope);
|
index.compile(target, scope, true);
|
||||||
target.add(Instruction.loadMember().locate(loc()));
|
target.add(Instruction.loadMember().locate(loc()));
|
||||||
target.get(start).setDebug(true);
|
target.get(start).setDebug(true);
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
compile(target, scope, false);
|
compile(target, scope, false, pollute);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexStatement(Location loc, Statement object, Statement index) {
|
public IndexStatement(Location loc, Statement object, Statement index) {
|
||||||
|
@ -11,29 +11,27 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
public class LazyAndStatement extends Statement {
|
public class LazyAndStatement extends Statement {
|
||||||
public final Statement first, second;
|
public final Statement first, second;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() {
|
public boolean pure() {
|
||||||
return first.pure() && second.pure();
|
return first.pure() && second.pure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (first instanceof ConstantStatement) {
|
if (first instanceof ConstantStatement) {
|
||||||
if (Values.not(((ConstantStatement)first).value)) {
|
if (Values.not(((ConstantStatement)first).value)) {
|
||||||
first.compileWithPollution(target, scope);
|
first.compile(target, scope, pollute);
|
||||||
}
|
}
|
||||||
else second.compileWithPollution(target, scope);
|
else second.compile(target, scope, pollute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
first.compileWithPollution(target, scope);
|
first.compile(target, scope, true);
|
||||||
target.add(Instruction.dup().locate(loc()));
|
if (pollute) target.add(Instruction.dup().locate(loc()));
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
target.add(Instruction.discard().locate(loc()));
|
target.add(Instruction.discard().locate(loc()));
|
||||||
second.compileWithPollution(target, scope);
|
second.compile(target, scope, pollute);
|
||||||
target.set(start, Instruction.jmpIfNot(target.size() - start).locate(loc()));
|
target.set(start, Instruction.jmpIfNot(target.size() - start).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,29 +11,27 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
public class LazyOrStatement extends Statement {
|
public class LazyOrStatement extends Statement {
|
||||||
public final Statement first, second;
|
public final Statement first, second;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() {
|
public boolean pure() {
|
||||||
return first.pure() && second.pure();
|
return first.pure() && second.pure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (first instanceof ConstantStatement) {
|
if (first instanceof ConstantStatement) {
|
||||||
if (Values.not(((ConstantStatement)first).value)) {
|
if (Values.not(((ConstantStatement)first).value)) {
|
||||||
second.compileWithPollution(target, scope);
|
second.compile(target, scope, pollute);
|
||||||
}
|
}
|
||||||
else first.compileWithPollution(target, scope);
|
else first.compile(target, scope, pollute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
first.compileWithPollution(target, scope);
|
first.compile(target, scope, true);
|
||||||
target.add(Instruction.dup().locate(loc()));
|
if (pollute) target.add(Instruction.dup().locate(loc()));
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
target.add(Instruction.discard().locate(loc()));
|
target.add(Instruction.discard().locate(loc()));
|
||||||
second.compileWithPollution(target, scope);
|
second.compile(target, scope, pollute);
|
||||||
target.set(start, Instruction.jmpIf(target.size() - start).locate(loc()));
|
target.set(start, Instruction.jmpIf(target.size() - start).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,14 +12,10 @@ public class NewStatement extends Statement {
|
|||||||
public final Statement[] args;
|
public final Statement[] args;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
func.compile(target, scope, true);
|
||||||
|
|
||||||
@Override
|
for (var arg : args) arg.compile(target, scope, true);
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
func.compileWithPollution(target, scope);
|
|
||||||
for (var arg : args) {
|
|
||||||
arg.compileWithPollution(target, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
target.add(Instruction.callNew(args.length).locate(loc()).setDebug(true));
|
target.add(Instruction.callNew(args.length).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,7 @@ public class ObjectStatement extends Statement {
|
|||||||
public final Map<Object, FunctionStatement> setters;
|
public final Map<Object, FunctionStatement> setters;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
target.add(Instruction.loadObj().locate(loc()));
|
target.add(Instruction.loadObj().locate(loc()));
|
||||||
|
|
||||||
for (var el : map.entrySet()) {
|
for (var el : map.entrySet()) {
|
||||||
@ -26,7 +23,7 @@ public class ObjectStatement extends Statement {
|
|||||||
target.add(Instruction.loadValue(el.getKey()).locate(loc()));
|
target.add(Instruction.loadValue(el.getKey()).locate(loc()));
|
||||||
var val = el.getValue();
|
var val = el.getValue();
|
||||||
if (val instanceof FunctionStatement) ((FunctionStatement)val).compile(target, scope, el.getKey().toString(), false);
|
if (val instanceof FunctionStatement) ((FunctionStatement)val).compile(target, scope, el.getKey().toString(), false);
|
||||||
else val.compileWithPollution(target, scope);
|
else val.compile(target, scope, true);
|
||||||
target.add(Instruction.storeMember().locate(loc()));
|
target.add(Instruction.storeMember().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,14 +35,16 @@ public class ObjectStatement extends Statement {
|
|||||||
if (key instanceof String) target.add(Instruction.loadValue((String)key).locate(loc()));
|
if (key instanceof String) target.add(Instruction.loadValue((String)key).locate(loc()));
|
||||||
else target.add(Instruction.loadValue((Double)key).locate(loc()));
|
else target.add(Instruction.loadValue((Double)key).locate(loc()));
|
||||||
|
|
||||||
if (getters.containsKey(key)) getters.get(key).compileWithPollution(target, scope);
|
if (getters.containsKey(key)) getters.get(key).compile(target, scope, true);
|
||||||
else target.add(Instruction.loadValue(null).locate(loc()));
|
else target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
|
|
||||||
if (setters.containsKey(key)) setters.get(key).compileWithPollution(target, scope);
|
if (setters.containsKey(key)) setters.get(key).compile(target, scope, true);
|
||||||
else target.add(Instruction.loadValue(null).locate(loc()));
|
else target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
|
|
||||||
target.add(Instruction.defProp().locate(loc()));
|
target.add(Instruction.defProp().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectStatement(Location loc, Map<Object, Statement> map, Map<Object, FunctionStatement> getters, Map<Object, FunctionStatement> setters) {
|
public ObjectStatement(Location loc, Map<Object, Statement> map, Map<Object, FunctionStatement> getters, Map<Object, FunctionStatement> setters) {
|
||||||
|
@ -16,15 +16,15 @@ public class OperationStatement extends Statement {
|
|||||||
public final Operation operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
for (var arg : args) {
|
for (var arg : args) {
|
||||||
arg.compileWithPollution(target, scope);
|
arg.compile(target, scope, true);
|
||||||
}
|
}
|
||||||
target.add(Instruction.operation(operation).locate(loc()));
|
|
||||||
|
if (pollute) target.add(Instruction.operation(operation).locate(loc()));
|
||||||
|
else target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() {
|
public boolean pure() {
|
||||||
for (var arg : args) {
|
for (var arg : args) {
|
||||||
|
@ -10,14 +10,13 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public class RegexStatement extends Statement {
|
public class RegexStatement extends Statement {
|
||||||
public final String pattern, flags;
|
public final String pattern, flags;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
target.add(Instruction.loadRegex(pattern, flags).locate(loc()));
|
target.add(Instruction.loadRegex(pattern, flags).locate(loc()));
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegexStatement(Location loc, String pattern, String flags) {
|
public RegexStatement(Location loc, String pattern, String flags) {
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
|
||||||
|
|
||||||
public class TernaryStatement extends Statement {
|
|
||||||
public final Statement condition;
|
|
||||||
public final Statement first;
|
|
||||||
public final Statement second;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
|
||||||
public boolean pure() { return true; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
if (condition instanceof ConstantStatement) {
|
|
||||||
if (!Values.toBoolean(((ConstantStatement)condition).value)) {
|
|
||||||
second.compileWithPollution(target, scope);
|
|
||||||
}
|
|
||||||
else first.compileWithPollution(target, scope);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
condition.compileWithPollution(target, scope);
|
|
||||||
int start = target.size();
|
|
||||||
target.add(Instruction.nop());
|
|
||||||
first.compileWithPollution(target, scope);
|
|
||||||
int mid = target.size();
|
|
||||||
target.add(Instruction.nop());
|
|
||||||
second.compileWithPollution(target, scope);
|
|
||||||
int end = target.size();
|
|
||||||
|
|
||||||
target.set(start, Instruction.jmpIfNot(mid - start + 1).locate(loc()));
|
|
||||||
target.set(mid, Instruction.jmp(end - mid).locate(loc()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Statement optimize() {
|
|
||||||
var cond = condition.optimize();
|
|
||||||
var f = first.optimize();
|
|
||||||
var s = second.optimize();
|
|
||||||
return new TernaryStatement(loc(), cond, f, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TernaryStatement(Location loc, Statement condition, Statement first, Statement second) {
|
|
||||||
super(loc);
|
|
||||||
this.condition = condition;
|
|
||||||
this.first = first;
|
|
||||||
this.second = second;
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,19 +5,18 @@ import java.util.List;
|
|||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
|
import me.topchetoeu.jscript.compilation.control.ArrayStatement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
|
||||||
public class TypeofStatement extends Statement {
|
public class TypeofStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
if (value instanceof VariableStatement) {
|
if (value instanceof VariableStatement) {
|
||||||
var i = scope.getKey(((VariableStatement)value).name);
|
var i = scope.getKey(((VariableStatement)value).name);
|
||||||
if (i instanceof String) {
|
if (i instanceof String) {
|
||||||
@ -25,7 +24,7 @@ public class TypeofStatement extends Statement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value.compileWithPollution(target, scope);
|
value.compile(target, scope, pollute);
|
||||||
target.add(Instruction.typeof().locate(loc()));
|
target.add(Instruction.typeof().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,36 +4,32 @@ import java.util.List;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.AssignStatement;
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableAssignStatement extends AssignStatement {
|
public class VariableAssignStatement extends Statement {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
public final Operation operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
|
|
||||||
var i = scope.getKey(name);
|
var i = scope.getKey(name);
|
||||||
if (operation != null) {
|
if (operation != null) {
|
||||||
target.add(Instruction.loadVar(i).locate(loc()));
|
target.add(Instruction.loadVar(i).locate(loc()));
|
||||||
if (retPrevValue) target.add(Instruction.dup().locate(loc()));
|
|
||||||
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
||||||
else value.compileWithPollution(target, scope);
|
else value.compile(target, scope, true);
|
||||||
target.add(Instruction.operation(operation).locate(loc()));
|
target.add(Instruction.operation(operation).locate(loc()));
|
||||||
target.add(Instruction.storeVar(i, !retPrevValue).locate(loc()));
|
target.add(Instruction.storeVar(i, false).locate(loc()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (retPrevValue) target.add(Instruction.loadVar(i).locate(loc()));
|
|
||||||
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
||||||
else value.compileWithPollution(target, scope);
|
else value.compile(target, scope, true);
|
||||||
target.add(Instruction.storeVar(i, !retPrevValue).locate(loc()));
|
target.add(Instruction.storeVar(i, false).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableAssignStatement(Location loc, String name, Statement val, Operation operation) {
|
public VariableAssignStatement(Location loc, String name, Statement val, Operation operation) {
|
||||||
|
@ -10,14 +10,12 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public class VariableIndexStatement extends Statement {
|
public class VariableIndexStatement extends Statement {
|
||||||
public final int index;
|
public final int index;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
target.add(Instruction.loadVar(index).locate(loc()));
|
if (pollute) target.add(Instruction.loadVar(index).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableIndexStatement(Location loc, int i) {
|
public VariableIndexStatement(Location loc, int i) {
|
||||||
|
@ -3,7 +3,6 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignStatement;
|
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
@ -13,20 +12,19 @@ import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
|||||||
public class VariableStatement extends AssignableStatement {
|
public class VariableStatement extends AssignableStatement {
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean pollutesStack() { return true; }
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssignStatement toAssign(Statement val, Operation operation) {
|
public Statement toAssign(Statement val, Operation operation) {
|
||||||
return new VariableAssignStatement(loc(), name, val, operation);
|
return new VariableAssignStatement(loc(), name, val, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
var i = scope.getKey(name);
|
var i = scope.getKey(name);
|
||||||
target.add(Instruction.loadVar(i).locate(loc()));
|
target.add(Instruction.loadVar(i).locate(loc()));
|
||||||
|
if (!pollute) target.add(Instruction.discard().locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableStatement(Location loc, String name) {
|
public VariableStatement(Location loc, String name) {
|
||||||
|
@ -11,12 +11,9 @@ public class VoidStatement extends Statement {
|
|||||||
public final Statement value;
|
public final Statement value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean pollute) {
|
||||||
|
if (value != null) value.compile(target, scope, false);
|
||||||
@Override
|
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
|
||||||
if (value != null) value.compileNoPollution(target, scope);
|
|
||||||
target.add(Instruction.loadValue(null).locate(loc()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -9,7 +9,6 @@ import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
|||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.SignalValue;
|
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
@ -20,9 +19,6 @@ public class Runners {
|
|||||||
public static Object execReturn(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execReturn(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
return frame.pop();
|
return frame.pop();
|
||||||
}
|
}
|
||||||
public static Object execSignal(Context ctx, Instruction instr, CodeFrame frame) {
|
|
||||||
return new SignalValue(instr.get(0));
|
|
||||||
}
|
|
||||||
public static Object execThrow(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execThrow(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
throw new EngineException(frame.pop());
|
throw new EngineException(frame.pop());
|
||||||
}
|
}
|
||||||
@ -343,11 +339,9 @@ public class Runners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object exec(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
public static Object exec(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
// System.out.println(instr + "@" + instr.location);
|
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case NOP: return execNop(ctx, instr, frame);
|
case NOP: return execNop(ctx, instr, frame);
|
||||||
case RETURN: return execReturn(ctx, instr, frame);
|
case RETURN: return execReturn(ctx, instr, frame);
|
||||||
case SIGNAL: return execSignal(ctx, instr, frame);
|
|
||||||
case THROW: return execThrow(ctx, instr, frame);
|
case THROW: return execThrow(ctx, instr, frame);
|
||||||
case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame);
|
case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame);
|
||||||
case CALL: return execCall(ctx, instr, frame);
|
case CALL: return execCall(ctx, instr, frame);
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
|
||||||
|
|
||||||
public final class SignalValue {
|
|
||||||
public final String data;
|
|
||||||
|
|
||||||
public SignalValue(String data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isSignal(Object signal, String value) {
|
|
||||||
if (!(signal instanceof SignalValue)) return false;
|
|
||||||
var val = ((SignalValue)signal).data;
|
|
||||||
|
|
||||||
if (value.endsWith("*")) return val.startsWith(value.substring(0, value.length() - 1));
|
|
||||||
else return val.equals(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -84,7 +84,6 @@ public class Values {
|
|||||||
obj instanceof String ||
|
obj instanceof String ||
|
||||||
obj instanceof Boolean ||
|
obj instanceof Boolean ||
|
||||||
obj instanceof Symbol ||
|
obj instanceof Symbol ||
|
||||||
obj instanceof SignalValue ||
|
|
||||||
obj == null ||
|
obj == null ||
|
||||||
obj == NULL;
|
obj == NULL;
|
||||||
}
|
}
|
||||||
@ -143,7 +142,6 @@ public class Values {
|
|||||||
if (val instanceof Boolean) return (Boolean)val ? "true" : "false";
|
if (val instanceof Boolean) return (Boolean)val ? "true" : "false";
|
||||||
if (val instanceof String) return (String)val;
|
if (val instanceof String) return (String)val;
|
||||||
if (val instanceof Symbol) return ((Symbol)val).toString();
|
if (val instanceof Symbol) return ((Symbol)val).toString();
|
||||||
if (val instanceof SignalValue) return "[signal '" + ((SignalValue)val).data + "']";
|
|
||||||
|
|
||||||
return "Unknown value";
|
return "Unknown value";
|
||||||
}
|
}
|
||||||
|
@ -1230,7 +1230,7 @@ public class Parsing {
|
|||||||
|
|
||||||
return ParseRes.res(new OperationStatement(loc, Operation.IN, prev, valRes.result), n);
|
return ParseRes.res(new OperationStatement(loc, Operation.IN, prev, valRes.result), n);
|
||||||
}
|
}
|
||||||
public static ParseRes<CommaStatement> parseComma(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
public static ParseRes<CompoundStatement> parseComma(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||||
var loc = getLoc(filename, tokens, i);
|
var loc = getLoc(filename, tokens, i);
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
@ -1241,9 +1241,9 @@ public class Parsing {
|
|||||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a value after the comma.", res);
|
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a value after the comma.", res);
|
||||||
n += res.n;
|
n += res.n;
|
||||||
|
|
||||||
return ParseRes.res(new CommaStatement(loc, prev, res.result), n);
|
return ParseRes.res(new CompoundStatement(loc, prev, res.result), n);
|
||||||
}
|
}
|
||||||
public static ParseRes<TernaryStatement> parseTernary(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
public static ParseRes<IfStatement> parseTernary(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||||
var loc = getLoc(filename, tokens, i);
|
var loc = getLoc(filename, tokens, i);
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
@ -1260,7 +1260,7 @@ public class Parsing {
|
|||||||
if (!b.isSuccess()) return ParseRes.error(loc, "Expected a second value after the ternary operator.", b);
|
if (!b.isSuccess()) return ParseRes.error(loc, "Expected a second value after the ternary operator.", b);
|
||||||
n += b.n;
|
n += b.n;
|
||||||
|
|
||||||
return ParseRes.res(new TernaryStatement(loc, prev, a.result, b.result), n);
|
return ParseRes.res(new IfStatement(loc, prev, a.result, b.result), n);
|
||||||
}
|
}
|
||||||
public static ParseRes<? extends Statement> parseOperator(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
public static ParseRes<? extends Statement> parseOperator(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||||
var loc = getLoc(filename, tokens, i);
|
var loc = getLoc(filename, tokens, i);
|
||||||
@ -1886,7 +1886,7 @@ public class Parsing {
|
|||||||
body.declare(target);
|
body.declare(target);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
body.compile(res, subscope);
|
body.compile(res, subscope, true);
|
||||||
FunctionStatement.checkBreakAndCont(res, 0);
|
FunctionStatement.checkBreakAndCont(res, 0);
|
||||||
}
|
}
|
||||||
catch (SyntaxException e) {
|
catch (SyntaxException e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user