Compare commits

...

5 Commits

4 changed files with 68 additions and 24 deletions

View File

@@ -1,15 +1,21 @@
package me.topchetoeu.jscript.runtime.values; package me.topchetoeu.jscript.runtime.values;
import java.util.WeakHashMap;
import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.Key;
public class NativeWrapper extends ObjectValue { public class NativeWrapper extends ObjectValue {
private static final Key<WeakHashMap<Object, NativeWrapper>> WRAPPERS = new Key<>();
private static final Object NATIVE_PROTO = new Object(); private static final Object NATIVE_PROTO = new Object();
public final Object wrapped; public final Object wrapped;
@Override @Override
public ObjectValue getPrototype(Context ctx) { public ObjectValue getPrototype(Context ctx) {
if (ctx.environment != null && prototype == NATIVE_PROTO) { if (ctx.environment != null && prototype == NATIVE_PROTO) {
var res = ctx.environment.wrappers.getProto(wrapped.getClass()); var clazz = wrapped.getClass();
var res = ctx.environment.wrappers.getProto(clazz);
if (res != null) return res; if (res != null) return res;
} }
return super.getPrototype(ctx); return super.getPrototype(ctx);
@@ -28,8 +34,20 @@ public class NativeWrapper extends ObjectValue {
return wrapped.hashCode(); return wrapped.hashCode();
} }
public NativeWrapper(Object wrapped) { private NativeWrapper(Object wrapped) {
this.wrapped = wrapped; this.wrapped = wrapped;
prototype = NATIVE_PROTO; prototype = NATIVE_PROTO;
} }
public static NativeWrapper of(Extensions exts, Object wrapped) {
var wrappers = exts == null ? null : exts.get(WRAPPERS);
if (wrappers == null) return new NativeWrapper(wrapped);
if (wrappers.containsKey(wrapped)) return wrappers.get(wrapped);
var res = new NativeWrapper(wrapped);
wrappers.put(wrapped, res);
return res;
}
} }

View File

@@ -58,9 +58,8 @@ public class Values {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T wrapper(Object val, Class<T> clazz) { public static <T> T wrapper(Object val, Class<T> clazz) {
if (!isWrapper(val)) val = new NativeWrapper(val); if (isWrapper(val)) val = ((NativeWrapper)val).wrapped;
var res = (NativeWrapper)val; if (val != null && clazz.isInstance(val)) return (T)val;
if (res != null && clazz.isInstance(res.wrapped)) return (T)res.wrapped;
else return null; else return null;
} }
@@ -471,7 +470,7 @@ public class Values {
else return ctx.environment.wrappers.getConstr((Class<?>)val); else return ctx.environment.wrappers.getConstr((Class<?>)val);
} }
return new NativeWrapper(val); return NativeWrapper.of(ctx, val);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -536,7 +535,7 @@ 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)) { if (clazz.isAssignableFrom(NativeWrapper.class)) {
return (T)new NativeWrapper(obj); return (T)NativeWrapper.of(ctx, obj);
} }
throw new ConvertException(type(obj), clazz.getSimpleName()); throw new ConvertException(type(obj), clazz.getSimpleName());

View File

@@ -42,6 +42,7 @@ public class SimpleDebugger implements Debugger {
public static final Set<String> VSCODE_EMPTY = Set.of( public static final Set<String> VSCODE_EMPTY = Set.of(
"function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}", "function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}",
"function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}", "function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}",
"function(...runtimeArgs){\n let r = 1024; let e = null;\n let t={},n=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return t;for(let[i,o]of Object.entries(this)){if(e)try{let s=e.call(o,n);if(s!==n){t[i]=String(s);continue}}catch(s){t[i]=`<<indescribable>>${JSON.stringify([String(s),i])}`;continue}if(typeof o==\"object\"&&o){let s;for(let a of runtimeArgs[0])if(typeof o[a]==\"function\")try{s=o[a]();break}catch{}!s&&!String(o.toString).includes(\"[native code]\")&&(s=String(o)),s&&!s.startsWith(\"[object \")&&(t[i]=s.length>=r?s.slice(0,r)+\"\\u2026\":s)}}return t\n ;\n\n}",
"function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}", "function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}",
"function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}" "function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}"
); );
@@ -226,6 +227,8 @@ public class SimpleDebugger implements Debugger {
private int stepOutPtr = 0; private int stepOutPtr = 0;
private boolean compare(String src, String target) { private boolean compare(String src, String target) {
src = src.replaceAll("\\s", "");
target = target.replaceAll("\\s", "");
if (src.length() != target.length()) return false; if (src.length() != target.length()) return false;
var diff = 0; var diff = 0;
var all = 0; var all = 0;

View File

@@ -288,8 +288,23 @@ public class NativeWrapperProvider implements WrapperProvider {
return res; return res;
} }
private void updateProtoChain(Class<?> clazz, ObjectValue proto, FunctionValue constr) {
var parent = clazz;
while (true) {
parent = parent.getSuperclass();
if (parent == null) return;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
}
}
private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) { private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) {
if (constr != null && proto != null) return; if (constr != null && proto != null || ignore.contains(clazz)) return;
// i vomit // i vomit
if ( if (
clazz == Object.class || clazz == Object.class ||
@@ -316,32 +331,35 @@ public class NativeWrapperProvider implements WrapperProvider {
prototypes.put(clazz, proto); prototypes.put(clazz, proto);
constructors.put(clazz, constr); constructors.put(clazz, constr);
var parent = clazz; updateProtoChain(clazz, proto, constr);
while (true) {
parent = parent.getSuperclass();
if (parent == null) return;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
}
} }
public ObjectValue getProto(Class<?> clazz) { public ObjectValue getProto(Class<?> clazz) {
initType(clazz, constructors.get(clazz), prototypes.get(clazz)); initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return prototypes.get(clazz); while (clazz != null) {
var res = prototypes.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
public ObjectValue getNamespace(Class<?> clazz) { public ObjectValue getNamespace(Class<?> clazz) {
if (!namespaces.containsKey(clazz)) namespaces.put(clazz, makeNamespace(env, clazz)); if (!namespaces.containsKey(clazz)) namespaces.put(clazz, makeNamespace(env, clazz));
return namespaces.get(clazz); while (clazz != null) {
var res = namespaces.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
public FunctionValue getConstr(Class<?> clazz) { public FunctionValue getConstr(Class<?> clazz) {
initType(clazz, constructors.get(clazz), prototypes.get(clazz)); initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return constructors.get(clazz); while (clazz != null) {
var res = constructors.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
@Override public WrapperProvider fork(Environment env) { @Override public WrapperProvider fork(Environment env) {
@@ -357,6 +375,12 @@ public class NativeWrapperProvider implements WrapperProvider {
prototypes.put(clazz, proto); prototypes.put(clazz, proto);
constructors.put(clazz, constructor); constructors.put(clazz, constructor);
ignore.remove(clazz); ignore.remove(clazz);
for (var el : prototypes.keySet()) {
if (clazz.isAssignableFrom(el)) {
updateProtoChain(el, getProto(el), getConstr(el));
}
}
} }
else { else {
prototypes.remove(clazz); prototypes.remove(clazz);