From a16e74dee6a1ac25dc583b7fd3e9315993924d01 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Tue, 23 Apr 2024 16:17:17 +0200 Subject: [PATCH] Added UnsafeReflect --- hscript/CustomClassHandler.hx | 8 +- hscript/Expr.hx | 14 ++- hscript/Interp.hx | 99 +++++++++-------- hscript/Parser.hx | 20 ++-- hscript/Tools.hx | 2 +- hscript/macros/ClassExtendMacro.hx | 7 +- hscript/utils/UnsafeReflect.hx | 157 +++++++++++++++++++++++++++ tests/src/benchmark/TestBenchmark.hx | 5 +- 8 files changed, 246 insertions(+), 66 deletions(-) create mode 100644 hscript/utils/UnsafeReflect.hx diff --git a/hscript/CustomClassHandler.hx b/hscript/CustomClassHandler.hx index 445a362..f59a5e4 100644 --- a/hscript/CustomClassHandler.hx +++ b/hscript/CustomClassHandler.hx @@ -1,5 +1,7 @@ package hscript; +import hscript.utils.UnsafeReflect; + using StringTools; class CustomClassHandler implements IHScriptCustomConstructor { @@ -87,15 +89,15 @@ class TemplateClass implements IHScriptCustomBehaviour { this.__interp.variables.set(name, val); return val; } - Reflect.setProperty(this, name, val); - return Reflect.field(this, name); + UnsafeReflect.setProperty(this, name, val); + return UnsafeReflect.field(this, name); } public function hget(name:String):Dynamic { if(this.__interp.variables.exists("get_" + name)) return this.__interp.variables.get("get_" + name)(); if (this.__interp.variables.exists(name)) return this.__interp.variables.get(name); - return Reflect.getProperty(this, name); + return UnsafeReflect.getProperty(this, name); } } diff --git a/hscript/Expr.hx b/hscript/Expr.hx index 00384ad..3c6d213 100644 --- a/hscript/Expr.hx +++ b/hscript/Expr.hx @@ -74,7 +74,7 @@ enum Expr ETry( e : Expr, v : String, t : Null, ecatch : Expr ); EObject( fl : Array<{ name : String, e : Expr }> ); ETernary( cond : Expr, e1 : Expr, e2 : Expr ); - ESwitch( e : Expr, cases : Array<{ values : Array, expr : Expr }>, ?defaultExpr : Expr ); + ESwitch( e : Expr, cases : Array, ?defaultExpr : Expr ); EDoWhile( cond : Expr, e : Expr); EMeta( name : String, args : Array, e : Expr ); ECheckType( e : Expr, t : CType ); @@ -83,6 +83,17 @@ enum Expr EClass( name:String, fields:Array, ?extend:String, interfaces:Array ); } +class SwitchCase { + public var values : Array; + public var expr : Expr; + + public function new(values, expr) { + this.values = values; + this.expr = expr; + } +} + + //typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr }; class Argument { public var name : String; @@ -145,7 +156,6 @@ enum Error EAlreadyExistingClass( className : String); } - enum ModuleDecl { DPackage( path : Array ); DImport( path : Array, ?everything : Bool ); diff --git a/hscript/Interp.hx b/hscript/Interp.hx index e8bdc05..9860d24 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -28,12 +28,13 @@ */ package hscript; -import haxe.iterators.StringKeyValueIteratorUnicode; -import haxe.EnumTools; -import haxe.display.Protocol.InitializeResult; -import haxe.PosInfos; -import hscript.Expr; import haxe.Constraints.IMap; +import haxe.EnumTools; +import haxe.PosInfos; +import haxe.display.Protocol.InitializeResult; +import haxe.iterators.StringKeyValueIteratorUnicode; +import hscript.Expr; +import hscript.utils.UnsafeReflect; using StringTools; @@ -257,19 +258,19 @@ class Interp { if (l == null) { if (!variables.exists(id) && !staticVariables.exists(id) && !publicVariables.exists(id) && _hasScriptObject) { if (_scriptObjectType == SObject) { - Reflect.setField(scriptObject, id, v); + UnsafeReflect.setField(scriptObject, id, v); } else { if (isBypassAccessor) { if (__instanceFields.contains(id)) { - Reflect.setField(scriptObject, id, v); + UnsafeReflect.setField(scriptObject, id, v); return v; } } if (__instanceFields.contains(id)) { - Reflect.setProperty(scriptObject, id, v); + UnsafeReflect.setProperty(scriptObject, id, v); } else if (__instanceFields.contains('set_$id')) { // setter - Reflect.getProperty(scriptObject, 'set_$id')(v); + UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); } else { setVar(id, v); } @@ -317,11 +318,11 @@ class Interp { if (l == null) { if(_hasScriptObject) { if(_scriptObjectType == SObject) { - Reflect.setField(scriptObject, id, v); + UnsafeReflect.setField(scriptObject, id, v); } else if (__instanceFields.contains(id)) { - Reflect.setProperty(scriptObject, id, v); + UnsafeReflect.setProperty(scriptObject, id, v); } else if (__instanceFields.contains('set_$id')) { // setter - Reflect.getProperty(scriptObject, 'set_$id')(v); + UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); } else { setVar(id, v); } @@ -386,12 +387,13 @@ class Interp { var arr:Dynamic = expr(e); var index:Dynamic = expr(index); if (isMap(arr)) { - var v = getMapValue(arr, index); + var map = getMap(arr); + var v = map.get(index); if (prefix) { v += delta; - setMapValue(arr, index, v); + map.set(index, v); } else { - setMapValue(arr, index, v + delta); + map.set(index, v + delta); } return v; } else { @@ -504,13 +506,13 @@ class Interp { // search in object if (id == "this") { return scriptObject; - } else if (_scriptObjectType == SObject && Reflect.hasField(scriptObject, id)) { - return Reflect.field(scriptObject, id); + } else if (_scriptObjectType == SObject && UnsafeReflect.hasField(scriptObject, id)) { + return UnsafeReflect.field(scriptObject, id); } else { if (__instanceFields.contains(id)) { - return Reflect.getProperty(scriptObject, id); + return UnsafeReflect.getProperty(scriptObject, id); } else if (__instanceFields.contains('get_$id')) { // getter - return Reflect.getProperty(scriptObject, 'get_$id')(); + return UnsafeReflect.getProperty(scriptObject, 'get_$id')(); } } } @@ -587,10 +589,10 @@ class Interp { var enumThingy = {}; for (c in en.getConstructors()) { try { - Reflect.setField(enumThingy, c, en.createByName(c)); + UnsafeReflect.setField(enumThingy, c, en.createByName(c)); } catch(e) { try { - Reflect.setField(enumThingy, c, Reflect.field(en, c)); + UnsafeReflect.setField(enumThingy, c, UnsafeReflect.field(en, c)); } catch(ex) { throw e; } @@ -995,8 +997,10 @@ class Interp { declared.push({n: ithv, old: locals.get(ithv), depth: depth}); declared.push({n: n, old: locals.get(n), depth: depth}); var it = makeIterator(expr(it), isKeyValue); - while (it.hasNext()) { - var next = it.next(); + var _hasNext = it.hasNext; + var _next = it.next; + while (_hasNext()) { + var next = _next(); if(isKeyValue) locals.set(ithv, {r: next.key, depth: depth}); locals.set(n, {r: isKeyValue ? next.value : next, depth: depth}); @@ -1019,6 +1023,10 @@ class Interp { return (o is IMap); } + inline function getMap(map:Dynamic):IMap { + return cast(map, IMap); + } + inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic { return cast(map, IMap).get(key); } @@ -1051,28 +1059,27 @@ class Interp { function get(o:Dynamic, f:String):Dynamic { if (o == null) error(EInvalidAccess(f)); - return { - var cls = Type.getClass(o); - var cl:Null = getClassType(o, cls); - if (useRedirects && cl != null && getRedirects.exists(cl) && (_getRedirect = getRedirects[cl]) != null) { - return _getRedirect(o, f); - } else if (o is IHScriptCustomBehaviour) { - var obj = cast(o, IHScriptCustomBehaviour); - return obj.hget(f); - } else { - var v = null; - if(isBypassAccessor) { - if ((v = Reflect.field(o, f)) == null) - v = Reflect.field(cls, f); - } - if(v == null) { - if ((v = Reflect.getProperty(o, f)) == null) - v = Reflect.getProperty(cls, f); - } - return v; - } + var cls = Type.getClass(o); + var cl:Null = getClassType(o, cls); + if (useRedirects && cl != null && getRedirects.exists(cl) && (_getRedirect = getRedirects[cl]) != null) { + return _getRedirect(o, f); + } else if (o is IHScriptCustomBehaviour) { + var obj = cast(o, IHScriptCustomBehaviour); + return obj.hget(f); } + + var v = null; + if(isBypassAccessor) { + if ((v = UnsafeReflect.field(o, f)) == null) + v = Reflect.field(cls, f); + } + + if(v == null) { + if ((v = UnsafeReflect.getProperty(o, f)) == null) + v = Reflect.getProperty(cls, f); + } + return v; } function set(o:Dynamic, f:String, v:Dynamic):Dynamic { @@ -1087,16 +1094,16 @@ class Interp { return obj.hset(f, v); } if(isBypassAccessor) { - Reflect.setField(o, f, v); + UnsafeReflect.setField(o, f, v); } else { - Reflect.setProperty(o, f, v); + UnsafeReflect.setProperty(o, f, v); } return v; } function fcall(o:Dynamic, f:String, args:Array):Dynamic { if(o == CustomClassHandler.staticHandler && _hasScriptObject) { - return Reflect.callMethod(scriptObject, Reflect.field(scriptObject, "_HX_SUPER__" + f), args); + return UnsafeReflect.callMethod(scriptObject, UnsafeReflect.field(scriptObject, "_HX_SUPER__" + f), args); } return call(o, get(o, f), args); } diff --git a/hscript/Parser.hx b/hscript/Parser.hx index c34c93a..badd2e7 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -373,10 +373,10 @@ class Parser { return mk(EFunction([], mk(EReturn(eret),p1)), p1); } push(tk); - var oldoo = disableOrOp; - disableOrOp = false; + //var oldoo = disableOrOp; + //disableOrOp = false; var e = parseExpr(); - disableOrOp = oldoo; + //disableOrOp = oldoo; tk = token(); switch( tk ) { case TPClose: @@ -448,10 +448,10 @@ class Parser { case TOp(op): if( op == "-" ) { var start = tokenMin; - var oldoo = disableOrOp; - disableOrOp = false; + //var oldoo = disableOrOp; + //disableOrOp = false; var e = parseExpr(); - disableOrOp = oldoo; + //disableOrOp = oldoo; if( e == null ) return makeUnop(op,e); switch( expr(e) ) { @@ -471,10 +471,10 @@ class Parser { tk = token(); while( tk != TBkClose && (!resumeErrors || tk != TEof) ) { push(tk); - var oldoo = disableOrOp; - disableOrOp = false; + //var oldoo = disableOrOp; + //disableOrOp = false; a.push(parseExpr()); - disableOrOp = oldoo; + //disableOrOp = oldoo; tk = token(); if( tk == TComma ) tk = token(); @@ -965,7 +965,7 @@ class Parser { var tk = token(); switch( tk ) { case TId("case"): - var c = { values : [], expr : null }; + var c = new SwitchCase([], null); cases.push(c); disableOrOp = true; while( true ) { diff --git a/hscript/Tools.hx b/hscript/Tools.hx index 92c03fe..7a2e864 100644 --- a/hscript/Tools.hx +++ b/hscript/Tools.hx @@ -86,7 +86,7 @@ class Tools { case ETry(e, v, t, c): ETry(f(e), v, t, f(c)); case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2)); - case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def)); + case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) new SwitchCase([for( v in c.values ) f(v)], f(c.expr))], def == null ? null : f(def)); case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e)); case ECheckType(e,t): ECheckType(f(e), t); case EImport(c): EImport(c); diff --git a/hscript/macros/ClassExtendMacro.hx b/hscript/macros/ClassExtendMacro.hx index 0bf6ada..b6d3d9a 100644 --- a/hscript/macros/ClassExtendMacro.hx +++ b/hscript/macros/ClassExtendMacro.hx @@ -262,6 +262,7 @@ class ClassExtendMacro { shadowClass.name = '${cl.name}$CLASS_SUFFIX'; var imports = Context.getLocalImports().copy(); Utils.setupMetas(shadowClass, imports); + Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect"); // Adding hscript getters and setters @@ -328,7 +329,7 @@ class ClassExtendMacro { return this.__interp.variables.get("get_" + name)(); if (this.__interp.variables.exists(name)) return this.__interp.variables.get(name); - return Reflect.getProperty(this, name); + return UnsafeReflect.getProperty(this, name); } } @@ -352,8 +353,8 @@ class ClassExtendMacro { this.__interp.variables.set(name, val); return val; } - Reflect.setProperty(this, name, val); - return Reflect.field(this, name); + UnsafeReflect.setProperty(this, name, val); + return UnsafeReflect.field(this, name); } } diff --git a/hscript/utils/UnsafeReflect.hx b/hscript/utils/UnsafeReflect.hx new file mode 100644 index 0000000..99403ce --- /dev/null +++ b/hscript/utils/UnsafeReflect.hx @@ -0,0 +1,157 @@ +package hscript.utils; + +#if cpp +import cpp.ObjectType; +#end + +@:analyzer(ignore) +class UnsafeReflect { + public #if !cpp inline #end static function hasField(o:Dynamic, field:String):Bool { + #if cpp + untyped { + return o.__HasField(field); + } + #else + return Reflect.hasField(o, field); + #end + } + + public #if !cpp inline #end static function field(o:Dynamic, field:String):Dynamic { + #if cpp + untyped { + return o.__Field(field, untyped __cpp__("::hx::paccNever")); + } + #else + return Reflect.field(o, field); + #end + } + + public #if !cpp inline #end static function setField(o:Dynamic, field:String, value:Dynamic):Void { + #if cpp + untyped { + o.__SetField(field, value, untyped __cpp__("::hx::paccNever")); + } + #else + return Reflect.setField(o, field, value); + #end + } + + public #if !cpp inline #end static function getProperty(o:Dynamic, field:String):Dynamic { + #if cpp + untyped { + return o.__Field(field, untyped __cpp__("::hx::paccAlways")); + } + #else + return Reflect.getProperty(o, field); + #end + } + + public #if !cpp inline #end static function setProperty(o:Dynamic, field:String, value:Dynamic):Void { + #if cpp + untyped { + o.__SetField(field, value, untyped __cpp__("::hx::paccAlways")); + } + #else + Reflect.setProperty(o, field); + #end + } + + public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array):Dynamic + return Reflect.callMethod(o, func, args); + /*untyped { + if (func != null && func.__GetType() == ObjectType.vtString) { + if (o == null) + throw cpp.ErrorConstants.invalidObject; + func = o.__Field(func, untyped __cpp__("::hx::paccDynamic")); + } + if (func == null) + throw cpp.ErrorConstants.nullFunctionPointer; + untyped func.__SetThis(o); + return untyped func.__Run(args); + }*/ + + public inline static function fields(o:Dynamic):Array + return Reflect.fields(o); + /*untyped { + if (o == null) + return new Array(); + var a:Array = []; + o.__GetFields(a); + return a; + }*/ + + public #if !cpp inline #end static function isFunction(f:Dynamic):Bool + #if cpp + untyped { + return f.__GetType() == ObjectType.vtFunction; + } + #else + return Reflect.isFunction(f); + #end + + public inline static function compare(a:T, b:T):Int { + return Reflect.compare(a, b); + //return (a == b) ? 0 : (((a : Dynamic) > (b : Dynamic)) ? 1 : -1); + } + + public inline static function compareMethods(f1:Dynamic, f2:Dynamic):Bool { + return Reflect.compareMethods(f1, f2); + } + + public #if !cpp inline #end static function isObject(v:Dynamic):Bool { + #if cpp + untyped { + var t:Int = v.__GetType(); + return t == ObjectType.vtObject || t == ObjectType.vtClass || t == ObjectType.vtString || t == ObjectType.vtArray; + } + #else + return Reflect.isObject(v); + #end + } + + public #if !cpp inline #end static function isEnumValue(v:Dynamic):Bool { + #if cpp + untyped { + return v.__GetType() == ObjectType.vtEnum; + } + #else + return Reflect.isEnumValue(v); + #end + } + + public #if !cpp inline #end static function deleteField(o:Dynamic, field:String):Bool { + #if cpp + untyped { + return untyped __global__.__hxcpp_anon_remove(o, field); + } + #else + return Reflect.deleteField(o, field); + #end + } + + public #if !cpp inline #end static function copy(o:Null):Null { + #if cpp + if (o == null) + return null; + if (untyped o.__GetType() == ObjectType.vtString) + return o; + if (untyped o.__GetType() == ObjectType.vtArray) + return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))(); + var o2:Dynamic = {}; + for (f in UnsafeReflect.fields(o)) + UnsafeReflect.setField(o2, f, UnsafeReflect.field(o, f)); + return o2; + #else + return Reflect.copy(o); + #end + } + + @:overload(function(f:Array->Void):Dynamic {}) + public static function makeVarArgs(f:Array->Dynamic):Dynamic { + #if cpp + return untyped __global__.__hxcpp_create_var_args(f); + #else + return inline Reflect.makeVarArgs(f); + #end + } +} diff --git a/tests/src/benchmark/TestBenchmark.hx b/tests/src/benchmark/TestBenchmark.hx index 8d2853f..f1b6b01 100644 --- a/tests/src/benchmark/TestBenchmark.hx +++ b/tests/src/benchmark/TestBenchmark.hx @@ -6,11 +6,14 @@ class TestBenchmark extends Benchmark { super("Test", 10000); } + var hscript = "var a:Array = []; for (i in 0...1000) a.push(i * 2 + 1 / 6);"; + public override function reset() { super.reset(); a = []; if(interp != null) interp.variables.remove("a"); + cacheExpr(hscript); } public var a:Array = []; @@ -19,6 +22,6 @@ class TestBenchmark extends Benchmark { } public override function hscriptBenchmark() { - execute("var a:Array = []; for (i in 0...1000) a.push(i * 2 + 1 / 6);"); + execute(hscript); } } \ No newline at end of file