fix: a lot of minor bugs

This commit is contained in:
TopchetoEU 2023-10-29 23:47:48 +02:00
parent d1e93c2088
commit b675411925
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
30 changed files with 86437 additions and 185 deletions

View File

@ -10,6 +10,7 @@ import me.topchetoeu.jscript.engine.Engine;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.debug.DebugServer;
import me.topchetoeu.jscript.engine.debug.SimpleDebugger;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.events.Observer;
@ -50,6 +51,10 @@ public class Main {
var server = new DebugServer();
server.targets.put("target", (ws, req) -> SimpleDebugger.get(ws, engine));
engineTask = engine.start();
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
// server.awaitConnection();
engine.pushMsg(false, null, new NativeFunction((ctx, thisArg, _a) -> {
new Internals().apply(env);
@ -69,10 +74,29 @@ public class Main {
});
return null;
}), null);
}), null).await();
try {
var ts = engine.pushMsg(
false, new Context(engine).pushEnv(env),
new Filename("file", "/mnt/data/repos/java-jscript/src/me/topchetoeu/jscript/js/ts.js"),
Reading.resourceToString("js/ts.js"), null
).await();
System.out.println("Loaded typescript!");
engine.pushMsg(
false, new Context(engine).pushEnv(env.child()),
new Filename("jscript", "internals/bootstrap.js"), Reading.resourceToString("js/bootstrap.js"), null,
ts, env, new ArrayValue(null, Reading.resourceToString("js/lib.d.ts"))
).await();
}
catch (EngineException e) {
Values.printError(e, "(while initializing TS)");
System.out.println("engine reported stack trace:");
for (var el : e.stackTrace) {
System.out.println(el);
}
}
engineTask = engine.start();
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
var reader = new Thread(() -> {
try {

View File

@ -251,8 +251,8 @@ public class Instruction {
return new Instruction(null, Type.TYPEOF, varName);
}
public static Instruction keys() {
return new Instruction(null, Type.KEYS);
public static Instruction keys(boolean forInFormat) {
return new Instruction(null, Type.KEYS, forInFormat);
}
public static Instruction defProp() {

View File

@ -12,6 +12,7 @@ public class ForInStatement extends Statement {
public final boolean isDeclaration;
public final Statement varValue, object, body;
public final String label;
public final Location varLocation;
@Override
public void declare(ScopeRecord globScope) {
@ -22,6 +23,8 @@ public class ForInStatement extends Statement {
@Override
public void compile(CompileTarget target, ScopeRecord scope, boolean pollute) {
var key = scope.getKey(varName);
int first = target.size();
if (key instanceof String) target.add(Instruction.makeVar((String)key));
if (varValue != null) {
@ -29,45 +32,37 @@ public class ForInStatement extends Statement {
target.add(Instruction.storeVar(scope.getKey(varName)));
}
object.compile(target, scope, true);
target.add(Instruction.keys());
object.compileWithDebug(target, scope, true);
target.add(Instruction.keys(true));
int start = target.size();
target.add(Instruction.dup());
target.add(Instruction.loadMember("length"));
target.add(Instruction.loadValue(0));
target.add(Instruction.operation(Operation.LESS_EQUALS));
target.add(Instruction.loadValue(null));
target.add(Instruction.operation(Operation.EQUALS));
int mid = target.size();
target.add(Instruction.nop());
target.add(Instruction.dup());
target.add(Instruction.dup());
target.add(Instruction.loadMember("length"));
target.add(Instruction.loadValue(1));
target.add(Instruction.operation(Operation.SUBTRACT));
target.add(Instruction.dup(1, 2));
target.add(Instruction.loadValue("length"));
target.add(Instruction.dup(1, 2));
target.add(Instruction.storeMember());
target.add(Instruction.loadMember());
target.add(Instruction.loadMember("value").locate(varLocation));
target.setDebug();
target.add(Instruction.storeVar(key));
for (var i = start; i < target.size(); i++) target.get(i).locate(loc());
body.compileWithDebug(target, scope, false);
int end = target.size();
WhileStatement.replaceBreaks(target, label, mid + 1, end, start, end + 1);
target.add(Instruction.jmp(start - end).locate(loc()));
target.add(Instruction.discard().locate(loc()));
target.set(mid, Instruction.jmpIf(end - mid + 1).locate(loc()));
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
target.add(Instruction.jmp(start - end));
target.add(Instruction.discard());
target.set(mid, Instruction.jmpIf(end - mid + 1));
if (pollute) target.add(Instruction.loadValue(null));
target.get(first).locate(loc());
target.setDebug(first);
}
public ForInStatement(Location loc, String label, boolean isDecl, String varName, Statement varValue, Statement object, Statement body) {
public ForInStatement(Location loc, Location varLocation, String label, boolean isDecl, String varName, Statement varValue, Statement object, Statement body) {
super(loc);
this.varLocation = varLocation;
this.label = label;
this.isDeclaration = isDecl;
this.varName = varName;

View File

@ -43,7 +43,7 @@ public class SwitchStatement extends Statement {
ccase.value.compile(target, scope, true);
target.add(Instruction.operation(Operation.EQUALS).locate(loc()));
caseMap.put(target.size(), ccase.statementI);
target.add(Instruction.nop());
target.add(Instruction.nop().locate(ccase.value.loc()));
}
int start = target.size();

View File

@ -15,7 +15,7 @@ public class ChangeStatement extends Statement {
@Override
public void compile(CompileTarget target, ScopeRecord scope, boolean pollute) {
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, postfix);
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, true);
if (!pollute) target.add(Instruction.discard().locate(loc()));
}

View File

@ -0,0 +1,38 @@
package me.topchetoeu.jscript.compilation.values;
import java.util.Vector;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.CompileTarget;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
public class CommaStatement extends Statement {
public final Statement[] values;
@Override
public void compile(CompileTarget target, ScopeRecord scope, boolean pollute) {
for (var i = 0; i < values.length; i++) {
values[i].compile(target, scope, i == values.length - 1 && pollute);
}
}
@Override
public Statement optimize() {
var res = new Vector<Statement>(values.length);
for (var i = 0; i < values.length; i++) {
var stm = values[i].optimize();
if (i < values.length - 1 && stm.pure()) continue;
res.add(stm);
}
if (res.size() == 1) return res.get(0);
else return new CommaStatement(loc(), res.toArray(Statement[]::new));
}
public CommaStatement(Location loc, Statement ...args) {
super(loc);
this.values = args;
}
}

View File

@ -20,15 +20,13 @@ public class VariableAssignStatement extends Statement {
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
else value.compile(target, scope, true);
target.add(Instruction.operation(operation).locate(loc()));
target.add(Instruction.storeVar(i, false).locate(loc()));
target.add(Instruction.storeVar(i, pollute).locate(loc()));
}
else {
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
else value.compile(target, scope, true);
target.add(Instruction.storeVar(i, false).locate(loc()));
target.add(Instruction.storeVar(i, pollute).locate(loc()));
}
if (pollute) target.add(Instruction.loadValue(null).locate(loc()));
}
public VariableAssignStatement(Location loc, String name, Statement val, Operation operation) {

View File

@ -6,6 +6,8 @@ import java.util.TreeSet;
import me.topchetoeu.jscript.Filename;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.parsing.Parsing;
@ -27,11 +29,24 @@ public class Context {
}
public FunctionValue compile(Filename filename, String raw) {
var src = Values.toString(this, environment().compile.call(this, null, raw, filename));
var transpiled = environment().compile.call(this, null, raw, filename.toString());
String source = null;
FunctionValue runner = null;
if (transpiled instanceof ObjectValue) {
source = Values.toString(this, Values.getMember(this, transpiled, "source"));
var _runner = Values.getMember(this, transpiled, "runner");
if (_runner instanceof FunctionValue) runner = (FunctionValue)_runner;
}
else source = Values.toString(this, transpiled);
var debugger = StackData.getDebugger(this);
var breakpoints = new TreeSet<Location>();
var res = Parsing.compile(engine.functions, breakpoints, environment(), filename, src);
if (debugger != null) debugger.onSource(filename, src, breakpoints);
FunctionValue res = Parsing.compile(engine.functions, breakpoints, environment(), filename, source);
if (debugger != null) debugger.onSource(filename, source, breakpoints);
if (runner != null) res = (FunctionValue)runner.call(this, null, res);
return res;
}

View File

@ -17,7 +17,7 @@ public class Environment {
private HashMap<String, ObjectValue> prototypes = new HashMap<>();
public final Data data = new Data();
public final HashMap<String, Symbol> symbols = new HashMap<>();
public static final HashMap<String, Symbol> symbols = new HashMap<>();
public GlobalScope global;
public WrappersProvider wrappers;
@ -57,7 +57,8 @@ public class Environment {
}
@Native public Environment fork() {
var res = new Environment(compile, wrappers, global);
var res = new Environment(compile, null, global);
res.wrappers = wrappers.fork(res);
res.regexConstructor = regexConstructor;
res.prototypes = new HashMap<>(prototypes);
return res;

View File

@ -7,4 +7,6 @@ public interface WrappersProvider {
public ObjectValue getProto(Class<?> obj);
public ObjectValue getNamespace(Class<?> obj);
public FunctionValue getConstr(Class<?> obj);
public WrappersProvider fork(Environment env);
}

View File

@ -10,6 +10,7 @@ import java.util.HashMap;
import me.topchetoeu.jscript.Metadata;
import me.topchetoeu.jscript.engine.debug.WebSocketMessage.Type;
import me.topchetoeu.jscript.events.Notifier;
import me.topchetoeu.jscript.exceptions.SyntaxException;
import me.topchetoeu.jscript.exceptions.UncheckedException;
import me.topchetoeu.jscript.exceptions.UncheckedIOException;
@ -23,6 +24,7 @@ public class DebugServer {
public final HashMap<String, DebuggerProvider> targets = new HashMap<>();
private final byte[] favicon, index, protocol;
private final Notifier connNotifier = new Notifier();
private static void send(HttpRequest req, String val) throws IOException {
req.writeResponse(200, "OK", "application/json", val.getBytes());
@ -67,7 +69,9 @@ public class DebugServer {
try {
switch (msg.name) {
case "Debugger.enable": debugger.enable(msg); continue;
case "Debugger.enable":
connNotifier.next();
debugger.enable(msg); continue;
case "Debugger.disable": debugger.disable(msg); continue;
case "Debugger.setBreakpoint": debugger.setBreakpoint(msg); continue;
@ -151,6 +155,10 @@ public class DebugServer {
}, "Debug Handler");
}
public void awaitConnection() {
connNotifier.await();
}
public void run(InetSocketAddress address) {
try {
ServerSocket server = new ServerSocket();

View File

@ -256,7 +256,7 @@ public class SimpleDebugger implements Debugger {
return id;
}
}
private JSONMap serializeObj(Context ctx, Object val, boolean recurse) {
private JSONMap serializeObj(Context ctx, Object val) {
val = Values.normalize(null, val);
if (val == Values.NULL) {
@ -277,13 +277,6 @@ public class SimpleDebugger implements Debugger {
if (obj instanceof FunctionValue) type = "function";
if (obj instanceof ArrayValue) subtype = "array";
if (Values.isWrapper(val, RegExpLib.class)) subtype = "regexp";
if (Values.isWrapper(val, DateLib.class)) subtype = "date";
if (Values.isWrapper(val, MapLib.class)) subtype = "map";
if (Values.isWrapper(val, SetLib.class)) subtype = "set";
if (Values.isWrapper(val, Generator.class)) subtype = "generator";
if (Values.isWrapper(val, PromiseLib.class)) subtype = "promise";
try { className = Values.toString(ctx, Values.getMember(ctx, obj.getMember(ctx, "constructor"), "name")); }
catch (Exception e) { }
@ -311,6 +304,7 @@ public class SimpleDebugger implements Debugger {
if (Double.POSITIVE_INFINITY == num) res.set("unserializableValue", "Infinity");
else if (Double.NEGATIVE_INFINITY == num) res.set("unserializableValue", "-Infinity");
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(-0d)) res.set("unserializableValue", "-0");
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(0d)) res.set("unserializableValue", "0");
else if (Double.isNaN(num)) res.set("unserializableValue", "NaN");
else res.set("value", num);
@ -319,9 +313,6 @@ public class SimpleDebugger implements Debugger {
throw new IllegalArgumentException("Unexpected JS object.");
}
private JSONMap serializeObj(Context ctx, Object val) {
return serializeObj(ctx, val, true);
}
private void setObjectGroup(String name, Object val) {
if (val instanceof ObjectValue) {
var obj = (ObjectValue)val;
@ -626,7 +617,7 @@ public class SimpleDebugger implements Debugger {
propDesc.set("isOwn", currOwn);
res.add(propDesc);
}
else if (!accessorPropertiesOnly) {
else {
propDesc.set("name", Values.toString(ctx, key));
propDesc.set("value", serializeObj(ctx, obj.getMember(ctx, key)));
propDesc.set("writable", obj.memberWritable(key));
@ -651,7 +642,7 @@ public class SimpleDebugger implements Debugger {
}
currOwn = false;
if (own) break;
if (true) break;
}
ws.send(msg.respond(new JSONMap().set("result", res)));

View File

@ -10,7 +10,7 @@ import me.topchetoeu.jscript.engine.debug.WebSocketMessage.Type;
import me.topchetoeu.jscript.exceptions.UncheckedIOException;
public class WebSocket implements AutoCloseable {
public long maxLength = 2000000;
public long maxLength = 1 << 20;
private Socket socket;
private boolean closed = false;
@ -61,39 +61,45 @@ public class WebSocket implements AutoCloseable {
else return new byte[4];
}
private void writeLength(long len) {
private void writeLength(int len) {
try {
if (len < 126) {
out().write((int)len);
}
else if (len < 0xFFFF) {
else if (len <= 0xFFFF) {
out().write(126);
out().write((int)(len >> 8) & 0xFF);
out().write((int)len & 0xFF);
}
else {
out().write(127);
out().write((int)(len >> 56) & 0xFF);
out().write((int)(len >> 48) & 0xFF);
out().write((int)(len >> 40) & 0xFF);
out().write((int)(len >> 32) & 0xFF);
out().write((int)(len >> 24) & 0xFF);
out().write((int)(len >> 16) & 0xFF);
out().write((int)(len >> 8) & 0xFF);
out().write((int)len & 0xFF);
out().write((len >> 56) & 0xFF);
out().write((len >> 48) & 0xFF);
out().write((len >> 40) & 0xFF);
out().write((len >> 32) & 0xFF);
out().write((len >> 24) & 0xFF);
out().write((len >> 16) & 0xFF);
out().write((len >> 8) & 0xFF);
out().write(len & 0xFF);
}
}
catch (IOException e) { throw new UncheckedIOException(e); }
}
private synchronized void write(int type, byte[] data) {
try {
for (int i = 0; i < (data.length >> 16); i++) {
out().write(type);
writeLength(0xFFFF);
out().write(data, i << 16, 0xFFFF);
}
out().write(type | 0x80);
writeLength(data.length);
for (int i = 0; i < data.length; i++) {
out().write(data[i]);
writeLength(data.length & 0xFFFF);
out().write(data, data.length & 0xFFFF0000, data.length & 0xFFFF);
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
catch (IOException e) { throw new UncheckedIOException(e); }
}
public void send(String data) {

View File

@ -125,12 +125,15 @@ public class CodeFrame {
}
private void setCause(Context ctx, EngineException err, EngineException cause) {
err.cause = cause;
// err.cause = cause;
err.setCause(cause);
}
private Object nextNoTry(Context ctx, Instruction instr) {
if (Thread.currentThread().isInterrupted()) throw new InterruptException();
if (codePtr < 0 || codePtr >= function.body.length) return null;
if (instr.location != null) prevLoc = instr.location;
try {
this.jumpFlag = false;
return Runners.exec(ctx, instr, this);

View File

@ -100,19 +100,29 @@ public class Runners {
public static Object execKeys(Context ctx, Instruction instr, CodeFrame frame) {
var val = frame.pop();
var arr = new ObjectValue();
var i = 0;
var members = Values.getMembers(ctx, val, false, false);
Collections.reverse(members);
frame.push(ctx, null);
for (var el : members) {
if (el instanceof Symbol) continue;
arr.defineProperty(ctx, i++, el);
var obj = new ObjectValue();
obj.defineProperty(ctx, "value", el);
frame.push(ctx, obj);
}
// var arr = new ObjectValue();
arr.defineProperty(ctx, "length", i);
// var members = Values.getMembers(ctx, val, false, false);
// Collections.reverse(members);
// for (var el : members) {
// if (el instanceof Symbol) continue;
// arr.defineProperty(ctx, i++, el);
// }
frame.push(ctx, arr);
// arr.defineProperty(ctx, "length", i);
// frame.push(ctx, arr);
frame.codePtr++;
return NO_RETURN;
}

View File

@ -14,13 +14,14 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
private Object[] values;
private int size;
private void alloc(int index) {
if (index < values.length) return;
private Object[] alloc(int index) {
index++;
if (index < values.length) return values;
if (index < values.length * 2) index = values.length * 2;
var arr = new Object[index];
System.arraycopy(values, 0, arr, 0, values.length);
values = arr;
return arr;
}
public int size() { return size; }
@ -28,7 +29,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
if (val < 0) return false;
if (size > val) shrink(size - val);
else {
alloc(val);
values = alloc(val);
size = val;
}
return true;
@ -43,7 +44,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
public void set(Context ctx, int i, Object val) {
if (i < 0) return;
alloc(i);
values = alloc(i);
val = Values.normalize(ctx, val);
if (val == null) val = UNDEFINED;
@ -97,7 +98,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
}
public void move(int srcI, int dstI, int n) {
alloc(dstI + n);
values = alloc(dstI + n);
System.arraycopy(values, srcI, values, dstI, n);

View File

@ -117,6 +117,7 @@ public class Values {
if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0;
if (val instanceof String) {
try { return Double.parseDouble((String)val); }
catch (NumberFormatException e) { return Double.NaN; }
catch (Throwable e) { throw new UncheckedException(e); }
}
return Double.NaN;
@ -257,7 +258,8 @@ public class Values {
public static Object getMember(Context ctx, Object obj, Object key) {
obj = normalize(ctx, obj); key = normalize(ctx, key);
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
if (obj == null)
throw new IllegalArgumentException("Tried to access member of undefined.");
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
if (isObject(obj)) return object(obj).getMember(ctx, key);
@ -277,7 +279,8 @@ public class Values {
}
public static boolean setMember(Context ctx, Object obj, Object key, Object val) {
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
if (obj == null)
throw EngineException.ofType("Tried to access member of undefined.");
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
if (key.equals("__proto__")) return setPrototype(ctx, obj, val);
if (isObject(obj)) return object(obj).setMember(ctx, key, val, false);
@ -366,11 +369,13 @@ public class Values {
}
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) {
if (!isFunction(func)) throw EngineException.ofType("Tried to call a non-function value.");
if (!isFunction(func))
throw EngineException.ofType("Tried to call a non-function value.");
return function(func).call(ctx, thisArg, args);
}
public static Object callNew(Context ctx, Object func, Object ...args) {
var res = new ObjectValue();
try {
var proto = Values.getMember(ctx, func, "prototype");
res.setPrototype(ctx, proto);
@ -379,6 +384,10 @@ public class Values {
if (ret != null && func instanceof FunctionValue && ((FunctionValue)func).special) return ret;
return res;
}
catch (IllegalArgumentException e) {
throw EngineException.ofType("Tried to call new on an invalid constructor.");
}
}
public static boolean strictEquals(Context ctx, Object a, Object b) {
a = normalize(ctx, a); b = normalize(ctx, b);
@ -515,6 +524,8 @@ public class Values {
public static Iterable<Object> toJavaIterable(Context ctx, Object obj) {
return () -> {
try {
var _ctx = ctx;
var _obj = obj;
var symbol = ctx.environment().symbol("Symbol.iterator");
var iteratorFunc = getMember(ctx, obj, symbol);

View File

@ -45,10 +45,10 @@ public class EngineException extends RuntimeException {
catch (EngineException e) {
ss.append("[Error while stringifying]\n");
}
// for (var line : stackTrace) {
// ss.append(" ").append(line).append('\n');
// }
// if (cause != null) ss.append("Caused by ").append(cause.toString(ctx)).append('\n');
for (var line : stackTrace) {
ss.append(" ").append(line).append('\n');
}
if (cause != null) ss.append("Caused by ").append(cause.toString(ctx)).append('\n');
ss.deleteCharAt(ss.length() - 1);
return ss.toString();
}

View File

@ -33,7 +33,7 @@ public class NativeWrapperProvider implements WrappersProvider {
var val = target.values.get(name);
if (!(val instanceof OverloadFunction)) target.defineProperty(null, name, val = new OverloadFunction(name.toString()));
if (!(val instanceof OverloadFunction)) target.defineProperty(null, name, val = new OverloadFunction(name.toString()), true, true, false);
((OverloadFunction)val).add(Overload.fromMethod(method, nat.thisArg()));
}
@ -53,7 +53,7 @@ public class NativeWrapperProvider implements WrappersProvider {
else getter = new OverloadFunction("get " + name);
getter.add(Overload.fromMethod(method, get.thisArg()));
target.defineProperty(null, name, getter, setter, true, true);
target.defineProperty(null, name, getter, setter, true, false);
}
if (set != null) {
if (set.thisArg() && !member || !set.thisArg() && !memberMatch) continue;
@ -70,7 +70,7 @@ public class NativeWrapperProvider implements WrappersProvider {
else setter = new OverloadFunction("set " + name);
setter.add(Overload.fromMethod(method, set.thisArg()));
target.defineProperty(null, name, getter, setter, true, true);
target.defineProperty(null, name, getter, setter, true, false);
}
}
}
@ -211,8 +211,8 @@ public class NativeWrapperProvider implements WrappersProvider {
if (constr == null) constr = makeConstructor(env, clazz);
if (proto == null) proto = makeProto(env, clazz);
proto.values.put("constructor", constr);
constr.values.put("prototype", proto);
proto.defineProperty(null, "constructor", constr, true, false, false);
constr.defineProperty(null, "prototype", proto, true, false, false);
prototypes.put(clazz, proto);
constructors.put(clazz, constr);
@ -240,6 +240,11 @@ public class NativeWrapperProvider implements WrappersProvider {
return constructors.get(clazz);
}
@Override
public WrappersProvider fork(Environment env) {
return new NativeWrapperProvider(env);
}
public void setProto(Class<?> clazz, ObjectValue value) {
prototypes.put(clazz, value);
}

View File

@ -44,9 +44,11 @@ public class Overload {
public static Overload setterFromField(Field field) {
if (Modifier.isFinal(field.getModifiers())) return null;
return new Overload(
(ctx, th, args) -> { field.set(th, args[0]); return null; }, false, false,
(ctx, th, args) -> {
field.set(th, args[0]); return null;
}, false, false,
Modifier.isStatic(field.getModifiers()) ? null : field.getDeclaringClass(),
new Class[0]
new Class[] { field.getType() }
);
}

View File

@ -84,6 +84,7 @@ public class OverloadFunction extends FunctionValue {
throw ((EngineException)e.getTargetException()).add(name, loc);
}
else if (e.getTargetException() instanceof NullPointerException) {
e.printStackTrace();
throw EngineException.ofType("Unexpected value of 'undefined'.").add(name, loc);
}
else {

View File

@ -1,11 +1,11 @@
// TODO: load this in java
var ts = require('./ts');
log("Loaded typescript!");
(function (_arguments) {
var ts = _arguments[0];
log("Loaded typescript!");
var src = '', lib = libs.concat([ 'declare const exit: never;' ]).join(''), decls = '', version = 0;
var libSnapshot = ts.ScriptSnapshot.fromString(lib);
var src = '', lib = _arguments[2].concat([ 'declare const exit: never;' ]).join(''), decls = '', version = 0;
var libSnapshot = ts.ScriptSnapshot.fromString(lib);
var settings = {
var settings = {
outDir: "/out",
declarationDir: "/out",
target: ts.ScriptTarget.ES5,
@ -17,10 +17,10 @@ var settings = {
forceConsistentCasingInFileNames: true,
experimentalDecorators: true,
strict: true,
};
};
var reg = ts.createDocumentRegistry();
var service = ts.createLanguageService({
var reg = ts.createDocumentRegistry();
var service = ts.createLanguageService({
getCurrentDirectory: function() { return "/"; },
getDefaultLibFileName: function() { return "/lib_.d.ts"; },
getScriptFileNames: function() { return [ "/src.ts", "/lib.d.ts", "/glob.d.ts" ]; },
@ -37,12 +37,12 @@ var service = ts.createLanguageService({
if (filename === "/lib.d.ts") return 0;
else return version;
},
}, reg);
}, reg);
service.getEmitOutput('/lib.d.ts');
log('Loaded libraries!');
service.getEmitOutput('/lib.d.ts');
log('Loaded libraries!');
function compile(filename, code) {
function compile(filename, code) {
src = code, version++;
var emit = service.getEmitOutput("/src.ts");
@ -70,17 +70,20 @@ function compile(filename, code) {
result: emit.outputFiles[0].text,
declaration: emit.outputFiles[1].text
};
}
}
init(function (filename, code) {
_arguments[1].compile = function (filename, code) {
var res = compile(filename, code);
return [
res.result,
function(func, th, args) {
var val = func.apply(th, args);
return {
source: res.result,
runner: function(func) {
return function() {
var val = func.apply(this, arguments);
decls += res.declaration;
return val;
}
];
});
}
}
}
})(arguments);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -69,7 +69,7 @@ public class ArrayLib {
@Native(thisArg = true) public static ArrayValue concat(Context ctx, ArrayValue thisArg, Object ...others) {
// TODO: Fully implement with non-array spreadable objects
var size = 0;
var size = thisArg.size();
for (int i = 0; i < others.length; i++) {
if (others[i] instanceof ArrayValue) size += ((ArrayValue)others[i]).size();
@ -77,8 +77,9 @@ public class ArrayLib {
}
var res = new ArrayValue(size);
thisArg.copyTo(ctx, res, 0, 0, thisArg.size());
for (int i = 0, j = 0; i < others.length; i++) {
for (int i = 0, j = thisArg.size(); i < others.length; i++) {
if (others[i] instanceof ArrayValue) {
int n = ((ArrayValue)others[i]).size();
((ArrayValue)others[i]).copyTo(ctx, res, 0, j, n);

View File

@ -91,6 +91,16 @@ public class Internals {
return NumberLib.parseFloat(ctx, val);
}
@Native public static boolean isNaN(Context ctx, double val) {
return NumberLib.isNaN(ctx, val);
}
@Native public static boolean isFinite(Context ctx, double val) {
return NumberLib.isFinite(ctx, val);
}
@Native public static boolean isInfinite(Context ctx, double val) {
return NumberLib.isInfinite(ctx, val);
}
public void apply(Environment env) {
var wp = env.wrappers;
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));
@ -133,6 +143,7 @@ public class Internals {
env.setProto("rangeErr", wp.getProto(RangeErrorLib.class));
wp.getProto(ObjectLib.class).setPrototype(null, null);
env.regexConstructor = wp.getConstr(RegExpLib.class);
System.out.println("Loaded polyfills!");
}

View File

@ -61,7 +61,7 @@ public class MapLib {
return map.size();
}
@NativeGetter public void forEach(Context ctx, FunctionValue func, Object thisArg) {
@Native public void forEach(Context ctx, FunctionValue func, Object thisArg) {
var keys = new ArrayList<>(map.keySet());
for (var el : keys) func.call(ctx, thisArg, el, map.get(el), this);

View File

@ -51,7 +51,7 @@ public class SetLib {
return set.size();
}
@NativeGetter public void forEach(Context ctx, FunctionValue func, Object thisArg) {
@Native public void forEach(Context ctx, FunctionValue func, Object thisArg) {
var keys = new ArrayList<>(set);
for (var el : keys) func.call(ctx, thisArg, el, el, this);

View File

@ -60,8 +60,18 @@ public class StringLib {
@Native(thisArg = true) public static String charAt(Context ctx, Object thisArg, int i) {
return passThis(ctx, "charAt", thisArg).charAt(i) + "";
}
@Native(thisArg = true) public static int charCodeAt(Context ctx, Object thisArg, int i) {
return passThis(ctx, "charCodeAt", thisArg).charAt(i);
// @Native(thisArg = true) public static int charCodeAt(Context ctx, Object thisArg, int i) {
// return passThis(ctx, "charCodeAt", thisArg).charAt(i);
// }
// @Native(thisArg = true) public static String charAt(Context ctx, Object thisArg, int i) {
// var str = passThis(ctx, "charAt", thisArg);
// if (i < 0 || i >= str.length()) return "";
// else return str.charAt(i) + "";
// }
@Native(thisArg = true) public static double charCodeAt(Context ctx, Object thisArg, int i) {
var str = passThis(ctx, "charCodeAt", thisArg);
if (i < 0 || i >= str.length()) return Double.NaN;
else return str.charAt(i);
}
@Native(thisArg = true) public static boolean startsWith(Context ctx, Object thisArg, String term, int pos) {

View File

@ -1235,7 +1235,7 @@ public class Parsing {
return ParseRes.res(new OperationStatement(loc, Operation.IN, prev, valRes.result), n);
}
public static ParseRes<CompoundStatement> parseComma(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
public static ParseRes<CommaStatement> parseComma(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
var loc = getLoc(filename, tokens, i);
var n = 0;
@ -1246,7 +1246,7 @@ public class Parsing {
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a value after the comma.", res);
n += res.n;
return ParseRes.res(new CompoundStatement(loc, prev, res.result), n);
return ParseRes.res(new CommaStatement(loc, prev, res.result), n);
}
public static ParseRes<IfStatement> parseTernary(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
var loc = getLoc(filename, tokens, i);
@ -1757,6 +1757,7 @@ public class Parsing {
var nameRes = parseIdentifier(tokens, i + n);
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a variable name for 'for' loop.");
var nameLoc = getLoc(filename, tokens, i + n);
n += nameRes.n;
Statement varVal = null;
@ -1790,7 +1791,7 @@ public class Parsing {
if (!bodyRes.isSuccess()) return ParseRes.error(loc, "Expected a for body.", bodyRes);
n += bodyRes.n;
return ParseRes.res(new ForInStatement(loc, labelRes.result, isDecl, nameRes.result, varVal, objRes.result, bodyRes.result), n);
return ParseRes.res(new ForInStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, varVal, objRes.result, bodyRes.result), n);
}
public static ParseRes<TryStatement> parseCatch(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);