Skip to content

Commit 781da51

Browse files
committed
added EForGen parsing and key=>value iterator support
1 parent f718d5f commit 781da51

File tree

8 files changed

+145
-21
lines changed

8 files changed

+145
-21
lines changed

hscript/Bytes.hx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ class Bytes {
173173
doEncodeString(v);
174174
doEncode(it);
175175
doEncode(e);
176+
case EForGen(it,e):
177+
doEncode(it);
178+
doEncode(e);
176179
case EBreak, EContinue:
177180
case EFunction(params,e,name,_):
178181
bout.addByte(params.length);
@@ -362,6 +365,8 @@ class Bytes {
362365
EMeta(name, args, doDecode());
363366
case 26:
364367
ECheckType(doDecode(), CTPath(["Void"]));
368+
case 27:
369+
EForGen(doDecode(), doDecode());
365370
case 255:
366371
null;
367372
default:

hscript/Checker.hx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,11 +1217,26 @@ class Checker {
12171217
case EFor(v, it, e):
12181218
var locals = saveLocals();
12191219
var itt = typeExpr(it, Value);
1220-
var vt = getIteratorType(it, itt);
1220+
var vt = getIteratorType(itt, it);
12211221
this.locals.set(v, vt);
12221222
typeExpr(e, NoValue);
12231223
this.locals = locals;
12241224
return TVoid;
1225+
case EForGen(it, e):
1226+
Tools.getKeyIterator(it,function(vk,vv,it) {
1227+
if( vk == null ) {
1228+
error("Invalid for expression", it);
1229+
return;
1230+
}
1231+
var locals = saveLocals();
1232+
var itt = typeExpr(it, Value);
1233+
var types = getKeyIteratorTypes(itt, it);
1234+
this.locals.set(vk, types.key);
1235+
this.locals.set(vv, types.value);
1236+
typeExpr(e, NoValue);
1237+
this.locals = locals;
1238+
});
1239+
return TVoid;
12251240
case EBinop(op, e1, e2):
12261241
switch( op ) {
12271242
case "&", "|", "^", ">>", ">>>", "<<":
@@ -1352,7 +1367,7 @@ class Checker {
13521367
return TDynamic;
13531368
}
13541369

1355-
function getIteratorType( it : Expr, itt : TType ) {
1370+
function getIteratorType( itt : TType, it : Expr ) {
13561371
switch( follow(itt) ) {
13571372
case TInst({name:"Array"},[t]):
13581373
return t;
@@ -1365,7 +1380,7 @@ class Checker {
13651380
// special case : we allow unconditional access
13661381
// to an abstract iterator() underlying value (eg: ArrayProxy)
13671382
var at = apply(a.t,a.params,args);
1368-
return getIteratorType(it, at);
1383+
return getIteratorType(at, it);
13691384
default:
13701385
}
13711386
if( ft != null )
@@ -1379,4 +1394,34 @@ class Checker {
13791394
return t;
13801395
}
13811396

1397+
1398+
function getKeyIteratorTypes( itt : TType, it : Expr ) {
1399+
switch( follow(itt) ) {
1400+
case TInst({name:"Array"},[t]):
1401+
return { key : TInt, value : t };
1402+
default:
1403+
}
1404+
var ft = getField(itt,"keyValueIterator", it);
1405+
if( ft == null )
1406+
switch( itt ) {
1407+
case TAbstract(a, args):
1408+
// special case : we allow unconditional access
1409+
// to an abstract keyValueIterator() underlying value (eg: ArrayProxy)
1410+
var at = apply(a.t,a.params,args);
1411+
return getKeyIteratorTypes(at, it);
1412+
default:
1413+
}
1414+
if( ft != null )
1415+
switch( ft ) {
1416+
case TFun([],ret): ft = ret;
1417+
default: ft = null;
1418+
}
1419+
var key = makeMono();
1420+
var value = makeMono();
1421+
var iter = makeIterator(TAnon([{name:"key",t:key,opt:false},{name:"value",t:value,opt:false}]));
1422+
unify(ft != null ? ft : itt,iter,it);
1423+
return { key : key, value : value };
1424+
}
1425+
1426+
13821427
}

hscript/Expr.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ enum Expr {
6767
EDoWhile( cond : Expr, e : Expr);
6868
EMeta( name : String, args : Array<Expr>, e : Expr );
6969
ECheckType( e : Expr, t : CType );
70+
EForGen( it : Expr, e : Expr );
7071
}
7172

7273
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };

hscript/Interp.hx

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,18 @@ class Interp {
364364
case EFor(v,it,e):
365365
forLoop(v,it,e);
366366
return null;
367+
case EForGen(it,e):
368+
Tools.getKeyIterator(it, function(vk,vv,it) {
369+
if( vk == null ) {
370+
#if hscriptPos
371+
curExpr = it;
372+
#end
373+
error(ECustom("Invalid for expression"));
374+
return;
375+
}
376+
forKeyValueLoop(vk,vv,it,e);
377+
});
378+
return null;
367379
case EBreak:
368380
throw SBreak;
369381
case EContinue:
@@ -554,9 +566,7 @@ class Interp {
554566
}
555567

556568
function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
557-
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0'))
558-
if ( v.iterator != null ) v = v.iterator();
559-
#elseif js
569+
#if js
560570
// don't use try/catch (very slow)
561571
if( v is Array )
562572
return (v : Array<Dynamic>).iterator();
@@ -568,6 +578,19 @@ class Interp {
568578
return v;
569579
}
570580

581+
function makeKeyValueIterator( v : Dynamic ) : KeyValueIterator<Dynamic,Dynamic> {
582+
#if js
583+
// don't use try/catch (very slow)
584+
if( v is Array )
585+
return (v : Array<Dynamic>).keyValueIterator();
586+
if( v.keyValueIterator != null ) v = v.keyValueIterator();
587+
#else
588+
try v = v.keyValueIterator() catch( e : Dynamic ) {};
589+
#end
590+
if( v.hasNext == null || v.next == null ) error(EInvalidIterator(v));
591+
return v;
592+
}
593+
571594
function forLoop(n,it,e) {
572595
var old = declared.length;
573596
declared.push({ n : n, old : locals.get(n) });
@@ -580,6 +603,21 @@ class Interp {
580603
restore(old);
581604
}
582605

606+
function forKeyValueLoop(vk,vv,it,e) {
607+
var old = declared.length;
608+
declared.push({ n : vk, old : locals.get(vk) });
609+
declared.push({ n : vv, old : locals.get(vv) });
610+
var it = makeKeyValueIterator(expr(it));
611+
while( it.hasNext() ) {
612+
var v = it.next();
613+
locals.set(vk,{ r : v.key });
614+
locals.set(vv,{ r : v.value });
615+
if( !loopRun(() -> expr(e)) )
616+
break;
617+
}
618+
restore(old);
619+
}
620+
583621
inline function loopRun( f : Void -> Void ) {
584622
var cont = true;
585623
try {

hscript/Macro.hx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,10 @@ class Macro {
171171
case EDoWhile(c, e):
172172
EWhile(convert(c), convert(e), false);
173173
case EFor(v, it, efor):
174-
#if (haxe_ver >= 4)
175-
var p = #if (!macro && hscriptPos) { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
176-
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
177-
#else
178-
var p = #if (!macro && hscriptPos) { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
179-
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
180-
#end
174+
var p = #if (!macro && hscriptPos) { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
175+
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
176+
case EForGen(it, efor):
177+
EFor(convert(it), convert(efor));
181178
case EBreak:
182179
EBreak;
183180
case EContinue:

hscript/Parser.hx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ class Parser {
118118
["&&"],
119119
["||"],
120120
["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>"],
121-
["->"]
121+
["->"],
122+
["in","is"]
122123
];
123124
opPriority = new Map();
124125
opRightAssoc = new Map();
@@ -532,6 +533,8 @@ class Parser {
532533
var edef = switch( expr(e) ) {
533534
case EFor(v, it, e2):
534535
EFor(v, it, mapCompr(tmp, e2));
536+
case EForGen(it, e2):
537+
EForGen(it, mapCompr(tmp, e2));
535538
case EWhile(cond, e2):
536539
EWhile(cond, mapCompr(tmp, e2));
537540
case EDoWhile(cond, e2):
@@ -563,7 +566,8 @@ class Parser {
563566
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
564567
return switch( expr(e) ) {
565568
case EBinop(op2,e2,e3):
566-
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
569+
var delta = opPriority.get(op) - opPriority.get(op2);
570+
if( delta < 0 || (delta == 0 && !opRightAssoc.exists(op)) )
567571
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
568572
else
569573
mk(EBinop(op, e1, e), pmin(e1), pmax(e));
@@ -638,12 +642,19 @@ class Parser {
638642
mk(EDoWhile(econd,e),p1,pmax(econd));
639643
case "for":
640644
ensure(TPOpen);
641-
var vname = getIdent();
642-
ensureToken(TId("in"));
643-
var eiter = parseExpr();
645+
var eit = parseExpr();
644646
ensure(TPClose);
645647
var e = parseExpr();
646-
mk(EFor(vname,eiter,e),p1,pmax(e));
648+
switch( expr(eit) ) {
649+
case EBinop("in",ev,eit):
650+
switch( expr(ev) ) {
651+
case EIdent(v):
652+
return mk(EFor(v,eit,e),p1,pmax(e));
653+
default:
654+
}
655+
default:
656+
}
657+
mk(EForGen(eit,e),p1,pmax(e));
647658
case "break": mk(EBreak);
648659
case "continue": mk(EContinue);
649660
case "else": unexpected(TId(id));
@@ -803,8 +814,8 @@ class Parser {
803814
return parseExprNext(mk(EUnop(op,false,e1),pmin(e1)));
804815
}
805816
return makeBinop(op,e1,parseExpr());
806-
case TId(op) if ( op == 'is' ):
807-
return makeBinop(op,e1,parseExpr());
817+
case TId(op) if( opPriority.exists(op) ):
818+
return parseExprNext(makeBinop(op,e1,parseExpr()));
808819
case TDot:
809820
var field = getIdent();
810821
return parseExprNext(mk(EField(e1,field),pmin(e1)));

hscript/Printer.hx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ class Printer {
208208
expr(it);
209209
add(" ) ");
210210
expr(e);
211+
case EForGen(it, e):
212+
add("for( ");
213+
expr(it);
214+
add(" ) ");
215+
expr(e);
211216
case EBreak:
212217
add("break");
213218
case EContinue:

hscript/Tools.hx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class Tools {
3838
case EWhile(c, e): f(c); f(e);
3939
case EDoWhile(c, e): f(c); f(e);
4040
case EFor(_, it, e): f(it); f(e);
41+
case EForGen(it, e): f(it); f(e);
4142
case EBreak,EContinue:
4243
case EFunction(_, e, _, _): f(e);
4344
case EReturn(e): if( e != null ) f(e);
@@ -74,6 +75,7 @@ class Tools {
7475
case EWhile(c, e): EWhile(f(c),f(e));
7576
case EDoWhile(c, e): EDoWhile(f(c),f(e));
7677
case EFor(v, it, e): EFor(v, f(it), f(e));
78+
case EForGen(it, e): EForGen(f(it), f(e));
7779
case EFunction(args, e, name, t): EFunction(args, f(e), name, t);
7880
case EReturn(e): EReturn(if( e != null ) f(e) else null);
7981
case EArray(e, i): EArray(f(e),f(i));
@@ -106,4 +108,24 @@ class Tools {
106108
#end
107109
}
108110

111+
public static inline function getKeyIterator<T>( e : Expr, callb : String -> String -> Expr -> T ) {
112+
var key = null, value = null, it = e;
113+
switch( expr(it) ) {
114+
case EBinop("in", ekv, eiter):
115+
switch( expr(ekv) ) {
116+
case EBinop("=>",v1,v2):
117+
switch( [expr(v1),expr(v2)] ) {
118+
case [EIdent(v1), EIdent(v2)]:
119+
key = v1;
120+
value = v2;
121+
it = eiter;
122+
default:
123+
}
124+
default:
125+
}
126+
default:
127+
}
128+
return callb(key,value,it);
129+
}
130+
109131
}

0 commit comments

Comments
 (0)