optimize the ast (eliminate (function(_) e)(null) calls)
treat function literals as synchronized by default
This commit is contained in:
+28
-18
@@ -79,8 +79,10 @@ class Async {
|
||||
|
||||
function buildSync( e : Expr, exit : Expr ) : Expr {
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_):
|
||||
return toCps(e, null, null);
|
||||
case EFunction(_,_,name,_):
|
||||
if( name != null )
|
||||
return toCps(e, null, null);
|
||||
return e;
|
||||
case EBlock(el):
|
||||
var v = saveVars();
|
||||
for( e in el )
|
||||
@@ -96,7 +98,7 @@ class Async {
|
||||
case EBreak if( currentBreak != null ):
|
||||
return currentBreak(e);
|
||||
case EContinue if( currentLoop != null ):
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)],e);
|
||||
return block([retNull(currentLoop, e), mk(EReturn(),e)],e);
|
||||
case EFor(_), EWhile(_):
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
currentLoop = null;
|
||||
@@ -106,7 +108,7 @@ class Async {
|
||||
currentBreak = oldBreak;
|
||||
return e;
|
||||
case EReturn(eret) if( exit != null ):
|
||||
return block([call(exit,[eret == null ? nullId : eret], e), mk(EReturn(),e)], e);
|
||||
return block([eret == null ? retNull(exit, e) : call(exit,[eret], e), mk(EReturn(),e)], e);
|
||||
default:
|
||||
return Tools.map(e, buildSync.bind(_, exit));
|
||||
}
|
||||
@@ -133,7 +135,9 @@ class Async {
|
||||
return mk(EFunction([for( a in arg ) { name : a, t : null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function block(arr, e) {
|
||||
inline function block(arr:Array<Expr>, e) {
|
||||
if( arr.length == 1 && expr(arr[0]).match(EBlock(_)) )
|
||||
return arr[0];
|
||||
return mk(EBlock(arr), e);
|
||||
}
|
||||
|
||||
@@ -149,8 +153,12 @@ class Async {
|
||||
return mk(ECall(e, args), inf);
|
||||
}
|
||||
|
||||
function retNull(e) : Expr {
|
||||
return call(e, [nullId],e);
|
||||
function retNull(e:Expr,?pos) : Expr {
|
||||
switch( expr(e) ) {
|
||||
case EFunction([{name:"_"}], e, _, _): return e;
|
||||
default:
|
||||
}
|
||||
return call(e, [nullId], pos == null ? e : pos);
|
||||
}
|
||||
|
||||
function makeCall( ecall, args : Array<Expr>, rest : Expr, exit, sync = false ) {
|
||||
@@ -179,7 +187,9 @@ class Async {
|
||||
if( !syncFlag )
|
||||
return;
|
||||
switch( expr(e) ) {
|
||||
case ECall(_), EFunction(_):
|
||||
case ECall(_):
|
||||
syncFlag = false;
|
||||
case EFunction(_,_,name,_) if( name != null ):
|
||||
syncFlag = false;
|
||||
case EMeta("sync" | "async", _, _):
|
||||
// isolated from the sync part
|
||||
@@ -206,7 +216,7 @@ class Async {
|
||||
// local recursion
|
||||
for( e in el )
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_, _, name, null): varNames.push(name);
|
||||
case EFunction(_, _, name, null): if( name != null ) varNames.push(name);
|
||||
default:
|
||||
}
|
||||
while( el.length > 0 ) {
|
||||
@@ -250,7 +260,7 @@ class Async {
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
var loop = ident("_loop" + id,e);
|
||||
currentLoop = loop;
|
||||
currentBreak = function(inf) return block([call(rest, [nullId], inf), mk(EReturn(),inf)], inf);
|
||||
currentBreak = function(inf) return block([retNull(rest, inf), mk(EReturn(),inf)], inf);
|
||||
var efor = block([
|
||||
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
||||
fun("_", block([
|
||||
@@ -258,7 +268,7 @@ class Async {
|
||||
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
||||
toCps(eloop, loop, exit),
|
||||
], it),"_loop" + id),
|
||||
call(loop, [nullId], e),
|
||||
retNull(loop, e),
|
||||
], e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
@@ -306,18 +316,18 @@ class Async {
|
||||
var loop = ident("_loop" + id, cond);
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
currentLoop = loop;
|
||||
currentBreak = function(e) return block([call(rest, [nullId], e), mk(EReturn(),e)],e);
|
||||
currentBreak = function(e) return block([retNull(rest,e), mk(EReturn(),e)],e);
|
||||
var ewhile = block([
|
||||
fun("_r",
|
||||
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), call(rest, [nullId], cond)),cond)), exit)
|
||||
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), retNull(rest,cond)),cond)), exit)
|
||||
, "_loop"+id),
|
||||
call(loop, [nullId], cond),
|
||||
retNull(loop, cond),
|
||||
],e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
return ewhile;
|
||||
case EReturn(eret):
|
||||
return eret == null ? call(exit, [nullId], e) : toCps(eret, exit, exit);
|
||||
return eret == null ? retNull(exit, e) : toCps(eret, exit, exit);
|
||||
case EObject(fields):
|
||||
var id = "_o" + uid++;
|
||||
var rest = call(rest, [ident(id,e)], e);
|
||||
@@ -353,10 +363,10 @@ class Async {
|
||||
return toCps(earr, fun(id1, toCps(eindex, fun(id2, call(rest, [mk(EArray(ident(id1,e), ident(id2,e)),e)], e)), exit)), exit);
|
||||
case EVar(v, t, ev):
|
||||
if( ev == null )
|
||||
return block([e, call(rest, [nullId],e)], e);
|
||||
return block([e, retNull(rest, e)], e);
|
||||
return block([
|
||||
mk(EVar(v, t),e),
|
||||
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), call(rest,[nullId],e)], e)), exit),
|
||||
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
|
||||
],e);
|
||||
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
||||
return call(rest, [e], e);
|
||||
@@ -375,7 +385,7 @@ class Async {
|
||||
return currentBreak(e);
|
||||
case EContinue:
|
||||
if( currentLoop == null ) throw "Continue outside loop";
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)], e);
|
||||
return block([retNull(currentLoop, e), mk(EReturn(),e)], e);
|
||||
case ESwitch(v, cases, def):
|
||||
var cases = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
|
||||
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||
|
||||
Reference in New Issue
Block a user