Compare commits
5 Commits
v0.10.8-be
...
v0.10.9-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
1670b64aaf
|
|||
|
1548938537
|
|||
|
e14d85e7a8
|
|||
|
4352550ae9
|
|||
|
3c4d05abd4
|
@@ -1,4 +1,4 @@
|
||||
project_group = me.topchetoeu.j2s
|
||||
project_name = j2s
|
||||
project_version = 0.10.8-beta
|
||||
project_version = 0.10.9-beta
|
||||
main_class = me.topchetoeu.j2s.repl.SimpleRepl
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-transform-class-properties": "^7.25.9",
|
||||
"@babel/plugin-transform-runtime": "^7.25.9",
|
||||
"@babel/plugin-transform-typescript": "^7.25.9",
|
||||
|
||||
@@ -34,7 +34,6 @@ const construct = (input, output) => defineConfig({
|
||||
optimizeConstEnums: true,
|
||||
allowDeclareFields: true,
|
||||
}],
|
||||
["@babel/plugin-transform-class-properties"],
|
||||
["@babel/plugin-transform-runtime", {
|
||||
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
|
||||
version: "^7.24.0",
|
||||
@@ -48,6 +47,7 @@ const construct = (input, output) => defineConfig({
|
||||
assumptions: {
|
||||
ignoreToPrimitiveHint: true,
|
||||
noClassCalls: true,
|
||||
privateFieldsAsProperties: true,
|
||||
},
|
||||
|
||||
env: {
|
||||
@@ -77,7 +77,8 @@ const construct = (input, output) => defineConfig({
|
||||
"@babel/plugin-transform-optional-chaining",
|
||||
"@babel/plugin-transform-logical-assignment-operators",
|
||||
"@babel/plugin-transform-numeric-separator",
|
||||
"@babel/plugin-transform-class-properties",
|
||||
"@babel/plugin-transform-private-methods",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-transform-class-static-block",
|
||||
"@babel/plugin-transform-regenerator",
|
||||
|
||||
|
||||
13
lib/src/lib/async.d.ts
vendored
13
lib/src/lib/async.d.ts
vendored
@@ -22,3 +22,16 @@ declare interface PromiseConstructor {
|
||||
resolve<T>(val: T): Promise<Awaited<T>>;
|
||||
reject<T>(err: unknown): Promise<T>;
|
||||
}
|
||||
|
||||
declare interface AsyncIterator<T, Return = unknown, Next = unknown> {
|
||||
next(): Promise<IterationData<T, Return>>;
|
||||
next(val: Next): Promise<IterationData<T, Return>>;
|
||||
error?(err: unknown): Promise<IterationData<T, Return>>;
|
||||
return?(val: Return): Promise<IterationData<T, Return>>;
|
||||
}
|
||||
declare interface AsyncIterableIterator<T, Return = unknown, Next = unknown> extends AsyncIterator<T, Return, Next> {
|
||||
[Symbol.iterator](): this;
|
||||
}
|
||||
declare interface AsyncIterable<T> {
|
||||
[Symbol.iterator](): AsyncIterator<T>;
|
||||
}
|
||||
|
||||
6
lib/src/lib/iterator.d.ts
vendored
6
lib/src/lib/iterator.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
declare interface NormalIterationData<T> {
|
||||
value: T;
|
||||
done: true;
|
||||
done: false;
|
||||
}
|
||||
declare interface DoneIterationData<T> {
|
||||
value: T;
|
||||
done?: false;
|
||||
done?: true;
|
||||
}
|
||||
declare type IterationData<T, Return> = NormalIterationData<T> | DoneIterationData<Return>;
|
||||
declare type IterationData<T, Return = void> = NormalIterationData<T> | DoneIterationData<Return>;
|
||||
|
||||
declare interface Iterator<T, Return = unknown, Next = unknown> {
|
||||
next(): IterationData<T, Return>;
|
||||
|
||||
@@ -59,6 +59,8 @@ public class Compilers {
|
||||
|
||||
public static Compiler transpilerFromSource(Compiler prev, Environment target, Filename compilerName, String compilerSrc) {
|
||||
var env = StdLib.apply(null);
|
||||
// var handler = new SimpleDebugHandler();
|
||||
// env.add(DebugHandler.KEY, handler);
|
||||
|
||||
var glob = Value.global(env);
|
||||
var compilerFactory = new FunctionValue[1];
|
||||
@@ -83,10 +85,20 @@ public class Compilers {
|
||||
}));
|
||||
|
||||
var compiled = JavaScript.compile(compilerName, compilerSrc, false);
|
||||
new CodeFunction(env, "intializer", compiled.body(), new Value[0][]).apply(env, Value.UNDEFINED);
|
||||
|
||||
// for (var el : compiled.all()) {
|
||||
// handler.onFunctionLoad(el.body(), el.map());
|
||||
// }
|
||||
|
||||
try {
|
||||
new CodeFunction(env, "intializer", compiled.body(), new Value[0][]).apply(env, Value.UNDEFINED);
|
||||
return wrap(prev, env, target, compilerFactory[0]);
|
||||
}
|
||||
catch (EngineException e) {
|
||||
System.out.println(Value.errorToReadable(env, e, "in transpiler initializer"));
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
public static Compiler babelCompiler(Compiler prev, Environment target) {
|
||||
return transpilerFromSource(prev, target,
|
||||
@@ -111,7 +123,7 @@ public class Compilers {
|
||||
Compiler create(Compiler prev, Environment target);
|
||||
}
|
||||
|
||||
public static Compiler chainTranspilers(Environment target, Compiler base, TranspilerFactory ...factories) {
|
||||
public static Compiler chainTranspilers(Compiler base, Environment target, TranspilerFactory ...factories) {
|
||||
var res = base;
|
||||
|
||||
for (var el : factories) {
|
||||
|
||||
@@ -690,5 +690,4 @@ public class Primordials {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,24 +6,36 @@ import me.topchetoeu.j2s.common.Metadata;
|
||||
import me.topchetoeu.j2s.common.Reading;
|
||||
import me.topchetoeu.j2s.compilation.CompileResult;
|
||||
import me.topchetoeu.j2s.compilation.JavaScript;
|
||||
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
||||
import me.topchetoeu.j2s.runtime.values.Value;
|
||||
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
|
||||
|
||||
public class StdLib {
|
||||
private static final CompileResult RUNNER = JavaScript.compile(new Filename(Metadata.name(), "init.js"), Reading.resourceToString("lib/stdlib.js"), false);
|
||||
private static final CompileResult RUNNER = JavaScript.compile(
|
||||
new Filename(Metadata.name(), "init.js"),
|
||||
Reading.resourceToString("lib/stdlib.js"), false
|
||||
);
|
||||
|
||||
public static Environment apply(Environment env) {
|
||||
if (env == null) {
|
||||
public static Environment apply(Environment env, CompileResult body) {
|
||||
env = new Environment();
|
||||
}
|
||||
|
||||
var stubEnv = new Environment();
|
||||
Value.global(stubEnv).defineOwnField(stubEnv, "target", Value.global(env));
|
||||
Value.global(stubEnv).defineOwnField(stubEnv, "primordials", Primordials.create(env));
|
||||
|
||||
var func = new CodeFunction(stubEnv, "intializer", RUNNER.body(), new Value[0][]);
|
||||
var func = new CodeFunction(stubEnv, "intializer", body.body(), new Value[0][]);
|
||||
try {
|
||||
func.apply(stubEnv, Value.UNDEFINED);
|
||||
}
|
||||
catch (EngineException e) {
|
||||
System.out.println(Value.errorToReadable(env, e, "in environment initializer"));
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
public static Environment apply(Environment env) {
|
||||
if (env == null) env = new Environment();
|
||||
return apply(env, RUNNER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -15,7 +15,7 @@ import me.topchetoeu.j2s.common.SyntaxException;
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONList;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
import me.topchetoeu.j2s.repl.debug.WebSocketMessage.Type;
|
||||
import me.topchetoeu.j2s.lib.debug.WebSocketMessage.Type;
|
||||
|
||||
public class DebugServer {
|
||||
public static String browserDisplayName = Metadata.name() + "/" + Metadata.version();
|
||||
37
lib/src/main/java/me/topchetoeu/j2s/lib/debug/Debugger.java
Normal file
37
lib/src/main/java/me/topchetoeu/j2s/lib/debug/Debugger.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
|
||||
|
||||
public interface Debugger extends DebugHandler {
|
||||
void close();
|
||||
|
||||
void enable(V8Message msg) throws IOException;
|
||||
void disable(V8Message msg) throws IOException;
|
||||
|
||||
void setBreakpointByUrl(V8Message msg) throws IOException;
|
||||
void removeBreakpoint(V8Message msg) throws IOException;
|
||||
void continueToLocation(V8Message msg) throws IOException;
|
||||
|
||||
void getScriptSource(V8Message msg) throws IOException;
|
||||
void getPossibleBreakpoints(V8Message msg) throws IOException;
|
||||
|
||||
void resume(V8Message msg) throws IOException;
|
||||
void pause(V8Message msg) throws IOException;
|
||||
|
||||
void stepInto(V8Message msg) throws IOException;
|
||||
void stepOut(V8Message msg) throws IOException;
|
||||
void stepOver(V8Message msg) throws IOException;
|
||||
|
||||
void setPauseOnExceptions(V8Message msg) throws IOException;
|
||||
|
||||
void evaluateOnCallFrame(V8Message msg) throws IOException;
|
||||
|
||||
void getProperties(V8Message msg) throws IOException;
|
||||
void releaseObjectGroup(V8Message msg) throws IOException;
|
||||
void releaseObject(V8Message msg) throws IOException;
|
||||
void callFunctionOn(V8Message msg) throws IOException;
|
||||
|
||||
void runtimeEnable(V8Message msg) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
public interface DebuggerProvider {
|
||||
Debugger getDebugger(WebSocket socket, HttpRequest req);
|
||||
}
|
||||
100
lib/src/main/java/me/topchetoeu/j2s/lib/debug/HttpRequest.java
Normal file
100
lib/src/main/java/me/topchetoeu/j2s/lib/debug/HttpRequest.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.IllegalFormatException;
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.j2s.common.Reading;
|
||||
|
||||
public class HttpRequest {
|
||||
public final String method;
|
||||
public final String path;
|
||||
public final Map<String, String> headers;
|
||||
public final OutputStream out;
|
||||
|
||||
public void writeCode(int code, String name) {
|
||||
try { out.write(("HTTP/1.1 " + code + " " + name + "\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeHeader(String name, String value) {
|
||||
try { out.write((name + ": " + value + "\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeLastHeader(String name, String value) {
|
||||
try { out.write((name + ": " + value + "\r\n\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeHeadersEnd() {
|
||||
try { out.write("\n".getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
|
||||
public void writeResponse(int code, String name, String type, byte[] data) {
|
||||
writeCode(code, name);
|
||||
writeHeader("Content-Type", type);
|
||||
writeLastHeader("Content-Length", data.length + "");
|
||||
try {
|
||||
out.write(data);
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeResponse(int code, String name, String type, InputStream data) {
|
||||
writeResponse(code, name, type, Reading.streamToBytes(data));
|
||||
}
|
||||
|
||||
public HttpRequest(String method, String path, Map<String, String> headers, OutputStream out) {
|
||||
this.method = method;
|
||||
this.path = path;
|
||||
this.headers = headers;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
// We dont need no http library
|
||||
public static HttpRequest read(Socket socket) {
|
||||
try {
|
||||
var str = socket.getInputStream();
|
||||
var lines = new BufferedReader(new InputStreamReader(str));
|
||||
var line = lines.readLine();
|
||||
var i1 = line.indexOf(" ");
|
||||
var i2 = line.indexOf(" ", i1 + 1);
|
||||
|
||||
if (i1 < 0 || i2 < 0) {
|
||||
socket.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = line.substring(0, i1).trim().toUpperCase();
|
||||
var path = line.substring(i1 + 1, i2).trim();
|
||||
var headers = new HashMap<String, String>();
|
||||
|
||||
while (!(line = lines.readLine()).isEmpty()) {
|
||||
var i = line.indexOf(":");
|
||||
if (i < 0) continue;
|
||||
var name = line.substring(0, i).trim().toLowerCase();
|
||||
var value = line.substring(i + 1).trim();
|
||||
|
||||
if (name.length() == 0) continue;
|
||||
headers.put(name, value);
|
||||
}
|
||||
|
||||
if (headers.containsKey("content-length")) {
|
||||
try {
|
||||
var i = Integer.parseInt(headers.get("content-length"));
|
||||
str.skip(i);
|
||||
}
|
||||
catch (IllegalFormatException e) { /* ¯\_(ツ)_/¯ */ }
|
||||
}
|
||||
|
||||
return new HttpRequest(method, path, headers, socket.getOutputStream());
|
||||
}
|
||||
catch (IOException | NullPointerException e) { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.WeakHashMap;
|
||||
@@ -69,14 +69,8 @@ public class SimpleDebugHandler implements DebugHandler {
|
||||
if (debugger != null) debugger.onFunctionLoad(func, map);
|
||||
}
|
||||
|
||||
private SimpleDebugHandler(boolean enabled) {
|
||||
if (enabled) {
|
||||
public SimpleDebugHandler() {
|
||||
sources = new HashMap<>();
|
||||
maps = new WeakHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleDebugHandler() {
|
||||
this(true);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import me.topchetoeu.j2s.common.Environment;
|
||||
import me.topchetoeu.j2s.runtime.Frame;
|
||||
19
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Error.java
Normal file
19
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Error.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Error {
|
||||
public final String message;
|
||||
|
||||
public V8Error(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap().set("error", new JSONMap()
|
||||
.set("message", message)
|
||||
));
|
||||
}
|
||||
}
|
||||
22
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Event.java
Normal file
22
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Event.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Event {
|
||||
public final String name;
|
||||
public final JSONMap params;
|
||||
|
||||
public V8Event(String name, JSONMap params) {
|
||||
this.name = name;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("method", name)
|
||||
.set("params", params)
|
||||
);
|
||||
}
|
||||
}
|
||||
50
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Message.java
Normal file
50
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Message.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONElement;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Message {
|
||||
public final String name;
|
||||
public final int id;
|
||||
public final JSONMap params;
|
||||
|
||||
public V8Message(String name, int id, Map<String, JSONElement> params) {
|
||||
this.name = name;
|
||||
this.params = new JSONMap(params);
|
||||
this.id = id;
|
||||
}
|
||||
public V8Result respond(JSONMap result) {
|
||||
return new V8Result(id, result);
|
||||
}
|
||||
public V8Result respond() {
|
||||
return new V8Result(id, new JSONMap());
|
||||
}
|
||||
|
||||
public V8Message(JSONMap raw) {
|
||||
if (!raw.isNumber("id")) throw new IllegalArgumentException("Expected number property 'id'.");
|
||||
if (!raw.isString("method")) throw new IllegalArgumentException("Expected string property 'method'.");
|
||||
|
||||
this.name = raw.string("method");
|
||||
this.id = (int)raw.number("id");
|
||||
this.params = raw.contains("params") ? raw.map("params") : new JSONMap();
|
||||
}
|
||||
public V8Message(String raw) {
|
||||
this(JSON.parse(null, raw).map());
|
||||
}
|
||||
|
||||
public JSONMap toMap() {
|
||||
var res = new JSONMap();
|
||||
return res;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("method", name)
|
||||
.set("params", params)
|
||||
.set("id", id)
|
||||
);
|
||||
}
|
||||
}
|
||||
22
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Result.java
Normal file
22
lib/src/main/java/me/topchetoeu/j2s/lib/debug/V8Result.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Result {
|
||||
public final int id;
|
||||
public final JSONMap result;
|
||||
|
||||
public V8Result(int id, JSONMap result) {
|
||||
this.id = id;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("id", id)
|
||||
.set("result", result)
|
||||
);
|
||||
}
|
||||
}
|
||||
186
lib/src/main/java/me/topchetoeu/j2s/lib/debug/WebSocket.java
Normal file
186
lib/src/main/java/me/topchetoeu/j2s/lib/debug/WebSocket.java
Normal file
@@ -0,0 +1,186 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import me.topchetoeu.j2s.lib.debug.WebSocketMessage.Type;
|
||||
|
||||
public class WebSocket implements AutoCloseable {
|
||||
public long maxLength = 1 << 20;
|
||||
|
||||
private Socket socket;
|
||||
private boolean closed = false;
|
||||
|
||||
private OutputStream out() throws IOException {
|
||||
return socket.getOutputStream();
|
||||
}
|
||||
private InputStream in() throws IOException {
|
||||
return socket.getInputStream();
|
||||
}
|
||||
|
||||
private long readLen(int byteLen) throws IOException {
|
||||
long res = 0;
|
||||
|
||||
if (byteLen == 126) {
|
||||
res |= in().read() << 8;
|
||||
res |= in().read();
|
||||
return res;
|
||||
}
|
||||
else if (byteLen == 127) {
|
||||
res |= in().read() << 56;
|
||||
res |= in().read() << 48;
|
||||
res |= in().read() << 40;
|
||||
res |= in().read() << 32;
|
||||
res |= in().read() << 24;
|
||||
res |= in().read() << 16;
|
||||
res |= in().read() << 8;
|
||||
res |= in().read();
|
||||
return res;
|
||||
}
|
||||
else return byteLen;
|
||||
}
|
||||
private byte[] readMask(boolean has) throws IOException {
|
||||
if (has) {
|
||||
return new byte[] {
|
||||
(byte)in().read(),
|
||||
(byte)in().read(),
|
||||
(byte)in().read(),
|
||||
(byte)in().read()
|
||||
};
|
||||
}
|
||||
else return new byte[4];
|
||||
}
|
||||
|
||||
private void writeLength(int len) throws IOException {
|
||||
if (len < 126) {
|
||||
out().write((int)len);
|
||||
}
|
||||
else if (len <= 0xFFFF) {
|
||||
out().write(126);
|
||||
out().write((int)(len >> 8) & 0xFF);
|
||||
out().write((int)len & 0xFF);
|
||||
}
|
||||
else {
|
||||
out().write(127);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write((len >> 24) & 0xFF);
|
||||
out().write((len >> 16) & 0xFF);
|
||||
out().write((len >> 8) & 0xFF);
|
||||
out().write(len & 0xFF);
|
||||
}
|
||||
}
|
||||
private synchronized void write(int type, byte[] data) throws IOException {
|
||||
out().write(type | 0x80);
|
||||
writeLength(data.length);
|
||||
out().write(data);
|
||||
}
|
||||
|
||||
public void send(String data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(1, data.getBytes());
|
||||
}
|
||||
public void send(byte[] data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(2, data);
|
||||
}
|
||||
public void send(WebSocketMessage msg) throws IOException {
|
||||
if (msg.type == Type.Binary) send(msg.binaryData());
|
||||
else send(msg.textData());
|
||||
}
|
||||
public void send(Object data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(1, data.toString().getBytes());
|
||||
}
|
||||
|
||||
public void close(String reason) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
write(8, reason.getBytes());
|
||||
socket.close();
|
||||
}
|
||||
catch (Throwable e) { }
|
||||
}
|
||||
|
||||
socket = null;
|
||||
closed = true;
|
||||
}
|
||||
public void close() {
|
||||
close("");
|
||||
}
|
||||
|
||||
private WebSocketMessage fail(String reason) {
|
||||
System.out.println("WebSocket Error: " + reason);
|
||||
close(reason);
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData() throws IOException {
|
||||
var maskLen = in().read();
|
||||
var hasMask = (maskLen & 0x80) != 0;
|
||||
var len = (int)readLen(maskLen & 0x7F);
|
||||
var mask = readMask(hasMask);
|
||||
|
||||
if (len > maxLength) fail("WebSocket Error: client exceeded configured max message size");
|
||||
else {
|
||||
var buff = new byte[len];
|
||||
|
||||
if (in().read(buff) < len) fail("WebSocket Error: payload too short");
|
||||
else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
buff[i] ^= mask[(int)(i % 4)];
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WebSocketMessage receive() throws IOException {
|
||||
var data = new ByteArrayOutputStream();
|
||||
var type = 0;
|
||||
|
||||
while (socket != null && !closed) {
|
||||
var finId = in().read();
|
||||
if (finId < 0) break;
|
||||
var fin = (finId & 0x80) != 0;
|
||||
int id = finId & 0x0F;
|
||||
|
||||
if (id == 0x8) { close(); return null; }
|
||||
if (id >= 0x8) {
|
||||
if (!fin) return fail("WebSocket Error: client-sent control frame was fragmented");
|
||||
if (id == 0x9) write(0xA, data.toByteArray());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == 0) type = id;
|
||||
if (type == 0) return fail("WebSocket Error: client used opcode 0x00 for first fragment");
|
||||
|
||||
var buff = readData();
|
||||
if (buff == null) break;
|
||||
|
||||
if (data.size() + buff.length > maxLength) return fail("WebSocket Error: client exceeded configured max message size");
|
||||
data.write(buff);
|
||||
|
||||
if (!fin) continue;
|
||||
var raw = data.toByteArray();
|
||||
|
||||
if (type == 1) {
|
||||
return new WebSocketMessage(new String(raw));
|
||||
}
|
||||
else return new WebSocketMessage(raw);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WebSocket(Socket socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package me.topchetoeu.j2s.lib.debug;
|
||||
|
||||
public class WebSocketMessage {
|
||||
public static enum Type {
|
||||
Text,
|
||||
Binary,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
private final Object data;
|
||||
|
||||
public final String textData() {
|
||||
if (type != Type.Text) throw new IllegalStateException("Message is not text.");
|
||||
return (String)data;
|
||||
}
|
||||
public final byte[] binaryData() {
|
||||
if (type != Type.Binary) throw new IllegalStateException("Message is not binary.");
|
||||
return (byte[])data;
|
||||
}
|
||||
|
||||
public WebSocketMessage(String data) {
|
||||
this.type = Type.Text;
|
||||
this.data = data;
|
||||
}
|
||||
public WebSocketMessage(byte[] data) {
|
||||
this.type = Type.Binary;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
3
lib/src/polyfills/classPrivateFieldLooseBase.js
Normal file
3
lib/src/polyfills/classPrivateFieldLooseBase.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function _classPrivateFieldLooseBase(obj) {
|
||||
return obj;
|
||||
}
|
||||
13
lib/src/polyfills/classPrivateFieldLooseKey.js
Normal file
13
lib/src/polyfills/classPrivateFieldLooseKey.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { print, self, symbol } from "../stdlib/primordials.ts";
|
||||
import { Object } from "../stdlib/values/object.ts";
|
||||
|
||||
self.Object = {
|
||||
defineProperty: function (obj, key, desc) {
|
||||
if (obj == null) return obj;
|
||||
Object.defineProperty(obj, key, desc);
|
||||
}
|
||||
};
|
||||
|
||||
export default function _classPrivateFieldLooseKey(key) {
|
||||
return symbol.makeSymbol(key);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { object } from "../stdlib/primordials.ts";
|
||||
import { func, object, print } from "../stdlib/primordials.ts";
|
||||
|
||||
function _defineProperties(target, arr) {
|
||||
if (!arr) return;
|
||||
@@ -31,5 +31,8 @@ export default function _createClass(clazz, instance, nonInstance) {
|
||||
_defineProperties(clazz.prototype, instance);
|
||||
_defineProperties(clazz, nonInstance);
|
||||
|
||||
func.setCallable(clazz, false);
|
||||
func.setConstructable(clazz, true);
|
||||
|
||||
return clazz;
|
||||
}
|
||||
@@ -1,25 +1,28 @@
|
||||
import { buffer, type InternalBuffer, map, symbol } from "../primordials.ts";
|
||||
|
||||
export const abs = new map(true);
|
||||
export const abKey: unique symbol = symbol.getSymbol("ArrayBuffer.impl") as any;
|
||||
|
||||
export class ArrayBuffer {
|
||||
public [abKey]!: InternalBuffer;
|
||||
#internal!: InternalBuffer;
|
||||
|
||||
public get byteLength() {
|
||||
return this[abKey].length;
|
||||
return this.#internal.length;
|
||||
}
|
||||
public get byteOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public constructor(val: unknown) {
|
||||
if (buffer.isBuff(val)) this[abKey] = val;
|
||||
else this[abKey] = buffer.buff(Number(val));
|
||||
if (buffer.isBuff(val)) this.#internal = val;
|
||||
else this.#internal = buffer.buff(Number(val));
|
||||
}
|
||||
|
||||
public static unwrap(instance: ArrayBuffer) {
|
||||
return instance.#internal;
|
||||
}
|
||||
}
|
||||
|
||||
export function getAB(buff: InternalBuffer): ArrayBuffer {
|
||||
function wrapAB(buff: InternalBuffer): ArrayBuffer {
|
||||
let res = abs.get(buff);
|
||||
if (res == null) {
|
||||
res = new ArrayBuffer(buff);
|
||||
@@ -28,3 +31,11 @@ export function getAB(buff: InternalBuffer): ArrayBuffer {
|
||||
|
||||
return res;
|
||||
}
|
||||
const unwrapAB = ArrayBuffer.unwrap;
|
||||
|
||||
delete (ArrayBuffer as any).unwrap;
|
||||
|
||||
|
||||
|
||||
export { wrapAB, unwrapAB };
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buffer } from "../primordials.ts";
|
||||
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
import { token, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
|
||||
const factory = buffer.int32;
|
||||
const funcs = typedArrayFuncs(4, factory);
|
||||
@@ -19,7 +19,7 @@ export class Int32Array extends TypedArray {
|
||||
}
|
||||
|
||||
public constructor(obj: any, start?: number, end?: number) {
|
||||
super(abstractIgnore);
|
||||
super(token);
|
||||
return funcs.construct(obj, start, end) as any;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { buffer, func, type InternalBuffer, object, string, symbol } from "../primordials.ts";
|
||||
import { symbols, wrapI } from "../utils.ts";
|
||||
import { Error, TypeError } from "../values/errors.ts";
|
||||
import { abKey, ArrayBuffer, getAB } from "./ArrayBuffer.ts";
|
||||
import { ArrayBuffer, unwrapAB, wrapAB } from "./ArrayBuffer.ts";
|
||||
|
||||
export const abstractIgnore = symbol.getSymbol("TypedArray.abstractIgnore");
|
||||
export const token = symbol.getSymbol("TypedArray.abstractIgnore");
|
||||
|
||||
export function typedArrayFuncs(perEl: number, constructor: (buff: InternalBuffer, start: number, end: number) => number[]) {
|
||||
return {
|
||||
@@ -56,7 +56,7 @@ export function typedArrayFuncs(perEl: number, constructor: (buff: InternalBuffe
|
||||
return constructor(buffer.buff(self * perEl), 0, self);
|
||||
}
|
||||
if (self instanceof ArrayBuffer) {
|
||||
const internal = self[abKey];
|
||||
const internal = unwrapAB(self);
|
||||
if (start === undefined) start = 0;
|
||||
if (end === undefined) end = (internal.length / perEl) | 0;
|
||||
return constructor(internal, start, end);
|
||||
@@ -90,7 +90,7 @@ export function typedArrayFuncs(perEl: number, constructor: (buff: InternalBuffe
|
||||
|
||||
export class TypedArray {
|
||||
public get buffer() {
|
||||
return getAB(buffer.backer(this as any));
|
||||
return wrapAB(buffer.backer(this as any));
|
||||
}
|
||||
public get byteOffset(): number {
|
||||
throw new Error("abstract");
|
||||
@@ -212,8 +212,8 @@ export class TypedArray {
|
||||
return this;
|
||||
}
|
||||
|
||||
public constructor(token?: typeof abstractIgnore) {
|
||||
if (token !== abstractIgnore) {
|
||||
public constructor(_token?: typeof token) {
|
||||
if (_token !== token) {
|
||||
throw new TypeError("TypedArray constructor can't be called");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buffer } from "../primordials.ts";
|
||||
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
import { token, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
|
||||
const factory = buffer.uint8;
|
||||
const funcs = typedArrayFuncs(1, factory);
|
||||
@@ -26,7 +26,7 @@ export class Uint8Array extends TypedArray {
|
||||
}
|
||||
|
||||
public constructor(obj: any, start?: number, end?: number) {
|
||||
super(abstractIgnore);
|
||||
super(token);
|
||||
return funcs.construct(obj, start, end) as any;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import { now, symbol } from "../primordials.ts";
|
||||
|
||||
const timeKey: unique symbol = symbol.makeSymbol("") as any;
|
||||
import { now, number, symbol } from "../primordials.ts";
|
||||
|
||||
export const Date = (() => {
|
||||
class Date {
|
||||
[timeKey]!: number;
|
||||
#time: number;
|
||||
|
||||
public constructor() {
|
||||
|
||||
this.#time = number.NaN;
|
||||
}
|
||||
|
||||
public static now() {
|
||||
|
||||
@@ -1,51 +1,49 @@
|
||||
import { Array } from "../values/array.ts";
|
||||
import { func, map, symbol } from "../primordials.ts";
|
||||
import { func, map } from "../primordials.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
const mapKey: unique symbol = symbol.makeSymbol("Map.impl") as any;
|
||||
|
||||
export class Map<K, V> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
#map: InstanceType<typeof map>;
|
||||
|
||||
public get size() {
|
||||
return this[mapKey].size();
|
||||
return this.#map.size();
|
||||
}
|
||||
|
||||
public get(key: K): V {
|
||||
return this[mapKey].get(key);
|
||||
return this.#map.get(key);
|
||||
}
|
||||
public has(key: K): boolean {
|
||||
return this[mapKey].has(key);
|
||||
return this.#map.has(key);
|
||||
}
|
||||
public set(key: K, val: V) {
|
||||
this[mapKey].set(key, val);
|
||||
this.#map.set(key, val);
|
||||
return this;
|
||||
}
|
||||
public delete(key: K): boolean {
|
||||
if (!this[mapKey].has(key)) return false;
|
||||
if (!this.#map.has(key)) return false;
|
||||
else {
|
||||
this[mapKey].delete(key);
|
||||
this.#map.delete(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
this.#map.clear();
|
||||
}
|
||||
|
||||
public keys(): K[] {
|
||||
return this[mapKey].keys();
|
||||
return this.#map.keys();
|
||||
}
|
||||
public values(): V[] {
|
||||
const res = this[mapKey].keys();
|
||||
const res = this.#map.keys();
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = this[mapKey].get(res[i]);
|
||||
res[i] = this.#map.get(res[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public entries(): [K, V][] {
|
||||
const res = this[mapKey].keys();
|
||||
const res = this.#map.keys();
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = [res[i], this[mapKey].get(res[i])];
|
||||
res[i] = [res[i], this.#map.get(res[i])];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -62,7 +60,7 @@ export class Map<K, V> {
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<[K, V]>) {
|
||||
const _map = this[mapKey] = new map();
|
||||
const _map = this.#map = new map();
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
@@ -81,31 +79,31 @@ export class Map<K, V> {
|
||||
}
|
||||
}
|
||||
export class WeakMap<K, V> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
#map: InstanceType<typeof map>;
|
||||
|
||||
public get(key: K): V {
|
||||
return this[mapKey].get(key);
|
||||
return this.#map.get(key);
|
||||
}
|
||||
public has(key: K): boolean {
|
||||
return this[mapKey].has(key);
|
||||
return this.#map.has(key);
|
||||
}
|
||||
public set(key: K, val: V) {
|
||||
this[mapKey].set(key, val);
|
||||
this.#map.set(key, val);
|
||||
return this;
|
||||
}
|
||||
public delete(key: K): boolean {
|
||||
if (!this[mapKey].has(key)) return false;
|
||||
if (!this.#map.has(key)) return false;
|
||||
else {
|
||||
this[mapKey].delete(key);
|
||||
this.#map.delete(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
this.#map.clear();
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<[K, V]>) {
|
||||
const _map = this[mapKey] = new map(true);
|
||||
const _map = this.#map = new map(true);
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
@@ -123,6 +121,3 @@ export class WeakMap<K, V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Map, false);
|
||||
func.setCallable(WeakMap, false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { func, next, object, symbol } from "../primordials.ts";
|
||||
import { next } from "../primordials.ts";
|
||||
|
||||
enum PromiseState {
|
||||
Pending = "pend",
|
||||
@@ -6,109 +6,106 @@ enum PromiseState {
|
||||
Rejected = "rej",
|
||||
}
|
||||
|
||||
const pState: unique symbol = symbol.makeSymbol("Promise.state") as any;
|
||||
const pValue: unique symbol = symbol.makeSymbol("Promise.value") as any;
|
||||
const pFulHandles: unique symbol = symbol.makeSymbol("Promise.fulfillHandles") as any;
|
||||
const pRejHandles: unique symbol = symbol.makeSymbol("Promise.rejectHandles") as any;
|
||||
export class Promise<T> {
|
||||
static #InternalPromise = function <T>(this: Promise<T>) {
|
||||
this.#state = PromiseState.Pending;
|
||||
this.#fulHandles = [];
|
||||
this.#rejHandles = [];
|
||||
} as any as new <T>() => Promise<T>;
|
||||
|
||||
function makePromise<T>(): Promise<T> {
|
||||
return object.setPrototype({
|
||||
[pState]: PromiseState.Pending,
|
||||
[pFulHandles]: [],
|
||||
[pRejHandles]: [],
|
||||
}, Promise.prototype) as Promise<T>;
|
||||
}
|
||||
static {
|
||||
this.#InternalPromise.prototype = this.prototype;
|
||||
}
|
||||
|
||||
function fulfill(self: Promise<any>, val: any) {
|
||||
if (self[pState] !== PromiseState.Pending) return;
|
||||
if (self === val) throw new Error("A promise may not be fulfilled with itself");
|
||||
#state: PromiseState;
|
||||
#value?: T | unknown;
|
||||
#fulHandles?: ((val: T) => void)[] = [];
|
||||
#rejHandles?: ((val: T) => void)[] = [];
|
||||
|
||||
#fulfill(val: any) {
|
||||
if (this.#state !== PromiseState.Pending) return;
|
||||
if (this === val) throw new Error("A promise may not be fulfilled with itself");
|
||||
|
||||
if (val != null && typeof val.then === "function") {
|
||||
val.then(
|
||||
(val: any) => fulfill(self, val),
|
||||
(err: any) => reject(self, err),
|
||||
(val: any) => this.#fulfill(val),
|
||||
(err: any) => this.#reject(err),
|
||||
);
|
||||
}
|
||||
else {
|
||||
self[pValue] = val;
|
||||
self[pState] = PromiseState.Fulfilled;
|
||||
this.#value = val;
|
||||
this.#state = PromiseState.Fulfilled;
|
||||
|
||||
const handles = self[pFulHandles]!;
|
||||
const handles = this.#fulHandles!;
|
||||
|
||||
for (let i = 0; i < handles.length; i++) {
|
||||
handles[i](val);
|
||||
}
|
||||
|
||||
self[pFulHandles] = undefined;
|
||||
self[pRejHandles] = undefined;
|
||||
this.#fulHandles = undefined;
|
||||
this.#rejHandles = undefined;
|
||||
}
|
||||
}
|
||||
function reject(self: Promise<any>, val: any) {
|
||||
if (self[pState] !== PromiseState.Pending) return;
|
||||
if (self === val) throw new Error("A promise may not be rejected with itself");
|
||||
}
|
||||
#reject(val: any) {
|
||||
if (this.#state !== PromiseState.Pending) return;
|
||||
if (this === val) throw new Error("A promise may not be rejected with itself");
|
||||
|
||||
if (val != null && typeof val.then === "function") {
|
||||
val.then(
|
||||
(val: any) => reject(self, val),
|
||||
(err: any) => reject(self, err),
|
||||
(val: any) => this.#reject(val),
|
||||
(err: any) => this.#reject(err),
|
||||
);
|
||||
}
|
||||
else {
|
||||
self[pValue] = val;
|
||||
self[pState] = PromiseState.Rejected;
|
||||
this.#value = val;
|
||||
this.#state = PromiseState.Rejected;
|
||||
|
||||
const handles = self[pRejHandles]!;
|
||||
const handles = this.#rejHandles!;
|
||||
|
||||
for (let i = 0; i < handles.length; i++) {
|
||||
handles[i](val);
|
||||
}
|
||||
|
||||
self[pFulHandles] = undefined;
|
||||
self[pRejHandles] = undefined;
|
||||
this.#fulHandles = undefined;
|
||||
this.#rejHandles = undefined;
|
||||
}
|
||||
}
|
||||
function handle<T>(self: Promise<T>, ful?: (val: T) => void, rej?: (err: any) => void) {
|
||||
if (self[pState] === PromiseState.Pending) {
|
||||
}
|
||||
#handle(ful?: (val: T) => void, rej?: (err: any) => void) {
|
||||
if (this.#state === PromiseState.Pending) {
|
||||
if (ful != null) {
|
||||
self[pFulHandles]![self[pFulHandles]!.length] = ful;
|
||||
this.#fulHandles![this.#fulHandles!.length] = ful;
|
||||
}
|
||||
if (rej != null) {
|
||||
self[pRejHandles]![self[pRejHandles]!.length] = rej;
|
||||
this.#rejHandles![this.#rejHandles!.length] = rej;
|
||||
}
|
||||
}
|
||||
else if (self[pState] === PromiseState.Fulfilled) {
|
||||
if (ful != null) ful(self[pValue] as T);
|
||||
else if (this.#state === PromiseState.Fulfilled) {
|
||||
if (ful != null) ful(this.#value as T);
|
||||
}
|
||||
else if (this.#state === PromiseState.Rejected) {
|
||||
if (rej != null) rej(this.#value);
|
||||
}
|
||||
else if (self[pState] === PromiseState.Rejected) {
|
||||
if (rej != null) rej(self[pValue]);
|
||||
}
|
||||
}
|
||||
|
||||
export class Promise<T> {
|
||||
public [pState]: PromiseState;
|
||||
public [pValue]?: T | unknown;
|
||||
public [pFulHandles]?: ((val: T) => void)[] = [];
|
||||
public [pRejHandles]?: ((val: T) => void)[] = [];
|
||||
|
||||
public then<Res>(ful?: (val: T) => Res, rej?: (err: any) => Res) {
|
||||
if (typeof ful !== "function") ful = undefined;
|
||||
if (typeof rej !== "function") rej = undefined;
|
||||
|
||||
const promise = makePromise<Res>();
|
||||
const promise = new Promise.#InternalPromise<Res>();
|
||||
|
||||
handle(this,
|
||||
this.#handle(
|
||||
val => next(() => {
|
||||
if (ful == null) fulfill(promise, val);
|
||||
if (ful == null) promise.#fulfill(val);
|
||||
else {
|
||||
try { fulfill(promise, ful(val)); }
|
||||
catch (e) { reject(promise, e); }
|
||||
try { promise.#fulfill(ful(val)); }
|
||||
catch (e) { promise.#reject(e); }
|
||||
}
|
||||
}),
|
||||
err => next(() => {
|
||||
if (rej == null) reject(promise, err);
|
||||
if (rej == null) promise.#reject(err);
|
||||
else {
|
||||
try { fulfill(promise, rej(err)); }
|
||||
catch (e) { reject(promise, e); }
|
||||
try { promise.#fulfill(rej(err)); }
|
||||
catch (e) { promise.#reject(e); }
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -134,21 +131,19 @@ export class Promise<T> {
|
||||
}
|
||||
|
||||
public constructor(fn: (fulfil: (val: T) => void, reject: (err: unknown) => void) => void) {
|
||||
this[pState] = PromiseState.Pending;
|
||||
this.#state = PromiseState.Pending;
|
||||
|
||||
fn(val => fulfill(this, val), err => reject(this, err));
|
||||
fn(val => this.#fulfill(val), err => this.#reject(err));
|
||||
}
|
||||
|
||||
public static resolve(val: any) {
|
||||
const res = makePromise();
|
||||
fulfill(res, val);
|
||||
const res = new this.#InternalPromise();
|
||||
res.#fulfill(val);
|
||||
return res;
|
||||
}
|
||||
public static reject(val: any) {
|
||||
const res = makePromise();
|
||||
reject(res, val);
|
||||
const res = new this.#InternalPromise();
|
||||
res.#reject(val);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Promise, false);
|
||||
|
||||
@@ -1,42 +1,40 @@
|
||||
import { Array } from "../values/array.ts";
|
||||
import { func, map, symbol } from "../primordials.ts";
|
||||
import { func, map } from "../primordials.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
const mapKey: unique symbol = symbol.makeSymbol("Set.impl") as any;
|
||||
|
||||
export class Set<T> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
#map: InstanceType<typeof map>;
|
||||
|
||||
public get size() {
|
||||
return this[mapKey].size();
|
||||
return this.#map.size();
|
||||
}
|
||||
|
||||
public has(key: T): boolean {
|
||||
return this[mapKey].has(key);
|
||||
return this.#map.has(key);
|
||||
}
|
||||
public add(val: T) {
|
||||
this[mapKey].set(val, true);
|
||||
this.#map.set(val, true);
|
||||
return this;
|
||||
}
|
||||
public delete(val: T): boolean {
|
||||
if (!this[mapKey].has(val)) return false;
|
||||
if (!this.#map.has(val)) return false;
|
||||
else {
|
||||
this[mapKey].delete(val);
|
||||
this.#map.delete(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
this.#map.clear();
|
||||
}
|
||||
|
||||
public keys(): T[] {
|
||||
return this[mapKey].keys();
|
||||
return this.#map.keys();
|
||||
}
|
||||
public values(): T[] {
|
||||
return this[mapKey].keys();
|
||||
return this.#map.keys();
|
||||
}
|
||||
public entries(): [T, T][] {
|
||||
const res = this[mapKey].keys();
|
||||
const res = this.#map.keys();
|
||||
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = [res[i], res[i]];
|
||||
@@ -57,7 +55,7 @@ export class Set<T> {
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<T>) {
|
||||
const _map = this[mapKey] = new map();
|
||||
const _map = this.#map = new map();
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
@@ -77,28 +75,28 @@ export class Set<T> {
|
||||
}
|
||||
|
||||
export class WeakSet<T> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
#map: InstanceType<typeof map>;
|
||||
|
||||
public has(key: T): boolean {
|
||||
return this[mapKey].has(key);
|
||||
return this.#map.has(key);
|
||||
}
|
||||
public add(val: T) {
|
||||
this[mapKey].set(val, true);
|
||||
this.#map.set(val, true);
|
||||
return this;
|
||||
}
|
||||
public delete(val: T): boolean {
|
||||
if (!this[mapKey].has(val)) return false;
|
||||
if (!this.#map.has(val)) return false;
|
||||
else {
|
||||
this[mapKey].delete(val);
|
||||
this.#map.delete(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
this.#map.clear();
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<T>) {
|
||||
const _map = this[mapKey] = new map(true);
|
||||
const _map = this.#map = new map(true);
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
@@ -116,6 +114,3 @@ export class WeakSet<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Set, false);
|
||||
func.setCallable(WeakSet, false);
|
||||
|
||||
@@ -4,6 +4,14 @@ export interface InternalBuffer {
|
||||
length: number;
|
||||
[buffSymbol]: "buffer";
|
||||
}
|
||||
export interface InternalSocket {
|
||||
read(onRes: (data: Uint8Array) => void, onErr: (err: unknown) => void, onDone: () => void): void;
|
||||
write(data: Uint8Array, onRes: () => void, onErr: (err: unknown) => void): void;
|
||||
}
|
||||
export interface InternalServer {
|
||||
bind(address: string, onRes: () => void, onErr: (err: unknown) => void): void;
|
||||
next(onRes: (socket: InternalSocket) => void, onErr: (err: unknown) => void, onDone: () => void): void;
|
||||
}
|
||||
|
||||
export interface SymbolPrimordials {
|
||||
makeSymbol(name: string): symbol;
|
||||
@@ -82,6 +90,9 @@ export interface JSONPrimordials {
|
||||
parse(data: string): any;
|
||||
stringify(data: any): string;
|
||||
}
|
||||
export interface NetPrimordials {
|
||||
server(): InternalServer;
|
||||
}
|
||||
|
||||
export interface Primordials {
|
||||
symbol: SymbolPrimordials;
|
||||
@@ -91,6 +102,7 @@ export interface Primordials {
|
||||
function: FunctionPrimordials;
|
||||
json: JSONPrimordials;
|
||||
buffer: BufferPrimordials;
|
||||
net: NetPrimordials;
|
||||
map: new (weak?: boolean) => {
|
||||
get(key: any): any;
|
||||
has(key: any): boolean;
|
||||
@@ -127,6 +139,7 @@ export const {
|
||||
buffer,
|
||||
function: func,
|
||||
json,
|
||||
net: socket,
|
||||
map,
|
||||
regex,
|
||||
setGlobalPrototypes,
|
||||
@@ -139,3 +152,4 @@ export const {
|
||||
} = primordials;
|
||||
|
||||
export type regex = InstanceType<typeof regex>;
|
||||
export const self = (globalThis as any);
|
||||
|
||||
63
lib/src/stdlib/sockets.ts
Normal file
63
lib/src/stdlib/sockets.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Promise as Promise } from "./classes/promise";
|
||||
import { func, InternalServer, InternalSocket, symbol } from "./primordials";
|
||||
import { Error } from "./values/errors";
|
||||
|
||||
const socketToken = symbol.makeSymbol("ServerSocket.token");
|
||||
|
||||
export class ServerSocket {
|
||||
#internal: InternalSocket;
|
||||
|
||||
public read() {
|
||||
return new Promise((ful, rej) => {
|
||||
this.#internal.read(ful, rej, ful as any);
|
||||
});
|
||||
}
|
||||
public write(data: Uint8Array) {
|
||||
return new Promise<void>((ful, rej) => {
|
||||
this.#internal.write(data, ful, rej);
|
||||
});
|
||||
}
|
||||
|
||||
public next() {
|
||||
return new Promise((ful, rej) => {
|
||||
this.#internal.read(
|
||||
data => ful({ value: data, done: false }),
|
||||
rej,
|
||||
() => ful({ value: undefined, done: true })
|
||||
);
|
||||
});
|
||||
}
|
||||
public [Symbol.iterator](): this {
|
||||
return this;
|
||||
}
|
||||
|
||||
public constructor(token: typeof socketToken, socket: InternalSocket) {
|
||||
if (token !== socketToken) throw new Error("Invalid token for creation");
|
||||
this.#internal = socket;
|
||||
}
|
||||
}
|
||||
|
||||
export class Server {
|
||||
#internal: InternalServer;
|
||||
|
||||
public bind(address: string) {
|
||||
return new Promise<void>((res, rej) => this.#internal.bind(address, res, rej));
|
||||
}
|
||||
|
||||
public next() {
|
||||
return new Promise((ful, rej) => {
|
||||
this.#internal.next(
|
||||
data => ful({ value: new ServerSocket(socketToken, data), done: false }),
|
||||
rej,
|
||||
() => ful({ value: undefined, done: true })
|
||||
);
|
||||
});
|
||||
}
|
||||
public [Symbol.iterator](): this {
|
||||
return this;
|
||||
}
|
||||
|
||||
public constructor(server: InternalServer) {
|
||||
this.#internal = server;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
import { func, regex, symbol } from "../primordials.ts";
|
||||
import { func, regex } from "../primordials.ts";
|
||||
import { String } from "./string.ts";
|
||||
import { type ReplaceRange } from "../utils.ts";
|
||||
import { applyReplaces } from "../utils.ts";
|
||||
import { applySplits } from "../utils.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
const regexKey: unique symbol = symbol.makeSymbol("RegExp.impl") as any;
|
||||
|
||||
export class RegExp {
|
||||
private [regexKey]!: InstanceType<typeof regex>;
|
||||
#regex!: InstanceType<typeof regex>;
|
||||
|
||||
public readonly source!: string;
|
||||
public readonly flags!: string;
|
||||
@@ -70,14 +68,14 @@ export class RegExp {
|
||||
this.unicodeSets = unicodeSets;
|
||||
this.sticky = sticky;
|
||||
|
||||
this[regexKey] = new regex(source, multiline, ignoreCase, dotall, unicode, unicodeSets);
|
||||
this.#regex = new regex(source, multiline, ignoreCase, dotall, unicode, unicodeSets);
|
||||
}
|
||||
|
||||
public exec(target: string) {
|
||||
const useLast = this.global || this.sticky;
|
||||
const start = useLast ? this.lastIndex : 0;
|
||||
|
||||
const match = this[regexKey].exec(target, start, this.indices);
|
||||
const match = this.#regex.exec(target, start, this.indices);
|
||||
if (match != null && !(this.sticky && match.matches.index !== start)) {
|
||||
if (useLast) this.lastIndex = match.end;
|
||||
return match.matches;
|
||||
@@ -92,7 +90,7 @@ export class RegExp {
|
||||
|
||||
public [symbols.split](target: string, limit?: number) {
|
||||
return applySplits(target, limit, offset => {
|
||||
const val = this[regexKey].exec(target, offset, false);
|
||||
const val = this.#regex.exec(target, offset, false);
|
||||
if (val == null) return undefined;
|
||||
|
||||
return { start: val.matches.index!, end: val.end };
|
||||
@@ -100,7 +98,7 @@ export class RegExp {
|
||||
}
|
||||
public [symbols.replace](target: string, replacer: any) {
|
||||
const matches: ReplaceRange[] = [];
|
||||
const regex = this[regexKey];
|
||||
const regex = this.#regex;
|
||||
|
||||
if (this.global) {
|
||||
let offset = 0;
|
||||
@@ -136,3 +134,6 @@ export class RegExp {
|
||||
return applyReplaces(target, matches, replacer, regex.groupCount() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(RegExp, true);
|
||||
func.setConstructable(RegExp, true);
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.topchetoeu.j2s.repl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -17,10 +18,10 @@ import me.topchetoeu.j2s.common.Reading;
|
||||
import me.topchetoeu.j2s.common.SyntaxException;
|
||||
import me.topchetoeu.j2s.lib.Compilers;
|
||||
import me.topchetoeu.j2s.lib.StdLib;
|
||||
import me.topchetoeu.j2s.repl.debug.SimpleDebugHandler;
|
||||
import me.topchetoeu.j2s.repl.debug.DebugServer;
|
||||
import me.topchetoeu.j2s.repl.debug.Debugger;
|
||||
import me.topchetoeu.j2s.repl.debug.SimpleDebugger;
|
||||
import me.topchetoeu.j2s.lib.debug.DebugServer;
|
||||
import me.topchetoeu.j2s.lib.debug.Debugger;
|
||||
import me.topchetoeu.j2s.lib.debug.SimpleDebugHandler;
|
||||
import me.topchetoeu.j2s.lib.debug.SimpleDebugger;
|
||||
import me.topchetoeu.j2s.runtime.Compiler;
|
||||
import me.topchetoeu.j2s.runtime.Engine;
|
||||
import me.topchetoeu.j2s.runtime.EventLoop;
|
||||
@@ -104,11 +105,10 @@ public class SimpleRepl {
|
||||
}
|
||||
|
||||
private static Environment createESEnv() {
|
||||
var env = new Environment();
|
||||
var env = StdLib.apply(null);
|
||||
env.add(EventLoop.KEY, engine);
|
||||
env.add(DebugHandler.KEY, new SimpleDebugHandler());
|
||||
env.add(Compiler.KEY, Compilers.chainTranspilers(environment, Compilers.jsCompiler(), Compilers::babelCompiler, Compilers::coffeescriptCompiler));
|
||||
StdLib.apply(env);
|
||||
env.add(Compiler.KEY, Compilers.chainTranspilers(Compilers.jsCompiler(), env, Compilers::babelCompiler));
|
||||
|
||||
var glob = Value.global(env);
|
||||
|
||||
@@ -116,6 +116,18 @@ public class SimpleRepl {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new CancellationException();
|
||||
}));
|
||||
glob.defineOwnField(null, "dofile", new NativeFunction("dofile", args -> {
|
||||
var file = args.get(0).toString(args.env);
|
||||
var filename = new Filename("file", new File(file).getAbsolutePath());
|
||||
|
||||
try {
|
||||
var src = Reading.streamToString(new FileInputStream(file));
|
||||
return Compiler.get(args.env).compile(args.env, filename, src, v -> v).apply(args.env, Value.UNDEFINED);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw EngineException.ofError("IOException", e.getMessage());
|
||||
}
|
||||
}));
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Error {
|
||||
public final String message;
|
||||
|
||||
public V8Error(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap().set("error", new JSONMap()
|
||||
.set("message", message)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
|
||||
|
||||
public interface Debugger extends DebugHandler {
|
||||
void close();
|
||||
|
||||
void enable(V8Message msg) throws IOException;
|
||||
void disable(V8Message msg) throws IOException;
|
||||
|
||||
void setBreakpointByUrl(V8Message msg) throws IOException;
|
||||
void removeBreakpoint(V8Message msg) throws IOException;
|
||||
void continueToLocation(V8Message msg) throws IOException;
|
||||
|
||||
void getScriptSource(V8Message msg) throws IOException;
|
||||
void getPossibleBreakpoints(V8Message msg) throws IOException;
|
||||
|
||||
void resume(V8Message msg) throws IOException;
|
||||
void pause(V8Message msg) throws IOException;
|
||||
|
||||
void stepInto(V8Message msg) throws IOException;
|
||||
void stepOut(V8Message msg) throws IOException;
|
||||
void stepOver(V8Message msg) throws IOException;
|
||||
|
||||
void setPauseOnExceptions(V8Message msg) throws IOException;
|
||||
|
||||
void evaluateOnCallFrame(V8Message msg) throws IOException;
|
||||
|
||||
void getProperties(V8Message msg) throws IOException;
|
||||
void releaseObjectGroup(V8Message msg) throws IOException;
|
||||
void releaseObject(V8Message msg) throws IOException;
|
||||
void callFunctionOn(V8Message msg) throws IOException;
|
||||
|
||||
void runtimeEnable(V8Message msg) throws IOException;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
public interface DebuggerProvider {
|
||||
Debugger getDebugger(WebSocket socket, HttpRequest req);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.IllegalFormatException;
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.j2s.common.Reading;
|
||||
|
||||
public class HttpRequest {
|
||||
public final String method;
|
||||
public final String path;
|
||||
public final Map<String, String> headers;
|
||||
public final OutputStream out;
|
||||
|
||||
|
||||
public void writeCode(int code, String name) {
|
||||
try { out.write(("HTTP/1.1 " + code + " " + name + "\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeHeader(String name, String value) {
|
||||
try { out.write((name + ": " + value + "\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeLastHeader(String name, String value) {
|
||||
try { out.write((name + ": " + value + "\r\n\r\n").getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeHeadersEnd() {
|
||||
try { out.write("\n".getBytes()); }
|
||||
catch (IOException e) { }
|
||||
}
|
||||
|
||||
public void writeResponse(int code, String name, String type, byte[] data) {
|
||||
writeCode(code, name);
|
||||
writeHeader("Content-Type", type);
|
||||
writeLastHeader("Content-Length", data.length + "");
|
||||
try {
|
||||
out.write(data);
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) { }
|
||||
}
|
||||
public void writeResponse(int code, String name, String type, InputStream data) {
|
||||
writeResponse(code, name, type, Reading.streamToBytes(data));
|
||||
}
|
||||
|
||||
public HttpRequest(String method, String path, Map<String, String> headers, OutputStream out) {
|
||||
this.method = method;
|
||||
this.path = path;
|
||||
this.headers = headers;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
// We dont need no http library
|
||||
public static HttpRequest read(Socket socket) {
|
||||
try {
|
||||
var str = socket.getInputStream();
|
||||
var lines = new BufferedReader(new InputStreamReader(str));
|
||||
var line = lines.readLine();
|
||||
var i1 = line.indexOf(" ");
|
||||
var i2 = line.indexOf(" ", i1 + 1);
|
||||
|
||||
if (i1 < 0 || i2 < 0) {
|
||||
socket.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = line.substring(0, i1).trim().toUpperCase();
|
||||
var path = line.substring(i1 + 1, i2).trim();
|
||||
var headers = new HashMap<String, String>();
|
||||
|
||||
while (!(line = lines.readLine()).isEmpty()) {
|
||||
var i = line.indexOf(":");
|
||||
if (i < 0) continue;
|
||||
var name = line.substring(0, i).trim().toLowerCase();
|
||||
var value = line.substring(i + 1).trim();
|
||||
|
||||
if (name.length() == 0) continue;
|
||||
headers.put(name, value);
|
||||
}
|
||||
|
||||
if (headers.containsKey("content-length")) {
|
||||
try {
|
||||
var i = Integer.parseInt(headers.get("content-length"));
|
||||
str.skip(i);
|
||||
}
|
||||
catch (IllegalFormatException e) { /* ¯\_(ツ)_/¯ */ }
|
||||
}
|
||||
|
||||
return new HttpRequest(method, path, headers, socket.getOutputStream());
|
||||
}
|
||||
catch (IOException | NullPointerException e) { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Error {
|
||||
public final String message;
|
||||
|
||||
public V8Error(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap().set("error", new JSONMap()
|
||||
.set("message", message)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Event {
|
||||
public final String name;
|
||||
public final JSONMap params;
|
||||
|
||||
public V8Event(String name, JSONMap params) {
|
||||
this.name = name;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("method", name)
|
||||
.set("params", params)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONElement;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Message {
|
||||
public final String name;
|
||||
public final int id;
|
||||
public final JSONMap params;
|
||||
|
||||
public V8Message(String name, int id, Map<String, JSONElement> params) {
|
||||
this.name = name;
|
||||
this.params = new JSONMap(params);
|
||||
this.id = id;
|
||||
}
|
||||
public V8Result respond(JSONMap result) {
|
||||
return new V8Result(id, result);
|
||||
}
|
||||
public V8Result respond() {
|
||||
return new V8Result(id, new JSONMap());
|
||||
}
|
||||
|
||||
public V8Message(JSONMap raw) {
|
||||
if (!raw.isNumber("id")) throw new IllegalArgumentException("Expected number property 'id'.");
|
||||
if (!raw.isString("method")) throw new IllegalArgumentException("Expected string property 'method'.");
|
||||
|
||||
this.name = raw.string("method");
|
||||
this.id = (int)raw.number("id");
|
||||
this.params = raw.contains("params") ? raw.map("params") : new JSONMap();
|
||||
}
|
||||
public V8Message(String raw) {
|
||||
this(JSON.parse(null, raw).map());
|
||||
}
|
||||
|
||||
public JSONMap toMap() {
|
||||
var res = new JSONMap();
|
||||
return res;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("method", name)
|
||||
.set("params", params)
|
||||
.set("id", id)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||
|
||||
public class V8Result {
|
||||
public final int id;
|
||||
public final JSONMap result;
|
||||
|
||||
public V8Result(int id, JSONMap result) {
|
||||
this.id = id;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.stringify(new JSONMap()
|
||||
.set("id", id)
|
||||
.set("result", result)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import me.topchetoeu.j2s.repl.debug.WebSocketMessage.Type;
|
||||
|
||||
public class WebSocket implements AutoCloseable {
|
||||
public long maxLength = 1 << 20;
|
||||
|
||||
private Socket socket;
|
||||
private boolean closed = false;
|
||||
|
||||
private OutputStream out() throws IOException {
|
||||
return socket.getOutputStream();
|
||||
}
|
||||
private InputStream in() throws IOException {
|
||||
return socket.getInputStream();
|
||||
}
|
||||
|
||||
private long readLen(int byteLen) throws IOException {
|
||||
long res = 0;
|
||||
|
||||
if (byteLen == 126) {
|
||||
res |= in().read() << 8;
|
||||
res |= in().read();
|
||||
return res;
|
||||
}
|
||||
else if (byteLen == 127) {
|
||||
res |= in().read() << 56;
|
||||
res |= in().read() << 48;
|
||||
res |= in().read() << 40;
|
||||
res |= in().read() << 32;
|
||||
res |= in().read() << 24;
|
||||
res |= in().read() << 16;
|
||||
res |= in().read() << 8;
|
||||
res |= in().read();
|
||||
return res;
|
||||
}
|
||||
else return byteLen;
|
||||
}
|
||||
private byte[] readMask(boolean has) throws IOException {
|
||||
if (has) {
|
||||
return new byte[] {
|
||||
(byte)in().read(),
|
||||
(byte)in().read(),
|
||||
(byte)in().read(),
|
||||
(byte)in().read()
|
||||
};
|
||||
}
|
||||
else return new byte[4];
|
||||
}
|
||||
|
||||
private void writeLength(int len) throws IOException {
|
||||
if (len < 126) {
|
||||
out().write((int)len);
|
||||
}
|
||||
else if (len <= 0xFFFF) {
|
||||
out().write(126);
|
||||
out().write((int)(len >> 8) & 0xFF);
|
||||
out().write((int)len & 0xFF);
|
||||
}
|
||||
else {
|
||||
out().write(127);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write(0);
|
||||
out().write((len >> 24) & 0xFF);
|
||||
out().write((len >> 16) & 0xFF);
|
||||
out().write((len >> 8) & 0xFF);
|
||||
out().write(len & 0xFF);
|
||||
}
|
||||
}
|
||||
private synchronized void write(int type, byte[] data) throws IOException {
|
||||
out().write(type | 0x80);
|
||||
writeLength(data.length);
|
||||
out().write(data);
|
||||
}
|
||||
|
||||
public void send(String data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(1, data.getBytes());
|
||||
}
|
||||
public void send(byte[] data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(2, data);
|
||||
}
|
||||
public void send(WebSocketMessage msg) throws IOException {
|
||||
if (msg.type == Type.Binary) send(msg.binaryData());
|
||||
else send(msg.textData());
|
||||
}
|
||||
public void send(Object data) throws IOException {
|
||||
if (closed) throw new IllegalStateException("Websocket is closed.");
|
||||
write(1, data.toString().getBytes());
|
||||
}
|
||||
|
||||
public void close(String reason) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
write(8, reason.getBytes());
|
||||
socket.close();
|
||||
}
|
||||
catch (Throwable e) { }
|
||||
}
|
||||
|
||||
socket = null;
|
||||
closed = true;
|
||||
}
|
||||
public void close() {
|
||||
close("");
|
||||
}
|
||||
|
||||
private WebSocketMessage fail(String reason) {
|
||||
System.out.println("WebSocket Error: " + reason);
|
||||
close(reason);
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData() throws IOException {
|
||||
var maskLen = in().read();
|
||||
var hasMask = (maskLen & 0x80) != 0;
|
||||
var len = (int)readLen(maskLen & 0x7F);
|
||||
var mask = readMask(hasMask);
|
||||
|
||||
if (len > maxLength) fail("WebSocket Error: client exceeded configured max message size");
|
||||
else {
|
||||
var buff = new byte[len];
|
||||
|
||||
if (in().read(buff) < len) fail("WebSocket Error: payload too short");
|
||||
else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
buff[i] ^= mask[(int)(i % 4)];
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WebSocketMessage receive() throws IOException {
|
||||
var data = new ByteArrayOutputStream();
|
||||
var type = 0;
|
||||
|
||||
while (socket != null && !closed) {
|
||||
var finId = in().read();
|
||||
if (finId < 0) break;
|
||||
var fin = (finId & 0x80) != 0;
|
||||
int id = finId & 0x0F;
|
||||
|
||||
if (id == 0x8) { close(); return null; }
|
||||
if (id >= 0x8) {
|
||||
if (!fin) return fail("WebSocket Error: client-sent control frame was fragmented");
|
||||
if (id == 0x9) write(0xA, data.toByteArray());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == 0) type = id;
|
||||
if (type == 0) return fail("WebSocket Error: client used opcode 0x00 for first fragment");
|
||||
|
||||
var buff = readData();
|
||||
if (buff == null) break;
|
||||
|
||||
if (data.size() + buff.length > maxLength) return fail("WebSocket Error: client exceeded configured max message size");
|
||||
data.write(buff);
|
||||
|
||||
if (!fin) continue;
|
||||
var raw = data.toByteArray();
|
||||
|
||||
if (type == 1) {
|
||||
return new WebSocketMessage(new String(raw));
|
||||
}
|
||||
else return new WebSocketMessage(raw);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WebSocket(Socket socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package me.topchetoeu.j2s.repl.debug;
|
||||
|
||||
public class WebSocketMessage {
|
||||
public static enum Type {
|
||||
Text,
|
||||
Binary,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
private final Object data;
|
||||
|
||||
public final String textData() {
|
||||
if (type != Type.Text) throw new IllegalStateException("Message is not text.");
|
||||
return (String)data;
|
||||
}
|
||||
public final byte[] binaryData() {
|
||||
if (type != Type.Binary) throw new IllegalStateException("Message is not binary.");
|
||||
return (byte[])data;
|
||||
}
|
||||
|
||||
public WebSocketMessage(String data) {
|
||||
this.type = Type.Text;
|
||||
this.data = data;
|
||||
}
|
||||
public WebSocketMessage(byte[] data) {
|
||||
this.type = Type.Binary;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ public final class Frame {
|
||||
returnValue = InstructionRunner.exec(env, instr, this);
|
||||
}
|
||||
catch (EngineException e) {
|
||||
error = e.add(env, function.name, dbg.getMapOrEmpty(env, function).toLocation(codePtr));
|
||||
error = e.add(env, function.name, dbg.getMapOrEmpty(env, function).toLocation(codePtr, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public final class CodeFunction extends FunctionValue {
|
||||
}
|
||||
|
||||
@Override protected Value onApply(Environment env, Value self, Value... args) {
|
||||
var frame = new Frame(env, false, null, self, args, this);
|
||||
var frame = new Frame(this.env, false, null, self, args, this);
|
||||
var res = onCall(frame);
|
||||
return res;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public final class CodeFunction extends FunctionValue {
|
||||
if (proto instanceof ObjectValue) self.setPrototype(env, (ObjectValue)proto);
|
||||
else if (proto == Value.NULL) self.setPrototype(env, null);
|
||||
|
||||
var frame = new Frame(env, true, target, self, args, this);
|
||||
var frame = new Frame(this.env, true, target, self, args, this);
|
||||
|
||||
var ret = onCall(frame);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user