diff --git a/folder-alias.json b/folder-alias.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/folder-alias.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/hscript/Checker.hx b/hscript/Checker.hx index 800f755..ca7ed9e 100644 --- a/hscript/Checker.hx +++ b/hscript/Checker.hx @@ -1078,7 +1078,7 @@ class Checker { return et; default: } - case EFor(v, it, e): + case EFor(k, v, it, e): var locals = saveLocals(); var itt = typeExpr(it, Value); var vt = switch( follow(itt) ) { diff --git a/hscript/Expr.hx b/hscript/Expr.hx index 62862ee..47da73e 100644 --- a/hscript/Expr.hx +++ b/hscript/Expr.hx @@ -54,7 +54,7 @@ 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 ); + EFor( k : String, v : String, it : Expr, e : Expr ); EBreak; EContinue; EFunction( args : Array, e : Expr, ?name : String, ?ret : CType ); @@ -115,6 +115,7 @@ enum Error { EInvalidPreprocessor( msg : String ); EUnknownVariable( v : String ); EInvalidIterator( v : String ); + EInvalidKeyValueIterator( v : String ); EInvalidOp( op : String ); EInvalidAccess( f : String ); ECustom( msg : String ); diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 890c913..22d837d 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -172,6 +172,7 @@ class Interp { if (Type.typeof(scriptObject) == TObject) { Reflect.setField(scriptObject, id, v); } else { + #if !web if (__instanceFields.contains(id)) { Reflect.setProperty(scriptObject, id, v); } else if (__instanceFields.contains('set_$id')) { // setter @@ -179,6 +180,13 @@ class Interp { } else { setVar(id, v); } + #else + try { + Reflect.setProperty(scriptObject, id, v); + } catch(e) { + setVar(id, v); + } + #end } } else { setVar(id, v); @@ -219,6 +227,7 @@ class Interp { var l = locals.get(id); v = fop(expr(e1), expr(e2)); if (l == null) { + #if !web if (__instanceFields.contains(id)) { Reflect.setProperty(scriptObject, id, v); } else if (__instanceFields.contains('set_$id')) { // setter @@ -226,6 +235,13 @@ class Interp { } else { setVar(id, v); } + #else + try { + Reflect.setProperty(scriptObject, id, v); + } catch(e) { + setVar(id, v); + } + #end } else l.r = v; @@ -330,7 +346,7 @@ class Interp { return v; } } catch(e) { - error(ECustom('${e.toString()}')); + error(ECustom('${Std.string(e)}')); } return null; } @@ -510,8 +526,8 @@ class Interp { case EDoWhile(econd, e): doWhileLoop(econd, e); return null; - case EFor(v, it, e): - forLoop(v, it, e); + case EFor(k, v, it, e): + forLoop(k, v, it, e); return null; case EBreak: throw SBreak; @@ -751,24 +767,47 @@ class Interp { function makeIterator(v:Dynamic):Iterator { #if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0')) - if (v.iterator != null) - v = v.iterator(); + if (v.keyValueIterator != null) + v = v.keyValueIterator(); #else try - v = v.iterator() + v = v.keyValueIterator() catch (e:Dynamic) {}; #end + if (v.hasNext == null || v.next == null) { + #if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0')) + if (v.iterator != null) + v = v.iterator(); + #else + try + v = v.iterator() + catch (e:Dynamic) {}; + #end + } if (v.hasNext == null || v.next == null) error(EInvalidIterator(v)); return v; } - function forLoop(n, it, e) { + function forLoop(k, n, it, e) { var old = declared.length; + if (k != null) declared.push({n: k, old: locals.get(k), depth: depth}); declared.push({n: n, old: locals.get(n), depth: depth}); var it = makeIterator(expr(it)); while (it.hasNext()) { - locals.set(n, {r: it.next(), depth: depth}); + var next = it.next(); + + if (k != null) { + if (next != null && next is Dynamic && Reflect.hasField(next, "key") && Reflect.hasField(next, "value")) { + trace("is key iterator"); + locals.set(k, {r: next.key, depth: depth}); + locals.set(n, {r: next.value, depth: depth}); + } else { + error(EInvalidKeyValueIterator(Std.string(it))); + return; + } + } else + locals.set(n, {r: next, depth: depth}); try { expr(e); } catch (err:Stop) { @@ -796,8 +835,8 @@ class Interp { cast(map, haxe.Constraints.IMap).set(key, value); } - public static var getRedirects:MapString->Dynamic> = []; - public static var setRedirects:MapString->Dynamic->Dynamic> = []; + public static var getRedirects:MapString->Dynamic)> = []; + public static var setRedirects:MapString->Dynamic->Dynamic)> = []; function get(o:Dynamic, f:String):Dynamic { if (o == null) @@ -816,12 +855,13 @@ class Interp { case _: null; }; - if (getRedirects.exists(cl = Type.getClassName(Type.getClass(o))) && (redirect = getRedirects[cl]) != null) { + var cla = Type.getClass(o); + if (cla != null && getRedirects.exists(cl = Type.getClassName(cla)) && (redirect = getRedirects[cl]) != null) { return redirect(o, f); } else { var v = null; - if ((v = Reflect.getProperty(o, f)) == null) - v = Reflect.getProperty(Type.getClass(o), f); + if ((v = Reflect.getProperty(o, f)) == null && cla != null) + v = Reflect.getProperty(cla, f); return v; } } @@ -844,7 +884,8 @@ class Interp { case _: null; }; - if (setRedirects.exists(cl = Type.getClassName(Type.getClass(o))) && (redirect = setRedirects[cl]) != null) + var cla = Type.getClass(o); + if (cla != null && setRedirects.exists(cl = Type.getClassName(cla)) && (redirect = setRedirects[cl]) != null) return redirect(o, f, v); Reflect.setProperty(o, f, v); diff --git a/hscript/Macro.hx b/hscript/Macro.hx index c9cc6c1..5c95db2 100644 --- a/hscript/Macro.hx +++ b/hscript/Macro.hx @@ -196,7 +196,7 @@ class Macro { EWhile(convert(c), convert(e), true); case EDoWhile(c, e): EWhile(convert(c), convert(e), false); - case EFor(v, it, efor): + case EFor(k, v, it, efor): #if (haxe_ver >= 4) var p = #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)); diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 2f1e646..35eeb1a 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -283,7 +283,7 @@ class Parser { case EUnop(_,prefix,e): !prefix && isBlock(e); case EWhile(_,e): isBlock(e); case EDoWhile(_,e): isBlock(e); - case EFor(_,_,e): isBlock(e); + case EFor(_,_,_,e): isBlock(e); case EReturn(e): e != null && isBlock(e); case ETry(_, _, _, e): isBlock(e); case EMeta(_, _, e): isBlock(e); @@ -534,8 +534,8 @@ class Parser { function mapCompr( tmp : String, e : Expr ) { if( e == null ) return null; var edef = switch( expr(e) ) { - case EFor(v, it, e2): - EFor(v, it, mapCompr(tmp, e2)); + case EFor(k, v, it, e2): + EFor(k, v, it, mapCompr(tmp, e2)); case EWhile(cond, e2): EWhile(cond, mapCompr(tmp, e2)); case EDoWhile(cond, e2): @@ -636,11 +636,22 @@ class Parser { case "for": ensure(TPOpen); var vname = getIdent(); - ensureToken(TId("in")); + var key:String = null; + var tk = token(); + switch(tk) { + case TOp("=>"): + key = vname; + vname = getIdent(); + ensureToken(TId("in")); + case TId("in"): + + default: + unexpected(tk); + } var eiter = parseExpr(); ensure(TPClose); var e = parseExpr(); - mk(EFor(vname,eiter,e),p1,pmax(e)); + mk(EFor(key, 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 d9972d1..0ec792f 100644 --- a/hscript/Printer.hx +++ b/hscript/Printer.hx @@ -200,8 +200,11 @@ class Printer { add(" while ( "); expr(cond); add(" )"); - case EFor(v, it, e): - add("for( "+v+" in "); + case EFor(k, v, it, e): + if (k != null) + add('for($k=>$v in '); + else + add('for($v in '); expr(it); add(" ) "); expr(e); @@ -340,6 +343,7 @@ class Printer { case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")"; case EUnknownVariable(v): "Unknown variable: "+v; case EInvalidIterator(v): "Invalid iterator: "+v; + case EInvalidKeyValueIterator(v): "Invalid key-value iterator: "+v; case EInvalidOp(op): "Invalid operator: "+op; case EInvalidAccess(f): "Invalid access to field " + f; case ECustom(msg): msg; diff --git a/hscript/Tools.hx b/hscript/Tools.hx index 64562f2..1c1d737 100644 --- a/hscript/Tools.hx +++ b/hscript/Tools.hx @@ -38,7 +38,7 @@ class Tools { case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2); 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 EFor(_, _, it, e): f(it); f(e); case EBreak,EContinue: case EFunction(_, e, _, _): f(e); case EReturn(e): if( e != null ) f(e); @@ -75,7 +75,7 @@ class Tools { case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null); 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 EFor(k, v, it, e): EFor(k, v, f(it), f(e)); 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));