diff --git a/lib/core.ts b/lib/core.ts index c59bd70..61b0cd3 100644 --- a/lib/core.ts +++ b/lib/core.ts @@ -12,6 +12,8 @@ interface Internals { bool: BooleanConstructor; number: NumberConstructor; string: StringConstructor; + symbol: SymbolConstructor; + map: typeof Map; set: typeof Set; @@ -26,7 +28,7 @@ interface Internals { char(val: string): number; stringFromStrings(arr: string[]): string; stringFromChars(arr: number[]): string; - symbol(name?: string): symbol; + getSymbol(name?: string): symbol; symbolToString(sym: symbol): string; isArray(obj: any): boolean; @@ -54,6 +56,7 @@ try { const Boolean = env.global.Boolean = internals.bool; const Number = env.global.Number = internals.number; const String = env.global.String = internals.string; + const Symbol = env.global.Symbol = internals.symbol; const Map = env.global.Map = internals.map; const Set = env.global.Set = internals.set; @@ -63,6 +66,7 @@ try { env.setProto('array', Array.prototype); env.setProto('number', Number.prototype); env.setProto('string', String.prototype); + env.setProto('symbol', Symbol.prototype); env.setProto('bool', Boolean.prototype); (Object.prototype as any).__proto__ = null; @@ -70,7 +74,6 @@ try { internals.getEnv(run)?.setProto('array', Array.prototype); globalThis.log = (...args) => internals.apply(internals.log, internals, args); - run('values/symbol'); run('values/errors'); run('regex'); run('timeout'); diff --git a/lib/tsconfig.json b/lib/tsconfig.json index bf26634..cdd853b 100644 --- a/lib/tsconfig.json +++ b/lib/tsconfig.json @@ -3,10 +3,7 @@ "lib.d.ts", "modules.ts", "utils.ts", - "values/symbol.ts", "values/errors.ts", - "map.ts", - "set.ts", "regex.ts", "timeout.ts", "core.ts" diff --git a/lib/utils.ts b/lib/utils.ts index fa3ca0a..fe45aaf 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -25,14 +25,3 @@ function setConstr(target: object, constr: Function) { true // configurable ); } - -function wrapI(max: number, i: number) { - i |= 0; - if (i < 0) i = max + i; - return i; -} -function clampI(max: number, i: number) { - if (i < 0) i = 0; - if (i > max) i = max; - return i; -} \ No newline at end of file diff --git a/lib/values/symbol.ts b/lib/values/symbol.ts deleted file mode 100644 index 8bcfe65..0000000 --- a/lib/values/symbol.ts +++ /dev/null @@ -1,36 +0,0 @@ -define("values/symbol", () => { - const symbols: Record = { }; - - var Symbol = env.global.Symbol = function(this: any, val?: string) { - if (this !== undefined && this !== null) throw new env.global.TypeError("Symbol may not be called with 'new'."); - if (typeof val !== 'string' && val !== undefined) throw new env.global.TypeError('val must be a string or undefined.'); - return internals.symbol(val); - } as SymbolConstructor; - - env.setProto('symbol', Symbol.prototype); - setConstr(Symbol.prototype, Symbol); - - setProps(Symbol, { - for(key) { - if (typeof key !== 'string' && key !== undefined) throw new env.global.TypeError('key must be a string or undefined.'); - if (key in symbols) return symbols[key]; - else return symbols[key] = internals.symbol(key); - }, - keyFor(sym) { - if (typeof sym !== 'symbol') throw new env.global.TypeError('sym must be a symbol.'); - return internals.symbolToString(sym); - }, - - typeName: env.symbol("Symbol.typeName") as any, - replace: env.symbol('Symbol.replace') as any, - match: env.symbol('Symbol.match') as any, - matchAll: env.symbol('Symbol.matchAll') as any, - split: env.symbol('Symbol.split') as any, - search: env.symbol('Symbol.search') as any, - iterator: env.symbol('Symbol.iterator') 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, Symbol.typeName, 'Window', false, false, false); -}); \ No newline at end of file diff --git a/src/me/topchetoeu/jscript/polyfills/Internals.java b/src/me/topchetoeu/jscript/polyfills/Internals.java index 6a5085f..5c2ceed 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, map, set; + @Native public final FunctionValue object, function, promise, array, bool, number, string, symbol, map, set; @Native public void markSpecial(FunctionValue ...funcs) { for (var func : funcs) { @@ -72,7 +72,7 @@ public class Internals { return stringFromChars(res); } - @Native public Symbol symbol(String str) { + @Native public Symbol getSymbol(String str) { return new Symbol(str); } @Native public String symbolToString(Symbol str) { @@ -160,6 +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.symbol = targetEnv.wrappersProvider.getConstr(SymbolPolyfill.class); this.map = targetEnv.wrappersProvider.getConstr(MapPolyfill.class); this.set = targetEnv.wrappersProvider.getConstr(SetPolyfill.class); } diff --git a/src/me/topchetoeu/jscript/polyfills/SymbolPolyfill.java b/src/me/topchetoeu/jscript/polyfills/SymbolPolyfill.java new file mode 100644 index 0000000..8671c4d --- /dev/null +++ b/src/me/topchetoeu/jscript/polyfills/SymbolPolyfill.java @@ -0,0 +1,69 @@ +package me.topchetoeu.jscript.polyfills; + +import java.util.HashMap; +import java.util.Map; + +import me.topchetoeu.jscript.engine.Context; +import me.topchetoeu.jscript.engine.values.ObjectValue; +import me.topchetoeu.jscript.engine.values.Symbol; +import me.topchetoeu.jscript.engine.values.Values; +import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.interop.Native; +import me.topchetoeu.jscript.interop.NativeConstructor; +import me.topchetoeu.jscript.interop.NativeGetter; + +public class SymbolPolyfill { + private static final Map symbols = new HashMap<>(); + @Native("@@Symbol.typeName") public final String name = "Symbol"; + + @NativeGetter public static Symbol typeName(Context ctx) { return ctx.env.symbol("Symbol.typeName"); } + @NativeGetter public static Symbol replace(Context ctx) { return ctx.env.symbol("Symbol.replace"); } + @NativeGetter public static Symbol match(Context ctx) { return ctx.env.symbol("Symbol.match"); } + @NativeGetter public static Symbol matchAll(Context ctx) { return ctx.env.symbol("Symbol.matchAll"); } + @NativeGetter public static Symbol split(Context ctx) { return ctx.env.symbol("Symbol.split"); } + @NativeGetter public static Symbol search(Context ctx) { return ctx.env.symbol("Symbol.search"); } + @NativeGetter public static Symbol iterator(Context ctx) { return ctx.env.symbol("Symbol.iterator"); } + @NativeGetter public static Symbol asyncIterator(Context ctx) { return ctx.env.symbol("Symbol.asyncIterator"); } + + public final Symbol value; + + private static Symbol passThis(String funcName, Object val) { + if (val instanceof SymbolPolyfill) return ((SymbolPolyfill)val).value; + else if (val instanceof Symbol) return (Symbol)val; + else throw EngineException.ofType(String.format("'%s' may only be called upon object and primitve symbols.", funcName)); + } + + @NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object val) throws InterruptedException { + if (thisArg instanceof ObjectValue) throw EngineException.ofType("Symbol constructor may not be called with new."); + if (val == null) return new Symbol(""); + else return new Symbol(Values.toString(ctx, val)); + } + @Native(thisArg = true) public static String toString(Context ctx, Object thisArg) throws InterruptedException { + return passThis("toString", thisArg).value; + } + @Native(thisArg = true) public static Symbol valueOf(Context ctx, Object thisArg) throws InterruptedException { + return passThis("valueOf", thisArg); + } + + @Native public static String fromCharCode(int ...val) { + char[] arr = new char[val.length]; + for (var i = 0; i < val.length; i++) arr[i] = (char)val[i]; + return new String(arr); + } + + @Native("for") public static Symbol _for(String key) { + if (symbols.containsKey(key)) return symbols.get(key); + else { + var sym = new Symbol(key); + symbols.put(key, sym); + return sym; + } + } + @Native public static String keyFor(Symbol sym) { + return sym.value; + } + + public SymbolPolyfill(Symbol val) { + this.value = val; + } +}