diff --git a/lib/core.ts b/lib/core.ts index 64c44ef..c59bd70 100644 --- a/lib/core.ts +++ b/lib/core.ts @@ -12,6 +12,8 @@ interface Internals { bool: BooleanConstructor; number: NumberConstructor; string: StringConstructor; + map: typeof Map; + set: typeof Set; markSpecial(...funcs: Function[]): void; getEnv(func: Function): Environment | undefined; @@ -45,19 +47,23 @@ interface Internals { try { var env: Environment = arguments[0], internals: Internals = arguments[1]; - var Object = env.global.Object = internals.object; - var Function = env.global.Function = internals.function; - var Array = env.global.Array = internals.array; - var Promise = env.global.Promise = internals.promise; - var Boolean = env.global.Boolean = internals.bool; - var Number = env.global.Number = internals.number; - var String = env.global.String = internals.string; + const Object = env.global.Object = internals.object; + const Function = env.global.Function = internals.function; + const Array = env.global.Array = internals.array; + const Promise = env.global.Promise = internals.promise; + const Boolean = env.global.Boolean = internals.bool; + const Number = env.global.Number = internals.number; + 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('function', Function.prototype); env.setProto('array', Array.prototype); env.setProto('number', Number.prototype); env.setProto('string', String.prototype); + env.setProto('bool', Boolean.prototype); (Object.prototype as any).__proto__ = null; @@ -66,8 +72,6 @@ try { run('values/symbol'); run('values/errors'); - run('map'); - run('set'); run('regex'); run('timeout'); diff --git a/lib/map.ts b/lib/map.ts deleted file mode 100644 index b7745af..0000000 --- a/lib/map.ts +++ /dev/null @@ -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 { - [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 { - 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 { - 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) => 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; -}); diff --git a/lib/set.ts b/lib/set.ts deleted file mode 100644 index a0ac277..0000000 --- a/lib/set.ts +++ /dev/null @@ -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 { - [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 { - 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 { - 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) => 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) { - 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; -}); diff --git a/lib/values/symbol.ts b/lib/values/symbol.ts index dff4b4f..8bcfe65 100644 --- a/lib/values/symbol.ts +++ b/lib/values/symbol.ts @@ -31,6 +31,6 @@ define("values/symbol", () => { asyncIterator: env.symbol('Symbol.asyncIterator') as any, }); - 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.Object.prototype, Symbol.typeName, 'Object', false, false, false); + // internals.defineField(env.global, Symbol.typeName, 'Window', false, false, false); }); \ No newline at end of file diff --git a/src/me/topchetoeu/jscript/engine/values/ArrayValue.java b/src/me/topchetoeu/jscript/engine/values/ArrayValue.java index 8841810..006c8d4 100644 --- a/src/me/topchetoeu/jscript/engine/values/ArrayValue.java +++ b/src/me/topchetoeu/jscript/engine/values/ArrayValue.java @@ -206,7 +206,7 @@ public class ArrayValue extends ObjectValue implements Iterable { } public ArrayValue(Context ctx, Object ...values) { this(); - values = new Object[values.length]; + this.values = new Object[values.length]; size = values.length; for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ctx, values[i]); diff --git a/src/me/topchetoeu/jscript/engine/values/Values.java b/src/me/topchetoeu/jscript/engine/values/Values.java index 0d753d2..d909ede 100644 --- a/src/me/topchetoeu/jscript/engine/values/Values.java +++ b/src/me/topchetoeu/jscript/engine/values/Values.java @@ -519,7 +519,7 @@ public class Values { throw new ConvertException(type(obj), clazz.getSimpleName()); } - public static Iterable toJavaIterable(Context ctx, Object obj) throws InterruptedException { + public static Iterable toJavaIterable(Context ctx, Object obj) { return () -> { try { var symbol = ctx.env.symbol("Symbol.iterator"); @@ -527,7 +527,7 @@ public class Values { var iteratorFunc = getMember(ctx, obj, symbol); if (!isFunction(iteratorFunc)) return Collections.emptyIterator(); var iterator = iteratorFunc instanceof FunctionValue ? - ((FunctionValue)iteratorFunc).call(ctx, iteratorFunc, obj) : + ((FunctionValue)iteratorFunc).call(ctx, obj, obj) : iteratorFunc; var nextFunc = getMember(ctx, call(ctx, iteratorFunc, obj), "next"); @@ -536,7 +536,7 @@ public class Values { return new Iterator() { private Object value = null; public boolean consumed = true; - private FunctionValue next = function(iterator); + private FunctionValue next = (FunctionValue)nextFunc; private void loadNext() throws InterruptedException { 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 it = iterable.iterator(); try { var key = getMember(ctx, getMember(ctx, ctx.env.proto("symbol"), "constructor"), "iterator"); @@ -606,6 +605,10 @@ public class Values { 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 passed, int tab) throws InterruptedException { if (passed.contains(val)) { System.out.print("[circular]"); diff --git a/src/me/topchetoeu/jscript/interop/Overload.java b/src/me/topchetoeu/jscript/interop/Overload.java index b325aeb..a4548e1 100644 --- a/src/me/topchetoeu/jscript/interop/Overload.java +++ b/src/me/topchetoeu/jscript/interop/Overload.java @@ -33,7 +33,7 @@ public class Overload { return new Overload( (ctx, th, args) -> method.newInstance(args), method.isVarArgs(), passThis, - Modifier.isStatic(method.getModifiers()) ? null : method.getDeclaringClass(), + null, method.getParameterTypes() ); } diff --git a/src/me/topchetoeu/jscript/interop/OverloadFunction.java b/src/me/topchetoeu/jscript/interop/OverloadFunction.java index 2ad62d2..bf0f20c 100644 --- a/src/me/topchetoeu/jscript/interop/OverloadFunction.java +++ b/src/me/topchetoeu/jscript/interop/OverloadFunction.java @@ -5,6 +5,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; +import me.topchetoeu.jscript.Location; import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.values.FunctionValue; 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; - 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 (overload.passThis) { @@ -74,15 +83,19 @@ public class OverloadFunction extends FunctionValue { continue; } catch (InvocationTargetException e) { + var loc = new Location(0, 0, ""); 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 { - throw EngineException.ofError(e.getTargetException().getMessage()); + throw EngineException.ofError(e.getTargetException().getMessage()).add(name, loc); } } catch (ReflectiveOperationException e) { - throw EngineException.ofError(e.getMessage()); + throw EngineException.ofError(e.getMessage()).add(name, new Location(0, 0, "")); } catch (Exception e) { throw e; diff --git a/src/me/topchetoeu/jscript/polyfills/ArrayPolyfill.java b/src/me/topchetoeu/jscript/polyfills/ArrayPolyfill.java index a2901a7..499c620 100644 --- a/src/me/topchetoeu/jscript/polyfills/ArrayPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/ArrayPolyfill.java @@ -14,6 +14,7 @@ import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeSetter; public class ArrayPolyfill { + @Native("@@Symbol.typeName") public final String name = "AsyncFunction"; @NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) throws InterruptedException { return thisArg.size(); } diff --git a/src/me/topchetoeu/jscript/polyfills/AsyncFunctionPolyfill.java b/src/me/topchetoeu/jscript/polyfills/AsyncFunctionPolyfill.java index 0661995..74d4996 100644 --- a/src/me/topchetoeu/jscript/polyfills/AsyncFunctionPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/AsyncFunctionPolyfill.java @@ -7,11 +7,13 @@ import me.topchetoeu.jscript.engine.values.CodeFunction; import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.interop.Native; public class AsyncFunctionPolyfill extends FunctionValue { public final FunctionValue factory; public static class AsyncHelper { + @Native("@@Symbol.typeName") public final String name = "AsyncFunction"; public PromisePolyfill promise = new PromisePolyfill(); public CodeFrame frame; diff --git a/src/me/topchetoeu/jscript/polyfills/AsyncGeneratorPolyfill.java b/src/me/topchetoeu/jscript/polyfills/AsyncGeneratorPolyfill.java index 4328d61..b2eb893 100644 --- a/src/me/topchetoeu/jscript/polyfills/AsyncGeneratorPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/AsyncGeneratorPolyfill.java @@ -16,6 +16,7 @@ public class AsyncGeneratorPolyfill extends FunctionValue { public final FunctionValue factory; public static class AsyncGenerator { + @Native("@@Symbol.typeName") public final String name = "AsyncGenerator"; private int state = 0; private boolean done = false; private PromisePolyfill currPromise; diff --git a/src/me/topchetoeu/jscript/polyfills/BooleanPolyfill.java b/src/me/topchetoeu/jscript/polyfills/BooleanPolyfill.java index 843e78b..df824b0 100644 --- a/src/me/topchetoeu/jscript/polyfills/BooleanPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/BooleanPolyfill.java @@ -7,6 +7,8 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; public class BooleanPolyfill { + @Native("@@Symbol.typeName") public final String name = "Boolean"; + public static final BooleanPolyfill TRUE = new BooleanPolyfill(true); public static final BooleanPolyfill FALSE = new BooleanPolyfill(false); diff --git a/src/me/topchetoeu/jscript/polyfills/FunctionPolyfill.java b/src/me/topchetoeu/jscript/polyfills/FunctionPolyfill.java index 439642e..d4ba763 100644 --- a/src/me/topchetoeu/jscript/polyfills/FunctionPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/FunctionPolyfill.java @@ -8,7 +8,9 @@ import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.interop.Native; 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()); } @Native(thisArg = true) public static Object call(Context ctx, FunctionValue func, Object thisArg, Object... args) throws InterruptedException { diff --git a/src/me/topchetoeu/jscript/polyfills/GeneratorPolyfill.java b/src/me/topchetoeu/jscript/polyfills/GeneratorPolyfill.java index 47f5080..429a2ca 100644 --- a/src/me/topchetoeu/jscript/polyfills/GeneratorPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/GeneratorPolyfill.java @@ -18,6 +18,8 @@ public class GeneratorPolyfill extends FunctionValue { private boolean done = false; public CodeFrame frame; + @Native("@@Symbol.typeName") public final String name = "Generator"; + private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) throws InterruptedException { if (done) { if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); diff --git a/src/me/topchetoeu/jscript/polyfills/Internals.java b/src/me/topchetoeu/jscript/polyfills/Internals.java index d37c148..6a5085f 100644 --- a/src/me/topchetoeu/jscript/polyfills/Internals.java +++ b/src/me/topchetoeu/jscript/polyfills/Internals.java @@ -14,7 +14,7 @@ import me.topchetoeu.jscript.interop.Native; public class Internals { 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) { for (var func : funcs) { @@ -160,5 +160,7 @@ public class Internals { this.bool = targetEnv.wrappersProvider.getConstr(BooleanPolyfill.class); this.number = targetEnv.wrappersProvider.getConstr(NumberPolyfill.class); this.string = targetEnv.wrappersProvider.getConstr(StringPolyfill.class); + this.map = targetEnv.wrappersProvider.getConstr(MapPolyfill.class); + this.set = targetEnv.wrappersProvider.getConstr(SetPolyfill.class); } } diff --git a/src/me/topchetoeu/jscript/polyfills/MapPolyfill.java b/src/me/topchetoeu/jscript/polyfills/MapPolyfill.java new file mode 100644 index 0000000..ce4277e --- /dev/null +++ b/src/me/topchetoeu/jscript/polyfills/MapPolyfill.java @@ -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 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) { } + } + } +} diff --git a/src/me/topchetoeu/jscript/polyfills/NumberPolyfill.java b/src/me/topchetoeu/jscript/polyfills/NumberPolyfill.java index a3859eb..ddc89a1 100644 --- a/src/me/topchetoeu/jscript/polyfills/NumberPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/NumberPolyfill.java @@ -7,6 +7,8 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; 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 MAX_SAFE_INTEGER = 9007199254740991.; @Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER; diff --git a/src/me/topchetoeu/jscript/polyfills/ObjectPolyfill.java b/src/me/topchetoeu/jscript/polyfills/ObjectPolyfill.java index 66387ee..9875a74 100644 --- a/src/me/topchetoeu/jscript/polyfills/ObjectPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/ObjectPolyfill.java @@ -11,6 +11,8 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; public class ObjectPolyfill { + @Native("@@Symbol.typeName") public final String name = "Object"; + @Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) throws InterruptedException { for (var obj : src) { 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 { if (arg == null || arg == Values.NULL) return new ObjectValue(); 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 String) return Values.callNew(ctx, ctx.env.global.get(ctx, "String"), arg); - else if (arg instanceof Symbol) return Values.callNew(ctx, ctx.env.global.get(ctx, "Symbol"), arg); + else if (arg instanceof Number) return NumberPolyfill.constructor(ctx, thisArg, arg); + else if (arg instanceof String) return StringPolyfill.constructor(ctx, thisArg, arg); + // else if (arg instanceof Symbol) return SymbolPolyfill.constructor(ctx, thisArg, arg); else return arg; } } diff --git a/src/me/topchetoeu/jscript/polyfills/PromisePolyfill.java b/src/me/topchetoeu/jscript/polyfills/PromisePolyfill.java index 741f052..41e977d 100644 --- a/src/me/topchetoeu/jscript/polyfills/PromisePolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/PromisePolyfill.java @@ -28,6 +28,8 @@ public class PromisePolyfill { } } + @Native("@@Symbol.typeName") public final String name = "Promise"; + @Native("resolve") public static PromisePolyfill ofResolved(Context ctx, Object val) throws InterruptedException { var res = new PromisePolyfill(); diff --git a/src/me/topchetoeu/jscript/polyfills/SetPolyfill.java b/src/me/topchetoeu/jscript/polyfills/SetPolyfill.java new file mode 100644 index 0000000..7822f2a --- /dev/null +++ b/src/me/topchetoeu/jscript/polyfills/SetPolyfill.java @@ -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 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); + } +} diff --git a/src/me/topchetoeu/jscript/polyfills/StringPolyfill.java b/src/me/topchetoeu/jscript/polyfills/StringPolyfill.java index 00bb90c..2068481 100644 --- a/src/me/topchetoeu/jscript/polyfills/StringPolyfill.java +++ b/src/me/topchetoeu/jscript/polyfills/StringPolyfill.java @@ -14,6 +14,8 @@ import me.topchetoeu.jscript.interop.NativeGetter; // TODO: implement index wrapping properly public class StringPolyfill { + @Native("@@Symbol.typeName") public final String name = "String"; + public final String value; private static String passThis(String funcName, Object val) {