Compare commits
40 Commits
v0.7.0-alp
...
v0.8.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
af35d7f20b
|
|||
|
cfa0e001b9
|
|||
|
c10d071346
|
|||
|
89eea7d62b
|
|||
| 18d22a1282 | |||
|
72a0d39d0b
|
|||
|
d8585a20bf
|
|||
|
e4c9a8756e
|
|||
|
c6e6425c7e
|
|||
|
292ca64cb9
|
|||
|
4572db5c46
|
|||
|
0251c4689d
|
|||
|
3173919b49
|
|||
|
45f133c6b0
|
|||
|
34276d720c
|
|||
|
2c634778c3
|
|||
|
4aa757e625
|
|||
|
918f2623cd
|
|||
|
a321fc14bc
|
|||
|
07a6f18b16
|
|||
|
5f4011aa0c
|
|||
|
71f735b812
|
|||
|
e575b3287e
|
|||
|
4fa5f5a815
|
|||
|
a61c6a494e
|
|||
|
978ee8db79
|
|||
|
e372941e99
|
|||
|
c36a0db860
|
|||
|
d6ee59363f
|
|||
|
d5fd6e650e
|
|||
|
c0b895e00a
|
|||
|
9ea5cd9277
|
|||
|
aaf9a6fa45
|
|||
|
579f09c837
|
|||
|
3343262e72
|
|||
|
153a1a9a49
|
|||
|
bf38587271
|
|||
|
21534efd60
|
|||
|
802f2f3f52
|
|||
|
38acc20a6f
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
!/src
|
!/src
|
||||||
!/src/**/*
|
!/src/**/*
|
||||||
|
|
||||||
/src/assets/js/ts.js
|
/src/assets/js/ts.js
|
||||||
|
|
||||||
|
!/doc
|
||||||
|
!/doc/**/*
|
||||||
|
|
||||||
!/tests
|
!/tests
|
||||||
!/tests/**/*
|
!/tests/**/*
|
||||||
|
|
||||||
|
|
||||||
!/.github
|
!/.github
|
||||||
!/.github/**/*
|
!/.github/**/*
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ JScript is an engine, capable of running EcmaScript 5, written entirely in Java.
|
|||||||
The following is going to execute a simple javascript statement:
|
The following is going to execute a simple javascript statement:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
var engine = new Engine(false);
|
var engine = new Engine();
|
||||||
// Initialize a standard environment, with implementations of most basic standard libraries (Object, Array, Symbol, etc.)
|
// Initialize a standard environment, with implementations of most basic standard libraries (Object, Array, Symbol, etc.)
|
||||||
var env = Internals.apply(new Environment());
|
var env = Internals.apply(new Environment());
|
||||||
|
|
||||||
@@ -26,4 +26,4 @@ System.out.println(awaitable.await());
|
|||||||
|
|
||||||
## NOTE:
|
## NOTE:
|
||||||
|
|
||||||
To setup the typescript bundle in your sources, run `node build.js init-ts`. This will download the latest version of typescript, minify it, and add it to your src/assets folder. If you are going to work with the `node build.js debug|release` command, this is not a necessary step.
|
To setup the typescript bundle in your sources, run `node build.js init-ts`. This will download the latest version of typescript, minify it, and add it to your src folder. If you are going to work with the `node build.js debug|release` command, this is not a necessary step.
|
||||||
|
|||||||
31
build.js
31
build.js
@@ -77,6 +77,7 @@ async function downloadTypescript(outFile) {
|
|||||||
console.log('Minifying typescript...');
|
console.log('Minifying typescript...');
|
||||||
|
|
||||||
const minified = minify((await fs.readFile('tmp/typescript-es5.js')).toString());
|
const minified = minify((await fs.readFile('tmp/typescript-es5.js')).toString());
|
||||||
|
// const minified = { code: (await fs.readFile('tmp/typescript-es5.js')).toString() };
|
||||||
if (minified.error) throw minified.error;
|
if (minified.error) throw minified.error;
|
||||||
|
|
||||||
// Patch unsupported regex syntax
|
// Patch unsupported regex syntax
|
||||||
@@ -117,7 +118,7 @@ The following is a minified version of the unmodified Typescript 5.2
|
|||||||
}
|
}
|
||||||
async function compileJava(conf) {
|
async function compileJava(conf) {
|
||||||
try {
|
try {
|
||||||
await fs.writeFile('Metadata.java', (await fs.readFile('src/me/topchetoeu/jscript/Metadata.java')).toString()
|
await fs.writeFile('Metadata.java', (await fs.readFile('src/me/topchetoeu/jscript/common/Metadata.java')).toString()
|
||||||
.replace('${VERSION}', conf.version)
|
.replace('${VERSION}', conf.version)
|
||||||
.replace('${NAME}', conf.name)
|
.replace('${NAME}', conf.name)
|
||||||
.replace('${AUTHOR}', conf.author)
|
.replace('${AUTHOR}', conf.author)
|
||||||
@@ -135,11 +136,22 @@ async function compileJava(conf) {
|
|||||||
await fs.rm('Metadata.java');
|
await fs.rm('Metadata.java');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function jar(conf, project, mainClass) {
|
||||||
|
const args = [
|
||||||
|
'jar', '-c',
|
||||||
|
'-f', `dst/${project}-v${conf.version}.jar`,
|
||||||
|
];
|
||||||
|
if (mainClass) args.push('-e', mainClass);
|
||||||
|
args.push('-C', 'dst/classes', project.replaceAll('.', '/'));
|
||||||
|
console.log(args.join(' '));
|
||||||
|
|
||||||
|
await run(true, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
if (argv[2] === 'init-ts') {
|
if (argv[2] === 'init-ts') {
|
||||||
await downloadTypescript('src/assets/js/ts.js');
|
await downloadTypescript('src/me/topchetoeu/jscript/utils/assets/js/ts.js');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const conf = {
|
const conf = {
|
||||||
@@ -155,12 +167,21 @@ async function compileJava(conf) {
|
|||||||
try { await fs.rm('dst', { recursive: true }); } catch {}
|
try { await fs.rm('dst', { recursive: true }); } catch {}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
downloadTypescript('dst/classes/assets/js/ts.js'),
|
(async () => {
|
||||||
copy('src', 'dst/classes', v => !v.endsWith('.java')),
|
await copy('src', 'dst/classes', v => !v.endsWith('.java'));
|
||||||
|
await downloadTypescript('dst/classes/me/topchetoeu/jscript/utils/assets/js/ts.js');
|
||||||
|
})(),
|
||||||
compileJava(conf),
|
compileJava(conf),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await run(true, 'jar', '-c', '-f', 'dst/jscript.jar', '-e', 'me.topchetoeu.jscript.Main', '-C', 'dst/classes', '.');
|
await Promise.all([
|
||||||
|
jar(conf, 'me.topchetoeu.jscript.common'),
|
||||||
|
jar(conf, 'me.topchetoeu.jscript.core'),
|
||||||
|
jar(conf, 'me.topchetoeu.jscript.lib'),
|
||||||
|
jar(conf, 'me.topchetoeu.jscript.utils'),
|
||||||
|
jar(conf, 'me.topchetoeu.jscript', 'me.topchetoeu.jscript.utils.JScriptRepl'),
|
||||||
|
]);
|
||||||
|
|
||||||
console.log('Done!');
|
console.log('Done!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
package me.topchetoeu.jscript;
|
|
||||||
|
|
||||||
public interface MessageReceiver {
|
|
||||||
void sendMessage(String msg);
|
|
||||||
void sendError(String msg);
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
public class Buffer {
|
public class Buffer {
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
public class Location implements Comparable<Location> {
|
public class Location implements Comparable<Location> {
|
||||||
public static final Location INTERNAL = new Location(0, 0, new Filename("jscript", "native"));
|
public static final Location INTERNAL = new Location(0, 0, new Filename("jscript", "native"));
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
public class Metadata {
|
public class Metadata {
|
||||||
private static final String VERSION = "${VERSION}";
|
private static final String VERSION = "${VERSION}";
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
|
||||||
|
|
||||||
public class Reading {
|
public class Reading {
|
||||||
private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
|
||||||
public static synchronized String read() throws IOException {
|
public static synchronized String readline() throws IOException {
|
||||||
return reader.readLine();
|
return reader.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the given stream to a string
|
||||||
|
* @param in
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static String streamToString(InputStream in) {
|
public static String streamToString(InputStream in) {
|
||||||
try { return new String(in.readAllBytes()); }
|
try {
|
||||||
catch (Throwable e) { throw new UncheckedException(e); }
|
return new String(in.readAllBytes());
|
||||||
|
}
|
||||||
|
catch (IOException e) { throw new UncheckedIOException(e); }
|
||||||
}
|
}
|
||||||
public static InputStream resourceToStream(String name) {
|
public static InputStream resourceToStream(String name) {
|
||||||
return Reading.class.getResourceAsStream("/assets/" + name);
|
return Reading.class.getResourceAsStream("/" + name);
|
||||||
}
|
}
|
||||||
public static String resourceToString(String name) {
|
public static String resourceToString(String name) {
|
||||||
return streamToString(resourceToStream(name));
|
return streamToString(resourceToStream(name));
|
||||||
5
src/me/topchetoeu/jscript/common/ResultRunnable.java
Normal file
5
src/me/topchetoeu/jscript/common/ResultRunnable.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package me.topchetoeu.jscript.common;
|
||||||
|
|
||||||
|
public interface ResultRunnable<T> {
|
||||||
|
T run();
|
||||||
|
}
|
||||||
27
src/me/topchetoeu/jscript/common/events/Awaitable.java
Normal file
27
src/me/topchetoeu/jscript/common/events/Awaitable.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package me.topchetoeu.jscript.common.events;
|
||||||
|
|
||||||
|
public interface Awaitable<T> {
|
||||||
|
public static interface ResultHandler<T> {
|
||||||
|
public void onResult(T data);
|
||||||
|
}
|
||||||
|
public static interface ErrorHandler {
|
||||||
|
public void onError(RuntimeException error);
|
||||||
|
}
|
||||||
|
|
||||||
|
T await();
|
||||||
|
|
||||||
|
default void handle(ResultHandler<T> onResult, ErrorHandler onError) {
|
||||||
|
var thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
onResult.onResult(await());
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
onError.onError(e);
|
||||||
|
}
|
||||||
|
}, "Awaiter");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
default void handle(ResultHandler<T> onResult) {
|
||||||
|
handle(onResult, err -> {});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.events;
|
package me.topchetoeu.jscript.common.events;
|
||||||
|
|
||||||
public class DataNotifier<T> implements Awaitable<T> {
|
public class DataNotifier<T> implements Awaitable<T> {
|
||||||
private Notifier notifier = new Notifier();
|
private Notifier notifier = new Notifier();
|
||||||
@@ -11,9 +11,6 @@ public class DataNotifier<T> implements Awaitable<T> {
|
|||||||
isErr = true;
|
isErr = true;
|
||||||
notifier.next();
|
notifier.next();
|
||||||
}
|
}
|
||||||
public void error(Throwable t) {
|
|
||||||
error(new RuntimeException(t));
|
|
||||||
}
|
|
||||||
public void next(T val) {
|
public void next(T val) {
|
||||||
this.val = val;
|
this.val = val;
|
||||||
isErr = false;
|
isErr = false;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.events;
|
package me.topchetoeu.jscript.common.events;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.exceptions.InterruptException;
|
import me.topchetoeu.jscript.core.exceptions.InterruptException;
|
||||||
|
|
||||||
public class Notifier {
|
public class Notifier {
|
||||||
private boolean ok = false;
|
private boolean ok = false;
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
package me.topchetoeu.jscript.json;
|
package me.topchetoeu.jscript.common.json;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.parsing.Operator;
|
import me.topchetoeu.jscript.core.parsing.Operator;
|
||||||
import me.topchetoeu.jscript.parsing.ParseRes;
|
import me.topchetoeu.jscript.core.parsing.ParseRes;
|
||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
import me.topchetoeu.jscript.core.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.parsing.Token;
|
import me.topchetoeu.jscript.core.parsing.Token;
|
||||||
|
|
||||||
public class JSON {
|
public class JSON {
|
||||||
public static Object toJs(JSONElement val) {
|
public static Object toJs(JSONElement val) {
|
||||||
@@ -58,8 +58,8 @@ public class JSON {
|
|||||||
|
|
||||||
var res = new JSONMap();
|
var res = new JSONMap();
|
||||||
|
|
||||||
for (var el : ((ObjectValue)val).keys(false)) {
|
for (var el : Values.getMembers(ctx, val, false, false)) {
|
||||||
var jsonEl = fromJs(ctx, ((ObjectValue)val).getMember(ctx, el), prev);
|
var jsonEl = fromJs(ctx, Values.getMember(ctx, val, el), prev);
|
||||||
if (jsonEl == null) continue;
|
if (jsonEl == null) continue;
|
||||||
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
|
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.json;
|
package me.topchetoeu.jscript.common.json;
|
||||||
|
|
||||||
public class JSONElement {
|
public class JSONElement {
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.json;
|
package me.topchetoeu.jscript.common.json;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.json;
|
package me.topchetoeu.jscript.common.json;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
|
|
||||||
public abstract class AssignableStatement extends Statement {
|
public abstract class AssignableStatement extends Statement {
|
||||||
public abstract Statement toAssign(Statement val, Operation operation);
|
public abstract Statement toAssign(Statement val, Operation operation);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
|
||||||
public final class CalculateResult {
|
public final class CalculateResult {
|
||||||
public final boolean exists;
|
public final boolean exists;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.core.engine.values.CodeFunction;
|
||||||
|
|
||||||
public class CompileTarget {
|
public class CompileTarget {
|
||||||
public final Vector<Instruction> target = new Vector<>();
|
public final Vector<Instruction> target = new Vector<>();
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
|
import me.topchetoeu.jscript.core.compilation.values.FunctionStatement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class CompoundStatement extends Statement {
|
public class CompoundStatement extends Statement {
|
||||||
public final Statement[] statements;
|
public final Statement[] statements;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
public class FunctionBody {
|
public class FunctionBody {
|
||||||
public final Instruction[] instructions;
|
public final Instruction[] instructions;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
|
|
||||||
public class Instruction {
|
public class Instruction {
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public abstract class Statement {
|
public abstract class Statement {
|
||||||
private Location _loc;
|
private Location _loc;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
|
|
||||||
public class ThrowSyntaxStatement extends Statement {
|
public class ThrowSyntaxStatement extends Statement {
|
||||||
public final String name;
|
public final String name;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.core.compilation;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
|
import me.topchetoeu.jscript.core.compilation.values.FunctionStatement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableDeclareStatement extends Statement {
|
public class VariableDeclareStatement extends Statement {
|
||||||
public static class Pair {
|
public static class Pair {
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class BreakStatement extends Statement {
|
public class BreakStatement extends Statement {
|
||||||
public final String label;
|
public final String label;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ContinueStatement extends Statement {
|
public class ContinueStatement extends Statement {
|
||||||
public final String label;
|
public final String label;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class DebugStatement extends Statement {
|
public class DebugStatement extends Statement {
|
||||||
@Override
|
@Override
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class DeleteStatement extends Statement {
|
public class DeleteStatement extends Statement {
|
||||||
public final Statement key;
|
public final Statement key;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class DoWhileStatement extends Statement {
|
public class DoWhileStatement extends Statement {
|
||||||
public final Statement condition, body;
|
public final Statement condition, body;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ForInStatement extends Statement {
|
public class ForInStatement extends Statement {
|
||||||
public final String varName;
|
public final String varName;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ForStatement extends Statement {
|
public class ForStatement extends Statement {
|
||||||
public final Statement declaration, assignment, condition, body;
|
public final Statement declaration, assignment, condition, body;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IfStatement extends Statement {
|
public class IfStatement extends Statement {
|
||||||
public final Statement condition, body, elseBody;
|
public final Statement condition, body, elseBody;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ReturnStatement extends Statement {
|
public class ReturnStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.core.compilation.Instruction.Type;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class SwitchStatement extends Statement {
|
public class SwitchStatement extends Statement {
|
||||||
public static class SwitchCase {
|
public static class SwitchCase {
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ThrowStatement extends Statement {
|
public class ThrowStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.core.engine.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.engine.scope.LocalScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.LocalScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class TryStatement extends Statement {
|
public class TryStatement extends Statement {
|
||||||
public final Statement tryBody;
|
public final Statement tryBody;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation.control;
|
package me.topchetoeu.jscript.core.compilation.control;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.core.compilation.Instruction.Type;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class WhileStatement extends Statement {
|
public class WhileStatement extends Statement {
|
||||||
public final Statement condition, body;
|
public final Statement condition, body;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ArrayStatement extends Statement {
|
public class ArrayStatement extends Statement {
|
||||||
public final Statement[] statements;
|
public final Statement[] statements;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class CallStatement extends Statement {
|
public class CallStatement extends Statement {
|
||||||
public final Statement func;
|
public final Statement func;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.core.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ChangeStatement extends Statement {
|
public class ChangeStatement extends Statement {
|
||||||
public final AssignableStatement value;
|
public final AssignableStatement value;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ConstantStatement extends Statement {
|
public class ConstantStatement extends Statement {
|
||||||
public final Object value;
|
public final Object value;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class DiscardStatement extends Statement {
|
public class DiscardStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.CompoundStatement;
|
import me.topchetoeu.jscript.core.compilation.CompoundStatement;
|
||||||
import me.topchetoeu.jscript.compilation.FunctionBody;
|
import me.topchetoeu.jscript.core.compilation.FunctionBody;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.core.compilation.Instruction.Type;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
|
|
||||||
public class FunctionStatement extends Statement {
|
public class FunctionStatement extends Statement {
|
||||||
public final CompoundStatement body;
|
public final CompoundStatement body;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class GlobalThisStatement extends Statement {
|
public class GlobalThisStatement extends Statement {
|
||||||
@Override public boolean pure() { return true; }
|
@Override public boolean pure() { return true; }
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IndexAssignStatement extends Statement {
|
public class IndexAssignStatement extends Statement {
|
||||||
public final Statement object;
|
public final Statement object;
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.core.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.core.compilation.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IndexStatement extends AssignableStatement {
|
public class IndexStatement extends AssignableStatement {
|
||||||
public final Statement object;
|
public final Statement object;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
|
||||||
public class LazyAndStatement extends Statement {
|
public class LazyAndStatement extends Statement {
|
||||||
public final Statement first, second;
|
public final Statement first, second;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
|
||||||
public class LazyOrStatement extends Statement {
|
public class LazyOrStatement extends Statement {
|
||||||
public final Statement first, second;
|
public final Statement first, second;
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ObjectStatement extends Statement {
|
public class ObjectStatement extends Statement {
|
||||||
public final Map<Object, Statement> map;
|
public final Map<Object, Statement> map;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class OperationStatement extends Statement {
|
public class OperationStatement extends Statement {
|
||||||
public final Statement[] args;
|
public final Statement[] args;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class RegexStatement extends Statement {
|
public class RegexStatement extends Statement {
|
||||||
public final String pattern, flags;
|
public final String pattern, flags;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class TypeofStatement extends Statement {
|
public class TypeofStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableAssignStatement extends Statement {
|
public class VariableAssignStatement extends Statement {
|
||||||
public final String name;
|
public final String name;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableIndexStatement extends Statement {
|
public class VariableIndexStatement extends Statement {
|
||||||
public final int index;
|
public final int index;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values;
|
package me.topchetoeu.jscript.core.compilation.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.core.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.CompileTarget;
|
import me.topchetoeu.jscript.core.compilation.CompileTarget;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.core.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.core.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableStatement extends AssignableStatement {
|
public class VariableStatement extends AssignableStatement {
|
||||||
public final String name;
|
public final String name;
|
||||||
166
src/me/topchetoeu/jscript/core/engine/Context.java
Normal file
166
src/me/topchetoeu/jscript/core/engine/Context.java
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
|
import me.topchetoeu.jscript.common.Location;
|
||||||
|
import me.topchetoeu.jscript.core.engine.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.core.engine.frame.CodeFrame;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.lib.EnvironmentLib;
|
||||||
|
import me.topchetoeu.jscript.utils.mapping.SourceMap;
|
||||||
|
|
||||||
|
public class Context implements Extensions {
|
||||||
|
public static final Context NULL = new Context(null);
|
||||||
|
|
||||||
|
public final Context parent;
|
||||||
|
public final Environment environment;
|
||||||
|
public final CodeFrame frame;
|
||||||
|
public final Engine engine;
|
||||||
|
public final int stackSize;
|
||||||
|
|
||||||
|
@Override public <T> void add(Symbol key, T obj) {
|
||||||
|
if (environment != null) environment.add(key, obj);
|
||||||
|
else if (engine != null) engine.add(key, obj);
|
||||||
|
}
|
||||||
|
@Override public <T> T get(Symbol key) {
|
||||||
|
if (environment != null && environment.has(key)) return environment.get(key);
|
||||||
|
else if (engine != null && engine.has(key)) return engine.get(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override public boolean has(Symbol key) {
|
||||||
|
return
|
||||||
|
environment != null && environment.has(key) ||
|
||||||
|
engine != null && engine.has(key);
|
||||||
|
}
|
||||||
|
@Override public boolean remove(Symbol key) {
|
||||||
|
var res = false;
|
||||||
|
|
||||||
|
if (environment != null) res |= environment.remove(key);
|
||||||
|
else if (engine != null) res |= engine.remove(key);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@Override public Iterable<Symbol> keys() {
|
||||||
|
if (engine == null && environment == null) return List.of();
|
||||||
|
if (engine == null) return environment.keys();
|
||||||
|
if (environment == null) return engine.keys();
|
||||||
|
|
||||||
|
return () -> Stream.concat(
|
||||||
|
StreamSupport.stream(engine.keys().spliterator(), false),
|
||||||
|
StreamSupport.stream(environment.keys().spliterator(), false)
|
||||||
|
).distinct().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FunctionValue compile(Filename filename, String raw) {
|
||||||
|
var env = environment;
|
||||||
|
var result = Environment.compileFunc(this).call(this, null, raw, filename.toString(), new EnvironmentLib(env));
|
||||||
|
|
||||||
|
var function = (FunctionValue)Values.getMember(this, result, "function");
|
||||||
|
if (!DebugContext.enabled(this)) return function;
|
||||||
|
|
||||||
|
var rawMapChain = ((ArrayValue)Values.getMember(this, result, "mapChain")).toArray();
|
||||||
|
var breakpoints = new TreeSet<>(
|
||||||
|
Arrays.stream(((ArrayValue)Values.getMember(this, result, "breakpoints")).toArray())
|
||||||
|
.map(v -> Location.parse(Values.toString(this, v)))
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
var maps = new SourceMap[rawMapChain.length];
|
||||||
|
|
||||||
|
for (var i = 0; i < maps.length; i++) maps[i] = SourceMap.parse(Values.toString(this, (String)rawMapChain[i]));
|
||||||
|
|
||||||
|
var map = SourceMap.chain(maps);
|
||||||
|
|
||||||
|
if (map != null) {
|
||||||
|
var newBreakpoints = new TreeSet<Location>();
|
||||||
|
for (var bp : breakpoints) {
|
||||||
|
bp = map.toCompiled(bp);
|
||||||
|
if (bp != null) newBreakpoints.add(bp);
|
||||||
|
}
|
||||||
|
breakpoints = newBreakpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugContext.get(this).onSource(filename, raw, breakpoints, map);
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context pushFrame(CodeFrame frame) {
|
||||||
|
var res = new Context(this, frame.function.environment, frame, engine, stackSize + 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<CodeFrame> frames() {
|
||||||
|
var self = this;
|
||||||
|
return () -> new Iterator<CodeFrame>() {
|
||||||
|
private Context curr = self;
|
||||||
|
|
||||||
|
private void update() {
|
||||||
|
while (curr != null && curr.frame == null) curr = curr.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean hasNext() {
|
||||||
|
update();
|
||||||
|
return curr != null;
|
||||||
|
}
|
||||||
|
@Override public CodeFrame next() {
|
||||||
|
update();
|
||||||
|
var res = curr.frame;
|
||||||
|
curr = curr.parent;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<String> stackTrace() {
|
||||||
|
var res = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (var el : frames()) {
|
||||||
|
var name = el.function.name;
|
||||||
|
Location loc = null;
|
||||||
|
|
||||||
|
for (var j = el.codePtr; j >= 0 && loc == null; j--) loc = el.function.body[j].location;
|
||||||
|
if (loc == null) loc = el.function.loc();
|
||||||
|
|
||||||
|
var trace = "";
|
||||||
|
|
||||||
|
if (loc != null) trace += "at " + loc.toString() + " ";
|
||||||
|
if (name != null && !name.equals("")) trace += "in " + name + " ";
|
||||||
|
|
||||||
|
trace = trace.trim();
|
||||||
|
|
||||||
|
if (!trace.equals("")) res.add(trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context(Context parent, Environment environment, CodeFrame frame, Engine engine, int stackSize) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.environment = environment;
|
||||||
|
this.frame = frame;
|
||||||
|
this.engine = engine;
|
||||||
|
this.stackSize = stackSize;
|
||||||
|
|
||||||
|
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) {
|
||||||
|
throw EngineException.ofRange("Stack overflow!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context(Engine engine) {
|
||||||
|
this(null, null, null, engine, 0);
|
||||||
|
}
|
||||||
|
public Context(Engine engine, Environment env) {
|
||||||
|
this(null, env, null, engine, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/me/topchetoeu/jscript/core/engine/Engine.java
Normal file
57
src/me/topchetoeu/jscript/core/engine/Engine.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
|
import me.topchetoeu.jscript.common.events.Awaitable;
|
||||||
|
import me.topchetoeu.jscript.core.compilation.FunctionBody;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
|
||||||
|
public class Engine extends EventLoop implements Extensions {
|
||||||
|
public static final HashMap<Long, FunctionBody> functions = new HashMap<>();
|
||||||
|
|
||||||
|
private final Environment env = new Environment();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void add(Symbol key, T obj) {
|
||||||
|
this.env.add(key, obj);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public <T> T get(Symbol key) {
|
||||||
|
return this.env.get(key);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean has(Symbol key) {
|
||||||
|
return this.env.has(key);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean remove(Symbol key) {
|
||||||
|
return this.env.remove(key);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Iterable<Symbol> keys() {
|
||||||
|
return env.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Engine copy() {
|
||||||
|
var res = new Engine();
|
||||||
|
res.env.addAll(env);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Awaitable<Object> pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) {
|
||||||
|
return pushMsg(() -> {
|
||||||
|
return func.call(new Context(this, env), thisArg, args);
|
||||||
|
}, micro);
|
||||||
|
}
|
||||||
|
public Awaitable<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) {
|
||||||
|
return pushMsg(() -> {
|
||||||
|
var ctx = new Context(this, env);
|
||||||
|
return ctx.compile(filename, raw).call(new Context(this, env), thisArg, args);
|
||||||
|
}, micro);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Engine() {
|
||||||
|
}
|
||||||
|
}
|
||||||
128
src/me/topchetoeu/jscript/core/engine/Environment.java
Normal file
128
src/me/topchetoeu/jscript/core/engine/Environment.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
|
import me.topchetoeu.jscript.common.Location;
|
||||||
|
import me.topchetoeu.jscript.core.engine.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.core.engine.scope.GlobalScope;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.NativeFunction;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.core.parsing.Parsing;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class Environment implements Extensions {
|
||||||
|
|
||||||
|
public static final HashMap<String, Symbol> symbols = new HashMap<>();
|
||||||
|
|
||||||
|
public static final Symbol WRAPPERS = Symbol.get("Environment.wrappers");
|
||||||
|
public static final Symbol COMPILE_FUNC = Symbol.get("Environment.compile");
|
||||||
|
|
||||||
|
public static final Symbol REGEX_CONSTR = Symbol.get("Environment.regexConstructor");
|
||||||
|
public static final Symbol STACK = Symbol.get("Environment.stack");
|
||||||
|
public static final Symbol MAX_STACK_COUNT = Symbol.get("Environment.maxStackCount");
|
||||||
|
public static final Symbol HIDE_STACK = Symbol.get("Environment.hideStack");
|
||||||
|
|
||||||
|
public static final Symbol OBJECT_PROTO = Symbol.get("Environment.objectPrototype");
|
||||||
|
public static final Symbol FUNCTION_PROTO = Symbol.get("Environment.functionPrototype");
|
||||||
|
public static final Symbol ARRAY_PROTO = Symbol.get("Environment.arrayPrototype");
|
||||||
|
public static final Symbol BOOL_PROTO = Symbol.get("Environment.boolPrototype");
|
||||||
|
public static final Symbol NUMBER_PROTO = Symbol.get("Environment.numberPrototype");
|
||||||
|
public static final Symbol STRING_PROTO = Symbol.get("Environment.stringPrototype");
|
||||||
|
public static final Symbol SYMBOL_PROTO = Symbol.get("Environment.symbolPrototype");
|
||||||
|
public static final Symbol ERROR_PROTO = Symbol.get("Environment.errorPrototype");
|
||||||
|
public static final Symbol SYNTAX_ERR_PROTO = Symbol.get("Environment.syntaxErrorPrototype");
|
||||||
|
public static final Symbol TYPE_ERR_PROTO = Symbol.get("Environment.typeErrorPrototype");
|
||||||
|
public static final Symbol RANGE_ERR_PROTO = Symbol.get("Environment.rangeErrorPrototype");
|
||||||
|
|
||||||
|
private HashMap<Symbol, Object> data = new HashMap<>();
|
||||||
|
|
||||||
|
public GlobalScope global;
|
||||||
|
public WrapperProvider wrappers;
|
||||||
|
|
||||||
|
@Override public <T> void add(Symbol key, T obj) {
|
||||||
|
data.put(key, obj);
|
||||||
|
}
|
||||||
|
@Override public <T> T get(Symbol key) {
|
||||||
|
return (T)data.get(key);
|
||||||
|
}
|
||||||
|
@Override public boolean remove(Symbol key) {
|
||||||
|
if (data.containsKey(key)) {
|
||||||
|
data.remove(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override public boolean has(Symbol key) {
|
||||||
|
return data.containsKey(key);
|
||||||
|
}
|
||||||
|
@Override public Iterable<Symbol> keys() {
|
||||||
|
return data.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FunctionValue compileFunc(Extensions ext) {
|
||||||
|
return ext.init(COMPILE_FUNC, new NativeFunction("compile", args -> {
|
||||||
|
var source = args.getString(0);
|
||||||
|
var filename = args.getString(1);
|
||||||
|
var env = Values.wrapper(Values.getMember(args.ctx, args.get(2), Symbol.get("env")), Environment.class);
|
||||||
|
var isDebug = DebugContext.enabled(args.ctx);
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
var target = Parsing.compile(env, Filename.parse(filename), source);
|
||||||
|
Engine.functions.putAll(target.functions);
|
||||||
|
Engine.functions.remove(0l);
|
||||||
|
|
||||||
|
res.defineProperty(args.ctx, "function", target.func(env));
|
||||||
|
res.defineProperty(args.ctx, "mapChain", new ArrayValue());
|
||||||
|
|
||||||
|
if (isDebug) res.defineProperty(
|
||||||
|
args.ctx, "breakpoints",
|
||||||
|
ArrayValue.of(args.ctx, target.breakpoints.stream().map(Location::toString).collect(Collectors.toList()))
|
||||||
|
);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
public static FunctionValue regexConstructor(Extensions ext) {
|
||||||
|
return ext.init(COMPILE_FUNC, new NativeFunction("RegExp", args -> {
|
||||||
|
throw EngineException.ofError("Regular expressions not supported.").setCtx(args.ctx.environment, args.ctx.engine);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment copy() {
|
||||||
|
var res = new Environment(null, global);
|
||||||
|
|
||||||
|
res.wrappers = wrappers.fork(res);
|
||||||
|
res.global = global;
|
||||||
|
res.data.putAll(data);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
public Environment child() {
|
||||||
|
var res = copy();
|
||||||
|
res.global = res.global.globalChild();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context context(Engine engine) {
|
||||||
|
return new Context(engine, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment(WrapperProvider nativeConverter, GlobalScope global) {
|
||||||
|
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider(this);
|
||||||
|
if (global == null) global = new GlobalScope();
|
||||||
|
|
||||||
|
this.wrappers = nativeConverter;
|
||||||
|
this.global = global;
|
||||||
|
}
|
||||||
|
public Environment() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/me/topchetoeu/jscript/core/engine/EventLoop.java
Normal file
81
src/me/topchetoeu/jscript/core/engine/EventLoop.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.ResultRunnable;
|
||||||
|
import me.topchetoeu.jscript.common.events.Awaitable;
|
||||||
|
import me.topchetoeu.jscript.common.events.DataNotifier;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.InterruptException;
|
||||||
|
|
||||||
|
public class EventLoop {
|
||||||
|
private static class Task implements Comparable<Task> {
|
||||||
|
public final ResultRunnable<?> runnable;
|
||||||
|
public final DataNotifier<Object> notifier = new DataNotifier<>();
|
||||||
|
public final boolean micro;
|
||||||
|
|
||||||
|
public Task(ResultRunnable<?> runnable, boolean micro) {
|
||||||
|
this.runnable = runnable;
|
||||||
|
this.micro = micro;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Task other) {
|
||||||
|
return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>();
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Awaitable<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
|
||||||
|
var msg = new Task(runnable, micro);
|
||||||
|
tasks.add(msg);
|
||||||
|
return (Awaitable<T>)msg.notifier;
|
||||||
|
}
|
||||||
|
public Awaitable<Object> pushMsg(Runnable runnable, boolean micro) {
|
||||||
|
return pushMsg(() -> { runnable.run(); return null; }, micro);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(boolean untilEmpty) {
|
||||||
|
while (!untilEmpty || !tasks.isEmpty()) {
|
||||||
|
try {
|
||||||
|
var task = tasks.take();
|
||||||
|
|
||||||
|
try {
|
||||||
|
task.notifier.next(task.runnable.run());
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
if (e instanceof InterruptException) throw e;
|
||||||
|
task.notifier.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException | InterruptException e) {
|
||||||
|
for (var msg : tasks) msg.notifier.error(new InterruptException(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thread thread() {
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
public Thread start() {
|
||||||
|
if (thread == null) {
|
||||||
|
thread = new Thread(() -> run(false), "Event loop #" + hashCode());
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
public void stop() {
|
||||||
|
if (thread != null) thread.interrupt();
|
||||||
|
thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inLoopThread() {
|
||||||
|
return Thread.currentThread() == thread;
|
||||||
|
}
|
||||||
|
public boolean isRunning() {
|
||||||
|
return this.thread != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/me/topchetoeu/jscript/core/engine/Extensions.java
Normal file
34
src/me/topchetoeu/jscript/core/engine/Extensions.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
|
||||||
|
public interface Extensions {
|
||||||
|
<T> T get(Symbol key);
|
||||||
|
<T> void add(Symbol key, T obj);
|
||||||
|
Iterable<Symbol> keys();
|
||||||
|
|
||||||
|
boolean has(Symbol key);
|
||||||
|
boolean remove(Symbol key);
|
||||||
|
|
||||||
|
default boolean hasNotNull(Symbol key) {
|
||||||
|
return has(key) && get(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T get(Symbol key, T defaultVal) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else return defaultVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T init(Symbol key, T val) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else {
|
||||||
|
add(key, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default void addAll(Extensions source) {
|
||||||
|
for (var key : source.keys()) {
|
||||||
|
add(key, source.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
public enum Operation {
|
public enum Operation {
|
||||||
INSTANCEOF(2, false),
|
INSTANCEOF(2, false),
|
||||||
12
src/me/topchetoeu/jscript/core/engine/WrapperProvider.java
Normal file
12
src/me/topchetoeu/jscript/core/engine/WrapperProvider.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
|
|
||||||
|
public interface WrapperProvider {
|
||||||
|
public ObjectValue getProto(Class<?> obj);
|
||||||
|
public ObjectValue getNamespace(Class<?> obj);
|
||||||
|
public FunctionValue getConstr(Class<?> obj);
|
||||||
|
|
||||||
|
public WrapperProvider fork(Environment env);
|
||||||
|
}
|
||||||
100
src/me/topchetoeu/jscript/core/engine/debug/DebugContext.java
Normal file
100
src/me/topchetoeu/jscript/core/engine/debug/DebugContext.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
|
import me.topchetoeu.jscript.common.Location;
|
||||||
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.core.engine.Extensions;
|
||||||
|
import me.topchetoeu.jscript.core.engine.frame.CodeFrame;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.utils.mapping.SourceMap;
|
||||||
|
|
||||||
|
public class DebugContext implements DebugController {
|
||||||
|
public static final Symbol ENV_KEY = Symbol.get("Engine.debug");
|
||||||
|
public static final Symbol IGNORE = Symbol.get("Engine.ignoreDebug");
|
||||||
|
|
||||||
|
private HashMap<Filename, String> sources;
|
||||||
|
private HashMap<Filename, TreeSet<Location>> bpts;
|
||||||
|
private HashMap<Filename, SourceMap> maps;
|
||||||
|
private DebugController debugger;
|
||||||
|
|
||||||
|
public boolean attachDebugger(DebugController debugger) {
|
||||||
|
if (this.debugger != null) return false;
|
||||||
|
|
||||||
|
if (sources != null) {
|
||||||
|
for (var source : sources.entrySet()) debugger.onSource(
|
||||||
|
source.getKey(), source.getValue(),
|
||||||
|
bpts.get(source.getKey()),
|
||||||
|
maps.get(source.getKey())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugger = debugger;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean detachDebugger() {
|
||||||
|
this.debugger = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebugController debugger() {
|
||||||
|
if (debugger == null) return DebugController.empty();
|
||||||
|
else return debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFramePop(Context ctx, CodeFrame frame) {
|
||||||
|
if (debugger != null) debugger.onFramePop(ctx, frame);
|
||||||
|
}
|
||||||
|
@Override public void onFramePush(Context ctx, CodeFrame frame) {
|
||||||
|
if (debugger != null) debugger.onFramePush(ctx, frame);
|
||||||
|
}
|
||||||
|
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
|
if (debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
@Override public void onSource(Filename filename, String source, TreeSet<Location> breakpoints, SourceMap map) {
|
||||||
|
if (debugger != null) debugger.onSource(filename, source, breakpoints, map);
|
||||||
|
if (sources != null) sources.put(filename, source);
|
||||||
|
if (bpts != null) bpts.put(filename, breakpoints);
|
||||||
|
if (maps != null) maps.put(filename, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location mapToCompiled(Location location) {
|
||||||
|
if (maps == null) return location;
|
||||||
|
|
||||||
|
var map = maps.get(location.filename());
|
||||||
|
if (map == null) return location;
|
||||||
|
return map.toCompiled(location);
|
||||||
|
}
|
||||||
|
public Location mapToOriginal(Location location) {
|
||||||
|
if (maps == null) return location;
|
||||||
|
|
||||||
|
var map = maps.get(location.filename());
|
||||||
|
if (map == null) return location;
|
||||||
|
return map.toOriginal(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DebugContext(boolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
sources = new HashMap<>();
|
||||||
|
bpts = new HashMap<>();
|
||||||
|
maps = new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebugContext() {
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean enabled(Extensions exts) {
|
||||||
|
return exts.hasNotNull(ENV_KEY) && !exts.has(IGNORE);
|
||||||
|
}
|
||||||
|
public static DebugContext get(Extensions exts) {
|
||||||
|
if (enabled(exts)) return exts.get(ENV_KEY);
|
||||||
|
else return new DebugContext(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.core.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.mapping.SourceMap;
|
import me.topchetoeu.jscript.utils.mapping.SourceMap;
|
||||||
|
|
||||||
public interface DebugController {
|
public interface DebugController {
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +27,7 @@ public interface DebugController {
|
|||||||
* @param frame The frame in which execution is occuring
|
* @param frame The frame in which execution is occuring
|
||||||
* @param instruction The instruction which was or will be executed
|
* @param instruction The instruction which was or will be executed
|
||||||
* @param loc The most recent location the code frame has been at
|
* @param loc The most recent location the code frame has been at
|
||||||
* @param returnVal The return value of the instruction, Runners.NO_RETURN if none
|
* @param returnVal The return value of the instruction, Values.NO_RETURN if none
|
||||||
* @param error The error that the instruction threw, null if none
|
* @param error The error that the instruction threw, null if none
|
||||||
* @param caught Whether or not the error has been caught
|
* @param caught Whether or not the error has been caught
|
||||||
* @return Whether or not the frame should restart
|
* @return Whether or not the frame should restart
|
||||||
@@ -48,4 +48,15 @@ public interface DebugController {
|
|||||||
* @param frame The code frame which was popped out
|
* @param frame The code frame which was popped out
|
||||||
*/
|
*/
|
||||||
void onFramePop(Context ctx, CodeFrame frame);
|
void onFramePop(Context ctx, CodeFrame frame);
|
||||||
|
|
||||||
|
public static DebugController empty() {
|
||||||
|
return new DebugController () {
|
||||||
|
@Override public void onFramePop(Context ctx, CodeFrame frame) { }
|
||||||
|
@Override public void onFramePush(Context ctx, CodeFrame frame) { }
|
||||||
|
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override public void onSource(Filename filename, String source, TreeSet<Location> breakpoints, SourceMap map) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface DebugHandler {
|
||||||
|
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,6 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@@ -8,16 +9,14 @@ import java.security.MessageDigest;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Metadata;
|
import me.topchetoeu.jscript.common.Metadata;
|
||||||
import me.topchetoeu.jscript.Reading;
|
import me.topchetoeu.jscript.common.Reading;
|
||||||
import me.topchetoeu.jscript.engine.debug.WebSocketMessage.Type;
|
import me.topchetoeu.jscript.common.events.Notifier;
|
||||||
import me.topchetoeu.jscript.events.Notifier;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.common.json.JSONList;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedIOException;
|
import me.topchetoeu.jscript.core.engine.debug.WebSocketMessage.Type;
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.json.JSONList;
|
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
|
||||||
|
|
||||||
public class DebugServer {
|
public class DebugServer {
|
||||||
public static String browserDisplayName = Metadata.name() + "/" + Metadata.version();
|
public static String browserDisplayName = Metadata.name() + "/" + Metadata.version();
|
||||||
@@ -36,8 +35,7 @@ public class DebugServer {
|
|||||||
try {
|
try {
|
||||||
return MessageDigest.getInstance("sha1");
|
return MessageDigest.getInstance("sha1");
|
||||||
}
|
}
|
||||||
catch (Throwable e) { throw new UncheckedException(e); }
|
catch (Throwable e) { throw new RuntimeException(e); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Thread runAsync(Runnable func, String name) {
|
private static Thread runAsync(Runnable func, String name) {
|
||||||
@@ -47,11 +45,9 @@ public class DebugServer {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handle(WebSocket ws, Debugger debugger) {
|
private void handle(WebSocket ws, Debugger debugger) throws IOException {
|
||||||
WebSocketMessage raw;
|
WebSocketMessage raw;
|
||||||
|
|
||||||
debugger.connect();
|
|
||||||
|
|
||||||
while ((raw = ws.receive()) != null) {
|
while ((raw = ws.receive()) != null) {
|
||||||
if (raw.type != Type.Text) {
|
if (raw.type != Type.Text) {
|
||||||
ws.send(new V8Error("Expected a text message."));
|
ws.send(new V8Error("Expected a text message."));
|
||||||
@@ -68,55 +64,50 @@ public class DebugServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
switch (msg.name) {
|
||||||
switch (msg.name) {
|
case "Debugger.enable":
|
||||||
case "Debugger.enable":
|
connNotifier.next();
|
||||||
connNotifier.next();
|
debugger.enable(msg);
|
||||||
debugger.enable(msg); continue;
|
continue;
|
||||||
case "Debugger.disable": debugger.disable(msg); continue;
|
case "Debugger.disable": debugger.close(); continue;
|
||||||
|
|
||||||
case "Debugger.setBreakpointByUrl": debugger.setBreakpointByUrl(msg); continue;
|
case "Debugger.setBreakpointByUrl": debugger.setBreakpointByUrl(msg); continue;
|
||||||
case "Debugger.removeBreakpoint": debugger.removeBreakpoint(msg); continue;
|
case "Debugger.removeBreakpoint": debugger.removeBreakpoint(msg); continue;
|
||||||
case "Debugger.continueToLocation": debugger.continueToLocation(msg); continue;
|
case "Debugger.continueToLocation": debugger.continueToLocation(msg); continue;
|
||||||
|
|
||||||
case "Debugger.getScriptSource": debugger.getScriptSource(msg); continue;
|
case "Debugger.getScriptSource": debugger.getScriptSource(msg); continue;
|
||||||
case "Debugger.getPossibleBreakpoints": debugger.getPossibleBreakpoints(msg); continue;
|
case "Debugger.getPossibleBreakpoints": debugger.getPossibleBreakpoints(msg); continue;
|
||||||
|
|
||||||
case "Debugger.resume": debugger.resume(msg); continue;
|
case "Debugger.resume": debugger.resume(msg); continue;
|
||||||
case "Debugger.pause": debugger.pause(msg); continue;
|
case "Debugger.pause": debugger.pause(msg); continue;
|
||||||
|
|
||||||
case "Debugger.stepInto": debugger.stepInto(msg); continue;
|
case "Debugger.stepInto": debugger.stepInto(msg); continue;
|
||||||
case "Debugger.stepOut": debugger.stepOut(msg); continue;
|
case "Debugger.stepOut": debugger.stepOut(msg); continue;
|
||||||
case "Debugger.stepOver": debugger.stepOver(msg); continue;
|
case "Debugger.stepOver": debugger.stepOver(msg); continue;
|
||||||
|
|
||||||
case "Debugger.setPauseOnExceptions": debugger.setPauseOnExceptions(msg); continue;
|
case "Debugger.setPauseOnExceptions": debugger.setPauseOnExceptions(msg); continue;
|
||||||
case "Debugger.evaluateOnCallFrame": debugger.evaluateOnCallFrame(msg); continue;
|
case "Debugger.evaluateOnCallFrame": debugger.evaluateOnCallFrame(msg); continue;
|
||||||
|
|
||||||
case "Runtime.releaseObjectGroup": debugger.releaseObjectGroup(msg); continue;
|
case "Runtime.releaseObjectGroup": debugger.releaseObjectGroup(msg); continue;
|
||||||
case "Runtime.releaseObject": debugger.releaseObject(msg); continue;
|
case "Runtime.releaseObject": debugger.releaseObject(msg); continue;
|
||||||
case "Runtime.getProperties": debugger.getProperties(msg); continue;
|
case "Runtime.getProperties": debugger.getProperties(msg); continue;
|
||||||
case "Runtime.callFunctionOn": debugger.callFunctionOn(msg); continue;
|
case "Runtime.callFunctionOn": debugger.callFunctionOn(msg); continue;
|
||||||
// case "NodeWorker.enable": debugger.nodeWorkerEnable(msg); continue;
|
// case "NodeWorker.enable": debugger.nodeWorkerEnable(msg); continue;
|
||||||
case "Runtime.enable": debugger.runtimeEnable(msg); continue;
|
case "Runtime.enable": debugger.runtimeEnable(msg); continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
msg.name.startsWith("DOM.") ||
|
|
||||||
msg.name.startsWith("DOMDebugger.") ||
|
|
||||||
msg.name.startsWith("Emulation.") ||
|
|
||||||
msg.name.startsWith("Input.") ||
|
|
||||||
msg.name.startsWith("Network.") ||
|
|
||||||
msg.name.startsWith("Page.")
|
|
||||||
) ws.send(new V8Error("This isn't a browser..."));
|
|
||||||
else ws.send(new V8Error("This API is not supported yet."));
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new UncheckedException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
msg.name.startsWith("DOM.") ||
|
||||||
|
msg.name.startsWith("DOMDebugger.") ||
|
||||||
|
msg.name.startsWith("Emulation.") ||
|
||||||
|
msg.name.startsWith("Input.") ||
|
||||||
|
msg.name.startsWith("Network.") ||
|
||||||
|
msg.name.startsWith("Page.")
|
||||||
|
) ws.send(new V8Error("This isn't a browser..."));
|
||||||
|
else ws.send(new V8Error("This API is not supported yet."));
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger.disconnect();
|
debugger.close();
|
||||||
}
|
}
|
||||||
private void onWsConnect(HttpRequest req, Socket socket, DebuggerProvider debuggerProvider) {
|
private void onWsConnect(HttpRequest req, Socket socket, DebuggerProvider debuggerProvider) {
|
||||||
var key = req.headers.get("sec-websocket-key");
|
var key = req.headers.get("sec-websocket-key");
|
||||||
@@ -148,10 +139,13 @@ public class DebugServer {
|
|||||||
|
|
||||||
runAsync(() -> {
|
runAsync(() -> {
|
||||||
try { handle(ws, debugger); }
|
try { handle(ws, debugger); }
|
||||||
catch (RuntimeException e) {
|
catch (RuntimeException | IOException e) {
|
||||||
ws.send(new V8Error(e.getMessage()));
|
try {
|
||||||
|
ws.send(new V8Error(e.getMessage()));
|
||||||
|
}
|
||||||
|
catch (IOException e2) { /* Shit outta luck */ }
|
||||||
}
|
}
|
||||||
finally { ws.close(); debugger.disconnect(); }
|
finally { ws.close(); debugger.close(); }
|
||||||
}, "Debug Handler");
|
}, "Debug Handler");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,14 +226,16 @@ public class DebugServer {
|
|||||||
|
|
||||||
public DebugServer() {
|
public DebugServer() {
|
||||||
try {
|
try {
|
||||||
this.favicon = Reading.resourceToStream("debugger/favicon.png").readAllBytes();
|
this.favicon = Reading.resourceToStream("me/topchetoeu/jscript/utils/assets/debugger/favicon.png").readAllBytes();
|
||||||
this.protocol = Reading.resourceToStream("debugger/protocol.json").readAllBytes();
|
this.protocol = Reading.resourceToStream("me/topchetoeu/jscript/utils/assets/debugger/protocol.json").readAllBytes();
|
||||||
this.index = Reading.resourceToString("debugger/index.html")
|
this.index = Reading.resourceToString("me/topchetoeu/jscript/utils/assets/debugger/index.html")
|
||||||
.replace("${NAME}", Metadata.name())
|
.replace("${NAME}", Metadata.name())
|
||||||
.replace("${VERSION}", Metadata.version())
|
.replace("${VERSION}", Metadata.version())
|
||||||
.replace("${AUTHOR}", Metadata.author())
|
.replace("${AUTHOR}", Metadata.author())
|
||||||
.getBytes();
|
.getBytes();
|
||||||
}
|
}
|
||||||
catch (IOException e) { throw new UncheckedIOException(e); }
|
catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
|
public interface Debugger extends DebugHandler, DebugController {
|
||||||
|
void close();
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
public interface DebuggerProvider {
|
public interface DebuggerProvider {
|
||||||
Debugger getDebugger(WebSocket socket, HttpRequest req);
|
Debugger getDebugger(WebSocket socket, HttpRequest req);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -9,29 +10,29 @@ import java.util.TreeSet;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.common.events.Notifier;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.common.json.JSONElement;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.common.json.JSONList;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.core.compilation.Instruction.Type;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.core.engine.Engine;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.core.engine.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.events.Notifier;
|
import me.topchetoeu.jscript.core.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.json.JSONElement;
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.json.JSONList;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.mapping.SourceMap;
|
import me.topchetoeu.jscript.core.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
import me.topchetoeu.jscript.utils.mapping.SourceMap;
|
||||||
|
|
||||||
// very simple indeed
|
// very simple indeed
|
||||||
public class SimpleDebugger implements Debugger {
|
public class SimpleDebugger implements Debugger {
|
||||||
@@ -109,34 +110,47 @@ public class SimpleDebugger implements Debugger {
|
|||||||
public ObjectValue local, capture, global, valstack;
|
public ObjectValue local, capture, global, valstack;
|
||||||
public JSONMap serialized;
|
public JSONMap serialized;
|
||||||
public Location location;
|
public Location location;
|
||||||
public boolean debugData = false;
|
|
||||||
|
|
||||||
public void updateLoc(Location loc) {
|
public void updateLoc(Location loc) {
|
||||||
if (loc == null) return;
|
if (loc == null) return;
|
||||||
this.location = loc;
|
this.location = loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Frame(Context ctx, CodeFrame frame, int id) {
|
public Frame(CodeFrame frame, int id) {
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.func = frame.function;
|
this.func = frame.function;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
this.global = frame.function.environment.global.obj;
|
this.global = frame.function.environment.global.obj;
|
||||||
this.local = frame.getLocalScope(ctx, true);
|
this.local = frame.getLocalScope(true);
|
||||||
this.capture = frame.getCaptureScope(ctx, true);
|
this.capture = frame.getCaptureScope(true);
|
||||||
this.local.setPrototype(ctx, capture);
|
Values.makePrototypeChain(frame.ctx, global, capture, local);
|
||||||
this.capture.setPrototype(ctx, global);
|
this.valstack = frame.getValStackScope();
|
||||||
this.valstack = frame.getValStackScope(ctx);
|
|
||||||
debugData = true;
|
|
||||||
|
|
||||||
this.serialized = new JSONMap()
|
this.serialized = new JSONMap()
|
||||||
.set("callFrameId", id + "")
|
.set("callFrameId", id + "")
|
||||||
.set("functionName", func.name)
|
.set("functionName", func.name)
|
||||||
.set("scopeChain", new JSONList()
|
.set("scopeChain", new JSONList()
|
||||||
.add(new JSONMap().set("type", "local").set("name", "Local Scope").set("object", serializeObj(ctx, local)))
|
.add(new JSONMap()
|
||||||
.add(new JSONMap().set("type", "closure").set("name", "Closure").set("object", serializeObj(ctx, capture)))
|
.set("type", "local")
|
||||||
.add(new JSONMap().set("type", "global").set("name", "Global Scope").set("object", serializeObj(ctx, global)))
|
.set("name", "Local Scope")
|
||||||
.add(new JSONMap().set("type", "other").set("name", "Value Stack").set("object", serializeObj(ctx, valstack)))
|
.set("object", serializeObj(frame.ctx, local))
|
||||||
|
)
|
||||||
|
.add(new JSONMap()
|
||||||
|
.set("type", "closure")
|
||||||
|
.set("name", "Closure")
|
||||||
|
.set("object", serializeObj(frame.ctx, capture))
|
||||||
|
)
|
||||||
|
.add(new JSONMap()
|
||||||
|
.set("type", "global")
|
||||||
|
.set("name", "Global Scope")
|
||||||
|
.set("object", serializeObj(frame.ctx, global))
|
||||||
|
)
|
||||||
|
.add(new JSONMap()
|
||||||
|
.set("type", "other")
|
||||||
|
.set("name", "Value Stack")
|
||||||
|
.set("object", serializeObj(frame.ctx, valstack))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +187,6 @@ public class SimpleDebugger implements Debugger {
|
|||||||
public State state = State.RESUMED;
|
public State state = State.RESUMED;
|
||||||
|
|
||||||
public final WebSocket ws;
|
public final WebSocket ws;
|
||||||
public final Engine target;
|
|
||||||
|
|
||||||
private ObjectValue emptyObject = new ObjectValue();
|
private ObjectValue emptyObject = new ObjectValue();
|
||||||
|
|
||||||
@@ -232,26 +245,29 @@ public class SimpleDebugger implements Debugger {
|
|||||||
return nextId++;
|
return nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void updateFrames(Context ctx) {
|
private synchronized Frame getFrame(CodeFrame frame) {
|
||||||
var frame = ctx.peekFrame();
|
|
||||||
if (frame == null) return;
|
|
||||||
|
|
||||||
if (!codeFrameToFrame.containsKey(frame)) {
|
if (!codeFrameToFrame.containsKey(frame)) {
|
||||||
var id = nextId();
|
var id = nextId();
|
||||||
var fr = new Frame(ctx, frame, id);
|
var fr = new Frame(frame, id);
|
||||||
|
|
||||||
idToFrame.put(id, fr);
|
idToFrame.put(id, fr);
|
||||||
codeFrameToFrame.put(frame, fr);
|
codeFrameToFrame.put(frame, fr);
|
||||||
}
|
|
||||||
|
|
||||||
currFrame = codeFrameToFrame.get(frame);
|
return fr;
|
||||||
|
}
|
||||||
|
else return codeFrameToFrame.get(frame);
|
||||||
|
}
|
||||||
|
private synchronized void updateFrames(Context ctx) {
|
||||||
|
var frame = ctx.frame;
|
||||||
|
if (frame == null) return;
|
||||||
|
|
||||||
|
currFrame = getFrame(frame);
|
||||||
}
|
}
|
||||||
private JSONList serializeFrames(Context ctx) {
|
private JSONList serializeFrames(Context ctx) {
|
||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
var frames = ctx.frames();
|
|
||||||
|
|
||||||
for (var i = frames.size() - 1; i >= 0; i--) {
|
for (var el : ctx.frames()) {
|
||||||
var frame = codeFrameToFrame.get(frames.get(i));
|
var frame = getFrame(el);
|
||||||
if (frame.location == null) continue;
|
if (frame.location == null) continue;
|
||||||
frame.serialized.set("location", serializeLocation(frame.location));
|
frame.serialized.set("location", serializeLocation(frame.location));
|
||||||
if (frame.location != null) res.add(frame.serialized);
|
if (frame.location != null) res.add(frame.serialized);
|
||||||
@@ -302,6 +318,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
private JSONMap serializeObj(Context ctx, Object val, boolean byValue) {
|
private JSONMap serializeObj(Context ctx, Object val, boolean byValue) {
|
||||||
val = Values.normalize(null, val);
|
val = Values.normalize(null, val);
|
||||||
|
ctx = new Context(ctx.engine.copy(), ctx.environment);
|
||||||
|
ctx.engine.add(DebugContext.IGNORE, true);
|
||||||
|
|
||||||
if (val == Values.NULL) {
|
if (val == Values.NULL) {
|
||||||
return new JSONMap()
|
return new JSONMap()
|
||||||
@@ -341,7 +359,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
try {
|
try {
|
||||||
defaultToString =
|
defaultToString =
|
||||||
Values.getMember(ctx, obj, "toString") ==
|
Values.getMember(ctx, obj, "toString") ==
|
||||||
Values.getMember(ctx, ctx.environment().proto("object"), "toString");
|
Values.getMember(ctx, ctx.get(Environment.OBJECT_PROTO), "toString");
|
||||||
}
|
}
|
||||||
catch (Exception e) { }
|
catch (Exception e) { }
|
||||||
|
|
||||||
@@ -435,55 +453,85 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void resume(State state) {
|
private void resume(State state) {
|
||||||
this.state = state;
|
try {
|
||||||
ws.send(new V8Event("Debugger.resumed", new JSONMap()));
|
this.state = state;
|
||||||
updateNotifier.next();
|
ws.send(new V8Event("Debugger.resumed", new JSONMap()));
|
||||||
|
updateNotifier.next();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ws.close();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private void pauseDebug(Context ctx, Breakpoint bp) {
|
private void pauseDebug(Context ctx, Breakpoint bp) {
|
||||||
state = State.PAUSED_NORMAL;
|
try {
|
||||||
var map = new JSONMap()
|
state = State.PAUSED_NORMAL;
|
||||||
.set("callFrames", serializeFrames(ctx))
|
var map = new JSONMap()
|
||||||
.set("reason", "debugCommand");
|
.set("callFrames", serializeFrames(ctx))
|
||||||
|
.set("reason", "debugCommand");
|
||||||
|
|
||||||
if (bp != null) map.set("hitBreakpoints", new JSONList().add(bp.id + ""));
|
if (bp != null) map.set("hitBreakpoints", new JSONList().add(bp.id + ""));
|
||||||
ws.send(new V8Event("Debugger.paused", map));
|
ws.send(new V8Event("Debugger.paused", map));
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ws.close();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private void pauseException(Context ctx) {
|
private void pauseException(Context ctx) {
|
||||||
state = State.PAUSED_EXCEPTION;
|
try {
|
||||||
var map = new JSONMap()
|
state = State.PAUSED_EXCEPTION;
|
||||||
.set("callFrames", serializeFrames(ctx))
|
var map = new JSONMap()
|
||||||
.set("reason", "exception");
|
.set("callFrames", serializeFrames(ctx))
|
||||||
|
.set("reason", "exception");
|
||||||
|
|
||||||
ws.send(new V8Event("Debugger.paused", map));
|
ws.send(new V8Event("Debugger.paused", map));
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ws.close();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendSource(Source src) {
|
private void sendSource(Source src){
|
||||||
ws.send(new V8Event("Debugger.scriptParsed", new JSONMap()
|
try {
|
||||||
.set("scriptId", src.id + "")
|
ws.send(new V8Event("Debugger.scriptParsed", new JSONMap()
|
||||||
.set("hash", src.source.hashCode())
|
.set("scriptId", src.id + "")
|
||||||
.set("url", src.filename + "")
|
.set("hash", src.source.hashCode())
|
||||||
));
|
.set("url", src.filename + "")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ws.close();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addBreakpoint(Breakpoint bpt) {
|
private void addBreakpoint(Breakpoint bpt) {
|
||||||
idToBreakpoint.put(bpt.id, bpt);
|
try {
|
||||||
locToBreakpoint.put(bpt.location, bpt);
|
idToBreakpoint.put(bpt.id, bpt);
|
||||||
|
locToBreakpoint.put(bpt.location, bpt);
|
||||||
|
|
||||||
ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap()
|
ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap()
|
||||||
.set("breakpointId", bpt.id)
|
.set("breakpointId", bpt.id)
|
||||||
.set("location", serializeLocation(bpt.location))
|
.set("location", serializeLocation(bpt.location))
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ws.close();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RunResult run(Frame codeFrame, String code) {
|
private RunResult run(Frame codeFrame, String code) {
|
||||||
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
||||||
var engine = new Engine(false);
|
var engine = new Engine();
|
||||||
var env = codeFrame.func.environment.fork();
|
var env = codeFrame.func.environment.copy();
|
||||||
|
|
||||||
env.global = new GlobalScope(codeFrame.local);
|
env.global = new GlobalScope(codeFrame.local);
|
||||||
|
|
||||||
var ctx = new Context(engine, env);
|
var ctx = new Context(engine, env);
|
||||||
var awaiter = engine.pushMsg(false, ctx.environment(), new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
var awaiter = engine.pushMsg(false, ctx.environment, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
||||||
|
|
||||||
engine.run(true);
|
engine.run(true);
|
||||||
|
|
||||||
@@ -495,7 +543,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
var passed = new HashSet<String>();
|
var passed = new HashSet<String>();
|
||||||
var tildas = "~";
|
var tildas = "~";
|
||||||
if (target == null) target = ctx.environment().getGlobal();
|
if (target == null) target = ctx.environment.global;
|
||||||
|
|
||||||
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
||||||
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
||||||
@@ -564,7 +612,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
return resObj;
|
return resObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void enable(V8Message msg) {
|
@Override public synchronized void enable(V8Message msg) throws IOException {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
|
|
||||||
@@ -573,17 +621,45 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
updateNotifier.next();
|
updateNotifier.next();
|
||||||
}
|
}
|
||||||
@Override public synchronized void disable(V8Message msg) {
|
@Override public synchronized void disable(V8Message msg) throws IOException {
|
||||||
enabled = false;
|
close();
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
|
}
|
||||||
|
public synchronized void close() {
|
||||||
|
enabled = false;
|
||||||
|
execptionType = CatchType.NONE;
|
||||||
|
state = State.RESUMED;
|
||||||
|
|
||||||
|
idToBptCand.clear();
|
||||||
|
|
||||||
|
idToBreakpoint.clear();
|
||||||
|
locToBreakpoint.clear();
|
||||||
|
tmpBreakpts.clear();
|
||||||
|
|
||||||
|
filenameToId.clear();
|
||||||
|
idToSource.clear();
|
||||||
|
pendingSources.clear();
|
||||||
|
|
||||||
|
idToFrame.clear();
|
||||||
|
codeFrameToFrame.clear();
|
||||||
|
|
||||||
|
idToObject.clear();
|
||||||
|
objectToId.clear();
|
||||||
|
objectGroups.clear();
|
||||||
|
|
||||||
|
pendingPause = false;
|
||||||
|
|
||||||
|
stepOutFrame = currFrame = null;
|
||||||
|
stepOutPtr = 0;
|
||||||
|
|
||||||
updateNotifier.next();
|
updateNotifier.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void getScriptSource(V8Message msg) {
|
@Override public synchronized void getScriptSource(V8Message msg) throws IOException {
|
||||||
int id = Integer.parseInt(msg.params.string("scriptId"));
|
int id = Integer.parseInt(msg.params.string("scriptId"));
|
||||||
ws.send(msg.respond(new JSONMap().set("scriptSource", idToSource.get(id).source)));
|
ws.send(msg.respond(new JSONMap().set("scriptSource", idToSource.get(id).source)));
|
||||||
}
|
}
|
||||||
@Override public synchronized void getPossibleBreakpoints(V8Message msg) {
|
@Override public synchronized void getPossibleBreakpoints(V8Message msg) throws IOException {
|
||||||
var src = idToSource.get(Integer.parseInt(msg.params.map("start").string("scriptId")));
|
var src = idToSource.get(Integer.parseInt(msg.params.map("start").string("scriptId")));
|
||||||
var start = deserializeLocation(msg.params.get("start"), false);
|
var start = deserializeLocation(msg.params.get("start"), false);
|
||||||
var end = msg.params.isMap("end") ? deserializeLocation(msg.params.get("end"), false) : null;
|
var end = msg.params.isMap("end") ? deserializeLocation(msg.params.get("end"), false) : null;
|
||||||
@@ -598,16 +674,16 @@ public class SimpleDebugger implements Debugger {
|
|||||||
ws.send(msg.respond(new JSONMap().set("locations", res)));
|
ws.send(msg.respond(new JSONMap().set("locations", res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void pause(V8Message msg) {
|
@Override public synchronized void pause(V8Message msg) throws IOException {
|
||||||
pendingPause = true;
|
pendingPause = true;
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void resume(V8Message msg) {
|
@Override public synchronized void resume(V8Message msg) throws IOException {
|
||||||
resume(State.RESUMED);
|
resume(State.RESUMED);
|
||||||
ws.send(msg.respond(new JSONMap()));
|
ws.send(msg.respond(new JSONMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void setBreakpointByUrl(V8Message msg) {
|
@Override public synchronized void setBreakpointByUrl(V8Message msg) throws IOException {
|
||||||
var line = (int)msg.params.number("lineNumber") + 1;
|
var line = (int)msg.params.number("lineNumber") + 1;
|
||||||
var col = (int)msg.params.number("columnNumber", 0) + 1;
|
var col = (int)msg.params.number("columnNumber", 0) + 1;
|
||||||
var cond = msg.params.string("condition", "").trim();
|
var cond = msg.params.string("condition", "").trim();
|
||||||
@@ -642,7 +718,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.set("locations", locs)
|
.set("locations", locs)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@Override public synchronized void removeBreakpoint(V8Message msg) {
|
@Override public synchronized void removeBreakpoint(V8Message msg) throws IOException {
|
||||||
var id = Integer.parseInt(msg.params.string("breakpointId"));
|
var id = Integer.parseInt(msg.params.string("breakpointId"));
|
||||||
|
|
||||||
if (idToBptCand.containsKey(id)) {
|
if (idToBptCand.containsKey(id)) {
|
||||||
@@ -659,7 +735,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void continueToLocation(V8Message msg) {
|
@Override public synchronized void continueToLocation(V8Message msg) throws IOException {
|
||||||
var loc = deserializeLocation(msg.params.get("location"), true);
|
var loc = deserializeLocation(msg.params.get("location"), true);
|
||||||
|
|
||||||
tmpBreakpts.add(loc);
|
tmpBreakpts.add(loc);
|
||||||
@@ -668,7 +744,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void setPauseOnExceptions(V8Message msg) {
|
@Override public synchronized void setPauseOnExceptions(V8Message msg) throws IOException {
|
||||||
switch (msg.params.string("state")) {
|
switch (msg.params.string("state")) {
|
||||||
case "none": execptionType = CatchType.NONE; break;
|
case "none": execptionType = CatchType.NONE; break;
|
||||||
case "all": execptionType = CatchType.ALL; break;
|
case "all": execptionType = CatchType.ALL; break;
|
||||||
@@ -681,7 +757,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void stepInto(V8Message msg) {
|
@Override public synchronized void stepInto(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = currFrame;
|
||||||
@@ -690,7 +766,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public synchronized void stepOut(V8Message msg) {
|
@Override public synchronized void stepOut(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = currFrame;
|
||||||
@@ -699,7 +775,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public synchronized void stepOver(V8Message msg) {
|
@Override public synchronized void stepOver(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = currFrame;
|
||||||
@@ -709,7 +785,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void evaluateOnCallFrame(V8Message msg) {
|
@Override public synchronized void evaluateOnCallFrame(V8Message msg) throws IOException {
|
||||||
var cfId = Integer.parseInt(msg.params.string("callFrameId"));
|
var cfId = Integer.parseInt(msg.params.string("callFrameId"));
|
||||||
var expr = msg.params.string("expression");
|
var expr = msg.params.string("expression");
|
||||||
var group = msg.params.string("objectGroup", null);
|
var group = msg.params.string("objectGroup", null);
|
||||||
@@ -723,12 +799,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ctx, res.result))));
|
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ctx, res.result))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void releaseObjectGroup(V8Message msg) {
|
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
|
||||||
var group = msg.params.string("objectGroup");
|
var group = msg.params.string("objectGroup");
|
||||||
releaseGroup(group);
|
releaseGroup(group);
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void releaseObject(V8Message msg) {
|
@Override public synchronized void releaseObject(V8Message msg) throws IOException {
|
||||||
var id = Integer.parseInt(msg.params.string("objectId"));
|
var id = Integer.parseInt(msg.params.string("objectId"));
|
||||||
var ref = idToObject.get(id);
|
var ref = idToObject.get(id);
|
||||||
ref.held = false;
|
ref.held = false;
|
||||||
@@ -740,7 +816,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void getProperties(V8Message msg) {
|
@Override public synchronized void getProperties(V8Message msg) throws IOException {
|
||||||
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var obj = ref.obj;
|
var obj = ref.obj;
|
||||||
|
|
||||||
@@ -764,7 +840,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("name", Values.toString(ctx, key));
|
||||||
propDesc.set("value", serializeObj(ctx, obj.getMember(ctx, key)));
|
propDesc.set("value", serializeObj(ctx, Values.getMember(ctx, obj, key)));
|
||||||
propDesc.set("writable", obj.memberWritable(key));
|
propDesc.set("writable", obj.memberWritable(key));
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
@@ -773,7 +849,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var proto = obj.getPrototype(ctx);
|
var proto = Values.getPrototype(ctx, obj);
|
||||||
|
|
||||||
var protoDesc = new JSONMap();
|
var protoDesc = new JSONMap();
|
||||||
protoDesc.set("name", "__proto__");
|
protoDesc.set("name", "__proto__");
|
||||||
@@ -787,7 +863,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
ws.send(msg.respond(new JSONMap().set("result", res)));
|
ws.send(msg.respond(new JSONMap().set("result", res)));
|
||||||
}
|
}
|
||||||
@Override public synchronized void callFunctionOn(V8Message msg) {
|
@Override public synchronized void callFunctionOn(V8Message msg) throws IOException {
|
||||||
var src = msg.params.string("functionDeclaration");
|
var src = msg.params.string("functionDeclaration");
|
||||||
var args = msg.params
|
var args = msg.params
|
||||||
.list("arguments", new JSONList())
|
.list("arguments", new JSONList())
|
||||||
@@ -835,7 +911,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ctx, e)))); }
|
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ctx, e)))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void runtimeEnable(V8Message msg) {
|
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,18 +942,20 @@ public class SimpleDebugger implements Debugger {
|
|||||||
Frame frame;
|
Frame frame;
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
frame = codeFrameToFrame.get(cf);
|
frame = getFrame(cf);
|
||||||
|
|
||||||
if (!frame.debugData) return false;
|
if (instruction.location != null) frame.updateLoc(DebugContext.get(ctx).mapToCompiled(instruction.location));
|
||||||
|
|
||||||
if (instruction.location != null) frame.updateLoc(ctx.engine.mapToCompiled(instruction.location));
|
|
||||||
loc = frame.location;
|
loc = frame.location;
|
||||||
isBreakpointable = loc != null && (instruction.breakpoint.shouldStepIn());
|
isBreakpointable = loc != null && (instruction.breakpoint.shouldStepIn());
|
||||||
|
|
||||||
if (error != null && (execptionType == CatchType.ALL || execptionType == CatchType.UNCAUGHT && !caught)) {
|
if (error != null && (execptionType == CatchType.ALL || execptionType == CatchType.UNCAUGHT && !caught)) {
|
||||||
pauseException(ctx);
|
pauseException(ctx);
|
||||||
}
|
}
|
||||||
else if (loc != null && (state == State.STEPPING_IN || state == State.STEPPING_OVER) && returnVal != Runners.NO_RETURN && stepOutFrame == frame) {
|
else if (
|
||||||
|
loc != null &&
|
||||||
|
(state == State.STEPPING_IN || state == State.STEPPING_OVER) &&
|
||||||
|
returnVal != Values.NO_RETURN && stepOutFrame == frame
|
||||||
|
) {
|
||||||
pauseDebug(ctx, null);
|
pauseDebug(ctx, null);
|
||||||
}
|
}
|
||||||
else if (isBreakpointable && locToBreakpoint.containsKey(loc)) {
|
else if (isBreakpointable && locToBreakpoint.containsKey(loc)) {
|
||||||
@@ -906,7 +984,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
case STEPPING_IN:
|
case STEPPING_IN:
|
||||||
case STEPPING_OVER:
|
case STEPPING_OVER:
|
||||||
if (stepOutFrame.frame == frame.frame) {
|
if (stepOutFrame.frame == frame.frame) {
|
||||||
if (returnVal != Runners.NO_RETURN || error != null) {
|
if (returnVal != Values.NO_RETURN || error != null) {
|
||||||
state = State.STEPPING_OUT;
|
state = State.STEPPING_OUT;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -943,7 +1021,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
try { idToFrame.remove(codeFrameToFrame.remove(frame).id); }
|
try { idToFrame.remove(codeFrameToFrame.remove(frame).id); }
|
||||||
catch (NullPointerException e) { }
|
catch (NullPointerException e) { }
|
||||||
|
|
||||||
if (ctx.frames().size() == 0) {
|
if (ctx.stackSize == 0) {
|
||||||
if (state == State.PAUSED_EXCEPTION || state == State.PAUSED_NORMAL) resume(State.RESUMED);
|
if (state == State.PAUSED_EXCEPTION || state == State.PAUSED_NORMAL) resume(State.RESUMED);
|
||||||
}
|
}
|
||||||
else if (stepOutFrame != null && stepOutFrame.frame == frame && state == State.STEPPING_OUT) {
|
else if (stepOutFrame != null && stepOutFrame.frame == frame && state == State.STEPPING_OUT) {
|
||||||
@@ -952,19 +1030,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void connect() {
|
public SimpleDebugger attach(DebugContext ctx) {
|
||||||
if (!target.attachDebugger(this)) {
|
ctx.attachDebugger(this);
|
||||||
ws.send(new V8Error("A debugger is already attached to this engine."));
|
return this;
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override public synchronized void disconnect() {
|
|
||||||
target.detachDebugger();
|
|
||||||
enabled = false;
|
|
||||||
updateNotifier.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleDebugger(WebSocket ws, Engine target) {
|
public SimpleDebugger(WebSocket ws) {
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
this.target = target;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
|
|
||||||
public class V8Error {
|
public class V8Error {
|
||||||
public final String message;
|
public final String message;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
|
|
||||||
public class V8Event {
|
public class V8Event {
|
||||||
public final String name;
|
public final String name;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.json.JSONElement;
|
import me.topchetoeu.jscript.common.json.JSONElement;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
|
|
||||||
public class V8Message {
|
public class V8Message {
|
||||||
public final String name;
|
public final String name;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.json.JSON;
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
|
|
||||||
public class V8Result {
|
public class V8Result {
|
||||||
public final int id;
|
public final int id;
|
||||||
193
src/me/topchetoeu/jscript/core/engine/debug/WebSocket.java
Normal file
193
src/me/topchetoeu/jscript/core/engine/debug/WebSocket.java
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.core.engine.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((len >> 56) & 0xFF);
|
||||||
|
out().write((len >> 48) & 0xFF);
|
||||||
|
out().write((len >> 40) & 0xFF);
|
||||||
|
out().write((len >> 32) & 0xFF);
|
||||||
|
out().write((len >> 24) & 0xFF);
|
||||||
|
out().write((len >> 16) & 0xFF);
|
||||||
|
out().write((len >> 8) & 0xFF);
|
||||||
|
out().write(len & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private synchronized void write(int type, byte[] data) throws IOException {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < data.length / 0xFFFF; i++) {
|
||||||
|
out().write(type);
|
||||||
|
writeLength(0xFFFF);
|
||||||
|
out().write(data, i * 0xFFFF, 0xFFFF);
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out().write(type | 0x80);
|
||||||
|
writeLength(data.length % 0xFFFF);
|
||||||
|
out().write(data, i * 0xFFFF, data.length % 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(String data) throws IOException {
|
||||||
|
if (closed) throw new IllegalStateException("Object is closed.");
|
||||||
|
write(1, data.getBytes());
|
||||||
|
}
|
||||||
|
public void send(byte[] data) throws IOException {
|
||||||
|
if (closed) throw new IllegalStateException("Object 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("Object 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,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.core.engine.debug;
|
||||||
|
|
||||||
public class WebSocketMessage {
|
public class WebSocketMessage {
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
package me.topchetoeu.jscript.engine.frame;
|
package me.topchetoeu.jscript.core.engine.frame;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.scope.LocalScope;
|
import me.topchetoeu.jscript.core.engine.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.core.engine.scope.LocalScope;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.core.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ScopeValue;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.ScopeValue;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.InterruptException;
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.InterruptException;
|
||||||
|
|
||||||
public class CodeFrame {
|
public class CodeFrame {
|
||||||
public static enum TryState {
|
public static enum TryState {
|
||||||
@@ -37,8 +38,10 @@ public class CodeFrame {
|
|||||||
return ptr >= start && ptr < end;
|
return ptr >= start && ptr < end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCause(EngineException target) {
|
||||||
|
if (error != null) target.setCause(error);
|
||||||
|
}
|
||||||
public TryCtx _catch(EngineException e) {
|
public TryCtx _catch(EngineException e) {
|
||||||
if (error != null) e.setCause(error);
|
|
||||||
return new TryCtx(TryState.CATCH, e, result, restoreStackPtr, start, end, -1, finallyStart);
|
return new TryCtx(TryState.CATCH, e, result, restoreStackPtr, start, end, -1, finallyStart);
|
||||||
}
|
}
|
||||||
public TryCtx _finally(PendingResult res) {
|
public TryCtx _finally(PendingResult res) {
|
||||||
@@ -93,13 +96,14 @@ public class CodeFrame {
|
|||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final Stack<TryCtx> tryStack = new Stack<>();
|
public final Stack<TryCtx> tryStack = new Stack<>();
|
||||||
public final CodeFunction function;
|
public final CodeFunction function;
|
||||||
|
public final Context ctx;
|
||||||
public Object[] stack = new Object[32];
|
public Object[] stack = new Object[32];
|
||||||
public int stackPtr = 0;
|
public int stackPtr = 0;
|
||||||
public int codePtr = 0;
|
public int codePtr = 0;
|
||||||
public boolean jumpFlag = false, popTryFlag = false;
|
public boolean jumpFlag = false, popTryFlag = false;
|
||||||
private Location prevLoc = null;
|
private Location prevLoc = null;
|
||||||
|
|
||||||
public ObjectValue getLocalScope(Context ctx, boolean props) {
|
public ObjectValue getLocalScope(boolean props) {
|
||||||
var names = new String[scope.locals.length];
|
var names = new String[scope.locals.length];
|
||||||
|
|
||||||
for (int i = 0; i < scope.locals.length; i++) {
|
for (int i = 0; i < scope.locals.length; i++) {
|
||||||
@@ -114,7 +118,7 @@ public class CodeFrame {
|
|||||||
|
|
||||||
return new ScopeValue(scope.locals, names);
|
return new ScopeValue(scope.locals, names);
|
||||||
}
|
}
|
||||||
public ObjectValue getCaptureScope(Context ctx, boolean props) {
|
public ObjectValue getCaptureScope(boolean props) {
|
||||||
var names = new String[scope.captures.length];
|
var names = new String[scope.captures.length];
|
||||||
|
|
||||||
for (int i = 0; i < scope.captures.length; i++) {
|
for (int i = 0; i < scope.captures.length; i++) {
|
||||||
@@ -125,7 +129,7 @@ public class CodeFrame {
|
|||||||
|
|
||||||
return new ScopeValue(scope.captures, names);
|
return new ScopeValue(scope.captures, names);
|
||||||
}
|
}
|
||||||
public ObjectValue getValStackScope(Context ctx) {
|
public ObjectValue getValStackScope() {
|
||||||
return new ObjectValue() {
|
return new ObjectValue() {
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Context ctx, Object key) {
|
||||||
@@ -177,7 +181,7 @@ public class CodeFrame {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public void push(Context ctx, Object val) {
|
public void push(Object val) {
|
||||||
if (stack.length <= stackPtr) {
|
if (stack.length <= stackPtr) {
|
||||||
var newStack = new Object[stack.length * 2];
|
var newStack = new Object[stack.length * 2];
|
||||||
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
||||||
@@ -186,20 +190,19 @@ public class CodeFrame {
|
|||||||
stack[stackPtr++] = Values.normalize(ctx, val);
|
stack[stackPtr++] = Values.normalize(ctx, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object next(Context ctx, Object value, Object returnValue, EngineException error) {
|
public Object next(Object value, Object returnValue, EngineException error) {
|
||||||
if (value != Runners.NO_RETURN) push(ctx, value);
|
if (value != Values.NO_RETURN) push(value);
|
||||||
|
|
||||||
Instruction instr = null;
|
Instruction instr = null;
|
||||||
if (codePtr >= 0 && codePtr < function.body.length) instr = function.body[codePtr];
|
if (codePtr >= 0 && codePtr < function.body.length) instr = function.body[codePtr];
|
||||||
|
|
||||||
if (returnValue == Runners.NO_RETURN && error == null) {
|
if (returnValue == Values.NO_RETURN && error == null) {
|
||||||
try {
|
try {
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptException();
|
if (Thread.currentThread().isInterrupted()) throw new InterruptException();
|
||||||
|
|
||||||
if (instr == null) returnValue = null;
|
if (instr == null) returnValue = null;
|
||||||
else {
|
else {
|
||||||
// System.out.println(instr + "@" + instr.location);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, Values.NO_RETURN, null, false);
|
||||||
ctx.engine.onInstruction(ctx, this, instr, Runners.NO_RETURN, null, false);
|
|
||||||
|
|
||||||
if (instr.location != null) prevLoc = instr.location;
|
if (instr.location != null) prevLoc = instr.location;
|
||||||
|
|
||||||
@@ -220,10 +223,11 @@ public class CodeFrame {
|
|||||||
TryCtx newCtx = null;
|
TryCtx newCtx = null;
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
tryCtx.setCause(error);
|
||||||
if (tryCtx.hasCatch()) newCtx = tryCtx._catch(error);
|
if (tryCtx.hasCatch()) newCtx = tryCtx._catch(error);
|
||||||
else if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofThrow(error, instr));
|
else if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofThrow(error, instr));
|
||||||
}
|
}
|
||||||
else if (returnValue != Runners.NO_RETURN) {
|
else if (returnValue != Values.NO_RETURN) {
|
||||||
if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofReturn(returnValue, instr));
|
if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofReturn(returnValue, instr));
|
||||||
}
|
}
|
||||||
else if (jumpFlag && !tryCtx.inBounds(codePtr)) {
|
else if (jumpFlag && !tryCtx.inBounds(codePtr)) {
|
||||||
@@ -250,7 +254,7 @@ public class CodeFrame {
|
|||||||
tryStack.push(newCtx);
|
tryStack.push(newCtx);
|
||||||
}
|
}
|
||||||
error = null;
|
error = null;
|
||||||
returnValue = Runners.NO_RETURN;
|
returnValue = Values.NO_RETURN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -268,15 +272,17 @@ public class CodeFrame {
|
|||||||
tryStack.pop();
|
tryStack.pop();
|
||||||
codePtr = tryCtx.end;
|
codePtr = tryCtx.end;
|
||||||
if (tryCtx.result.instruction != null) instr = tryCtx.result.instruction;
|
if (tryCtx.result.instruction != null) instr = tryCtx.result.instruction;
|
||||||
if (tryCtx.result.isJump) {
|
if (!jumpFlag && returnValue == Values.NO_RETURN && error == null) {
|
||||||
codePtr = tryCtx.result.ptr;
|
if (tryCtx.result.isJump) {
|
||||||
jumpFlag = true;
|
codePtr = tryCtx.result.ptr;
|
||||||
|
jumpFlag = true;
|
||||||
|
}
|
||||||
|
if (tryCtx.result.isReturn) returnValue = tryCtx.result.value;
|
||||||
|
if (error == null && tryCtx.result.isThrow) {
|
||||||
|
error = tryCtx.result.error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tryCtx.result.isReturn) returnValue = tryCtx.result.value;
|
if (error != null) tryCtx.setCause(error);
|
||||||
if (tryCtx.result.isThrow) {
|
|
||||||
error = tryCtx.result.error;
|
|
||||||
}
|
|
||||||
if (error != null) error.setCause(tryCtx.error);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,15 +297,22 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.engine.onInstruction(ctx, this, instr, null, error, caught);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, null, error, caught);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
if (returnValue != Runners.NO_RETURN) {
|
if (returnValue != Values.NO_RETURN) {
|
||||||
ctx.engine.onInstruction(ctx, this, instr, returnValue, null, false);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, returnValue, null, false);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Runners.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPush() {
|
||||||
|
DebugContext.get(ctx).onFramePush(ctx, this);
|
||||||
|
}
|
||||||
|
public void onPop() {
|
||||||
|
DebugContext.get(ctx.parent).onFramePop(ctx.parent, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFrame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
public CodeFrame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
||||||
@@ -314,5 +327,6 @@ public class CodeFrame {
|
|||||||
|
|
||||||
this.thisArg = thisArg;
|
this.thisArg = thisArg;
|
||||||
this.function = func;
|
this.function = func;
|
||||||
|
this.ctx = ctx.pushFrame(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.frame;
|
package me.topchetoeu.jscript.core.engine.frame;
|
||||||
|
|
||||||
public enum ConvertHint {
|
public enum ConvertHint {
|
||||||
TOSTRING,
|
TOSTRING,
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
package me.topchetoeu.jscript.engine.frame;
|
package me.topchetoeu.jscript.core.engine.frame;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.core.engine.Engine;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.core.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.core.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.engine.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
|
||||||
public class Runners {
|
public class Runners {
|
||||||
public static final Object NO_RETURN = new Object();
|
|
||||||
|
|
||||||
public static Object execReturn(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execReturn(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
return frame.pop();
|
return frame.pop();
|
||||||
}
|
}
|
||||||
@@ -32,26 +32,26 @@ public class Runners {
|
|||||||
var func = frame.pop();
|
var func = frame.pop();
|
||||||
var thisArg = frame.pop();
|
var thisArg = frame.pop();
|
||||||
|
|
||||||
frame.push(ctx, Values.call(ctx, func, thisArg, callArgs));
|
frame.push(Values.call(ctx, func, thisArg, callArgs));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execCallNew(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execCallNew(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var funcObj = frame.pop();
|
var funcObj = frame.pop();
|
||||||
|
|
||||||
frame.push(ctx, Values.callNew(ctx, funcObj, callArgs));
|
frame.push(Values.callNew(ctx, funcObj, callArgs));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execMakeVar(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execMakeVar(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var name = (String)instr.get(0);
|
var name = (String)instr.get(0);
|
||||||
ctx.environment().global.define(name);
|
ctx.environment.global.define(name);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execDefProp(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execDefProp(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var setter = frame.pop();
|
var setter = frame.pop();
|
||||||
@@ -59,14 +59,14 @@ public class Runners {
|
|||||||
var name = frame.pop();
|
var name = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
if (getter != null && !Values.isFunction(getter)) throw EngineException.ofType("Getter must be a function or undefined.");
|
if (getter != null && !(getter instanceof FunctionValue)) throw EngineException.ofType("Getter must be a function or undefined.");
|
||||||
if (setter != null && !Values.isFunction(setter)) throw EngineException.ofType("Setter must be a function or undefined.");
|
if (setter != null && !(setter instanceof FunctionValue)) throw EngineException.ofType("Setter must be a function or undefined.");
|
||||||
if (!Values.isObject(obj)) throw EngineException.ofType("Property apply target must be an object.");
|
if (!(obj instanceof ObjectValue)) throw EngineException.ofType("Property apply target must be an object.");
|
||||||
Values.object(obj).defineProperty(ctx, name, Values.function(getter), Values.function(setter), false, false);
|
Values.object(obj).defineProperty(ctx, name, Values.function(getter), Values.function(setter), false, false);
|
||||||
|
|
||||||
frame.push(ctx, obj);
|
frame.push(obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execInstanceof(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execInstanceof(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var type = frame.pop();
|
var type = frame.pop();
|
||||||
@@ -74,14 +74,14 @@ public class Runners {
|
|||||||
|
|
||||||
if (!Values.isPrimitive(type)) {
|
if (!Values.isPrimitive(type)) {
|
||||||
var proto = Values.getMember(ctx, type, "prototype");
|
var proto = Values.getMember(ctx, type, "prototype");
|
||||||
frame.push(ctx, Values.isInstanceOf(ctx, obj, proto));
|
frame.push(Values.isInstanceOf(ctx, obj, proto));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
frame.push(ctx, false);
|
frame.push(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execKeys(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execKeys(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
@@ -89,17 +89,17 @@ public class Runners {
|
|||||||
var members = Values.getMembers(ctx, val, false, false);
|
var members = Values.getMembers(ctx, val, false, false);
|
||||||
Collections.reverse(members);
|
Collections.reverse(members);
|
||||||
|
|
||||||
frame.push(ctx, null);
|
frame.push(null);
|
||||||
|
|
||||||
for (var el : members) {
|
for (var el : members) {
|
||||||
if (el instanceof Symbol) continue;
|
if (el instanceof Symbol) continue;
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(ctx, "value", el);
|
obj.defineProperty(ctx, "value", el);
|
||||||
frame.push(ctx, obj);
|
frame.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execTryStart(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execTryStart(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
@@ -111,58 +111,58 @@ public class Runners {
|
|||||||
int end = (int)instr.get(2) + start;
|
int end = (int)instr.get(2) + start;
|
||||||
frame.addTry(start, end, catchStart, finallyStart);
|
frame.addTry(start, end, catchStart, finallyStart);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execTryEnd(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execTryEnd(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.popTryFlag = true;
|
frame.popTryFlag = true;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDup(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execDup(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
int count = instr.get(0);
|
int count = instr.get(0);
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
frame.push(ctx, frame.peek(count - 1));
|
frame.push(frame.peek(count - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadUndefined(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadUndefined(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, null);
|
frame.push(null);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadValue(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadValue(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, instr.get(0));
|
frame.push(instr.get(0));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadVar(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadVar(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) frame.push(ctx, ctx.environment().global.get(ctx, (String)i));
|
if (i instanceof String) frame.push(ctx.environment.global.get(ctx, (String)i));
|
||||||
else frame.push(ctx, frame.scope.get((int)i).get(ctx));
|
else frame.push(frame.scope.get((int)i).get(ctx));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadObj(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadObj(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, new ObjectValue());
|
frame.push(new ObjectValue());
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadGlob(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadGlob(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, ctx.environment().global.obj);
|
frame.push(ctx.environment.global.obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadArr(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadArr(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
res.setSize(instr.get(0));
|
res.setSize(instr.get(0));
|
||||||
frame.push(ctx, res);
|
frame.push(res);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
long id = (Long)instr.get(0);
|
long id = (Long)instr.get(0);
|
||||||
@@ -172,40 +172,45 @@ public class Runners {
|
|||||||
captures[i - 1] = frame.scope.get(instr.get(i));
|
captures[i - 1] = frame.scope.get(instr.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
var func = new CodeFunction(ctx.environment(), "", Engine.functions.get(id), captures);
|
var func = new CodeFunction(ctx.environment, "", Engine.functions.get(id), captures);
|
||||||
|
|
||||||
frame.push(ctx, func);
|
frame.push(func);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadMember(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadMember(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
frame.push(ctx, Values.getMember(ctx, obj, key));
|
frame.push(Values.getMember(ctx, obj, key));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
throw EngineException.ofType(e.getMessage());
|
throw EngineException.ofType(e.getMessage());
|
||||||
}
|
}
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadKeyMember(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadKeyMember(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, instr.get(0));
|
frame.push(instr.get(0));
|
||||||
return execLoadMember(ctx, instr, frame);
|
return execLoadMember(ctx, instr, frame);
|
||||||
}
|
}
|
||||||
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, ctx.environment().regexConstructor.call(ctx, null, instr.get(0), instr.get(1)));
|
if (ctx.hasNotNull(Environment.REGEX_CONSTR)) {
|
||||||
|
frame.push(Values.callNew(ctx, ctx.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw EngineException.ofSyntax("Regex is not supported.");
|
||||||
|
}
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDiscard(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execDiscard(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreMember(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execStoreMember(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
@@ -213,30 +218,30 @@ public class Runners {
|
|||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
if (!Values.setMember(ctx, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'.");
|
if (!Values.setMember(ctx, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'.");
|
||||||
if ((boolean)instr.get(0)) frame.push(ctx, val);
|
if ((boolean)instr.get(0)) frame.push(val);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreVar(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execStoreVar(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) ctx.environment().global.set(ctx, (String)i, val);
|
if (i instanceof String) ctx.environment.global.set(ctx, (String)i, val);
|
||||||
else frame.scope.get((int)i).set(ctx, val);
|
else frame.scope.get((int)i).set(ctx, val);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreSelfFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execStoreSelfFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function);
|
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execJmp(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execJmp(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execJmpIf(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execJmpIf(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
if (Values.toBoolean(frame.pop())) {
|
if (Values.toBoolean(frame.pop())) {
|
||||||
@@ -244,7 +249,7 @@ public class Runners {
|
|||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
}
|
}
|
||||||
else frame.codePtr ++;
|
else frame.codePtr ++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execJmpIfNot(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execJmpIfNot(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
if (Values.not(frame.pop())) {
|
if (Values.not(frame.pop())) {
|
||||||
@@ -252,37 +257,37 @@ public class Runners {
|
|||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
}
|
}
|
||||||
else frame.codePtr ++;
|
else frame.codePtr ++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execIn(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execIn(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
var index = frame.pop();
|
var index = frame.pop();
|
||||||
|
|
||||||
frame.push(ctx, Values.hasMember(ctx, obj, index, false));
|
frame.push(Values.hasMember(ctx, obj, index, false));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execTypeof(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execTypeof(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
String name = instr.get(0);
|
String name = instr.get(0);
|
||||||
Object obj;
|
Object obj;
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
if (ctx.environment().global.has(ctx, name)) {
|
if (ctx.environment.global.has(ctx, name)) {
|
||||||
obj = ctx.environment().global.get(ctx, name);
|
obj = ctx.environment.global.get(ctx, name);
|
||||||
}
|
}
|
||||||
else obj = null;
|
else obj = null;
|
||||||
}
|
}
|
||||||
else obj = frame.pop();
|
else obj = frame.pop();
|
||||||
|
|
||||||
frame.push(ctx, Values.type(obj));
|
frame.push(Values.type(obj));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execNop(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execNop(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDelete(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execDelete(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
@@ -291,7 +296,7 @@ public class Runners {
|
|||||||
|
|
||||||
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execOperation(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execOperation(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
@@ -300,9 +305,9 @@ public class Runners {
|
|||||||
|
|
||||||
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
||||||
|
|
||||||
frame.push(ctx, Values.operation(ctx, op, args));
|
frame.push(Values.operation(ctx, op, args));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object exec(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object exec(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.core.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.core.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
|
|
||||||
public class GlobalScope implements ScopeRecord {
|
public class GlobalScope implements ScopeRecord {
|
||||||
public final ObjectValue obj;
|
public final ObjectValue obj;
|
||||||
|
|
||||||
public boolean has(Context ctx, String name) {
|
public boolean has(Context ctx, String name) {
|
||||||
return obj.hasMember(ctx, name, false);
|
return Values.hasMember(null, obj, name, false);
|
||||||
}
|
}
|
||||||
public Object getKey(String name) {
|
public Object getKey(String name) {
|
||||||
return name;
|
return name;
|
||||||
@@ -21,7 +22,7 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
|
|
||||||
public GlobalScope globalChild() {
|
public GlobalScope globalChild() {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.setPrototype(null, this.obj);
|
Values.setPrototype(null, obj, this.obj);
|
||||||
return new GlobalScope(obj);
|
return new GlobalScope(obj);
|
||||||
}
|
}
|
||||||
public LocalScopeRecord child() {
|
public LocalScopeRecord child() {
|
||||||
@@ -29,14 +30,14 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object define(String name) {
|
public Object define(String name) {
|
||||||
if (obj.hasMember(null, name, true)) return name;
|
if (Values.hasMember(Context.NULL, obj, name, false)) return name;
|
||||||
obj.defineProperty(null, name, null);
|
obj.defineProperty(Context.NULL, name, null);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
public void define(String name, Variable val) {
|
public void define(String name, Variable val) {
|
||||||
obj.defineProperty(null, name,
|
obj.defineProperty(Context.NULL, name,
|
||||||
new NativeFunction("get " + name, (ctx, th, a) -> val.get(ctx)),
|
new NativeFunction("get " + name, args -> val.get(args.ctx)),
|
||||||
new NativeFunction("set " + name, (ctx, th, args) -> { val.set(ctx, args.length > 0 ? args[0] : null); return null; }),
|
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
|
||||||
true, true
|
true, true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -51,12 +52,12 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Context ctx, String name) {
|
public Object get(Context ctx, String name) {
|
||||||
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
else return obj.getMember(ctx, name);
|
else return Values.getMember(ctx, obj, name);
|
||||||
}
|
}
|
||||||
public void set(Context ctx, String name, Object val) {
|
public void set(Context ctx, String name, Object val) {
|
||||||
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
if (!obj.setMember(ctx, name, val, false)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
if (!Values.setMember(ctx, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> keys() {
|
public Set<String> keys() {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
public interface ScopeRecord {
|
public interface ScopeRecord {
|
||||||
public Object getKey(String name);
|
public Object getKey(String name);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
|
||||||
public class ValueVariable implements Variable {
|
public class ValueVariable implements Variable {
|
||||||
public boolean readonly;
|
public boolean readonly;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.core.engine.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
|
||||||
public interface Variable {
|
public interface Variable {
|
||||||
Object get(Context ctx);
|
Object get(Context ctx);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -6,7 +6,7 @@ import java.util.Comparator;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
|
||||||
// TODO: Make methods generic
|
// TODO: Make methods generic
|
||||||
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
||||||
@@ -84,6 +84,8 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
public void copyTo(Context ctx, ArrayValue arr, int sourceStart, int destStart, int count) {
|
public void copyTo(Context ctx, ArrayValue arr, int sourceStart, int destStart, int count) {
|
||||||
// Iterate in reverse to reallocate at most once
|
// Iterate in reverse to reallocate at most once
|
||||||
|
if (destStart + count > arr.size) arr.size = destStart + count;
|
||||||
|
|
||||||
for (var i = count - 1; i >= 0; i--) {
|
for (var i = count - 1; i >= 0; i--) {
|
||||||
if (i + sourceStart < 0 || i + sourceStart >= size) arr.remove(i + destStart);
|
if (i + sourceStart < 0 || i + sourceStart >= size) arr.remove(i + destStart);
|
||||||
if (values[i + sourceStart] == UNDEFINED) arr.set(ctx, i + destStart, null);
|
if (values[i + sourceStart] == UNDEFINED) arr.set(ctx, i + destStart, null);
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.compilation.FunctionBody;
|
import me.topchetoeu.jscript.core.compilation.FunctionBody;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.core.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.core.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
import me.topchetoeu.jscript.core.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
|
||||||
|
|
||||||
public class CodeFunction extends FunctionValue {
|
public class CodeFunction extends FunctionValue {
|
||||||
public final int localsN;
|
public final int localsN;
|
||||||
@@ -32,16 +31,17 @@ public class CodeFunction extends FunctionValue {
|
|||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Context ctx, Object thisArg, Object ...args) {
|
||||||
var frame = new CodeFrame(ctx, thisArg, args, this);
|
var frame = new CodeFrame(ctx, thisArg, args, this);
|
||||||
try {
|
|
||||||
ctx.pushFrame(frame);
|
|
||||||
|
|
||||||
|
frame.onPush();
|
||||||
|
|
||||||
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
var res = frame.next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, null);
|
var res = frame.next(Values.NO_RETURN, Values.NO_RETURN, null);
|
||||||
if (res != Runners.NO_RETURN) return res;
|
if (res != Values.NO_RETURN) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
ctx.popFrame(frame);
|
frame.onPop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
|
||||||
public abstract class FunctionValue extends ObjectValue {
|
public abstract class FunctionValue extends ObjectValue {
|
||||||
public String name = "";
|
public String name = "";
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.Arguments;
|
||||||
|
|
||||||
public class NativeFunction extends FunctionValue {
|
public class NativeFunction extends FunctionValue {
|
||||||
public static interface NativeFunctionRunner {
|
public static interface NativeFunctionRunner {
|
||||||
Object run(Context ctx, Object thisArg, Object[] args);
|
Object run(Arguments args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final NativeFunctionRunner action;
|
public final NativeFunctionRunner action;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Context ctx, Object thisArg, Object ...args) {
|
||||||
return action.run(ctx, thisArg, args);
|
return action.run(new Arguments(ctx, thisArg, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeFunction(String name, NativeFunctionRunner action) {
|
public NativeFunction(String name, NativeFunctionRunner action) {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
|
||||||
public class NativeWrapper extends ObjectValue {
|
public class NativeWrapper extends ObjectValue {
|
||||||
private static final Object NATIVE_PROTO = new Object();
|
private static final Object NATIVE_PROTO = new Object();
|
||||||
@@ -8,7 +8,7 @@ public class NativeWrapper extends ObjectValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectValue getPrototype(Context ctx) {
|
public ObjectValue getPrototype(Context ctx) {
|
||||||
if (prototype == NATIVE_PROTO) return ctx.environment().wrappers.getProto(wrapped.getClass());
|
if (prototype == NATIVE_PROTO) return ctx.environment.wrappers.getProto(wrapped.getClass());
|
||||||
else return super.getPrototype(ctx);
|
else return super.getPrototype(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -6,7 +6,8 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
|
|
||||||
public class ObjectValue {
|
public class ObjectValue {
|
||||||
public static enum PlaceholderProto {
|
public static enum PlaceholderProto {
|
||||||
@@ -53,6 +54,13 @@ public class ObjectValue {
|
|||||||
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
||||||
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private Property getProperty(Context ctx, Object key) {
|
||||||
|
if (properties.containsKey(key)) return properties.get(key);
|
||||||
|
var proto = getPrototype(ctx);
|
||||||
|
if (proto != null) return proto.getProperty(ctx, key);
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean memberWritable(Object key) {
|
public final boolean memberWritable(Object key) {
|
||||||
if (state == State.FROZEN) return false;
|
if (state == State.FROZEN) return false;
|
||||||
return !values.containsKey(key) || !nonWritableSet.contains(key);
|
return !values.containsKey(key) || !nonWritableSet.contains(key);
|
||||||
@@ -146,45 +154,18 @@ public class ObjectValue {
|
|||||||
|
|
||||||
public ObjectValue getPrototype(Context ctx) {
|
public ObjectValue getPrototype(Context ctx) {
|
||||||
try {
|
try {
|
||||||
if (prototype == OBJ_PROTO) return ctx.environment().proto("object");
|
if (prototype == OBJ_PROTO) return ctx.get(Environment.OBJECT_PROTO);
|
||||||
if (prototype == ARR_PROTO) return ctx.environment().proto("array");
|
if (prototype == ARR_PROTO) return ctx.get(Environment.ARRAY_PROTO);
|
||||||
if (prototype == FUNC_PROTO) return ctx.environment().proto("function");
|
if (prototype == FUNC_PROTO) return ctx.get(Environment.FUNCTION_PROTO);
|
||||||
if (prototype == ERR_PROTO) return ctx.environment().proto("error");
|
if (prototype == ERR_PROTO) return ctx.get(Environment.ERROR_PROTO);
|
||||||
if (prototype == RANGE_ERR_PROTO) return ctx.environment().proto("rangeErr");
|
if (prototype == RANGE_ERR_PROTO) return ctx.get(Environment.RANGE_ERR_PROTO);
|
||||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.environment().proto("syntaxErr");
|
if (prototype == SYNTAX_ERR_PROTO) return ctx.get(Environment.SYNTAX_ERR_PROTO);
|
||||||
if (prototype == TYPE_ERR_PROTO) return ctx.environment().proto("typeErr");
|
if (prototype == TYPE_ERR_PROTO) return ctx.get(Environment.TYPE_ERR_PROTO);
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) { return null; }
|
catch (NullPointerException e) { return null; }
|
||||||
|
|
||||||
return (ObjectValue)prototype;
|
return (ObjectValue)prototype;
|
||||||
}
|
}
|
||||||
public final boolean setPrototype(Context ctx, Object val) {
|
|
||||||
val = Values.normalize(ctx, val);
|
|
||||||
|
|
||||||
if (!extensible()) return false;
|
|
||||||
if (val == null || val == Values.NULL) {
|
|
||||||
prototype = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (Values.isObject(val)) {
|
|
||||||
var obj = Values.object(val);
|
|
||||||
|
|
||||||
if (ctx != null && ctx.environment() != null) {
|
|
||||||
if (obj == ctx.environment().proto("object")) prototype = OBJ_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("array")) prototype = ARR_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("function")) prototype = FUNC_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("error")) prototype = ERR_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("syntaxErr")) prototype = SYNTAX_ERR_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("typeErr")) prototype = TYPE_ERR_PROTO;
|
|
||||||
else if (obj == ctx.environment().proto("rangeErr")) prototype = RANGE_ERR_PROTO;
|
|
||||||
else prototype = obj;
|
|
||||||
}
|
|
||||||
else prototype = obj;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public final boolean setPrototype(PlaceholderProto val) {
|
public final boolean setPrototype(PlaceholderProto val) {
|
||||||
if (!extensible()) return false;
|
if (!extensible()) return false;
|
||||||
switch (val) {
|
switch (val) {
|
||||||
@@ -200,18 +181,21 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Property getProperty(Context ctx, Object key) {
|
/**
|
||||||
if (properties.containsKey(key)) return properties.get(key);
|
* A method, used to get the value of a field. If a property is bound to
|
||||||
var proto = getPrototype(ctx);
|
* this key, but not a field, this method should return null.
|
||||||
if (proto != null) return proto.getProperty(ctx, key);
|
*/
|
||||||
else return null;
|
|
||||||
}
|
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Context ctx, Object key) {
|
||||||
if (values.containsKey(key)) return values.get(key);
|
if (values.containsKey(key)) return values.get(key);
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ctx);
|
||||||
if (proto != null) return proto.getField(ctx, key);
|
if (proto != null) return proto.getField(ctx, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Changes the value of a field, that is bound to the given key. If no field is
|
||||||
|
* bound to this key, a new field should be created with the given value
|
||||||
|
* @return Whether or not the operation was successful
|
||||||
|
*/
|
||||||
protected boolean setField(Context ctx, Object key, Object val) {
|
protected boolean setField(Context ctx, Object key, Object val) {
|
||||||
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
||||||
((FunctionValue)val).name = Values.toString(ctx, key);
|
((FunctionValue)val).name = Values.toString(ctx, key);
|
||||||
@@ -220,9 +204,16 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Deletes the field bound to the given key.
|
||||||
|
*/
|
||||||
protected void deleteField(Context ctx, Object key) {
|
protected void deleteField(Context ctx, Object key) {
|
||||||
values.remove(key);
|
values.remove(key);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Returns whether or not there is a field bound to the given key.
|
||||||
|
* This must ignore properties
|
||||||
|
*/
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Context ctx, Object key) {
|
||||||
return values.containsKey(key);
|
return values.containsKey(key);
|
||||||
}
|
}
|
||||||
@@ -243,10 +234,6 @@ public class ObjectValue {
|
|||||||
}
|
}
|
||||||
else return getField(ctx, key);
|
else return getField(ctx, key);
|
||||||
}
|
}
|
||||||
public final Object getMember(Context ctx, Object key) {
|
|
||||||
return getMember(ctx, key, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean setMember(Context ctx, Object key, Object val, Object thisArg, boolean onlyProps) {
|
public final boolean setMember(Context ctx, Object key, Object val, Object thisArg, boolean onlyProps) {
|
||||||
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
|
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
|
||||||
|
|
||||||
@@ -266,10 +253,6 @@ public class ObjectValue {
|
|||||||
else if (nonWritableSet.contains(key)) return false;
|
else if (nonWritableSet.contains(key)) return false;
|
||||||
else return setField(ctx, key, val);
|
else return setField(ctx, key, val);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Context ctx, Object key, Object val, boolean onlyProps) {
|
|
||||||
return setMember(ctx, Values.normalize(ctx, key), Values.normalize(ctx, val), this, onlyProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean hasMember(Context ctx, Object key, boolean own) {
|
public final boolean hasMember(Context ctx, Object key, boolean own) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ctx, key);
|
||||||
|
|
||||||
@@ -290,6 +273,33 @@ public class ObjectValue {
|
|||||||
deleteField(ctx, key);
|
deleteField(ctx, key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public final boolean setPrototype(Context ctx, Object val) {
|
||||||
|
val = Values.normalize(ctx, val);
|
||||||
|
|
||||||
|
if (!extensible()) return false;
|
||||||
|
if (val == null || val == Values.NULL) {
|
||||||
|
prototype = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (val instanceof ObjectValue) {
|
||||||
|
var obj = Values.object(val);
|
||||||
|
|
||||||
|
if (ctx != null) {
|
||||||
|
if (obj == ctx.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
||||||
|
else if (obj == ctx.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
||||||
|
else prototype = obj;
|
||||||
|
}
|
||||||
|
else prototype = obj;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public final ObjectValue getMemberDescriptor(Context ctx, Object key) {
|
public final ObjectValue getMemberDescriptor(Context ctx, Object key) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ctx, key);
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.core.engine.scope.ValueVariable;
|
||||||
|
|
||||||
public class ScopeValue extends ObjectValue {
|
public class ScopeValue extends ObjectValue {
|
||||||
public final ValueVariable[] variables;
|
public final ValueVariable[] variables;
|
||||||
@@ -23,7 +23,7 @@ public class ScopeValue extends ObjectValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ctx);
|
||||||
if (proto != null && proto.hasField(ctx, key) && proto.setField(ctx, key, val)) return true;
|
if (proto != null && proto.hasMember(ctx, key, false) && proto.setField(ctx, key, val)) return true;
|
||||||
|
|
||||||
return super.setField(ctx, key, val);
|
return super.setField(ctx, key, val);
|
||||||
}
|
}
|
||||||
28
src/me/topchetoeu/jscript/core/engine/values/Symbol.java
Normal file
28
src/me/topchetoeu/jscript/core/engine/values/Symbol.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public final class Symbol {
|
||||||
|
private static final HashMap<String, Symbol> registry = new HashMap<>();
|
||||||
|
|
||||||
|
public final String value;
|
||||||
|
|
||||||
|
public Symbol(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (value == null) return "Symbol";
|
||||||
|
else return "@@" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Symbol get(String name) {
|
||||||
|
if (registry.containsKey(name)) return registry.get(name);
|
||||||
|
else {
|
||||||
|
var res = new Symbol(name);
|
||||||
|
registry.put(name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.core.engine.values;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -10,13 +12,13 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
import me.topchetoeu.jscript.core.engine.Operation;
|
||||||
import me.topchetoeu.jscript.exceptions.ConvertException;
|
import me.topchetoeu.jscript.core.engine.frame.ConvertHint;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.core.exceptions.ConvertException;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.core.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib;
|
import me.topchetoeu.jscript.lib.PromiseLib;
|
||||||
|
|
||||||
public class Values {
|
public class Values {
|
||||||
@@ -39,10 +41,8 @@ public class Values {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final Object NULL = new Object();
|
public static final Object NULL = new Object();
|
||||||
|
public static final Object NO_RETURN = new Object();
|
||||||
|
|
||||||
public static boolean isObject(Object val) { return val instanceof ObjectValue; }
|
|
||||||
public static boolean isFunction(Object val) { return val instanceof FunctionValue; }
|
|
||||||
public static boolean isArray(Object val) { return val instanceof ArrayValue; }
|
|
||||||
public static boolean isWrapper(Object val) { return val instanceof NativeWrapper; }
|
public static boolean isWrapper(Object val) { return val instanceof NativeWrapper; }
|
||||||
public static boolean isWrapper(Object val, Class<?> clazz) {
|
public static boolean isWrapper(Object val, Class<?> clazz) {
|
||||||
if (!isWrapper(val)) return false;
|
if (!isWrapper(val)) return false;
|
||||||
@@ -89,8 +89,8 @@ public class Values {
|
|||||||
private static Object tryCallConvertFunc(Context ctx, Object obj, String name) {
|
private static Object tryCallConvertFunc(Context ctx, Object obj, String name) {
|
||||||
var func = getMember(ctx, obj, name);
|
var func = getMember(ctx, obj, name);
|
||||||
|
|
||||||
if (func != null) {
|
if (func instanceof FunctionValue) {
|
||||||
var res = ((FunctionValue)func).call(ctx, obj);
|
var res = Values.call(ctx, func, obj);
|
||||||
if (isPrimitive(res)) return res;
|
if (isPrimitive(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +136,6 @@ public class Values {
|
|||||||
if (val instanceof String) {
|
if (val instanceof String) {
|
||||||
try { return Double.parseDouble((String)val); }
|
try { return Double.parseDouble((String)val); }
|
||||||
catch (NumberFormatException e) { return Double.NaN; }
|
catch (NumberFormatException e) { return Double.NaN; }
|
||||||
catch (Throwable e) { throw new UncheckedException(e); }
|
|
||||||
}
|
}
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
}
|
}
|
||||||
@@ -284,7 +283,7 @@ public class Values {
|
|||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
||||||
if (isObject(obj)) return object(obj).getMember(ctx, key);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMember(ctx, key, obj);
|
||||||
|
|
||||||
if (obj instanceof String && key instanceof Number) {
|
if (obj instanceof String && key instanceof Number) {
|
||||||
var i = number(key);
|
var i = number(key);
|
||||||
@@ -310,7 +309,7 @@ public class Values {
|
|||||||
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
||||||
if (key != null && "__proto__".equals(key)) return setPrototype(ctx, obj, val);
|
if (key != null && "__proto__".equals(key)) return setPrototype(ctx, obj, val);
|
||||||
if (isObject(obj)) return object(obj).setMember(ctx, key, val, false);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).setMember(ctx, key, val, obj, false);
|
||||||
|
|
||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto.setMember(ctx, key, val, obj, true);
|
return proto.setMember(ctx, key, val, obj, true);
|
||||||
@@ -320,7 +319,7 @@ public class Values {
|
|||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
|
||||||
if ("__proto__".equals(key)) return true;
|
if ("__proto__".equals(key)) return true;
|
||||||
if (isObject(obj)) return object(obj).hasMember(ctx, key, own);
|
if (obj instanceof ObjectValue) return object(obj).hasMember(ctx, key, own);
|
||||||
|
|
||||||
if (obj instanceof String && key instanceof Number) {
|
if (obj instanceof String && key instanceof Number) {
|
||||||
var i = number(key);
|
var i = number(key);
|
||||||
@@ -337,30 +336,35 @@ public class Values {
|
|||||||
if (obj == null || obj == NULL) return false;
|
if (obj == null || obj == NULL) return false;
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
|
||||||
if (isObject(obj)) return object(obj).deleteMember(ctx, key);
|
if (obj instanceof ObjectValue) return object(obj).deleteMember(ctx, key);
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public static ObjectValue getPrototype(Context ctx, Object obj) {
|
public static ObjectValue getPrototype(Context ctx, Object obj) {
|
||||||
if (obj == null || obj == NULL) return null;
|
if (obj == null || obj == NULL) return null;
|
||||||
obj = normalize(ctx, obj);
|
obj = normalize(ctx, obj);
|
||||||
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ctx);
|
||||||
if (ctx == null) return null;
|
if (ctx == null) return null;
|
||||||
|
|
||||||
if (obj instanceof String) return ctx.environment().proto("string");
|
if (obj instanceof String) return ctx.get(Environment.STRING_PROTO);
|
||||||
else if (obj instanceof Number) return ctx.environment().proto("number");
|
else if (obj instanceof Number) return ctx.get(Environment.NUMBER_PROTO);
|
||||||
else if (obj instanceof Boolean) return ctx.environment().proto("bool");
|
else if (obj instanceof Boolean) return ctx.get(Environment.BOOL_PROTO);
|
||||||
else if (obj instanceof Symbol) return ctx.environment().proto("symbol");
|
else if (obj instanceof Symbol) return ctx.get(Environment.SYMBOL_PROTO);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static boolean setPrototype(Context ctx, Object obj, Object proto) {
|
public static boolean setPrototype(Context ctx, Object obj, Object proto) {
|
||||||
obj = normalize(ctx, obj);
|
obj = normalize(ctx, obj);
|
||||||
return isObject(obj) && object(obj).setPrototype(ctx, proto);
|
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ctx, proto);
|
||||||
|
}
|
||||||
|
public static void makePrototypeChain(Context ctx, Object... chain) {
|
||||||
|
for(var i = 1; i < chain.length; i++) {
|
||||||
|
setPrototype(ctx, chain[i], chain[i - 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) {
|
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) {
|
||||||
List<Object> res = new ArrayList<>();
|
List<Object> res = new ArrayList<>();
|
||||||
|
|
||||||
if (isObject(obj)) res = object(obj).keys(includeNonEnumerable);
|
if (obj instanceof ObjectValue) res = object(obj).keys(includeNonEnumerable);
|
||||||
if (obj instanceof String) {
|
if (obj instanceof String) {
|
||||||
for (var i = 0; i < ((String)obj).length(); i++) res.add((double)i);
|
for (var i = 0; i < ((String)obj).length(); i++) res.add((double)i);
|
||||||
}
|
}
|
||||||
@@ -370,7 +374,7 @@ public class Values {
|
|||||||
|
|
||||||
while (proto != null) {
|
while (proto != null) {
|
||||||
res.addAll(proto.keys(includeNonEnumerable));
|
res.addAll(proto.keys(includeNonEnumerable));
|
||||||
proto = proto.getPrototype(ctx);
|
proto = getPrototype(ctx, proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,14 +400,14 @@ public class Values {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) {
|
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) {
|
||||||
if (!isFunction(func)) throw EngineException.ofType("Tried to call a non-function value.");
|
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
|
||||||
return function(func).call(ctx, thisArg, args);
|
return function(func).call(ctx, thisArg, args);
|
||||||
}
|
}
|
||||||
public static Object callNew(Context ctx, Object func, Object ...args) {
|
public static Object callNew(Context ctx, Object func, Object ...args) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
try {
|
try {
|
||||||
var proto = Values.getMember(ctx, func, "prototype");
|
var proto = Values.getMember(ctx, func, "prototype");
|
||||||
res.setPrototype(ctx, proto);
|
setPrototype(ctx, res, proto);
|
||||||
|
|
||||||
var ret = call(ctx, func, res, args);
|
var ret = call(ctx, func, res, args);
|
||||||
|
|
||||||
@@ -476,7 +480,7 @@ public class Values {
|
|||||||
|
|
||||||
if (val instanceof Class) {
|
if (val instanceof Class) {
|
||||||
if (ctx == null) return null;
|
if (ctx == null) return null;
|
||||||
else return ctx.environment().wrappers.getConstr((Class<?>)val);
|
else return ctx.environment.wrappers.getConstr((Class<?>)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NativeWrapper(val);
|
return new NativeWrapper(val);
|
||||||
@@ -543,6 +547,9 @@ public class Values {
|
|||||||
|
|
||||||
if (obj == null) return null;
|
if (obj == null) return null;
|
||||||
if (clazz.isInstance(obj)) return (T)obj;
|
if (clazz.isInstance(obj)) return (T)obj;
|
||||||
|
if (clazz.isAssignableFrom(NativeWrapper.class)) {
|
||||||
|
return (T)new NativeWrapper(obj);
|
||||||
|
}
|
||||||
|
|
||||||
throw new ConvertException(type(obj), clazz.getSimpleName());
|
throw new ConvertException(type(obj), clazz.getSimpleName());
|
||||||
}
|
}
|
||||||
@@ -550,16 +557,16 @@ public class Values {
|
|||||||
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
|
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var symbol = ctx.environment().symbol("Symbol.iterator");
|
var symbol = Symbol.get("Symbol.iterator");
|
||||||
|
|
||||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
var iteratorFunc = getMember(ctx, obj, symbol);
|
||||||
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
var iterator = iteratorFunc instanceof FunctionValue ?
|
var iterator = iteratorFunc instanceof FunctionValue ?
|
||||||
((FunctionValue)iteratorFunc).call(ctx, obj, obj) :
|
((FunctionValue)iteratorFunc).call(ctx, obj, obj) :
|
||||||
iteratorFunc;
|
iteratorFunc;
|
||||||
var nextFunc = getMember(ctx, call(ctx, iteratorFunc, obj), "next");
|
var nextFunc = getMember(ctx, call(ctx, iteratorFunc, obj), "next");
|
||||||
|
|
||||||
if (!isFunction(nextFunc)) return Collections.emptyIterator();
|
if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
|
|
||||||
return new Iterator<Object>() {
|
return new Iterator<Object>() {
|
||||||
private Object value = null;
|
private Object value = null;
|
||||||
@@ -569,11 +576,11 @@ public class Values {
|
|||||||
private void loadNext() {
|
private void loadNext() {
|
||||||
if (next == null) value = null;
|
if (next == null) value = null;
|
||||||
else if (consumed) {
|
else if (consumed) {
|
||||||
var curr = object(next.call(ctx, iterator));
|
var curr = next.call(ctx, iterator);
|
||||||
if (curr == null) { next = null; value = null; }
|
if (curr == null) { next = null; value = null; }
|
||||||
if (toBoolean(curr.getMember(ctx, "done"))) { next = null; value = null; }
|
if (toBoolean(Values.getMember(ctx, curr, "done"))) { next = null; value = null; }
|
||||||
else {
|
else {
|
||||||
this.value = curr.getMember(ctx, "value");
|
this.value = Values.getMember(ctx, curr, "value");
|
||||||
consumed = false;
|
consumed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,16 +611,16 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMember(ctx, getMember(ctx, ctx.environment().proto("symbol"), "constructor"), "iterator");
|
var key = getMember(ctx, getMember(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty(ctx, "next", new NativeFunction("", (_ctx, _th, _args) -> {
|
res.defineProperty(ctx, "next", new NativeFunction("", args -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(_ctx, "value", it.next());
|
obj.defineProperty(args.ctx, "value", it.next());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -629,17 +636,17 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMemberPath(ctx, ctx.environment().proto("symbol"), "constructor", "asyncIterator");
|
var key = getMemberPath(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty(ctx, "next", new NativeFunction("", (_ctx, _th, _args) -> {
|
res.defineProperty(ctx, "next", new NativeFunction("", args -> {
|
||||||
return PromiseLib.await(ctx, () -> {
|
return PromiseLib.await(args.ctx, () -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(_ctx, "value", it.next());
|
obj.defineProperty(args.ctx, "value", it.next());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -658,104 +665,107 @@ public class Values {
|
|||||||
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private static void printValue(Context ctx, Object val, HashSet<Object> passed, int tab) {
|
private static String toReadable(Context ctx, Object val, HashSet<Object> passed, int tab) {
|
||||||
if (tab == 0 && val instanceof String) {
|
if (tab == 0 && val instanceof String) return (String)val;
|
||||||
System.out.print(val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passed.contains(val)) {
|
if (passed.contains(val)) return "[circular]";
|
||||||
System.out.print("[circular]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var printed = true;
|
var printed = true;
|
||||||
|
var res = new StringBuilder();
|
||||||
|
|
||||||
if (val instanceof FunctionValue) {
|
if (val instanceof FunctionValue) {
|
||||||
System.out.print(val.toString());
|
res.append(val.toString());
|
||||||
var loc = val instanceof CodeFunction ? ((CodeFunction)val).loc() : null;
|
var loc = val instanceof CodeFunction ? ((CodeFunction)val).loc() : null;
|
||||||
|
|
||||||
if (loc != null) System.out.print(" @ " + loc);
|
if (loc != null) res.append(" @ " + loc);
|
||||||
}
|
}
|
||||||
else if (val instanceof ArrayValue) {
|
else if (val instanceof ArrayValue) {
|
||||||
System.out.print("[");
|
res.append("[");
|
||||||
var obj = ((ArrayValue)val);
|
var obj = ((ArrayValue)val);
|
||||||
for (int i = 0; i < obj.size(); i++) {
|
for (int i = 0; i < obj.size(); i++) {
|
||||||
if (i != 0) System.out.print(", ");
|
if (i != 0) res.append(", ");
|
||||||
else System.out.print(" ");
|
else res.append(" ");
|
||||||
if (obj.has(i)) printValue(ctx, obj.get(i), passed, tab);
|
if (obj.has(i)) res.append(toReadable(ctx, obj.get(i), passed, tab));
|
||||||
else System.out.print("<empty>");
|
else res.append("<empty>");
|
||||||
}
|
}
|
||||||
System.out.print(" ] ");
|
res.append(" ] ");
|
||||||
}
|
}
|
||||||
else if (val instanceof NativeWrapper) {
|
else if (val instanceof NativeWrapper) {
|
||||||
var obj = ((NativeWrapper)val).wrapped;
|
var obj = ((NativeWrapper)val).wrapped;
|
||||||
System.out.print("Native " + obj.toString() + " ");
|
res.append("Native " + obj.toString() + " ");
|
||||||
}
|
}
|
||||||
else printed = false;
|
else printed = false;
|
||||||
|
|
||||||
if (val instanceof ObjectValue) {
|
if (val instanceof ObjectValue) {
|
||||||
if (tab > 3) {
|
if (tab > 3) {
|
||||||
System.out.print("{...}");
|
return "{...}";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
passed.add(val);
|
passed.add(val);
|
||||||
|
|
||||||
var obj = (ObjectValue)val;
|
var obj = (ObjectValue)val;
|
||||||
if (obj.values.size() + obj.properties.size() == 0 || isEmptyFunc(obj)) {
|
if (obj.values.size() + obj.properties.size() == 0 || isEmptyFunc(obj)) {
|
||||||
if (!printed) System.out.println("{}");
|
if (!printed) res.append("{}\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
System.out.println("{");
|
res.append("{\n");
|
||||||
|
|
||||||
for (var el : obj.values.entrySet()) {
|
for (var el : obj.values.entrySet()) {
|
||||||
for (int i = 0; i < tab + 1; i++) System.out.print(" ");
|
for (int i = 0; i < tab + 1; i++) System.out.print(" ");
|
||||||
printValue(ctx, el.getKey(), passed, tab + 1);
|
res.append(toReadable(ctx, el.getKey(), passed, tab + 1));
|
||||||
System.out.print(": ");
|
res.append(": ");
|
||||||
printValue(ctx, el.getValue(), passed, tab + 1);
|
res.append(toReadable(ctx, el.getValue(), passed, tab + 1));
|
||||||
System.out.println(",");
|
res.append(",\n");
|
||||||
}
|
}
|
||||||
for (var el : obj.properties.entrySet()) {
|
for (var el : obj.properties.entrySet()) {
|
||||||
for (int i = 0; i < tab + 1; i++) System.out.print(" ");
|
for (int i = 0; i < tab + 1; i++) System.out.print(" ");
|
||||||
printValue(ctx, el.getKey(), passed, tab + 1);
|
res.append(toReadable(ctx, el.getKey(), passed, tab + 1));
|
||||||
System.out.println(": [prop],");
|
res.append(": [prop],\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < tab; i++) System.out.print(" ");
|
for (int i = 0; i < tab; i++) res.append(" ");
|
||||||
System.out.print("}");
|
res.append("}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
passed.remove(val);
|
passed.remove(val);
|
||||||
}
|
}
|
||||||
else if (val == null) System.out.print("undefined");
|
else if (val == null) return "undefined";
|
||||||
else if (val == Values.NULL) System.out.print("null");
|
else if (val == Values.NULL) return "null";
|
||||||
else if (val instanceof String) System.out.print("'" + val + "'");
|
else if (val instanceof String) return "'" + val + "'";
|
||||||
else System.out.print(Values.toString(ctx, val));
|
else return Values.toString(ctx, val);
|
||||||
|
|
||||||
|
return res.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toReadable(Context ctx, Object val) {
|
||||||
|
return toReadable(ctx, val, new HashSet<>(), 0);
|
||||||
|
}
|
||||||
|
public static String errorToReadable(RuntimeException err, String prefix) {
|
||||||
|
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
||||||
|
if (err instanceof EngineException) {
|
||||||
|
var ee = ((EngineException)err);
|
||||||
|
try {
|
||||||
|
return prefix + " " + ee.toString(new Context(ee.engine, ee.env));
|
||||||
|
}
|
||||||
|
catch (EngineException ex) {
|
||||||
|
return prefix + " " + toReadable(new Context(ee.engine, ee.env), ee.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (err instanceof SyntaxException) {
|
||||||
|
return prefix + " SyntaxError " + ((SyntaxException)err).msg;
|
||||||
|
}
|
||||||
|
else if (err.getCause() instanceof InterruptedException) return "";
|
||||||
|
else {
|
||||||
|
var str = new ByteArrayOutputStream();
|
||||||
|
err.printStackTrace(new PrintStream(str));
|
||||||
|
|
||||||
|
return prefix + " internal error " + str.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static void printValue(Context ctx, Object val) {
|
public static void printValue(Context ctx, Object val) {
|
||||||
printValue(ctx, val, new HashSet<>(), 0);
|
System.out.print(toReadable(ctx, val));
|
||||||
}
|
}
|
||||||
public static void printError(RuntimeException err, String prefix) {
|
public static void printError(RuntimeException err, String prefix) {
|
||||||
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
System.out.println(errorToReadable(err, prefix));
|
||||||
try {
|
|
||||||
if (err instanceof EngineException) {
|
|
||||||
var ee = ((EngineException)err);
|
|
||||||
System.out.println(prefix + " " + ee.toString(new Context(ee.engine, ee.env)));
|
|
||||||
}
|
|
||||||
else if (err instanceof SyntaxException) {
|
|
||||||
System.out.println("Syntax error:" + ((SyntaxException)err).msg);
|
|
||||||
}
|
|
||||||
else if (err.getCause() instanceof InterruptedException) return;
|
|
||||||
else {
|
|
||||||
System.out.println("Internal error ocurred:");
|
|
||||||
err.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (EngineException ex) {
|
|
||||||
System.out.println("Uncaught ");
|
|
||||||
Values.printValue(null, ((EngineException)err).value);
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.exceptions;
|
package me.topchetoeu.jscript.core.exceptions;
|
||||||
|
|
||||||
public class ConvertException extends RuntimeException {
|
public class ConvertException extends RuntimeException {
|
||||||
public final String source, target;
|
public final String source, target;
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
package me.topchetoeu.jscript.exceptions;
|
package me.topchetoeu.jscript.core.exceptions;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.core.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.core.engine.Engine;
|
||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.core.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.core.engine.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.core.engine.values.ObjectValue.PlaceholderProto;
|
||||||
|
|
||||||
public class EngineException extends RuntimeException {
|
public class EngineException extends RuntimeException {
|
||||||
public static class StackElement {
|
public static class StackElement {
|
||||||
@@ -18,13 +19,13 @@ public class EngineException extends RuntimeException {
|
|||||||
public final Context ctx;
|
public final Context ctx;
|
||||||
|
|
||||||
public boolean visible() {
|
public boolean visible() {
|
||||||
return ctx == null || ctx.environment() == null || ctx.environment().stackVisible;
|
return ctx == null || !ctx.get(Environment.HIDE_STACK, false);
|
||||||
}
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
var res = "";
|
var res = "";
|
||||||
var loc = location;
|
var loc = location;
|
||||||
|
|
||||||
if (loc != null && ctx != null && ctx.engine != null) loc = ctx.engine.mapToCompiled(loc);
|
if (loc != null && ctx != null && ctx.engine != null) loc = DebugContext.get(ctx).mapToCompiled(loc);
|
||||||
|
|
||||||
if (loc != null) res += "at " + loc.toString() + " ";
|
if (loc != null) res += "at " + loc.toString() + " ";
|
||||||
if (function != null && !function.equals("")) res += "in " + function + " ";
|
if (function != null && !function.equals("")) res += "in " + function + " ";
|
||||||
@@ -37,7 +38,7 @@ public class EngineException extends RuntimeException {
|
|||||||
if (function.equals("")) function = null;
|
if (function.equals("")) function = null;
|
||||||
|
|
||||||
if (ctx == null) this.ctx = null;
|
if (ctx == null) this.ctx = null;
|
||||||
else this.ctx = new Context(ctx.engine, ctx.environment());
|
else this.ctx = new Context(ctx.engine, ctx.environment);
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
@@ -52,7 +53,7 @@ public class EngineException extends RuntimeException {
|
|||||||
public EngineException add(Context ctx, String name, Location location) {
|
public EngineException add(Context ctx, String name, Location location) {
|
||||||
var el = new StackElement(ctx, location, name);
|
var el = new StackElement(ctx, location, name);
|
||||||
if (el.function == null && el.location == null) return this;
|
if (el.function == null && el.location == null) return this;
|
||||||
setCtx(ctx.environment(), ctx.engine);
|
setCtx(ctx.environment, ctx.engine);
|
||||||
stackTrace.add(el);
|
stackTrace.add(el);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,11 @@ public class EngineException extends RuntimeException {
|
|||||||
if (this.engine == null) this.engine = engine;
|
if (this.engine == null) this.engine = engine;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public EngineException setCtx(Context ctx) {
|
||||||
|
if (this.env == null) this.env = ctx.environment;
|
||||||
|
if (this.engine == null) this.engine = ctx.engine;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString(Context ctx) {
|
public String toString(Context ctx) {
|
||||||
var ss = new StringBuilder();
|
var ss = new StringBuilder();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.jscript.exceptions;
|
package me.topchetoeu.jscript.core.exceptions;
|
||||||
|
|
||||||
public class InterruptException extends RuntimeException {
|
public class InterruptException extends RuntimeException {
|
||||||
public InterruptException() { }
|
public InterruptException() { }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.exceptions;
|
package me.topchetoeu.jscript.core.exceptions;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
|
|
||||||
public class SyntaxException extends RuntimeException {
|
public class SyntaxException extends RuntimeException {
|
||||||
public final Location loc;
|
public final Location loc;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user