feat: implement map and set polyfills in java
This commit is contained in:
parent
cf36b7adc5
commit
e16c0fedb1
22
lib/core.ts
22
lib/core.ts
@ -12,6 +12,8 @@ interface Internals {
|
|||||||
bool: BooleanConstructor;
|
bool: BooleanConstructor;
|
||||||
number: NumberConstructor;
|
number: NumberConstructor;
|
||||||
string: StringConstructor;
|
string: StringConstructor;
|
||||||
|
map: typeof Map;
|
||||||
|
set: typeof Set;
|
||||||
|
|
||||||
markSpecial(...funcs: Function[]): void;
|
markSpecial(...funcs: Function[]): void;
|
||||||
getEnv(func: Function): Environment | undefined;
|
getEnv(func: Function): Environment | undefined;
|
||||||
@ -45,19 +47,23 @@ interface Internals {
|
|||||||
try {
|
try {
|
||||||
var env: Environment = arguments[0], internals: Internals = arguments[1];
|
var env: Environment = arguments[0], internals: Internals = arguments[1];
|
||||||
|
|
||||||
var Object = env.global.Object = internals.object;
|
const Object = env.global.Object = internals.object;
|
||||||
var Function = env.global.Function = internals.function;
|
const Function = env.global.Function = internals.function;
|
||||||
var Array = env.global.Array = internals.array;
|
const Array = env.global.Array = internals.array;
|
||||||
var Promise = env.global.Promise = internals.promise;
|
const Promise = env.global.Promise = internals.promise;
|
||||||
var Boolean = env.global.Boolean = internals.bool;
|
const Boolean = env.global.Boolean = internals.bool;
|
||||||
var Number = env.global.Number = internals.number;
|
const Number = env.global.Number = internals.number;
|
||||||
var String = env.global.String = internals.string;
|
const String = env.global.String = internals.string;
|
||||||
|
|
||||||
|
const Map = env.global.Map = internals.map;
|
||||||
|
const Set = env.global.Set = internals.set;
|
||||||
|
|
||||||
env.setProto('object', Object.prototype);
|
env.setProto('object', Object.prototype);
|
||||||
env.setProto('function', Function.prototype);
|
env.setProto('function', Function.prototype);
|
||||||
env.setProto('array', Array.prototype);
|
env.setProto('array', Array.prototype);
|
||||||
env.setProto('number', Number.prototype);
|
env.setProto('number', Number.prototype);
|
||||||
env.setProto('string', String.prototype);
|
env.setProto('string', String.prototype);
|
||||||
|
env.setProto('bool', Boolean.prototype);
|
||||||
|
|
||||||
(Object.prototype as any).__proto__ = null;
|
(Object.prototype as any).__proto__ = null;
|
||||||
|
|
||||||
@ -66,8 +72,6 @@ try {
|
|||||||
|
|
||||||
run('values/symbol');
|
run('values/symbol');
|
||||||
run('values/errors');
|
run('values/errors');
|
||||||
run('map');
|
|
||||||
run('set');
|
|
||||||
run('regex');
|
run('regex');
|
||||||
run('timeout');
|
run('timeout');
|
||||||
|
|
||||||
|
93
lib/map.ts
93
lib/map.ts
@ -1,93 +0,0 @@
|
|||||||
define("map", () => {
|
|
||||||
const syms = { values: internals.symbol('Map.values') } as { readonly values: unique symbol };
|
|
||||||
const Object = env.global.Object;
|
|
||||||
|
|
||||||
class Map<KeyT, ValueT> {
|
|
||||||
[syms.values]: any = {};
|
|
||||||
|
|
||||||
public [env.global.Symbol.iterator](): IterableIterator<[KeyT, ValueT]> {
|
|
||||||
return this.entries();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
|
||||||
this[syms.values] = {};
|
|
||||||
}
|
|
||||||
public delete(key: KeyT) {
|
|
||||||
if ((key as any) in this[syms.values]) {
|
|
||||||
delete this[syms.values];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public entries(): IterableIterator<[KeyT, ValueT]> {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: () => {
|
|
||||||
if (i >= keys.length) return { done: true };
|
|
||||||
else return { done: false, value: [ keys[i], this[syms.values][keys[i++]] ] }
|
|
||||||
},
|
|
||||||
[env.global.Symbol.iterator]() { return this; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public keys(): IterableIterator<KeyT> {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: () => {
|
|
||||||
if (i >= keys.length) return { done: true };
|
|
||||||
else return { done: false, value: keys[i] }
|
|
||||||
},
|
|
||||||
[env.global.Symbol.iterator]() { return this; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public values(): IterableIterator<ValueT> {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: () => {
|
|
||||||
if (i >= keys.length) return { done: true };
|
|
||||||
else return { done: false, value: this[syms.values][keys[i++]] }
|
|
||||||
},
|
|
||||||
[env.global.Symbol.iterator]() { return this; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: KeyT) {
|
|
||||||
return this[syms.values][key];
|
|
||||||
}
|
|
||||||
public set(key: KeyT, val: ValueT) {
|
|
||||||
this[syms.values][key] = val;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public has(key: KeyT) {
|
|
||||||
return (key as any) in this[syms.values][key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public get size() {
|
|
||||||
return internals.ownPropKeys(this[syms.values]).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(func: (key: KeyT, val: ValueT, map: Map<KeyT, ValueT>) => void, thisArg?: any) {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
func(keys[i], this[syms.values][keys[i]], this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public constructor(iterable: Iterable<[KeyT, ValueT]>) {
|
|
||||||
const it = iterable[env.global.Symbol.iterator]();
|
|
||||||
|
|
||||||
for (let el = it.next(); !el.done; el = it.next()) {
|
|
||||||
this[syms.values][el.value[0]] = el.value[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env.global.Map = Map;
|
|
||||||
});
|
|
81
lib/set.ts
81
lib/set.ts
@ -1,81 +0,0 @@
|
|||||||
define("set", () => {
|
|
||||||
const syms = { values: internals.symbol('Map.values') } as { readonly values: unique symbol };
|
|
||||||
const Object = env.global.Object;
|
|
||||||
|
|
||||||
class Set<T> {
|
|
||||||
[syms.values]: any = {};
|
|
||||||
|
|
||||||
public [env.global.Symbol.iterator](): IterableIterator<[T, T]> {
|
|
||||||
return this.entries();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
|
||||||
this[syms.values] = {};
|
|
||||||
}
|
|
||||||
public delete(key: T) {
|
|
||||||
if ((key as any) in this[syms.values]) {
|
|
||||||
delete this[syms.values];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public entries(): IterableIterator<[T, T]> {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: () => {
|
|
||||||
if (i >= keys.length) return { done: true };
|
|
||||||
else return { done: false, value: [ keys[i], keys[i] ] }
|
|
||||||
},
|
|
||||||
[env.global.Symbol.iterator]() { return this; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public keys(): IterableIterator<T> {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: () => {
|
|
||||||
if (i >= keys.length) return { done: true };
|
|
||||||
else return { done: false, value: keys[i] }
|
|
||||||
},
|
|
||||||
[env.global.Symbol.iterator]() { return this; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public values(): IterableIterator<T> {
|
|
||||||
return this.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public add(val: T) {
|
|
||||||
this[syms.values][val] = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public has(key: T) {
|
|
||||||
return (key as any) in this[syms.values][key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public get size() {
|
|
||||||
return internals.ownPropKeys(this[syms.values]).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(func: (key: T, val: T, map: Set<T>) => void, thisArg?: any) {
|
|
||||||
const keys = internals.ownPropKeys(this[syms.values]);
|
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
func(keys[i], this[syms.values][keys[i]], this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public constructor(iterable: Iterable<T>) {
|
|
||||||
const it = iterable[env.global.Symbol.iterator]();
|
|
||||||
|
|
||||||
for (let el = it.next(); !el.done; el = it.next()) {
|
|
||||||
this[syms.values][el.value] = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env.global.Set = Set;
|
|
||||||
});
|
|
@ -31,6 +31,6 @@ define("values/symbol", () => {
|
|||||||
asyncIterator: env.symbol('Symbol.asyncIterator') as any,
|
asyncIterator: env.symbol('Symbol.asyncIterator') as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
internals.defineField(env.global.Object.prototype, Symbol.typeName, 'Object', false, false, false);
|
// internals.defineField(env.global.Object.prototype, Symbol.typeName, 'Object', false, false, false);
|
||||||
internals.defineField(env.global, Symbol.typeName, 'Window', false, false, false);
|
// internals.defineField(env.global, Symbol.typeName, 'Window', false, false, false);
|
||||||
});
|
});
|
@ -206,7 +206,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
public ArrayValue(Context ctx, Object ...values) {
|
public ArrayValue(Context ctx, Object ...values) {
|
||||||
this();
|
this();
|
||||||
values = new Object[values.length];
|
this.values = new Object[values.length];
|
||||||
size = values.length;
|
size = values.length;
|
||||||
|
|
||||||
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ctx, values[i]);
|
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ctx, values[i]);
|
||||||
|
@ -519,7 +519,7 @@ public class Values {
|
|||||||
throw new ConvertException(type(obj), clazz.getSimpleName());
|
throw new ConvertException(type(obj), clazz.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<Object> toJavaIterable(Context ctx, Object obj) throws InterruptedException {
|
public static Iterable<Object> toJavaIterable(Context ctx, Object obj) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var symbol = ctx.env.symbol("Symbol.iterator");
|
var symbol = ctx.env.symbol("Symbol.iterator");
|
||||||
@ -527,7 +527,7 @@ public class Values {
|
|||||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
var iteratorFunc = getMember(ctx, obj, symbol);
|
||||||
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
||||||
var iterator = iteratorFunc instanceof FunctionValue ?
|
var iterator = iteratorFunc instanceof FunctionValue ?
|
||||||
((FunctionValue)iteratorFunc).call(ctx, iteratorFunc, 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");
|
||||||
|
|
||||||
@ -536,7 +536,7 @@ public class Values {
|
|||||||
return new Iterator<Object>() {
|
return new Iterator<Object>() {
|
||||||
private Object value = null;
|
private Object value = null;
|
||||||
public boolean consumed = true;
|
public boolean consumed = true;
|
||||||
private FunctionValue next = function(iterator);
|
private FunctionValue next = (FunctionValue)nextFunc;
|
||||||
|
|
||||||
private void loadNext() throws InterruptedException {
|
private void loadNext() throws InterruptedException {
|
||||||
if (next == null) value = null;
|
if (next == null) value = null;
|
||||||
@ -588,9 +588,8 @@ public class Values {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue fromJavaIterable(Context ctx, Iterable<?> iterable) throws InterruptedException {
|
public static ObjectValue fromJavaIterator(Context ctx, Iterator<?> it) throws InterruptedException {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
var it = iterable.iterator();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMember(ctx, getMember(ctx, ctx.env.proto("symbol"), "constructor"), "iterator");
|
var key = getMember(ctx, getMember(ctx, ctx.env.proto("symbol"), "constructor"), "iterator");
|
||||||
@ -606,6 +605,10 @@ public class Values {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ObjectValue fromJavaIterable(Context ctx, Iterable<?> it) throws InterruptedException {
|
||||||
|
return fromJavaIterator(ctx, it.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
private static void printValue(Context ctx, Object val, HashSet<Object> passed, int tab) throws InterruptedException {
|
private static void printValue(Context ctx, Object val, HashSet<Object> passed, int tab) throws InterruptedException {
|
||||||
if (passed.contains(val)) {
|
if (passed.contains(val)) {
|
||||||
System.out.print("[circular]");
|
System.out.print("[circular]");
|
||||||
|
@ -33,7 +33,7 @@ public class Overload {
|
|||||||
return new Overload(
|
return new Overload(
|
||||||
(ctx, th, args) -> method.newInstance(args),
|
(ctx, th, args) -> method.newInstance(args),
|
||||||
method.isVarArgs(), passThis,
|
method.isVarArgs(), passThis,
|
||||||
Modifier.isStatic(method.getModifiers()) ? null : method.getDeclaringClass(),
|
null,
|
||||||
method.getParameterTypes()
|
method.getParameterTypes()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
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.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
@ -56,7 +57,15 @@ public class OverloadFunction extends FunctionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var thisArgType = overload.passThis ? overload.params[consumesEngine ? 1 : 0] : overload.thisArg;
|
var thisArgType = overload.passThis ? overload.params[consumesEngine ? 1 : 0] : overload.thisArg;
|
||||||
Object _this = thisArgType == null ? null : Values.convert(ctx, thisArg, thisArgType);
|
Object _this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
_this = thisArgType == null ? null : Values.convert(ctx, thisArg, thisArgType);
|
||||||
|
}
|
||||||
|
catch (ConvertException e) {
|
||||||
|
if (overloads.size() > 1) continue loop;
|
||||||
|
else throw EngineException.ofType(String.format("This argument can't be converted from %s to %s", e.source, e.target));
|
||||||
|
}
|
||||||
|
|
||||||
if (consumesEngine) newArgs[0] = ctx;
|
if (consumesEngine) newArgs[0] = ctx;
|
||||||
if (overload.passThis) {
|
if (overload.passThis) {
|
||||||
@ -74,15 +83,19 @@ public class OverloadFunction extends FunctionValue {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e) {
|
catch (InvocationTargetException e) {
|
||||||
|
var loc = new Location(0, 0, "<internal>");
|
||||||
if (e.getTargetException() instanceof EngineException) {
|
if (e.getTargetException() instanceof EngineException) {
|
||||||
throw ((EngineException)e.getTargetException());
|
throw ((EngineException)e.getTargetException()).add(name, loc);
|
||||||
|
}
|
||||||
|
else if (e.getTargetException() instanceof NullPointerException) {
|
||||||
|
throw EngineException.ofType("Unexpected value of 'undefined'.").add(name, loc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw EngineException.ofError(e.getTargetException().getMessage());
|
throw EngineException.ofError(e.getTargetException().getMessage()).add(name, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ReflectiveOperationException e) {
|
catch (ReflectiveOperationException e) {
|
||||||
throw EngineException.ofError(e.getMessage());
|
throw EngineException.ofError(e.getMessage()).add(name, new Location(0, 0, "<internal>"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -14,6 +14,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
import me.topchetoeu.jscript.interop.NativeSetter;
|
import me.topchetoeu.jscript.interop.NativeSetter;
|
||||||
|
|
||||||
public class ArrayPolyfill {
|
public class ArrayPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "AsyncFunction";
|
||||||
@NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) throws InterruptedException {
|
@NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) throws InterruptedException {
|
||||||
return thisArg.size();
|
return thisArg.size();
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,13 @@ import me.topchetoeu.jscript.engine.values.CodeFunction;
|
|||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
|
||||||
public class AsyncFunctionPolyfill extends FunctionValue {
|
public class AsyncFunctionPolyfill extends FunctionValue {
|
||||||
public final FunctionValue factory;
|
public final FunctionValue factory;
|
||||||
|
|
||||||
public static class AsyncHelper {
|
public static class AsyncHelper {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "AsyncFunction";
|
||||||
public PromisePolyfill promise = new PromisePolyfill();
|
public PromisePolyfill promise = new PromisePolyfill();
|
||||||
public CodeFrame frame;
|
public CodeFrame frame;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ public class AsyncGeneratorPolyfill extends FunctionValue {
|
|||||||
public final FunctionValue factory;
|
public final FunctionValue factory;
|
||||||
|
|
||||||
public static class AsyncGenerator {
|
public static class AsyncGenerator {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "AsyncGenerator";
|
||||||
private int state = 0;
|
private int state = 0;
|
||||||
private boolean done = false;
|
private boolean done = false;
|
||||||
private PromisePolyfill currPromise;
|
private PromisePolyfill currPromise;
|
||||||
|
@ -7,6 +7,8 @@ import me.topchetoeu.jscript.interop.Native;
|
|||||||
import me.topchetoeu.jscript.interop.NativeConstructor;
|
import me.topchetoeu.jscript.interop.NativeConstructor;
|
||||||
|
|
||||||
public class BooleanPolyfill {
|
public class BooleanPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Boolean";
|
||||||
|
|
||||||
public static final BooleanPolyfill TRUE = new BooleanPolyfill(true);
|
public static final BooleanPolyfill TRUE = new BooleanPolyfill(true);
|
||||||
public static final BooleanPolyfill FALSE = new BooleanPolyfill(false);
|
public static final BooleanPolyfill FALSE = new BooleanPolyfill(false);
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
|
||||||
public class FunctionPolyfill {
|
public class FunctionPolyfill {
|
||||||
@Native(thisArg = true) public static Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) throws InterruptedException {
|
@Native("@@Symbol.typeName") public final String name = "Function";
|
||||||
|
|
||||||
|
@Native(thisArg = true) public static Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) throws InterruptedException {
|
||||||
return func.call(ctx, thisArg, args.toArray());
|
return func.call(ctx, thisArg, args.toArray());
|
||||||
}
|
}
|
||||||
@Native(thisArg = true) public static Object call(Context ctx, FunctionValue func, Object thisArg, Object... args) throws InterruptedException {
|
@Native(thisArg = true) public static Object call(Context ctx, FunctionValue func, Object thisArg, Object... args) throws InterruptedException {
|
||||||
|
@ -18,6 +18,8 @@ public class GeneratorPolyfill extends FunctionValue {
|
|||||||
private boolean done = false;
|
private boolean done = false;
|
||||||
public CodeFrame frame;
|
public CodeFrame frame;
|
||||||
|
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Generator";
|
||||||
|
|
||||||
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) throws InterruptedException {
|
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) throws InterruptedException {
|
||||||
if (done) {
|
if (done) {
|
||||||
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
|
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
|
||||||
|
@ -14,7 +14,7 @@ import me.topchetoeu.jscript.interop.Native;
|
|||||||
public class Internals {
|
public class Internals {
|
||||||
public final Environment targetEnv;
|
public final Environment targetEnv;
|
||||||
|
|
||||||
@Native public final FunctionValue object, function, promise, array, bool, number, string;
|
@Native public final FunctionValue object, function, promise, array, bool, number, string, map, set;
|
||||||
|
|
||||||
@Native public void markSpecial(FunctionValue ...funcs) {
|
@Native public void markSpecial(FunctionValue ...funcs) {
|
||||||
for (var func : funcs) {
|
for (var func : funcs) {
|
||||||
@ -160,5 +160,7 @@ public class Internals {
|
|||||||
this.bool = targetEnv.wrappersProvider.getConstr(BooleanPolyfill.class);
|
this.bool = targetEnv.wrappersProvider.getConstr(BooleanPolyfill.class);
|
||||||
this.number = targetEnv.wrappersProvider.getConstr(NumberPolyfill.class);
|
this.number = targetEnv.wrappersProvider.getConstr(NumberPolyfill.class);
|
||||||
this.string = targetEnv.wrappersProvider.getConstr(StringPolyfill.class);
|
this.string = targetEnv.wrappersProvider.getConstr(StringPolyfill.class);
|
||||||
|
this.map = targetEnv.wrappersProvider.getConstr(MapPolyfill.class);
|
||||||
|
this.set = targetEnv.wrappersProvider.getConstr(SetPolyfill.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
78
src/me/topchetoeu/jscript/polyfills/MapPolyfill.java
Normal file
78
src/me/topchetoeu/jscript/polyfills/MapPolyfill.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
import me.topchetoeu.jscript.interop.NativeGetter;
|
||||||
|
|
||||||
|
public class MapPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Map";
|
||||||
|
private LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
@Native("@@Symbol.iterator") public ObjectValue iterator(Context ctx) throws InterruptedException {
|
||||||
|
return this.entries(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public void clear() {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
@Native public boolean delete(Object key) {
|
||||||
|
if (map.containsKey(key)) {
|
||||||
|
map.remove(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public ObjectValue entries(Context ctx) throws InterruptedException {
|
||||||
|
var res = map.entrySet().stream().map(v -> {
|
||||||
|
return new ArrayValue(ctx, v.getKey(), v.getValue());
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
@Native public ObjectValue keys(Context ctx) throws InterruptedException {
|
||||||
|
var res = new ArrayList<>(map.keySet());
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
@Native public ObjectValue values(Context ctx) throws InterruptedException {
|
||||||
|
var res = new ArrayList<>(map.values());
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public Object get(Object key) {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
@Native public MapPolyfill set(Object key, Object val) {
|
||||||
|
map.put(key, val);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Native public boolean has(Object key) {
|
||||||
|
return map.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NativeGetter public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NativeGetter public void forEach(Context ctx, FunctionValue func, Object thisArg) throws InterruptedException {
|
||||||
|
var keys = new ArrayList<>(map.keySet());
|
||||||
|
|
||||||
|
for (var el : keys) func.call(ctx, thisArg, el, map.get(el), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public MapPolyfill(Context ctx, Object iterable) throws InterruptedException {
|
||||||
|
for (var el : Values.toJavaIterable(ctx, iterable)) {
|
||||||
|
try {
|
||||||
|
set(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,8 @@ import me.topchetoeu.jscript.interop.Native;
|
|||||||
import me.topchetoeu.jscript.interop.NativeConstructor;
|
import me.topchetoeu.jscript.interop.NativeConstructor;
|
||||||
|
|
||||||
public class NumberPolyfill {
|
public class NumberPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Number";
|
||||||
|
|
||||||
@Native public static final double EPSILON = java.lang.Math.ulp(1.0);
|
@Native public static final double EPSILON = java.lang.Math.ulp(1.0);
|
||||||
@Native public static final double MAX_SAFE_INTEGER = 9007199254740991.;
|
@Native public static final double MAX_SAFE_INTEGER = 9007199254740991.;
|
||||||
@Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER;
|
@Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER;
|
||||||
|
@ -11,6 +11,8 @@ import me.topchetoeu.jscript.interop.Native;
|
|||||||
import me.topchetoeu.jscript.interop.NativeConstructor;
|
import me.topchetoeu.jscript.interop.NativeConstructor;
|
||||||
|
|
||||||
public class ObjectPolyfill {
|
public class ObjectPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Object";
|
||||||
|
|
||||||
@Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) throws InterruptedException {
|
@Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) throws InterruptedException {
|
||||||
for (var obj : src) {
|
for (var obj : src) {
|
||||||
for (var key : Values.getMembers(ctx, obj, true, true)) {
|
for (var key : Values.getMembers(ctx, obj, true, true)) {
|
||||||
@ -204,9 +206,9 @@ public class ObjectPolyfill {
|
|||||||
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object arg) throws InterruptedException {
|
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object arg) throws InterruptedException {
|
||||||
if (arg == null || arg == Values.NULL) return new ObjectValue();
|
if (arg == null || arg == Values.NULL) return new ObjectValue();
|
||||||
else if (arg instanceof Boolean) return BooleanPolyfill.constructor(ctx, thisArg, arg);
|
else if (arg instanceof Boolean) return BooleanPolyfill.constructor(ctx, thisArg, arg);
|
||||||
else if (arg instanceof Number) return Values.callNew(ctx, ctx.env.global.get(ctx, "Number"), arg);
|
else if (arg instanceof Number) return NumberPolyfill.constructor(ctx, thisArg, arg);
|
||||||
else if (arg instanceof String) return Values.callNew(ctx, ctx.env.global.get(ctx, "String"), arg);
|
else if (arg instanceof String) return StringPolyfill.constructor(ctx, thisArg, arg);
|
||||||
else if (arg instanceof Symbol) return Values.callNew(ctx, ctx.env.global.get(ctx, "Symbol"), arg);
|
// else if (arg instanceof Symbol) return SymbolPolyfill.constructor(ctx, thisArg, arg);
|
||||||
else return arg;
|
else return arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ public class PromisePolyfill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Promise";
|
||||||
|
|
||||||
@Native("resolve")
|
@Native("resolve")
|
||||||
public static PromisePolyfill ofResolved(Context ctx, Object val) throws InterruptedException {
|
public static PromisePolyfill ofResolved(Context ctx, Object val) throws InterruptedException {
|
||||||
var res = new PromisePolyfill();
|
var res = new PromisePolyfill();
|
||||||
|
63
src/me/topchetoeu/jscript/polyfills/SetPolyfill.java
Normal file
63
src/me/topchetoeu/jscript/polyfills/SetPolyfill.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
import me.topchetoeu.jscript.interop.NativeGetter;
|
||||||
|
|
||||||
|
public class SetPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "Set";
|
||||||
|
private LinkedHashSet<Object> set = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
@Native("@@Symbol.iterator") public ObjectValue iterator(Context ctx) throws InterruptedException {
|
||||||
|
return this.values(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public ObjectValue entries(Context ctx) throws InterruptedException {
|
||||||
|
var res = set.stream().map(v -> new ArrayValue(ctx, v, v)).collect(Collectors.toList());
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
@Native public ObjectValue keys(Context ctx) throws InterruptedException {
|
||||||
|
var res = new ArrayList<>(set);
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
@Native public ObjectValue values(Context ctx) throws InterruptedException {
|
||||||
|
var res = new ArrayList<>(set);
|
||||||
|
return Values.fromJavaIterator(ctx, res.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public Object add(Object key) {
|
||||||
|
return set.add(key);
|
||||||
|
}
|
||||||
|
@Native public boolean delete(Object key) {
|
||||||
|
return set.remove(key);
|
||||||
|
}
|
||||||
|
@Native public boolean has(Object key) {
|
||||||
|
return set.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public void clear() {
|
||||||
|
set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NativeGetter public int size() {
|
||||||
|
return set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NativeGetter public void forEach(Context ctx, FunctionValue func, Object thisArg) throws InterruptedException {
|
||||||
|
var keys = new ArrayList<>(set);
|
||||||
|
|
||||||
|
for (var el : keys) func.call(ctx, thisArg, el, el, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public SetPolyfill(Context ctx, Object iterable) throws InterruptedException {
|
||||||
|
for (var el : Values.toJavaIterable(ctx, iterable)) add(el);
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
|
|
||||||
// TODO: implement index wrapping properly
|
// TODO: implement index wrapping properly
|
||||||
public class StringPolyfill {
|
public class StringPolyfill {
|
||||||
|
@Native("@@Symbol.typeName") public final String name = "String";
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
|
|
||||||
private static String passThis(String funcName, Object val) {
|
private static String passThis(String funcName, Object val) {
|
||||||
|
Loading…
Reference in New Issue
Block a user