Skip to content

Commit 79b3906

Browse files
Merge branch 'HaxeFoundation:master' into funkin-dev
2 parents 27c86f9 + ce81886 commit 79b3906

File tree

9 files changed

+264
-43
lines changed

9 files changed

+264
-43
lines changed

TestHScript.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class TestHScript extends TestCase {
7373
assertScript("3 * 2 // + 5 \n + 6",12);
7474
assertScript("3 /* 2\n */ + 5",8);
7575
assertScript("[55,66,77][1]",66);
76+
assertScript("[11,22,33,][2]", 33);
7677
assertScript("var a = [55]; a[0] *= 2; a[0]",110);
7778
assertScript("x",55,{ x : 55 });
7879
assertScript("var y = 33; y",33);

hscript/Bytes.hx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class Bytes {
122122
doEncodeInt(e.line);
123123
var e = e.e;
124124
#end
125-
bout.addByte(Type.enumIndex(e));
125+
bout.addByte(exprIndex(e));
126126
switch( e ) {
127127
case EConst(c):
128128
doEncodeConst(c);
@@ -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);
@@ -235,6 +238,39 @@ class Bytes {
235238
}
236239
}
237240

241+
function exprIndex(e):Int {
242+
return switch (e) {
243+
case EConst(_): 0;
244+
case EIdent(_): 1;
245+
case EVar(_): 2;
246+
case EParent(_): 3;
247+
case EBlock(_): 4;
248+
case EField(_): 5;
249+
case EBinop(_): 6;
250+
case EUnop(_): 7;
251+
case ECall(_): 8;
252+
case EIf(_): 9;
253+
case EWhile(_): 10;
254+
case EFor(_): 11;
255+
case EBreak: 12;
256+
case EContinue: 13;
257+
case EFunction(_): 14;
258+
case EReturn(_): 15;
259+
case EArray(_): 16;
260+
case EArrayDecl(_): 17;
261+
case ENew(_): 18;
262+
case EThrow(_): 19;
263+
case ETry(_): 20;
264+
case EObject(_): 21;
265+
case ETernary(_): 22;
266+
case ESwitch(_): 23;
267+
case EDoWhile(_): 24;
268+
case EMeta(_): 25;
269+
case ECheckType(_): 26;
270+
case EForGen(_): 27;
271+
}
272+
}
273+
238274
function doDecode() : Expr {
239275
#if hscriptPos
240276
if (bin.get(pin) == 255) {
@@ -362,6 +398,8 @@ class Bytes {
362398
EMeta(name, args, doDecode());
363399
case 26:
364400
ECheckType(doDecode(), CTPath(["Void"]));
401+
case 27:
402+
EForGen(doDecode(), doDecode());
365403
case 255:
366404
null;
367405
default:

hscript/Checker.hx

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ typedef CTypedef = {> CNamedType,
7777

7878
typedef CAbstract = {> CNamedType,
7979
var t : TType;
80+
var from : Array<TType>;
81+
var to : Array<TType>;
8082
}
8183

8284
class Completion {
@@ -233,13 +235,21 @@ class CheckerTypes {
233235
name : a.path,
234236
params : [],
235237
t : null,
238+
from : [],
239+
to : [],
236240
};
237241
addMeta(a,ta);
238242
for( p in a.params )
239243
ta.params.push(TParam(p));
240244
todo.push(function() {
241245
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
242246
ta.t = makeXmlType(a.athis);
247+
for( f in a.from )
248+
if( f.field == null )
249+
ta.from.push(makeXmlType(f.t));
250+
for( t in a.to )
251+
if( t.field == null )
252+
ta.to.push(makeXmlType(t.t));
243253
localParams = null;
244254
});
245255
types.set(a.path, CTAbstract(ta));
@@ -338,15 +348,22 @@ class Checker {
338348
this.types = types;
339349
}
340350

341-
public function setGlobals( cl : CClass, allowPrivate = false ) {
351+
public function setGlobals( cl : CClass, ?params : Array<TType>, allowPrivate = false ) {
352+
if( params == null )
353+
params = [for( p in cl.params ) makeMono()];
342354
while( true ) {
343355
for( f in cl.fields )
344356
if( f.isPublic || allowPrivate )
345-
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() return apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
357+
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() {
358+
var t = apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()]);
359+
return apply(t, cl.params, params);
360+
}));
346361
if( cl.superClass == null )
347362
break;
348363
cl = switch( cl.superClass ) {
349-
case TInst(c,_): c;
364+
case TInst(csup,pl):
365+
params = [for( p in pl ) apply(p,cl.params,params)];
366+
csup;
350367
default: throw "assert";
351368
}
352369
}
@@ -465,6 +482,9 @@ class Checker {
465482
return makeType(t,e);
466483
case CTOpt(t):
467484
return makeType(t,e);
485+
case CTExpr(_):
486+
error("Unsupported expr type parameter", e);
487+
return null;
468488
}
469489
}
470490

@@ -722,6 +742,18 @@ class Checker {
722742
return true;
723743
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
724744
return true;
745+
case [_, TAbstract(a, args)]:
746+
for( ft in a.from ) {
747+
var t = apply(ft,a.params,args);
748+
if( tryUnify(t1,t) )
749+
return true;
750+
}
751+
case [TAbstract(a, args), _]:
752+
for( tt in a.to ) {
753+
var t = apply(tt,a.params,args);
754+
if( tryUnify(t,t2) )
755+
return true;
756+
}
725757
default:
726758
}
727759
return typeEq(t1,t2);
@@ -1185,11 +1217,26 @@ class Checker {
11851217
case EFor(v, it, e):
11861218
var locals = saveLocals();
11871219
var itt = typeExpr(it, Value);
1188-
var vt = getIteratorType(it, itt);
1220+
var vt = getIteratorType(itt, it);
11891221
this.locals.set(v, vt);
11901222
typeExpr(e, NoValue);
11911223
this.locals = locals;
11921224
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;
11931240
case EBinop(op, e1, e2):
11941241
switch( op ) {
11951242
case "&", "|", "^", ">>", ">>>", "<<":
@@ -1320,7 +1367,7 @@ class Checker {
13201367
return TDynamic;
13211368
}
13221369

1323-
function getIteratorType( it : Expr, itt : TType ) {
1370+
function getIteratorType( itt : TType, it : Expr ) {
13241371
switch( follow(itt) ) {
13251372
case TInst({name:"Array"},[t]):
13261373
return t;
@@ -1333,7 +1380,7 @@ class Checker {
13331380
// special case : we allow unconditional access
13341381
// to an abstract iterator() underlying value (eg: ArrayProxy)
13351382
var at = apply(a.t,a.params,args);
1336-
return getIteratorType(it, at);
1383+
return getIteratorType(at, it);
13371384
default:
13381385
}
13391386
if( ft != null )
@@ -1347,4 +1394,34 @@ class Checker {
13471394
return t;
13481395
}
13491396

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+
13501427
}

hscript/Expr.hx

Lines changed: 2 additions & 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 };
@@ -80,6 +81,7 @@ enum CType {
8081
CTParent( t : CType );
8182
CTOpt( t : CType );
8283
CTNamed( n : String, t : CType );
84+
CTExpr( e : Expr ); // for type parameters only
8385
}
8486

8587
#if hscriptPos

hscript/Interp.hx

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

557569
function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
558-
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0'))
559-
if ( v.iterator != null ) v = v.iterator();
560-
#elseif js
570+
#if js
561571
// don't use try/catch (very slow)
562572
if( v is Array )
563573
return (v : Array<Dynamic>).iterator();
@@ -570,6 +580,19 @@ class Interp {
570580
return v;
571581
}
572582

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

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

hscript/Macro.hx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class Macro {
9090
}
9191
}
9292

93-
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
93+
function map<T,R>( a : Array<T>, f : T -> R ) : Array<R> {
9494
var b = new Array();
9595
for( x in a )
9696
b.push(f(x));
@@ -102,9 +102,13 @@ class Macro {
102102
case CTOpt(t): TOptional(convertType(t));
103103
case CTPath(pack, args):
104104
var params = [];
105-
if( args != null )
105+
if( args != null ) {
106106
for( t in args )
107-
params.push(TPType(convertType(t)));
107+
params.push(switch( t ) {
108+
case CTExpr(e): TPExpr(convert(e));
109+
default: TPType(convertType(t));
110+
});
111+
}
108112
TPath({
109113
pack : pack,
110114
name : pack.pop(),
@@ -127,6 +131,8 @@ class Macro {
127131
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
128132
}
129133
TAnonymous(tf);
134+
case CTExpr(_):
135+
throw "assert";
130136
};
131137
}
132138

@@ -165,13 +171,10 @@ class Macro {
165171
case EDoWhile(c, e):
166172
EWhile(convert(c), convert(e), false);
167173
case EFor(v, it, efor):
168-
#if (haxe_ver >= 4)
169-
var p = #if (!macro && hscriptPos) { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
170-
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
171-
#else
172-
var p = #if (!macro && hscriptPos) { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
173-
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
174-
#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));
175178
case EBreak:
176179
EBreak;
177180
case EContinue:

0 commit comments

Comments
 (0)