forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			315 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			315 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright (C)2005-2019 Haxe Foundation
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Permission is hereby granted, free of charge, to any person obtaining a
							 | 
						||
| 
								 | 
							
								 * copy of this software and associated documentation files (the "Software"),
							 | 
						||
| 
								 | 
							
								 * to deal in the Software without restriction, including without limitation
							 | 
						||
| 
								 | 
							
								 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
							 | 
						||
| 
								 | 
							
								 * and/or sell copies of the Software, and to permit persons to whom the
							 | 
						||
| 
								 | 
							
								 * Software is furnished to do so, subject to the following conditions:
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * The above copyright notice and this permission notice shall be included in
							 | 
						||
| 
								 | 
							
								 * all copies or substantial portions of the Software.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
							 | 
						||
| 
								 | 
							
								 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
							 | 
						||
| 
								 | 
							
								 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
							 | 
						||
| 
								 | 
							
								 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
							 | 
						||
| 
								 | 
							
								 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
							 | 
						||
| 
								 | 
							
								 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
							 | 
						||
| 
								 | 
							
								 * DEALINGS IN THE SOFTWARE.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package haxe.macro;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import haxe.macro.Expr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								using Lambda;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
									This class provides some utility methods to work with expressions. It is
							 | 
						||
| 
								 | 
							
									best used through 'using haxe.macro.ExprTools' syntax and then provides
							 | 
						||
| 
								 | 
							
									additional methods on haxe.macro.Expr instances.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									While mainly intended to be used in macros, it works in non-macro code as
							 | 
						||
| 
								 | 
							
									well.
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								class ExprTools {
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
										Converts expression `e` to a human-readable String representation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										The result is guaranteed to be valid Haxe code, but there may be
							 | 
						||
| 
								 | 
							
										differences from the original lexical syntax.
							 | 
						||
| 
								 | 
							
									**/
							 | 
						||
| 
								 | 
							
									static public function toString(e:Expr):String
							 | 
						||
| 
								 | 
							
										return new Printer().printExpr(e);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
										Calls function `f` on each sub-expression of `e`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										If `e` has no sub-expressions, this operation has no effect.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Otherwise `f` is called once per sub-expression of `e`, with the
							 | 
						||
| 
								 | 
							
										sub-expression as argument. These calls are done in order of the
							 | 
						||
| 
								 | 
							
										sub-expression declarations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										This method does not call itself recursively. It should instead be used
							 | 
						||
| 
								 | 
							
										in a recursive function which handles the expression nodes of interest.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Usage example:
							 | 
						||
| 
								 | 
							
										```haxe
							 | 
						||
| 
								 | 
							
										function findStrings(e:Expr) {
							 | 
						||
| 
								 | 
							
											switch(e.expr) {
							 | 
						||
| 
								 | 
							
												case EConst(CString(s)):
							 | 
						||
| 
								 | 
							
													// handle s
							 | 
						||
| 
								 | 
							
												case _:
							 | 
						||
| 
								 | 
							
													ExprTools.iter(e, findStrings);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										```
							 | 
						||
| 
								 | 
							
									**/
							 | 
						||
| 
								 | 
							
									static public function iter(e:Expr, f:Expr->Void):Void {
							 | 
						||
| 
								 | 
							
										switch (e.expr) {
							 | 
						||
| 
								 | 
							
											case EConst(_), EContinue, EBreak, EDisplayNew(_):
							 | 
						||
| 
								 | 
							
											case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EIs(e, _) | EMeta(_, e):
							 | 
						||
| 
								 | 
							
												f(e);
							 | 
						||
| 
								 | 
							
											case EArray(e1, e2), EWhile(e1, e2, _), EBinop(_, e1, e2), EFor(e1, e2):
							 | 
						||
| 
								 | 
							
												f(e1);
							 | 
						||
| 
								 | 
							
												f(e2);
							 | 
						||
| 
								 | 
							
											case EVars(vl):
							 | 
						||
| 
								 | 
							
												for (v in vl)
							 | 
						||
| 
								 | 
							
													opt2(v.expr, f);
							 | 
						||
| 
								 | 
							
											case ETry(e, cl):
							 | 
						||
| 
								 | 
							
												f(e);
							 | 
						||
| 
								 | 
							
												for (c in cl)
							 | 
						||
| 
								 | 
							
													f(c.expr);
							 | 
						||
| 
								 | 
							
											case ETernary(e1, e2, e3) | EIf(e1, e2, e3):
							 | 
						||
| 
								 | 
							
												f(e1);
							 | 
						||
| 
								 | 
							
												f(e2);
							 | 
						||
| 
								 | 
							
												opt2(e3, f);
							 | 
						||
| 
								 | 
							
											case EArrayDecl(el), ENew(_, el), EBlock(el):
							 | 
						||
| 
								 | 
							
												ExprArrayTools.iter(el, f);
							 | 
						||
| 
								 | 
							
											case EObjectDecl(fl):
							 | 
						||
| 
								 | 
							
												for (fd in fl)
							 | 
						||
| 
								 | 
							
													f(fd.expr);
							 | 
						||
| 
								 | 
							
											case ECall(e, el):
							 | 
						||
| 
								 | 
							
												f(e);
							 | 
						||
| 
								 | 
							
												ExprArrayTools.iter(el, f);
							 | 
						||
| 
								 | 
							
											case EReturn(e):
							 | 
						||
| 
								 | 
							
												opt2(e, f);
							 | 
						||
| 
								 | 
							
											case EFunction(_, func):
							 | 
						||
| 
								 | 
							
												for (arg in func.args)
							 | 
						||
| 
								 | 
							
													opt2(arg.value, f);
							 | 
						||
| 
								 | 
							
												opt2(func.expr, f);
							 | 
						||
| 
								 | 
							
											case ESwitch(e, cl, edef):
							 | 
						||
| 
								 | 
							
												f(e);
							 | 
						||
| 
								 | 
							
												for (c in cl) {
							 | 
						||
| 
								 | 
							
													ExprArrayTools.iter(c.values, f);
							 | 
						||
| 
								 | 
							
													opt2(c.guard, f);
							 | 
						||
| 
								 | 
							
													opt2(c.expr, f);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												if (edef != null && edef.expr != null)
							 | 
						||
| 
								 | 
							
													f(edef);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
										Transforms the sub-expressions of `e` by calling `f` on each of them.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										If `e` has no sub-expressions, this operation returns `e` unchanged.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Otherwise `f` is called once per sub-expression of `e`, with the
							 | 
						||
| 
								 | 
							
										sub-expression as argument. These calls are done in order of the
							 | 
						||
| 
								 | 
							
										sub-expression declarations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										This method does not call itself recursively. It should instead be used
							 | 
						||
| 
								 | 
							
										in a recursive function which handles the expression nodes of interest.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Usage example:
							 | 
						||
| 
								 | 
							
										```haxe
							 | 
						||
| 
								 | 
							
										function capitalizeStrings(e:Expr) {
							 | 
						||
| 
								 | 
							
											return switch(e.expr) {
							 | 
						||
| 
								 | 
							
												case EConst(CString(s)):
							 | 
						||
| 
								 | 
							
													{ expr: EConst(CString(s.toUpperCase())), pos: e.pos };
							 | 
						||
| 
								 | 
							
												case _:
							 | 
						||
| 
								 | 
							
													ExprTools.map(e, capitalizeStrings);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										```
							 | 
						||
| 
								 | 
							
									**/
							 | 
						||
| 
								 | 
							
									static public function map(e:Expr, f:Expr->Expr):Expr {
							 | 
						||
| 
								 | 
							
										return {
							 | 
						||
| 
								 | 
							
											pos: e.pos,
							 | 
						||
| 
								 | 
							
											expr: switch (e.expr) {
							 | 
						||
| 
								 | 
							
												case EConst(_): e.expr;
							 | 
						||
| 
								 | 
							
												case EArray(e1, e2): EArray(f(e1), f(e2));
							 | 
						||
| 
								 | 
							
												case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
							 | 
						||
| 
								 | 
							
												case EField(e, field): EField(f(e), field);
							 | 
						||
| 
								 | 
							
												case EParenthesis(e): EParenthesis(f(e));
							 | 
						||
| 
								 | 
							
												case EObjectDecl(fields):
							 | 
						||
| 
								 | 
							
													var ret = [];
							 | 
						||
| 
								 | 
							
													for (field in fields)
							 | 
						||
| 
								 | 
							
														ret.push({field: field.field, expr: f(field.expr), quotes: field.quotes});
							 | 
						||
| 
								 | 
							
													EObjectDecl(ret);
							 | 
						||
| 
								 | 
							
												case EArrayDecl(el): EArrayDecl(ExprArrayTools.map(el, f));
							 | 
						||
| 
								 | 
							
												case ECall(e, params): ECall(f(e), ExprArrayTools.map(params, f));
							 | 
						||
| 
								 | 
							
												case ENew(tp, params): ENew(tp, ExprArrayTools.map(params, f));
							 | 
						||
| 
								 | 
							
												case EUnop(op, postFix, e): EUnop(op, postFix, f(e));
							 | 
						||
| 
								 | 
							
												case EVars(vars):
							 | 
						||
| 
								 | 
							
													var ret = [];
							 | 
						||
| 
								 | 
							
													for (v in vars) {
							 | 
						||
| 
								 | 
							
														var v2:Var = {name: v.name, type: v.type, expr: opt(v.expr, f)};
							 | 
						||
| 
								 | 
							
														if (v.isFinal != null)
							 | 
						||
| 
								 | 
							
															v2.isFinal = v.isFinal;
							 | 
						||
| 
								 | 
							
														ret.push(v2);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													EVars(ret);
							 | 
						||
| 
								 | 
							
												case EBlock(el): EBlock(ExprArrayTools.map(el, f));
							 | 
						||
| 
								 | 
							
												case EFor(it, expr): EFor(f(it), f(expr));
							 | 
						||
| 
								 | 
							
												case EIf(econd, eif, eelse): EIf(f(econd), f(eif), opt(eelse, f));
							 | 
						||
| 
								 | 
							
												case EWhile(econd, e, normalWhile): EWhile(f(econd), f(e), normalWhile);
							 | 
						||
| 
								 | 
							
												case EReturn(e): EReturn(opt(e, f));
							 | 
						||
| 
								 | 
							
												case EUntyped(e): EUntyped(f(e));
							 | 
						||
| 
								 | 
							
												case EThrow(e): EThrow(f(e));
							 | 
						||
| 
								 | 
							
												case ECast(e, t): ECast(f(e), t);
							 | 
						||
| 
								 | 
							
												case EIs(e, t): EIs(f(e), t);
							 | 
						||
| 
								 | 
							
												case EDisplay(e, dk): EDisplay(f(e), dk);
							 | 
						||
| 
								 | 
							
												case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse));
							 | 
						||
| 
								 | 
							
												case ECheckType(e, t): ECheckType(f(e), t);
							 | 
						||
| 
								 | 
							
												case EDisplayNew(_), EContinue, EBreak:
							 | 
						||
| 
								 | 
							
													e.expr;
							 | 
						||
| 
								 | 
							
												case ETry(e, catches):
							 | 
						||
| 
								 | 
							
													var ret = [];
							 | 
						||
| 
								 | 
							
													for (c in catches)
							 | 
						||
| 
								 | 
							
														ret.push({name: c.name, type: c.type, expr: f(c.expr)});
							 | 
						||
| 
								 | 
							
													ETry(f(e), ret);
							 | 
						||
| 
								 | 
							
												case ESwitch(e, cases, edef):
							 | 
						||
| 
								 | 
							
													var ret = [];
							 | 
						||
| 
								 | 
							
													for (c in cases)
							 | 
						||
| 
								 | 
							
														ret.push({expr: opt(c.expr, f), guard: opt(c.guard, f), values: ExprArrayTools.map(c.values, f)});
							 | 
						||
| 
								 | 
							
													ESwitch(f(e), ret, edef == null || edef.expr == null ? edef : f(edef));
							 | 
						||
| 
								 | 
							
												case EFunction(kind, func):
							 | 
						||
| 
								 | 
							
													var ret = [];
							 | 
						||
| 
								 | 
							
													for (arg in func.args)
							 | 
						||
| 
								 | 
							
														ret.push({
							 | 
						||
| 
								 | 
							
															name: arg.name,
							 | 
						||
| 
								 | 
							
															opt: arg.opt,
							 | 
						||
| 
								 | 
							
															type: arg.type,
							 | 
						||
| 
								 | 
							
															value: opt(arg.value, f)
							 | 
						||
| 
								 | 
							
														});
							 | 
						||
| 
								 | 
							
													EFunction(kind, {
							 | 
						||
| 
								 | 
							
														args: ret,
							 | 
						||
| 
								 | 
							
														ret: func.ret,
							 | 
						||
| 
								 | 
							
														params: func.params,
							 | 
						||
| 
								 | 
							
														expr: f(func.expr)
							 | 
						||
| 
								 | 
							
													});
							 | 
						||
| 
								 | 
							
												case EMeta(m, e): EMeta(m, f(e));
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
										Returns the value `e` represents.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Supported expressions are:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 - `Int`, `Float` and `String` literals
							 | 
						||
| 
								 | 
							
										 - identifiers `true`, `false` and `null`
							 | 
						||
| 
								 | 
							
										 - structure declarations if all their fields are values
							 | 
						||
| 
								 | 
							
										 - array declarations if all their elements are values
							 | 
						||
| 
								 | 
							
										 - unary operators `-`, `!` and `~` if the operand is a value
							 | 
						||
| 
								 | 
							
										 - binary operators except `=>`, `...` and assignments
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Parentheses, metadata and the `untyped` keyword are ignored.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										If any non-value is encountered, an exception of type `String` is
							 | 
						||
| 
								 | 
							
										thrown.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										If `e` is null, the result is unspecified.
							 | 
						||
| 
								 | 
							
									**/
							 | 
						||
| 
								 | 
							
									static public function getValue(e:Expr):Dynamic {
							 | 
						||
| 
								 | 
							
										return switch (e.expr) {
							 | 
						||
| 
								 | 
							
											case EConst(CInt(v)): Std.parseInt(v);
							 | 
						||
| 
								 | 
							
											case EConst(CFloat(v)): Std.parseFloat(v);
							 | 
						||
| 
								 | 
							
											case EConst(CString(s)): s;
							 | 
						||
| 
								 | 
							
											case EConst(CIdent("true")): true;
							 | 
						||
| 
								 | 
							
											case EConst(CIdent("false")): false;
							 | 
						||
| 
								 | 
							
											case EConst(CIdent("null")): null;
							 | 
						||
| 
								 | 
							
											case EParenthesis(e1) | EUntyped(e1) | EMeta(_, e1): getValue(e1);
							 | 
						||
| 
								 | 
							
											case EObjectDecl(fields):
							 | 
						||
| 
								 | 
							
												var obj = {};
							 | 
						||
| 
								 | 
							
												for (field in fields) {
							 | 
						||
| 
								 | 
							
													Reflect.setField(obj, field.field, getValue(field.expr));
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												obj;
							 | 
						||
| 
								 | 
							
											case EArrayDecl(el): el.map(getValue);
							 | 
						||
| 
								 | 
							
											case EIf(econd, eif, eelse) | ETernary(econd, eif, eelse):
							 | 
						||
| 
								 | 
							
												if (eelse == null) {
							 | 
						||
| 
								 | 
							
													throw "If statements only have a value if the else clause is defined";
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													var econd:Dynamic = getValue(econd);
							 | 
						||
| 
								 | 
							
													econd ? getValue(eif) : getValue(eelse);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											case EUnop(op, false, e1):
							 | 
						||
| 
								 | 
							
												var e1:Dynamic = getValue(e1);
							 | 
						||
| 
								 | 
							
												switch (op) {
							 | 
						||
| 
								 | 
							
													case OpNot: !e1;
							 | 
						||
| 
								 | 
							
													case OpNeg: -e1;
							 | 
						||
| 
								 | 
							
													case OpNegBits: ~e1;
							 | 
						||
| 
								 | 
							
													case _: throw 'Unsupported expression: $e';
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											case EBinop(op, e1, e2):
							 | 
						||
| 
								 | 
							
												var e1:Dynamic = getValue(e1);
							 | 
						||
| 
								 | 
							
												var e2:Dynamic = getValue(e2);
							 | 
						||
| 
								 | 
							
												switch (op) {
							 | 
						||
| 
								 | 
							
													case OpAdd: e1 + e2;
							 | 
						||
| 
								 | 
							
													case OpSub: e1 - e2;
							 | 
						||
| 
								 | 
							
													case OpMult: e1 * e2;
							 | 
						||
| 
								 | 
							
													case OpDiv: e1 / e2;
							 | 
						||
| 
								 | 
							
													case OpMod: e1 % e2;
							 | 
						||
| 
								 | 
							
													case OpEq: e1 == e2;
							 | 
						||
| 
								 | 
							
													case OpNotEq: e1 != e2;
							 | 
						||
| 
								 | 
							
													case OpLt: e1 < e2;
							 | 
						||
| 
								 | 
							
													case OpLte: e1 <= e2;
							 | 
						||
| 
								 | 
							
													case OpGt: e1 > e2;
							 | 
						||
| 
								 | 
							
													case OpGte: e1 >= e2;
							 | 
						||
| 
								 | 
							
													case OpOr: e1 | e2;
							 | 
						||
| 
								 | 
							
													case OpAnd: e1 & e2;
							 | 
						||
| 
								 | 
							
													case OpXor: e1 ^ e2;
							 | 
						||
| 
								 | 
							
													case OpBoolAnd: e1 && e2;
							 | 
						||
| 
								 | 
							
													case OpBoolOr: e1 || e2;
							 | 
						||
| 
								 | 
							
													case OpShl: e1 << e2;
							 | 
						||
| 
								 | 
							
													case OpShr: e1 >> e2;
							 | 
						||
| 
								 | 
							
													case OpUShr: e1 >>> e2;
							 | 
						||
| 
								 | 
							
													case _: throw 'Unsupported expression: $e';
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											case _: throw 'Unsupported expression: $e';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static inline function opt(e:Null<Expr>, f:Expr->Expr):Expr
							 | 
						||
| 
								 | 
							
										return e == null ? null : f(e);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static inline function opt2(e:Null<Expr>, f:Expr->Void):Void
							 | 
						||
| 
								 | 
							
										if (e != null)
							 | 
						||
| 
								 | 
							
											f(e);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
									This class provides functions on expression arrays for convenience. For a
							 | 
						||
| 
								 | 
							
									detailed reference on each method, see the documentation of ExprTools.
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								class ExprArrayTools {
							 | 
						||
| 
								 | 
							
									static public function map(el:Array<Expr>, f:Expr->Expr):Array<Expr> {
							 | 
						||
| 
								 | 
							
										var ret = [];
							 | 
						||
| 
								 | 
							
										for (e in el)
							 | 
						||
| 
								 | 
							
											ret.push(f(e));
							 | 
						||
| 
								 | 
							
										return ret;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static public function iter(el:Array<Expr>, f:Expr->Void):Void {
							 | 
						||
| 
								 | 
							
										for (e in el)
							 | 
						||
| 
								 | 
							
											f(e);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |