EMapDecl + Map Comprehension
This commit is contained in:
+10
-1
@@ -30,6 +30,14 @@ enum Const {
|
||||
#end
|
||||
}
|
||||
|
||||
enum MapType {
|
||||
IntMap;
|
||||
StringMap;
|
||||
EnumMap;
|
||||
ObjectMap;
|
||||
UnknownMap;
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
class Expr {
|
||||
public var e : ExprDef;
|
||||
@@ -69,7 +77,8 @@ enum Expr
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
EMapDecl( type: MapType, keys: Array<Expr>, values: Array<Expr> );
|
||||
EArrayDecl( e : Array<Expr> );
|
||||
ENew( cl : String, params : Array<Expr> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
|
||||
+45
-66
@@ -789,77 +789,54 @@ class Interp {
|
||||
}
|
||||
}
|
||||
return f;
|
||||
case EArrayDecl(arr, wantedType):
|
||||
var isTypeMap = wantedType != null;
|
||||
var isMap = if(isTypeMap) {
|
||||
wantedType.match(CTPath(["Map"], [_, _]));
|
||||
} else {
|
||||
arr.length > 0 && Tools.expr(arr[0]).match(EBinop("=>", _));
|
||||
}
|
||||
if (isMap) {
|
||||
var isAllString:Bool = true;
|
||||
var isAllInt:Bool = true;
|
||||
var isAllObject:Bool = true;
|
||||
var isAllEnum:Bool = true;
|
||||
var keys:Array<Dynamic> = [];
|
||||
var values:Array<Dynamic> = [];
|
||||
for (e in arr) {
|
||||
switch (Tools.expr(e)) {
|
||||
case EBinop("=>", eKey, eValue): {
|
||||
var key:Dynamic = expr(eKey);
|
||||
var value:Dynamic = expr(eValue);
|
||||
if(isAllString)
|
||||
isAllString = (key is String);
|
||||
if(isAllInt)
|
||||
isAllInt = (key is Int);
|
||||
if(isAllObject)
|
||||
isAllObject = Reflect.isObject(key);
|
||||
if(isAllEnum)
|
||||
isAllEnum = Reflect.isEnumValue(key);
|
||||
keys.push(key);
|
||||
values.push(value);
|
||||
}
|
||||
default: throw("=> expected");
|
||||
}
|
||||
case EMapDecl(type, _keys, _values):
|
||||
var keys:Array<Dynamic> = [];
|
||||
var values:Array<Dynamic> = [];
|
||||
if(type == UnknownMap) {
|
||||
var isKeyString:Bool = false;
|
||||
var isKeyInt:Bool = false;
|
||||
var isKeyObject:Bool = false;
|
||||
var isKeyEnum:Bool = false;
|
||||
for (i in 0..._keys.length) {
|
||||
var key:Dynamic = expr(_keys[i]);
|
||||
var value:Dynamic = expr(_values[i]);
|
||||
|
||||
if(!isKeyString) isKeyString = (key is String);
|
||||
if(!isKeyInt) isKeyInt = (key is Int);
|
||||
if(!isKeyObject) isKeyObject = Reflect.isObject(key);
|
||||
if(!isKeyEnum) isKeyEnum = Reflect.isEnumValue(key);
|
||||
|
||||
keys.push(key);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
if(isTypeMap) {
|
||||
isAllString = wantedType.match(CTPath(["Map"], [CTPath(["String"], _), _]));
|
||||
isAllInt = wantedType.match(CTPath(["Map"], [CTPath(["Int"], _), _]));
|
||||
if(isAllString || isAllInt) {
|
||||
isAllObject = false;
|
||||
isAllEnum = false;
|
||||
} else {
|
||||
if(!isAllObject && !isAllEnum) {
|
||||
throw("Unknown Type Key");
|
||||
}
|
||||
}
|
||||
}
|
||||
var t = b2i(isKeyString) + b2i(isKeyInt) + b2i(isKeyObject) + b2i(isKeyEnum);
|
||||
|
||||
var map:IMap<Dynamic, Dynamic> = {
|
||||
if (isAllInt)
|
||||
new haxe.ds.IntMap<Dynamic>();
|
||||
else if (isAllString)
|
||||
new haxe.ds.StringMap<Dynamic>();
|
||||
else if (isAllEnum)
|
||||
new haxe.ds.EnumValueMap<Dynamic, Dynamic>();
|
||||
else if (isAllObject)
|
||||
new haxe.ds.ObjectMap<Dynamic, Dynamic>();
|
||||
else
|
||||
throw 'Inconsistent key types';
|
||||
}
|
||||
for (n in 0...keys.length) {
|
||||
map.set(keys[n], values[n]);
|
||||
}
|
||||
return map;
|
||||
if(t != 1)
|
||||
error(ECustom("Unknown Map Type"));
|
||||
else if(isKeyInt) type = IntMap;
|
||||
else if(isKeyString) type = StringMap;
|
||||
else if(isKeyEnum) type = EnumMap;
|
||||
else if(isKeyObject) type = ObjectMap;
|
||||
} else {
|
||||
//var a = new Array();
|
||||
//for (e in arr) {
|
||||
// a.push(expr(e));
|
||||
//}
|
||||
//return a;
|
||||
return [for (j in 0...arr.length) expr(arr[j])];
|
||||
for(i in 0..._keys.length) {
|
||||
keys.push(expr(_keys[i]));
|
||||
values.push(expr(_values[i]));
|
||||
}
|
||||
}
|
||||
var map:IMap<Dynamic, Dynamic> = switch(type) {
|
||||
case IntMap: new haxe.ds.IntMap<Dynamic>();
|
||||
case StringMap: new haxe.ds.StringMap<Dynamic>();
|
||||
case EnumMap: new haxe.ds.EnumValueMap<Dynamic, Dynamic>();
|
||||
case ObjectMap: new haxe.ds.ObjectMap<Dynamic, Dynamic>();
|
||||
default: null;
|
||||
}
|
||||
for (n in 0...keys.length) {
|
||||
map.set(keys[n], values[n]);
|
||||
}
|
||||
return map;
|
||||
case EArrayDecl(arr):
|
||||
return [for (j in 0...arr.length) expr(arr[j])];
|
||||
case EArray(e, index):
|
||||
var arr:Dynamic = expr(e);
|
||||
var index:Dynamic = expr(index);
|
||||
@@ -1163,4 +1140,6 @@ class Interp {
|
||||
c = Type.resolveClass(cl);
|
||||
return (c is IHScriptCustomConstructor) ? cast(c, IHScriptCustomConstructor).hnew(args) : Type.createInstance(c, args);
|
||||
}
|
||||
|
||||
static inline function b2i(b:Bool) return b ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -239,6 +239,12 @@ class Macro {
|
||||
EReturn(e == null ? null : convert(e));
|
||||
case EArray(e, index):
|
||||
EArray(convert(e), convert(index));
|
||||
case EMapDecl(type, keys, values): // port to array decl, haxe still uses EArrayDecl but with => as a binop
|
||||
var el = [];
|
||||
for( i in 0...keys.length ) {
|
||||
el.push( hscript.Expr.EBinop("=>", keys[i], values[i]) );
|
||||
}
|
||||
EArrayDecl(map(el,convert));
|
||||
case EArrayDecl(el):
|
||||
EArrayDecl(map(el,convert));
|
||||
case ENew(cl, params):
|
||||
|
||||
+29
-10
@@ -20,6 +20,7 @@ class Optimizer {
|
||||
// TODO: Remove Std.string if its the right side of a binop of a string
|
||||
// TODO: Add EForComprehension, EWhileComprehension, EDoWhileComprehension for better optimization
|
||||
// TODO: Optimize EFor(v, it, EBlock([e1])) to EFor(v, it, e1)
|
||||
// TODO: Optimize EIf(cond, e1, e2) to EBlock([cond, e1]) if e1 == e2, if cond is constant or side effect free then convert to EParent(e1)
|
||||
|
||||
switch(e) {
|
||||
// Parse all expressions and recreate the AST
|
||||
@@ -247,22 +248,40 @@ class Optimizer {
|
||||
|
||||
return mk(ESwitch(e, cases, def), s);
|
||||
|
||||
case EArrayDecl(arr, wantedType):
|
||||
case EMapDecl(type, keys, values):
|
||||
keys = keys.map((v) -> optimize(v));
|
||||
values = values.map((v) -> optimize(v));
|
||||
return mk(EMapDecl(type, keys, values), s);
|
||||
|
||||
case EArrayDecl(arr):
|
||||
arr = arr.map((v) -> optimize(v));
|
||||
return mk(EArrayDecl(arr, wantedType), s);
|
||||
return mk(EArrayDecl(arr), s);
|
||||
|
||||
case EArray(e, index):
|
||||
e = optimize(e);
|
||||
index = optimize(index);
|
||||
if(isConstant(index) && Tools.expr(e).match(EArrayDecl(_, _))) {
|
||||
var arr = switch(Tools.expr(e)) {
|
||||
case EArrayDecl(arr, _): arr;
|
||||
default: null;
|
||||
};
|
||||
if(isConstant(index)) {
|
||||
if(Tools.expr(e).match(EArrayDecl(_))) {
|
||||
var arr = switch(Tools.expr(e)) {
|
||||
case EArrayDecl(arr): arr;
|
||||
default: null;
|
||||
};
|
||||
|
||||
var constant = Lambda.exists(arr, isConstant);
|
||||
if(constant) {
|
||||
return mk(Tools.expr(arr[getConstant(index)]), s);
|
||||
var constant = Lambda.exists(arr, isConstant);
|
||||
if(constant) {
|
||||
return mk(Tools.expr(arr[getConstant(index)]), s);
|
||||
}
|
||||
}
|
||||
if(Tools.expr(e).match(EMapDecl(_))) {
|
||||
var map = switch(Tools.expr(e)) {
|
||||
case EMapDecl(type, keys, vals): [keys, vals];
|
||||
default: null;
|
||||
};
|
||||
|
||||
var constant = Lambda.exists(map, (v) -> isConstant(v[0]) && isConstant(v[1]));
|
||||
if(constant) {
|
||||
return mk(Tools.expr(map[getConstant(index)][1]), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mk(EArray(e, index), s);
|
||||
|
||||
+160
-24
@@ -115,8 +115,6 @@ class Parser {
|
||||
var startIdents : Array<Bool>;
|
||||
var uid : Int = 0;
|
||||
|
||||
var disableOrOp : Bool = false;
|
||||
|
||||
#if hscriptPos
|
||||
var origin : String;
|
||||
var tokenMin : Int;
|
||||
@@ -481,10 +479,7 @@ class Parser {
|
||||
return mk(EFunction([], mk(EReturn(eret),p1)), p1);
|
||||
}
|
||||
push(tk);
|
||||
//var oldoo = disableOrOp;
|
||||
//disableOrOp = false;
|
||||
var e = parseExpr();
|
||||
//disableOrOp = oldoo;
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TPClose:
|
||||
@@ -556,10 +551,7 @@ class Parser {
|
||||
case TOp(op):
|
||||
if( op == "-" ) {
|
||||
var start = tokenMin;
|
||||
//var oldoo = disableOrOp;
|
||||
//disableOrOp = false;
|
||||
var e = parseExpr();
|
||||
//disableOrOp = oldoo;
|
||||
if( e == null )
|
||||
return makeUnop(op,e);
|
||||
switch( Tools.expr(e) ) {
|
||||
@@ -579,27 +571,104 @@ class Parser {
|
||||
tk = token();
|
||||
while( tk != TBkClose && (!resumeErrors || tk != TEof) ) {
|
||||
push(tk);
|
||||
//var oldoo = disableOrOp;
|
||||
//disableOrOp = false;
|
||||
a.push(parseExpr());
|
||||
//disableOrOp = oldoo;
|
||||
tk = token();
|
||||
if( tk == TComma )
|
||||
tk = token();
|
||||
}
|
||||
if( a.length == 1 && a[0] != null ) // Checks if its a for comprehension
|
||||
if( a.length == 1 && a[0] != null ) {// Checks if its a for comprehension
|
||||
switch( Tools.expr(a[0]) ) {
|
||||
case EFor(_), EForKeyValue(_), EWhile(_), EDoWhile(_):
|
||||
case EFor(_, _, e), EForKeyValue(_, _, e, _), EWhile(_, e), EDoWhile(_, e):
|
||||
var e = Tools.expr(e);
|
||||
|
||||
if(isMapCompr(a[0])) {
|
||||
var tmp = "__m_" + (uid++);
|
||||
var tmp2 = "__m_" + (uid++);
|
||||
var e = mk(EBlock([
|
||||
// TODO: Make it detect simple map comprehensions so we can optimize the map type
|
||||
mk(EVar(tmp, null, mk(EMapDecl(ObjectMap, [], []), p1)), p1), // Assume ObjectMap, since it supports dynamic keys
|
||||
mk(EVar(tmp2, null, mk(EField(mk(EIdent(tmp), p1), "set"), p1)), p1),
|
||||
mapMapCompr(tmp2, a[0]),
|
||||
mk(EIdent(tmp),p1),
|
||||
]),p1);
|
||||
return parseExprNext(e);
|
||||
}
|
||||
|
||||
var tmp = "__a_" + (uid++);
|
||||
var tmp2 = "__a_" + (uid++);
|
||||
var e = mk(EBlock([
|
||||
mk(EVar(tmp, null, mk(EArrayDecl([]), p1)), p1),
|
||||
mapCompr(tmp, a[0]),
|
||||
mk(EVar(tmp2, null, mk(EField(mk(EIdent(tmp), p1), "push"), p1)), p1),
|
||||
mapArrCompr(tmp2, a[0]),
|
||||
mk(EIdent(tmp),p1),
|
||||
]),p1);
|
||||
return parseExprNext(e);
|
||||
default:
|
||||
}
|
||||
return parseExprNext(mk(EArrayDecl(a, nextType), p1));
|
||||
}
|
||||
|
||||
var isTypeMap = (nextType != null) && nextType.match(CTPath(["Map"], [_, _]));
|
||||
var isMap = isTypeMap;
|
||||
if(!isMap) {
|
||||
isMap = Lambda.exists(a, (e) -> Tools.expr(e).match(EBinop("=>", _))); // Check if any element is a => b
|
||||
}
|
||||
if(isMap) {
|
||||
// TODO: clean up this code more
|
||||
var isKeyString:Bool = false;
|
||||
var isKeyInt:Bool = false;
|
||||
var isKeyObject:Bool = false;
|
||||
var isKeyEnum:Bool = false;
|
||||
var keys:Array<Expr> = [];
|
||||
var values:Array<Expr> = [];
|
||||
for (e in a) {
|
||||
switch (Tools.expr(e)) {
|
||||
case EBinop("=>", eKey, eValue): {
|
||||
switch(Tools.expr(eKey)) {
|
||||
case EConst(CInt(_)):// | EConst(CFloat(_)):
|
||||
isKeyInt = true;
|
||||
case EConst(CString(_)):
|
||||
isKeyString = true;
|
||||
case EIdent(_):
|
||||
isKeyObject = true;
|
||||
// TODO: add more stuffs for isKeyObject
|
||||
default:
|
||||
}
|
||||
keys.push(eKey);
|
||||
values.push(eValue);
|
||||
}
|
||||
default:
|
||||
error(ECustom("Expected a => b"), p1, p1);
|
||||
}
|
||||
}
|
||||
|
||||
if(isTypeMap) {
|
||||
isKeyString = nextType.match(CTPath(["Map"], [CTPath(["String"], _), _]));
|
||||
isKeyInt = nextType.match(CTPath(["Map"], [CTPath(["Int"], _), _]));
|
||||
if(isKeyString || isKeyInt) {
|
||||
isKeyObject = false;
|
||||
isKeyEnum = false;
|
||||
} else {
|
||||
if(!isKeyObject && !isKeyEnum) {
|
||||
error(ECustom("Unknown Type Key"), p1, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var t = b2i(isKeyString) + b2i(isKeyInt) + b2i(isKeyObject) + b2i(isKeyEnum);
|
||||
|
||||
var type:MapType = null;
|
||||
if(t != 1) type = UnknownMap;
|
||||
else if(isKeyInt) type = IntMap;
|
||||
else if(isKeyString) type = StringMap;
|
||||
else if(isKeyEnum) type = EnumMap;
|
||||
else if(isKeyObject) type = ObjectMap;
|
||||
|
||||
if(type == null)
|
||||
error(ECustom("Unknown Map Type"), p1, p1);
|
||||
|
||||
return parseExprNext(mk(EMapDecl(type, keys, values), p1));
|
||||
}
|
||||
return parseExprNext(mk(EArrayDecl(a), p1));
|
||||
case TMeta(id) if( allowMetadata ):
|
||||
var args = parseMetaArgs();
|
||||
return mk(EMeta(id, args, parseExpr()),p1);
|
||||
@@ -608,6 +677,8 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
static inline function b2i(b:Bool) return b ? 1 : 0;
|
||||
|
||||
function parseLambda( args : Array<Argument>, pmin ) {
|
||||
while( true ) {
|
||||
var id = getIdent();
|
||||
@@ -652,29 +723,92 @@ class Parser {
|
||||
return args;
|
||||
}
|
||||
|
||||
function mapCompr( tmp : String, e : Expr ) {
|
||||
function mapArrCompr( tmp : String, e : Expr ) {
|
||||
if( e == null ) return null;
|
||||
var edef = switch( Tools.expr(e) ) {
|
||||
case EFor(v, it, e2):
|
||||
EFor(v, it, mapCompr(tmp, e2));
|
||||
EFor(v, it, mapArrCompr(tmp, e2));
|
||||
case EForKeyValue(v, it, e2, ithv):
|
||||
EForKeyValue(v, it, mapCompr(tmp, e2), ithv);
|
||||
EForKeyValue(v, it, mapArrCompr(tmp, e2), ithv);
|
||||
case EWhile(cond, e2):
|
||||
EWhile(cond, mapCompr(tmp, e2));
|
||||
EWhile(cond, mapArrCompr(tmp, e2));
|
||||
case EDoWhile(cond, e2):
|
||||
EDoWhile(cond, mapCompr(tmp, e2));
|
||||
EDoWhile(cond, mapArrCompr(tmp, e2));
|
||||
case EIf(cond, e1, e2) if( e2 == null ):
|
||||
EIf(cond, mapCompr(tmp, e1), null);
|
||||
EIf(cond, mapArrCompr(tmp, e1), null);
|
||||
case EIf(cond, e1, e2) if( e2 != null ):
|
||||
EIf(cond, mapArrCompr(tmp, e1), mapArrCompr(tmp, e2));
|
||||
case EBlock([e]):
|
||||
EBlock([mapCompr(tmp, e)]);
|
||||
EBlock([mapArrCompr(tmp, e)]);
|
||||
case EParent(e2):
|
||||
EParent(mapCompr(tmp, e2));
|
||||
EParent(mapArrCompr(tmp, e2));
|
||||
default:
|
||||
ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "push"), pmin(e), pmax(e)), [e]);
|
||||
// tmp.push(v);
|
||||
//ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "push"), pmin(e), pmax(e)), [e]);
|
||||
ECall( mk(EIdent(tmp), pmin(e), pmax(e)), [e]);
|
||||
}
|
||||
return mk(edef, pmin(e), pmax(e));
|
||||
}
|
||||
|
||||
function mapMapCompr( tmp : String, e : Expr ) {
|
||||
if( e == null ) return null;
|
||||
var edef = switch( Tools.expr(e) ) {
|
||||
case EFor(v, it, e2):
|
||||
EFor(v, it, mapMapCompr(tmp, e2));
|
||||
case EForKeyValue(v, it, e2, ithv):
|
||||
EForKeyValue(v, it, mapMapCompr(tmp, e2), ithv);
|
||||
case EWhile(cond, e2):
|
||||
EWhile(cond, mapMapCompr(tmp, e2));
|
||||
case EDoWhile(cond, e2):
|
||||
EDoWhile(cond, mapMapCompr(tmp, e2));
|
||||
case EIf(cond, e1, e2) if( e2 == null ):
|
||||
EIf(cond, mapMapCompr(tmp, e1), null);
|
||||
case EIf(cond, e1, e2) if( e2 != null ):
|
||||
EIf(cond, mapMapCompr(tmp, e1), mapMapCompr(tmp, e2));
|
||||
case EBlock([e]):
|
||||
EBlock([mapMapCompr(tmp, e)]);
|
||||
case EParent(e2):
|
||||
EParent(mapMapCompr(tmp, e2));
|
||||
default:
|
||||
// tmp.set(k, v);
|
||||
switch( Tools.expr(e) ) {
|
||||
case EBinop("=>", e1, e2):
|
||||
//ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "set"), pmin(e), pmax(e)), [e1, e2]);
|
||||
ECall( mk(EIdent(tmp), pmin(e), pmax(e)), [e1, e2]);
|
||||
default: // default incase of error
|
||||
//ECall( mk(EField(mk(EIdent(tmp), pmin(e), pmax(e)), "push"), pmin(e), pmax(e)), [e]);
|
||||
ECall( mk(EIdent(tmp), pmin(e), pmax(e)), [e, mk(EIdent("null"), pmin(e), pmax(e))]);
|
||||
}
|
||||
}
|
||||
return mk(edef, pmin(e), pmax(e));
|
||||
}
|
||||
|
||||
function isMapCompr( e : Expr ) {
|
||||
if( e == null ) throw "Invalid map comprehension";
|
||||
//if( e == null ) return true;
|
||||
return switch( Tools.expr(e) ) {
|
||||
case EFor(v, it, e2):
|
||||
isMapCompr(e2);
|
||||
case EForKeyValue(v, it, e2, ithv):
|
||||
isMapCompr(e2);
|
||||
case EWhile(cond, e2):
|
||||
isMapCompr(e2);
|
||||
case EDoWhile(cond, e2):
|
||||
isMapCompr(e2);
|
||||
case EIf(cond, e1, e2) if( e2 == null ):
|
||||
isMapCompr(e1);
|
||||
case EIf(cond, e1, e2) if( e2 != null ):
|
||||
isMapCompr(e1) && isMapCompr(e1);
|
||||
case EBlock([e]):
|
||||
isMapCompr(e);
|
||||
case EParent(e2):
|
||||
isMapCompr(e2);
|
||||
default:
|
||||
// tmp.set(k, v);
|
||||
return Tools.expr(e).match(EBinop("=>", _));
|
||||
}
|
||||
}
|
||||
|
||||
function makeUnop( op, e ) {
|
||||
if( e == null && resumeErrors )
|
||||
return null;
|
||||
@@ -1151,6 +1285,8 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
var disableOrOp:Bool = false;
|
||||
|
||||
function parseExprNext( e1 : Expr ) {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
|
||||
+31
-3
@@ -238,7 +238,22 @@ class Printer {
|
||||
add(v);
|
||||
case EVar(n, t, e): // TODO: static, public, override
|
||||
add("var " + n);
|
||||
addType(t);
|
||||
if( t != null )
|
||||
addType(t);
|
||||
else
|
||||
switch( Tools.expr(e) ) {
|
||||
case EMapDecl(type, _, _):
|
||||
add(" : Map<");
|
||||
switch( type ) {
|
||||
case ObjectMap: add("Dynamic");
|
||||
case StringMap: add("String");
|
||||
case EnumMap: add("EnumValue");
|
||||
case IntMap: add("Int");
|
||||
case UnknownMap: add("?");
|
||||
}
|
||||
add(", Dynamic>");
|
||||
default:
|
||||
}
|
||||
if( e != null ) {
|
||||
add(" = ");
|
||||
expr(e);
|
||||
@@ -286,7 +301,10 @@ class Printer {
|
||||
} else {
|
||||
expr(e1);
|
||||
}
|
||||
add(" " + op + " ");
|
||||
if(op == "...")
|
||||
add(op);
|
||||
else
|
||||
add(" " + op + " ");
|
||||
if(paran == 1 || paran == 2) {
|
||||
add("(");
|
||||
expr(e2);
|
||||
@@ -383,7 +401,17 @@ class Printer {
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el, _):
|
||||
case EMapDecl(type, keys, values):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( i in 0...keys.length ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(keys[i]);
|
||||
add(" => ");
|
||||
expr(values[i]);
|
||||
}
|
||||
add("]");
|
||||
case EArrayDecl(el):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
|
||||
@@ -45,6 +45,7 @@ class Tools {
|
||||
case EFunction(_, e, _, _): f(e);
|
||||
case EReturn(e): if( e != null ) f(e);
|
||||
case EArray(e, i): f(e); f(i);
|
||||
case EMapDecl(type, keys, values): for( e in keys ) f(e); for( e in values ) f(e);
|
||||
case EArrayDecl(el): for( e in el ) f(e);
|
||||
case ENew(_,el): for( e in el ) f(e);
|
||||
case EThrow(e): f(e);
|
||||
@@ -82,6 +83,7 @@ class Tools {
|
||||
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));
|
||||
case EMapDecl(type, keys, values): EMapDecl(type, [for( e in keys ) f(e)], [for( e in values ) f(e)]);
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case EThrow(e): EThrow(f(e));
|
||||
|
||||
Reference in New Issue
Block a user