feat: add async function
This commit is contained in:
parent
6da7720c67
commit
79a93ef971
@ -14,6 +14,7 @@ interface FunctionConstructor extends Function {
|
|||||||
(...args: string[]): (...args: any[]) => any;
|
(...args: string[]): (...args: any[]) => any;
|
||||||
new (...args: string[]): (...args: any[]) => any;
|
new (...args: string[]): (...args: any[]) => any;
|
||||||
prototype: Function;
|
prototype: Function;
|
||||||
|
async<ArgsT extends any[], RetT>(func: (await: <T>(val: T) => Awaited<T>, args: ArgsT) => RetT): Promise<RetT>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CallableFunction extends Function {
|
interface CallableFunction extends Function {
|
||||||
@ -75,4 +76,10 @@ setProps(Function.prototype, {
|
|||||||
toString() {
|
toString() {
|
||||||
return 'function (...) { ... }';
|
return 'function (...) { ... }';
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
setProps(Function, {
|
||||||
|
async(func) {
|
||||||
|
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
||||||
|
return internals.makeAsync(func);
|
||||||
|
}
|
||||||
|
})
|
@ -4,6 +4,8 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
@ -12,7 +14,6 @@ import me.topchetoeu.jscript.events.Observer;
|
|||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
|
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
|
||||||
import me.topchetoeu.jscript.polyfills.TypescriptEngine;
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
static Thread task;
|
static Thread task;
|
||||||
@ -52,7 +53,7 @@ public class Main {
|
|||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
var in = new BufferedReader(new InputStreamReader(System.in));
|
var in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
engine = new TypescriptEngine(new File("."));
|
engine = new PolyfillEngine(new File("."));
|
||||||
var scope = engine.global().globalChild();
|
var scope = engine.global().globalChild();
|
||||||
var exited = new boolean[1];
|
var exited = new boolean[1];
|
||||||
|
|
||||||
@ -61,6 +62,15 @@ public class Main {
|
|||||||
task.interrupt();
|
task.interrupt();
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
});
|
});
|
||||||
|
scope.define("go", ctx -> {
|
||||||
|
try {
|
||||||
|
var func = engine.compile(scope, "do.js", new String(Files.readAllBytes(Path.of("do.js"))));
|
||||||
|
return func.call(ctx);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new EngineException("Couldn't open do.js");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
task = engine.start();
|
task = engine.start();
|
||||||
var reader = new Thread(() -> {
|
var reader = new Thread(() -> {
|
||||||
@ -68,7 +78,7 @@ public class Main {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
var raw = in.readLine();
|
var raw = in.readLine();
|
||||||
|
|
||||||
if (raw == null) break;
|
if (raw == null) break;
|
||||||
engine.pushMsg(false, scope, Map.of(), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
engine.pushMsg(false, scope, Map.of(), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ public class CodeFrame {
|
|||||||
public final Object thisArg;
|
public final Object thisArg;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final List<Object> stack = new ArrayList<>();
|
public final List<Object> stack = new ArrayList<>();
|
||||||
|
public final List<TryContext> tryCtxs = new ArrayList<>();
|
||||||
public final CodeFunction function;
|
public final CodeFunction function;
|
||||||
|
|
||||||
public int codePtr = 0;
|
public int codePtr = 0;
|
||||||
@ -47,7 +48,7 @@ public class CodeFrame {
|
|||||||
stack.add(stack.size(), Values.normalize(val));
|
stack.add(stack.size(), Values.normalize(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanup(CallContext ctx) {
|
public void cleanup(CallContext ctx) {
|
||||||
stack.clear();
|
stack.clear();
|
||||||
codePtr = 0;
|
codePtr = 0;
|
||||||
debugCmd = null;
|
debugCmd = null;
|
||||||
@ -61,7 +62,7 @@ public class CodeFrame {
|
|||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
||||||
|
|
||||||
if (debugCmd == null) {
|
if (debugCmd == null) {
|
||||||
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 1000))
|
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 100000))
|
||||||
throw EngineException.ofRange("Stack overflow!");
|
throw EngineException.ofRange("Stack overflow!");
|
||||||
ctx.changeData(STACK_N_KEY);
|
ctx.changeData(STACK_N_KEY);
|
||||||
|
|
||||||
@ -72,7 +73,10 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
||||||
|
if (codePtr < 0 || codePtr >= function.body.length) return null;
|
||||||
|
|
||||||
var instr = function.body[codePtr];
|
var instr = function.body[codePtr];
|
||||||
|
|
||||||
var loc = instr.location;
|
var loc = instr.location;
|
||||||
if (loc != null) prevLoc = loc;
|
if (loc != null) prevLoc = loc;
|
||||||
|
|
||||||
@ -92,73 +96,80 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var res = Runners.exec(debugCmd, instr, this, ctx);
|
return Runners.exec(debugCmd, instr, this, ctx);
|
||||||
if (res != Runners.NO_RETURN) cleanup(ctx);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
cleanup(ctx);
|
|
||||||
throw e.add(function.name, prevLoc);
|
throw e.add(function.name, prevLoc);
|
||||||
}
|
}
|
||||||
catch (RuntimeException e) {
|
|
||||||
cleanup(ctx);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object run(CallContext ctx) throws InterruptedException {
|
public Object run(CallContext ctx) throws InterruptedException {
|
||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
DebugCommand command = ctx.getData(STOP_AT_START_KEY, false) ? DebugCommand.STEP_OVER : DebugCommand.NORMAL;
|
|
||||||
|
|
||||||
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 200)) throw EngineException.ofRange("Stack overflow!");
|
|
||||||
ctx.changeData(STACK_N_KEY);
|
|
||||||
|
|
||||||
if (debugState != null) debugState.pushFrame(this);
|
|
||||||
|
|
||||||
Location loc = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (codePtr >= 0 && codePtr < function.body.length) {
|
while (true) {
|
||||||
var _loc = function.body[codePtr].location;
|
var res = next(ctx);
|
||||||
if (_loc != null) loc = _loc;
|
if (res != Runners.NO_RETURN) return res;
|
||||||
|
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
|
||||||
var instr = function.body[codePtr];
|
|
||||||
|
|
||||||
if (debugState != null && loc != null) {
|
|
||||||
if (
|
|
||||||
instr.type == Type.NOP && instr.match("debug") ||
|
|
||||||
(
|
|
||||||
(command == DebugCommand.STEP_INTO || command == DebugCommand.STEP_OVER) &&
|
|
||||||
ctx.getData(STEPPING_TROUGH_KEY, false)
|
|
||||||
) ||
|
|
||||||
debugState.breakpoints.contains(loc)
|
|
||||||
) {
|
|
||||||
ctx.setData(STEPPING_TROUGH_KEY, true);
|
|
||||||
|
|
||||||
debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
|
||||||
command = debugState.commandNotifier.toAwaitable().await();
|
|
||||||
if (command == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var res = Runners.exec(command, instr, this, ctx);
|
|
||||||
if (res != Runners.NO_RETURN) return res;
|
|
||||||
}
|
|
||||||
catch (EngineException e) {
|
|
||||||
throw e.add(function.name, instr.location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
// catch (StackOverflowError e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// throw EngineException.ofRange("Stack overflow!").add(function.name, loc);
|
|
||||||
// }
|
|
||||||
finally {
|
finally {
|
||||||
ctx.changeData(STACK_N_KEY, -1);
|
cleanup(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
||||||
|
// DebugCommand command = ctx.getData(STOP_AT_START_KEY, false) ? DebugCommand.STEP_OVER : DebugCommand.NORMAL;
|
||||||
|
|
||||||
|
// if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 200)) throw EngineException.ofRange("Stack overflow!");
|
||||||
|
// ctx.changeData(STACK_N_KEY);
|
||||||
|
|
||||||
|
// if (debugState != null) debugState.pushFrame(this);
|
||||||
|
|
||||||
|
// Location loc = null;
|
||||||
|
|
||||||
|
|
||||||
|
// Location loc = null;
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// while (codePtr >= 0 && codePtr < function.body.length) {
|
||||||
|
// var _loc = function.body[codePtr].location;
|
||||||
|
// if (_loc != null) loc = _loc;
|
||||||
|
|
||||||
|
// if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
||||||
|
// var instr = function.body[codePtr];
|
||||||
|
|
||||||
|
// if (debugState != null && loc != null) {
|
||||||
|
// if (
|
||||||
|
// instr.type == Type.NOP && instr.match("debug") ||
|
||||||
|
// (
|
||||||
|
// (command == DebugCommand.STEP_INTO || command == DebugCommand.STEP_OVER) &&
|
||||||
|
// ctx.getData(STEPPING_TROUGH_KEY, false)
|
||||||
|
// ) ||
|
||||||
|
// debugState.breakpoints.contains(loc)
|
||||||
|
// ) {
|
||||||
|
// ctx.setData(STEPPING_TROUGH_KEY, true);
|
||||||
|
|
||||||
|
// debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
||||||
|
// command = debugState.commandNotifier.toAwaitable().await();
|
||||||
|
// if (command == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// var res = Runners.exec(command, instr, this, ctx);
|
||||||
|
// if (res != Runners.NO_RETURN) return res;
|
||||||
|
// }
|
||||||
|
// catch (EngineException e) {
|
||||||
|
// throw e.add(function.name, instr.location);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// // catch (StackOverflowError e) {
|
||||||
|
// // e.printStackTrace();
|
||||||
|
// // throw EngineException.ofRange("Stack overflow!").add(function.name, loc);
|
||||||
|
// // }
|
||||||
|
// finally {
|
||||||
|
// ctx.changeData(STACK_N_KEY, -1);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFrame(Object thisArg, Object[] args, CodeFunction func) {
|
public CodeFrame(Object thisArg, Object[] args, CodeFunction func) {
|
||||||
|
@ -56,7 +56,7 @@ public class ModuleManager {
|
|||||||
if (realName == null) return null;
|
if (realName == null) return null;
|
||||||
if (cache.containsKey(realName)) return cache.get(realName);
|
if (cache.containsKey(realName)) return cache.get(realName);
|
||||||
var mod = files.getModule(cwd, name);
|
var mod = files.getModule(cwd, name);
|
||||||
// cache.put(mod.name(), mod);
|
cache.put(mod.name(), mod);
|
||||||
mod.execute(ctx);
|
mod.execute(ctx);
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ public class ModuleManager {
|
|||||||
if (realName == null) continue;
|
if (realName == null) continue;
|
||||||
if (cache.containsKey(realName)) return cache.get(realName);
|
if (cache.containsKey(realName)) return cache.get(realName);
|
||||||
var mod = provider.getModule(cwd, name);
|
var mod = provider.getModule(cwd, name);
|
||||||
// cache.put(mod.name(), mod);
|
cache.put(mod.name(), mod);
|
||||||
mod.execute(ctx);
|
mod.execute(ctx);
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import me.topchetoeu.jscript.engine.CallContext;
|
|||||||
|
|
||||||
public class NativeFunction extends FunctionValue {
|
public class NativeFunction extends FunctionValue {
|
||||||
public static interface NativeFunctionRunner {
|
public static interface NativeFunctionRunner {
|
||||||
Object run(CallContext ctx, Object thisArg, Object[] values) throws InterruptedException;
|
Object run(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final NativeFunctionRunner action;
|
public final NativeFunctionRunner action;
|
||||||
@ -18,4 +18,8 @@ public class NativeFunction extends FunctionValue {
|
|||||||
super(name, 0);
|
super(name, 0);
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
public NativeFunction(NativeFunctionRunner action) {
|
||||||
|
super("", 0);
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,19 +391,21 @@ public class Values {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof ArrayValue) {
|
if (obj instanceof ArrayValue) {
|
||||||
var raw = array(obj).toArray();
|
|
||||||
|
|
||||||
if (clazz.isAssignableFrom(ArrayList.class)) {
|
if (clazz.isAssignableFrom(ArrayList.class)) {
|
||||||
|
var raw = array(obj).toArray();
|
||||||
var res = new ArrayList<>();
|
var res = new ArrayList<>();
|
||||||
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
||||||
return (T)new ArrayList<>(res);
|
return (T)new ArrayList<>(res);
|
||||||
}
|
}
|
||||||
if (clazz.isAssignableFrom(HashSet.class)) {
|
if (clazz.isAssignableFrom(HashSet.class)) {
|
||||||
|
var raw = array(obj).toArray();
|
||||||
var res = new HashSet<>();
|
var res = new HashSet<>();
|
||||||
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
||||||
return (T)new HashSet<>(res);
|
return (T)new HashSet<>(res);
|
||||||
}
|
}
|
||||||
if (clazz.isArray()) {
|
if (clazz.isArray()) {
|
||||||
|
var raw = array(obj).toArray();
|
||||||
Object res = Array.newInstance(clazz.arrayType(), raw.length);
|
Object res = Array.newInstance(clazz.arrayType(), raw.length);
|
||||||
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ctx, raw[i], Object.class));
|
||||||
return (T)res;
|
return (T)res;
|
||||||
|
76
src/me/topchetoeu/jscript/js/bootstrap.js
vendored
76
src/me/topchetoeu/jscript/js/bootstrap.js
vendored
@ -1,7 +1,8 @@
|
|||||||
// TODO: load this in java
|
// TODO: load this in java
|
||||||
var ts = require('./ts__');
|
var ts = require('./ts__');
|
||||||
|
log("Loaded typescript!");
|
||||||
|
|
||||||
var src = '', lib = libs.join(''), decls = [], version = 0;
|
var src = '', lib = libs.join(''), decls = '', version = 0;
|
||||||
var libSnapshot = ts.ScriptSnapshot.fromString(lib);
|
var libSnapshot = ts.ScriptSnapshot.fromString(lib);
|
||||||
|
|
||||||
var settings = {
|
var settings = {
|
||||||
@ -9,7 +10,7 @@ var settings = {
|
|||||||
declarationDir: "/out",
|
declarationDir: "/out",
|
||||||
target: ts.ScriptTarget.ES5,
|
target: ts.ScriptTarget.ES5,
|
||||||
lib: [ ],
|
lib: [ ],
|
||||||
module: ts.ModuleKind.CommonJS,
|
module: ts.ModuleKind.None,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
stripInternal: true,
|
stripInternal: true,
|
||||||
downlevelIteration: true,
|
downlevelIteration: true,
|
||||||
@ -20,41 +21,17 @@ var settings = {
|
|||||||
|
|
||||||
var reg = ts.createDocumentRegistry();
|
var reg = ts.createDocumentRegistry();
|
||||||
var service = ts.createLanguageService({
|
var service = ts.createLanguageService({
|
||||||
getCanonicalFileName: function (fileName) { return fileName; },
|
|
||||||
useCaseSensitiveFileNames: function () { return true; },
|
|
||||||
getNewLine: function () { return "\n"; },
|
|
||||||
getEnvironmentVariable: function () { return ""; },
|
|
||||||
|
|
||||||
log: function() {
|
|
||||||
log.apply(undefined, arguments);
|
|
||||||
},
|
|
||||||
fileExists: function (fileName) {
|
|
||||||
return (
|
|
||||||
fileName === "/src.ts" ||
|
|
||||||
fileName === "/lib.d.ts" ||
|
|
||||||
fileName === "/glob.d.ts"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
readFile: function (fileName) {
|
|
||||||
if (fileName === "/src.ts") return src;
|
|
||||||
if (fileName === "/lib.d.ts") return lib;
|
|
||||||
if (fileName === "/glob.d.ts") return decls.join('\n');
|
|
||||||
throw new Error("File '" + fileName + "' doesn't exist.");
|
|
||||||
},
|
|
||||||
writeFile: function (fileName, data) {
|
|
||||||
if (fileName.endsWith(".js")) res = data;
|
|
||||||
else if (fileName.endsWith(".d.ts")) decls.push(data);
|
|
||||||
else throw new Error("File '" + fileName + "' isn't writable.");
|
|
||||||
},
|
|
||||||
getCompilationSettings: function () {
|
|
||||||
return settings;
|
|
||||||
},
|
|
||||||
getCurrentDirectory: function() { return "/"; },
|
getCurrentDirectory: function() { return "/"; },
|
||||||
getDefaultLibFileName: function() { return "/lib_.d.ts"; },
|
getDefaultLibFileName: function() { return "/lib_.d.ts"; },
|
||||||
getScriptFileNames: function() { return [ "/src.ts", "/lib.d.ts", "/glob.d.ts" ]; },
|
getScriptFileNames: function() { return [ "/src.ts", "/lib.d.ts", "/glob.d.ts" ]; },
|
||||||
|
getCompilationSettings: function () { return settings; },
|
||||||
|
fileExists: function(filename) { return filename === "/lib.d.ts" || filename === "/src.ts" || filename === "/glob.d.ts"; },
|
||||||
|
|
||||||
getScriptSnapshot: function(filename) {
|
getScriptSnapshot: function(filename) {
|
||||||
if (filename === "/lib.d.ts") return libSnapshot;
|
if (filename === "/lib.d.ts") return libSnapshot;
|
||||||
else return ts.ScriptSnapshot.fromString(this.readFile(filename));
|
if (filename === "/src.ts") return ts.ScriptSnapshot.fromString(src);
|
||||||
|
if (filename === "/glob.d.ts") return ts.ScriptSnapshot.fromString(decls);
|
||||||
|
throw new Error("File '" + filename + "' doesn't exist.");
|
||||||
},
|
},
|
||||||
getScriptVersion: function (filename) {
|
getScriptVersion: function (filename) {
|
||||||
if (filename === "/lib.d.ts") return 0;
|
if (filename === "/lib.d.ts") return 0;
|
||||||
@ -65,16 +42,11 @@ var service = ts.createLanguageService({
|
|||||||
service.getEmitOutput('/lib.d.ts');
|
service.getEmitOutput('/lib.d.ts');
|
||||||
log('Loaded libraries!');
|
log('Loaded libraries!');
|
||||||
|
|
||||||
|
function compile(filename, code) {
|
||||||
function compile(code) {
|
src = code, version++;
|
||||||
src = code;
|
|
||||||
version++;
|
|
||||||
|
|
||||||
var emit = service.getEmitOutput("/src.ts");
|
var emit = service.getEmitOutput("/src.ts");
|
||||||
|
|
||||||
var res = emit.outputFiles[0].text;
|
|
||||||
var decl = emit.outputFiles[1].text;
|
|
||||||
|
|
||||||
var diagnostics = []
|
var diagnostics = []
|
||||||
.concat(service.getCompilerOptionsDiagnostics())
|
.concat(service.getCompilerOptionsDiagnostics())
|
||||||
.concat(service.getSyntacticDiagnostics("/src.ts"))
|
.concat(service.getSyntacticDiagnostics("/src.ts"))
|
||||||
@ -83,7 +55,9 @@ function compile(code) {
|
|||||||
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||||
if (diagnostic.file) {
|
if (diagnostic.file) {
|
||||||
var pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
var pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||||
return diagnostic.file.fileName.substring(1) + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message;
|
var file = diagnostic.file.fileName.substring(1);
|
||||||
|
if (file === "src.ts") file = filename;
|
||||||
|
return file + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message;
|
||||||
}
|
}
|
||||||
else return "Error: " + message;
|
else return "Error: " + message;
|
||||||
});
|
});
|
||||||
@ -92,17 +66,21 @@ function compile(code) {
|
|||||||
throw new SyntaxError(diagnostics.join('\n'));
|
throw new SyntaxError(diagnostics.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
decls.push(decl);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: res,
|
result: emit.outputFiles[0].text,
|
||||||
diagnostics: diagnostics
|
declaration: emit.outputFiles[1].text
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Loaded typescript!");
|
init(function (filename, code) {
|
||||||
init(function (code) {
|
var res = compile(filename, code);
|
||||||
var res = compile(code);
|
|
||||||
return res.result;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
res.result,
|
||||||
|
function(func, th, args) {
|
||||||
|
var val = func.apply(th, args);
|
||||||
|
decls += res.declaration;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
@ -68,7 +68,7 @@ public class Parsing {
|
|||||||
reserved.add("yield");
|
reserved.add("yield");
|
||||||
// Although the standards allow it, these are keywords in newer ES, so we won't allow them
|
// Although the standards allow it, these are keywords in newer ES, so we won't allow them
|
||||||
reserved.add("const");
|
reserved.add("const");
|
||||||
reserved.add("await");
|
// reserved.add("await");
|
||||||
reserved.add("async");
|
reserved.add("async");
|
||||||
// These are allowed too, however our parser considers them keywords
|
// These are allowed too, however our parser considers them keywords
|
||||||
reserved.add("undefined");
|
reserved.add("undefined");
|
||||||
|
87
src/me/topchetoeu/jscript/polyfills/AsyncFunction.java
Normal file
87
src/me/topchetoeu/jscript/polyfills/AsyncFunction.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
|
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
|
public class AsyncFunction extends FunctionValue {
|
||||||
|
public final CodeFunction body;
|
||||||
|
|
||||||
|
private class CallHandler {
|
||||||
|
private boolean awaiting = false;
|
||||||
|
private Object awaited = null;
|
||||||
|
public final Promise promise = new Promise();
|
||||||
|
public CodeFrame frame;
|
||||||
|
private final NativeFunction fulfillFunc = new NativeFunction("", this::fulfill);
|
||||||
|
private final NativeFunction rejectFunc = new NativeFunction("", this::reject);
|
||||||
|
|
||||||
|
private Object reject(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException {
|
||||||
|
if (args.length > 0) promise.reject(ctx, args[0]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public Object fulfill(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException {
|
||||||
|
if (args.length == 1) frame.push(args[0]);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
awaiting = false;
|
||||||
|
awaited = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var res = frame.next(ctx);
|
||||||
|
if (res != Runners.NO_RETURN) {
|
||||||
|
promise.fulfill(ctx, res);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (EngineException e) {
|
||||||
|
promise.reject(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!awaiting) continue;
|
||||||
|
|
||||||
|
frame.pop();
|
||||||
|
|
||||||
|
if (awaited instanceof Promise) ((Promise)awaited).then(ctx, fulfillFunc, rejectFunc);
|
||||||
|
else if (Values.isPrimitive(awaited)) frame.push(awaited);
|
||||||
|
try {
|
||||||
|
var res = Values.getMember(ctx, awaited, "then");
|
||||||
|
if (res instanceof FunctionValue) {
|
||||||
|
Values.function(res).call(ctx, awaited, fulfillFunc, rejectFunc);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else frame.push(awaited);
|
||||||
|
}
|
||||||
|
catch (EngineException e) {
|
||||||
|
promise.reject(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object await(CallContext ctx, Object thisArg, Object[] args) {
|
||||||
|
this.awaiting = true;
|
||||||
|
this.awaited = args[0];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object call(CallContext _ctx, Object thisArg, Object... args) throws InterruptedException {
|
||||||
|
var handler = new CallHandler();
|
||||||
|
handler.frame = new CodeFrame(thisArg, new Object[] { new NativeFunction("await", handler::await), new ArrayValue(args) }, body);
|
||||||
|
handler.fulfill(_ctx, null, new Object[0]);
|
||||||
|
return handler.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncFunction(CodeFunction body) {
|
||||||
|
super(body.name, body.length);
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
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.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
@ -235,6 +236,12 @@ public class Internals {
|
|||||||
return res.exports();
|
return res.exports();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Native
|
||||||
|
public AsyncFunction makeAsync(FunctionValue func) {
|
||||||
|
if (func instanceof CodeFunction) return new AsyncFunction((CodeFunction)func);
|
||||||
|
else throw EngineException.ofType("Can't create an async function with a non-js function.");
|
||||||
|
}
|
||||||
|
|
||||||
@NativeGetter("err")
|
@NativeGetter("err")
|
||||||
public ObjectValue errProto(CallContext ctx) {
|
public ObjectValue errProto(CallContext ctx) {
|
||||||
return ctx.engine.errorProto();
|
return ctx.engine.errorProto();
|
||||||
|
@ -203,11 +203,11 @@ public class Promise {
|
|||||||
public void fulfill(CallContext ctx, Object val) {
|
public void fulfill(CallContext ctx, Object val) {
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
new NativeFunction(null, (e, th, args) -> {
|
||||||
this.fulfill(args[0]);
|
this.fulfill(e, args[0]);
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
new NativeFunction(null, (e, th, args) -> {
|
||||||
this.reject(args[0]);
|
this.reject(e, args[0]);
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -231,11 +231,11 @@ public class Promise {
|
|||||||
public void reject(CallContext ctx, Object val) {
|
public void reject(CallContext ctx, Object val) {
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
new NativeFunction(null, (e, th, args) -> {
|
||||||
this.reject(args[0]);
|
this.reject(e, args[0]);
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
new NativeFunction(null, (e, th, args) -> {
|
||||||
this.reject(args[0]);
|
this.reject(e, args[0]);
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -6,16 +6,26 @@ import java.util.Map;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
||||||
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.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
|
||||||
public class TypescriptEngine extends PolyfillEngine {
|
public class TypescriptEngine extends PolyfillEngine {
|
||||||
private FunctionValue ts;
|
private FunctionValue ts;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeFunction compile(GlobalScope scope, String filename, String raw) throws InterruptedException {
|
public FunctionValue compile(GlobalScope scope, String filename, String raw) throws InterruptedException {
|
||||||
if (ts != null) raw = (String)ts.call(context(), null, raw);
|
if (ts != null) {
|
||||||
|
var res = Values.array(ts.call(context(), null, filename, raw));
|
||||||
|
var src = Values.toString(context(), res.get(0));
|
||||||
|
var func = Values.function(res.get(1));
|
||||||
|
|
||||||
|
var compiled = super.compile(scope, filename, src);
|
||||||
|
|
||||||
|
return new NativeFunction(null, (ctx, thisArg, args) -> {
|
||||||
|
return func.call(context(), null, compiled, thisArg, new ArrayValue(args));
|
||||||
|
});
|
||||||
|
}
|
||||||
return super.compile(scope, filename, raw);
|
return super.compile(scope, filename, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +52,7 @@ public class TypescriptEngine extends PolyfillEngine {
|
|||||||
|
|
||||||
scope.define("libs", true, ArrayValue.of(decls));
|
scope.define("libs", true, ArrayValue.of(decls));
|
||||||
scope.define(true, new NativeFunction("init", (el, t, args) -> {
|
scope.define(true, new NativeFunction("init", (el, t, args) -> {
|
||||||
ts = (FunctionValue)args[0];
|
ts = Values.function(args[0]);
|
||||||
return null;
|
return null;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user