feat: implement symbols in java
This commit is contained in:
parent
e16c0fedb1
commit
6c71911575
@ -12,6 +12,8 @@ interface Internals {
|
|||||||
bool: BooleanConstructor;
|
bool: BooleanConstructor;
|
||||||
number: NumberConstructor;
|
number: NumberConstructor;
|
||||||
string: StringConstructor;
|
string: StringConstructor;
|
||||||
|
symbol: SymbolConstructor;
|
||||||
|
|
||||||
map: typeof Map;
|
map: typeof Map;
|
||||||
set: typeof Set;
|
set: typeof Set;
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ interface Internals {
|
|||||||
char(val: string): number;
|
char(val: string): number;
|
||||||
stringFromStrings(arr: string[]): string;
|
stringFromStrings(arr: string[]): string;
|
||||||
stringFromChars(arr: number[]): string;
|
stringFromChars(arr: number[]): string;
|
||||||
symbol(name?: string): symbol;
|
getSymbol(name?: string): symbol;
|
||||||
symbolToString(sym: symbol): string;
|
symbolToString(sym: symbol): string;
|
||||||
|
|
||||||
isArray(obj: any): boolean;
|
isArray(obj: any): boolean;
|
||||||
@ -54,6 +56,7 @@ try {
|
|||||||
const Boolean = env.global.Boolean = internals.bool;
|
const Boolean = env.global.Boolean = internals.bool;
|
||||||
const Number = env.global.Number = internals.number;
|
const Number = env.global.Number = internals.number;
|
||||||
const String = env.global.String = internals.string;
|
const String = env.global.String = internals.string;
|
||||||
|
const Symbol = env.global.Symbol = internals.symbol;
|
||||||
|
|
||||||
const Map = env.global.Map = internals.map;
|
const Map = env.global.Map = internals.map;
|
||||||
const Set = env.global.Set = internals.set;
|
const Set = env.global.Set = internals.set;
|
||||||
@ -63,6 +66,7 @@ try {
|
|||||||
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('symbol', Symbol.prototype);
|
||||||
env.setProto('bool', Boolean.prototype);
|
env.setProto('bool', Boolean.prototype);
|
||||||
|
|
||||||
(Object.prototype as any).__proto__ = null;
|
(Object.prototype as any).__proto__ = null;
|
||||||
@ -70,7 +74,6 @@ try {
|
|||||||
internals.getEnv(run)?.setProto('array', Array.prototype);
|
internals.getEnv(run)?.setProto('array', Array.prototype);
|
||||||
globalThis.log = (...args) => internals.apply(internals.log, internals, args);
|
globalThis.log = (...args) => internals.apply(internals.log, internals, args);
|
||||||
|
|
||||||
run('values/symbol');
|
|
||||||
run('values/errors');
|
run('values/errors');
|
||||||
run('regex');
|
run('regex');
|
||||||
run('timeout');
|
run('timeout');
|
||||||
|
@ -3,10 +3,7 @@
|
|||||||
"lib.d.ts",
|
"lib.d.ts",
|
||||||
"modules.ts",
|
"modules.ts",
|
||||||
"utils.ts",
|
"utils.ts",
|
||||||
"values/symbol.ts",
|
|
||||||
"values/errors.ts",
|
"values/errors.ts",
|
||||||
"map.ts",
|
|
||||||
"set.ts",
|
|
||||||
"regex.ts",
|
"regex.ts",
|
||||||
"timeout.ts",
|
"timeout.ts",
|
||||||
"core.ts"
|
"core.ts"
|
||||||
|
11
lib/utils.ts
11
lib/utils.ts
@ -25,14 +25,3 @@ function setConstr(target: object, constr: Function) {
|
|||||||
true // configurable
|
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;
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
define("values/symbol", () => {
|
|
||||||
const symbols: Record<string, symbol> = { };
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
@ -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, map, set;
|
@Native public final FunctionValue object, function, promise, array, bool, number, string, symbol, map, set;
|
||||||
|
|
||||||
@Native public void markSpecial(FunctionValue ...funcs) {
|
@Native public void markSpecial(FunctionValue ...funcs) {
|
||||||
for (var func : funcs) {
|
for (var func : funcs) {
|
||||||
@ -72,7 +72,7 @@ public class Internals {
|
|||||||
|
|
||||||
return stringFromChars(res);
|
return stringFromChars(res);
|
||||||
}
|
}
|
||||||
@Native public Symbol symbol(String str) {
|
@Native public Symbol getSymbol(String str) {
|
||||||
return new Symbol(str);
|
return new Symbol(str);
|
||||||
}
|
}
|
||||||
@Native public String symbolToString(Symbol str) {
|
@Native public String symbolToString(Symbol str) {
|
||||||
@ -160,6 +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.symbol = targetEnv.wrappersProvider.getConstr(SymbolPolyfill.class);
|
||||||
this.map = targetEnv.wrappersProvider.getConstr(MapPolyfill.class);
|
this.map = targetEnv.wrappersProvider.getConstr(MapPolyfill.class);
|
||||||
this.set = targetEnv.wrappersProvider.getConstr(SetPolyfill.class);
|
this.set = targetEnv.wrappersProvider.getConstr(SetPolyfill.class);
|
||||||
}
|
}
|
||||||
|
69
src/me/topchetoeu/jscript/polyfills/SymbolPolyfill.java
Normal file
69
src/me/topchetoeu/jscript/polyfills/SymbolPolyfill.java
Normal file
@ -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<String, Symbol> 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user