From a7271484479d964c271cca574d30711ebede819e Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Tue, 23 Apr 2024 16:52:26 +0200 Subject: [PATCH] More Optimizations --- hscript/Expr.hx | 15 ++++++- hscript/Interp.hx | 90 ++++++++++++++++++++++++++----------- hscript/Macro.hx | 14 +++++- hscript/Parser.hx | 40 ++++++++++------- hscript/Printer.hx | 12 ++--- hscript/Tools.hx | 4 +- tests/src/tests/ListCase.hx | 2 + 7 files changed, 125 insertions(+), 52 deletions(-) diff --git a/hscript/Expr.hx b/hscript/Expr.hx index 3c6d213..1b9d085 100644 --- a/hscript/Expr.hx +++ b/hscript/Expr.hx @@ -62,7 +62,8 @@ enum Expr ECall( e : Expr, params : Array ); EIf( cond : Expr, e1 : Expr, ?e2 : Expr ); EWhile( cond : Expr, e : Expr ); - EFor( v : String, it : Expr, e : Expr, ?ithv: String); + EFor( v : String, it : Expr, e : Expr); + EForKeyValue( v : String, it : Expr, e : Expr, ithv: String); EBreak; EContinue; EFunction( args : Array, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool ); @@ -72,7 +73,7 @@ enum Expr ENew( cl : String, params : Array ); EThrow( e : Expr ); ETry( e : Expr, v : String, t : Null, ecatch : Expr ); - EObject( fl : Array<{ name : String, e : Expr }> ); + EObject( fl : Array ); ETernary( cond : Expr, e1 : Expr, e2 : Expr ); ESwitch( e : Expr, cases : Array, ?defaultExpr : Expr ); EDoWhile( cond : Expr, e : Expr); @@ -83,6 +84,16 @@ enum Expr EClass( name:String, fields:Array, ?extend:String, interfaces:Array ); } +class ObjectField { + public var name:String; + public var e:Expr; + + public function new(name, e) { + this.name = name; + this.e = e; + } +} + class SwitchCase { public var values : Array; public var expr : Expr; diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 9860d24..e16d093 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -341,8 +341,10 @@ class Interp { var arr:Dynamic = expr(e); var index:Dynamic = expr(index); if (isMap(arr)) { - v = fop(getMapValue(arr, index), expr(e2)); - setMapValue(arr, index, v); + var map = getMap(arr); + + v = fop(map.get(index), expr(e2)); + map.set(index, v); } else { v = fop(arr[index], expr(e2)); arr[index] = v; @@ -694,8 +696,11 @@ class Interp { case EDoWhile(econd, e): doWhileLoop(econd, e); return null; - case EFor(v, it, e, ithv): - forLoop(v, it, e, ithv); + case EFor(v, it, e): + forLoop(v, it, e); + return null; + case EForKeyValue(v, it, e, ithv): + forLoopKeyValue(v, it, e, ithv); return null; case EBreak: throw SBreak; @@ -844,7 +849,6 @@ class Interp { } for (n in 0...keys.length) { map.set(keys[n], values[n]); - //setMapValue(map, keys[n], values[n]); } return map; } else { @@ -896,7 +900,8 @@ class Interp { case EObject(fl): var o = {}; for (f in fl) - set(o, f.name, expr(f.e)); + UnsafeReflect.setField(o, f.name, expr(f.e)); + //set(o, f.name, expr(f.e)); return o; case ETernary(econd, e1, e2): return if (expr(econd) == true) expr(e1) else expr(e2); @@ -919,9 +924,8 @@ class Interp { return val; case EMeta(a, b, e): var oldAccessor = isBypassAccessor; - if(a == ":bypassAccessor") { + if(a == ":bypassAccessor") isBypassAccessor = true; - } var val = expr(e); isBypassAccessor = oldAccessor; @@ -968,17 +972,11 @@ class Interp { restore(old); } - function makeIterator(v:Dynamic, ?allowKeyValue = false):Iterator { + function makeIterator(v:Dynamic):Iterator { #if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0')) if (v.iterator != null) v = v.iterator(); #else - if(allowKeyValue) { - try - v = v.keyValueIterator() - catch (e:Dynamic) {}; - } - if(v.hasNext == null || v.next == null) { try v = v.iterator() @@ -990,20 +988,62 @@ class Interp { return v; } - function forLoop(n, it, e, ?ithv) { - var isKeyValue = ithv != null; + function makeKeyValueIterator(v:Dynamic):Iterator { + #if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0')) + if (v.keyValueIterator != null) + v = v.keyValueIterator(); + + if (v.iterator != null) + v = v.iterator(); + + if (v.hasNext == null || v.next == null) + error(EInvalidIterator(v)); + #else + try + v = v.keyValueIterator() + catch (e:Dynamic) {}; + + if (v.hasNext == null || v.next == null) + v = makeIterator(v); + #end + return v; + } + + function forLoop(n, it, e) { var old = declared.length; - if(isKeyValue) - 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); + var it = makeIterator(expr(it)); 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}); + locals.set(n, {r: next, depth: depth}); + try { + expr(e); + } catch (err:Stop) { + switch (err) { + case SContinue: + case SBreak: + break; + case SReturn: + throw err; + } + } + } + restore(old); + } + + function forLoopKeyValue(n, it, e, ithv) { + var old = declared.length; + declared.push({n: ithv, old: locals.get(ithv), depth: depth}); + declared.push({n: n, old: locals.get(n), depth: depth}); + var it = makeKeyValueIterator(expr(it)); + var _hasNext = it.hasNext; + var _next = it.next; + while (_hasNext()) { + var next = _next(); + locals.set(ithv, {r: next.key, depth: depth}); + locals.set(n, {r: next.value, depth: depth}); try { expr(e); } catch (err:Stop) { @@ -1043,7 +1083,7 @@ class Interp { public var useRedirects:Bool = true; - static function getClassType(o:Dynamic, ?cls:Class):String { + static function getClassType(o:Dynamic, ?cls:Class):Null { return switch (Type.typeof(o)) { case TNull: "Null"; case TInt: "Int"; @@ -1093,6 +1133,7 @@ class Interp { var obj = cast(o, IHScriptCustomBehaviour); return obj.hset(f, v); } + // Can use unsafe reflect here, since we checked for null above if(isBypassAccessor) { UnsafeReflect.setField(o, f, v); } else { @@ -1116,7 +1157,6 @@ class Interp { } function cnew(cl:String, args:Array):Dynamic { - var cl:String = cast cl; var c:Dynamic = resolve(cl); if (c == null) c = Type.resolveClass(cl); diff --git a/hscript/Macro.hx b/hscript/Macro.hx index 527c9b2..d49f466 100644 --- a/hscript/Macro.hx +++ b/hscript/Macro.hx @@ -198,14 +198,24 @@ class Macro { EWhile(convert(c), convert(e), false); case EFor(v, it, efor): #if (haxe_ver >= 4) - var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; + var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); #elseif (haxe_211 || haxe3) - var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; + var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); #else EFor(v, convert(it), convert(efor)); #end + case EForKeyValue(v, it, efor, ithv): + #if (haxe_ver >= 4) + var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; + EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor), ithv); + #elseif (haxe_211 || haxe3) + var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; + EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor), ithv); + #else + EFor(v, convert(it), convert(efor), ithv); + #end case EBreak: EBreak; case EContinue: diff --git a/hscript/Parser.hx b/hscript/Parser.hx index badd2e7..c843c73 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -288,6 +288,7 @@ class Parser { case EWhile(_,e): isBlock(e); case EDoWhile(_,e): isBlock(e); case EFor(_,_,e): isBlock(e); + case EForKeyValue(_,_,e,_): isBlock(e); case EReturn(e): e != null && isBlock(e); case ETry(_, _, _, e): isBlock(e); case EMeta(_, _, e): isBlock(e); @@ -337,7 +338,7 @@ class Parser { break; } ensure(TDoubleDot); - fl.push({ name : id, e : parseExpr() }); + fl.push(new ObjectField(id, parseExpr())); tk = token(); switch( tk ) { case TBrClose: @@ -481,7 +482,7 @@ class Parser { } if( a.length == 1 && a[0] != null ) // What is this for??? switch( expr(a[0]) ) { - case EFor(_), EWhile(_), EDoWhile(_): + case EFor(_), EForKeyValue(_), EWhile(_), EDoWhile(_): var tmp = "__a_" + (uid++); var e = mk(EBlock([ mk(EVar(tmp, null, mk(EArrayDecl([]), p1)), p1), @@ -547,20 +548,22 @@ class Parser { function mapCompr( tmp : String, e : Expr ) { if( e == null ) return null; var edef = switch( expr(e) ) { - case EFor(v, it, e2, ithv): - EFor(v, it, mapCompr(tmp, e2), ithv); - case EWhile(cond, e2): - EWhile(cond, mapCompr(tmp, e2)); - case EDoWhile(cond, e2): - EDoWhile(cond, mapCompr(tmp, e2)); - case EIf(cond, e1, e2) if( e2 == null ): - EIf(cond, mapCompr(tmp, e1), null); - case EBlock([e]): - EBlock([mapCompr(tmp, e)]); - case EParent(e2): - EParent(mapCompr(tmp, e2)); - default: - ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "push"), pmin(e), pmax(e)), [e]); + case EFor(v, it, e2): + EFor(v, it, mapCompr(tmp, e2)); + case EForKeyValue(v, it, e2, ithv): + EForKeyValue(v, it, mapCompr(tmp, e2), ithv); + case EWhile(cond, e2): + EWhile(cond, mapCompr(tmp, e2)); + case EDoWhile(cond, e2): + EDoWhile(cond, mapCompr(tmp, e2)); + case EIf(cond, e1, e2) if( e2 == null ): + EIf(cond, mapCompr(tmp, e1), null); + case EBlock([e]): + EBlock([mapCompr(tmp, e)]); + case EParent(e2): + EParent(mapCompr(tmp, e2)); + default: + ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "push"), pmin(e), pmax(e)), [e]); } return mk(edef, pmin(e), pmax(e)); } @@ -759,7 +762,10 @@ class Parser { var eiter = parseExpr(); ensure(TPClose); var e = parseExpr(); - mk(EFor(vname,eiter,e,ithv),p1,pmax(e)); + if(ithv != null) + mk(EForKeyValue(vname,eiter,e,ithv),p1,pmax(e)); + else + mk(EFor(vname,eiter,e),p1,pmax(e)); case "break": mk(EBreak); case "continue": mk(EContinue); case "else": unexpected(TId(id)); diff --git a/hscript/Printer.hx b/hscript/Printer.hx index 9e1f883..3db0b0f 100644 --- a/hscript/Printer.hx +++ b/hscript/Printer.hx @@ -217,11 +217,13 @@ class Printer { add(" while ( "); expr(cond); add(" )"); - case EFor(v, it, e, ithv): - if(ithv != null) - add("for( "+ithv+" => "+v+" in "); - else - add("for( "+v+" in "); + case EFor(v, it, e): + add("for( "+v+" in "); + expr(it); + add(" ) "); + expr(e); + case EForKeyValue(v, it, e, ithv): + add("for( "+ithv+" => "+v+" in "); expr(it); add(" ) "); expr(e); diff --git a/hscript/Tools.hx b/hscript/Tools.hx index 7a2e864..6855773 100644 --- a/hscript/Tools.hx +++ b/hscript/Tools.hx @@ -40,6 +40,7 @@ class Tools { case EWhile(c, e): f(c); f(e); case EDoWhile(c, e): f(c); f(e); case EFor(_, it, e): f(it); f(e); + case EForKeyValue(_, it, e, _): f(it); f(e); case EBreak,EContinue: case EFunction(_, e, _, _): f(e); case EReturn(e): if( e != null ) f(e); @@ -77,6 +78,7 @@ class Tools { case EWhile(c, e): EWhile(f(c),f(e)); case EDoWhile(c, e): EDoWhile(f(c),f(e)); case EFor(v, it, e): EFor(v, f(it), f(e)); + case EForKeyValue(v, it, e, ithv): EForKeyValue(v, f(it), f(e), ithv); case EFunction(args, e, name, t): EFunction(args, f(e), name, t); case EReturn(e): EReturn(if( e != null ) f(e) else null); case EArray(e, i): EArray(f(e),f(i)); @@ -84,7 +86,7 @@ class Tools { case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]); case EThrow(e): EThrow(f(e)); 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 EObject(fl): EObject([for( fi in fl ) new ObjectField(fi.name, 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 ) 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)); diff --git a/tests/src/tests/ListCase.hx b/tests/src/tests/ListCase.hx index 92ad2f8..d8f648c 100644 --- a/tests/src/tests/ListCase.hx +++ b/tests/src/tests/ListCase.hx @@ -29,6 +29,8 @@ class ListCase extends TestCase { assertEq("[for (k=>v in l4) k]", [for (k=>v in l4) k]); assertEq("[for (k=>v in l4) v]", [for (k=>v in l4) v]); assertEq("[for (k=>v in l4) k*v]", [for (k=>v in l4) k*v]); + + assertEq("[for (v in l4) v]", [for (v in l4) v]); } override function teardown() {