forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			565 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			565 lines
		
	
	
		
			19 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;
							 | 
						||
| 
								 | 
							
								using StringTools;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
									This class provides some utility methods to convert elements from the
							 | 
						||
| 
								 | 
							
									macro context to a human-readable String representation.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class Printer {
							 | 
						||
| 
								 | 
							
									var tabs:String;
							 | 
						||
| 
								 | 
							
									var tabString:String;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function new(?tabString = "\t") {
							 | 
						||
| 
								 | 
							
										tabs = "";
							 | 
						||
| 
								 | 
							
										this.tabString = tabString;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printUnop(op:Unop)
							 | 
						||
| 
								 | 
							
										return switch (op) {
							 | 
						||
| 
								 | 
							
											case OpIncrement: "++";
							 | 
						||
| 
								 | 
							
											case OpDecrement: "--";
							 | 
						||
| 
								 | 
							
											case OpNot: "!";
							 | 
						||
| 
								 | 
							
											case OpNeg: "-";
							 | 
						||
| 
								 | 
							
											case OpNegBits: "~";
							 | 
						||
| 
								 | 
							
											case OpSpread: "...";
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printBinop(op:Binop)
							 | 
						||
| 
								 | 
							
										return switch (op) {
							 | 
						||
| 
								 | 
							
											case OpAdd: "+";
							 | 
						||
| 
								 | 
							
											case OpMult: "*";
							 | 
						||
| 
								 | 
							
											case OpDiv: "/";
							 | 
						||
| 
								 | 
							
											case OpSub: "-";
							 | 
						||
| 
								 | 
							
											case OpAssign: "=";
							 | 
						||
| 
								 | 
							
											case OpEq: "==";
							 | 
						||
| 
								 | 
							
											case OpNotEq: "!=";
							 | 
						||
| 
								 | 
							
											case OpGt: ">";
							 | 
						||
| 
								 | 
							
											case OpGte: ">=";
							 | 
						||
| 
								 | 
							
											case OpLt: "<";
							 | 
						||
| 
								 | 
							
											case OpLte: "<=";
							 | 
						||
| 
								 | 
							
											case OpAnd: "&";
							 | 
						||
| 
								 | 
							
											case OpOr: "|";
							 | 
						||
| 
								 | 
							
											case OpXor: "^";
							 | 
						||
| 
								 | 
							
											case OpBoolAnd: "&&";
							 | 
						||
| 
								 | 
							
											case OpBoolOr: "||";
							 | 
						||
| 
								 | 
							
											case OpShl: "<<";
							 | 
						||
| 
								 | 
							
											case OpShr: ">>";
							 | 
						||
| 
								 | 
							
											case OpUShr: ">>>";
							 | 
						||
| 
								 | 
							
											case OpMod: "%";
							 | 
						||
| 
								 | 
							
											case OpInterval: "...";
							 | 
						||
| 
								 | 
							
											case OpArrow: "=>";
							 | 
						||
| 
								 | 
							
											case OpIn: "in";
							 | 
						||
| 
								 | 
							
											case OpAssignOp(op):
							 | 
						||
| 
								 | 
							
												printBinop(op) + "=";
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function escapeString(s:String, delim:String) {
							 | 
						||
| 
								 | 
							
										return delim
							 | 
						||
| 
								 | 
							
											+ s.replace("\n", "\\n")
							 | 
						||
| 
								 | 
							
												.replace("\t", "\\t")
							 | 
						||
| 
								 | 
							
												.replace("\r", "\\r")
							 | 
						||
| 
								 | 
							
												.replace("'", "\\'")
							 | 
						||
| 
								 | 
							
												.replace('"', "\\\"") #if sys .replace("\x00", "\\x00") #end + delim;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printFormatString(s:String) {
							 | 
						||
| 
								 | 
							
										return escapeString(s, "'");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printString(s:String) {
							 | 
						||
| 
								 | 
							
										return escapeString(s, '"');
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printConstant(c:Constant)
							 | 
						||
| 
								 | 
							
										return switch (c) {
							 | 
						||
| 
								 | 
							
											case CString(s, SingleQuotes): printFormatString(s);
							 | 
						||
| 
								 | 
							
											case CString(s, _): printString(s);
							 | 
						||
| 
								 | 
							
											case CIdent(s), CInt(s), CFloat(s):
							 | 
						||
| 
								 | 
							
												s;
							 | 
						||
| 
								 | 
							
											case CRegexp(s, opt): '~/$s/$opt';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printTypeParam(param:TypeParam)
							 | 
						||
| 
								 | 
							
										return switch (param) {
							 | 
						||
| 
								 | 
							
											case TPType(ct): printComplexType(ct);
							 | 
						||
| 
								 | 
							
											case TPExpr(e): printExpr(e);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printTypePath(tp:TypePath)
							 | 
						||
| 
								 | 
							
										return (tp.pack.length > 0 ? tp.pack.join(".") + "." : "")
							 | 
						||
| 
								 | 
							
											+ tp.name
							 | 
						||
| 
								 | 
							
											+ (tp.sub != null ? '.${tp.sub}' : "")
							 | 
						||
| 
								 | 
							
											+ (tp.params == null ? "" : tp.params.length > 0 ? "<" + tp.params.map(printTypeParam).join(", ") + ">" : "");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// TODO: check if this can cause loops
							 | 
						||
| 
								 | 
							
									public function printComplexType(ct:ComplexType)
							 | 
						||
| 
								 | 
							
										return switch (ct) {
							 | 
						||
| 
								 | 
							
											case TPath(tp): printTypePath(tp);
							 | 
						||
| 
								 | 
							
											case TFunction(args, ret):
							 | 
						||
| 
								 | 
							
												var wrapArgumentsInParentheses = switch args {
							 | 
						||
| 
								 | 
							
													// type `:(a:X) -> Y` has args as [TParent(TNamed(...))], i.e `a:X` gets wrapped in `TParent()`. We don't add parentheses to avoid printing `:((a:X)) -> Y`
							 | 
						||
| 
								 | 
							
													case [TParent(t)]: false;
							 | 
						||
| 
								 | 
							
													// this case catches a single argument that's a type-path, so that `X -> Y` prints `X -> Y` not `(X) -> Y`
							 | 
						||
| 
								 | 
							
													case [TPath(_) | TOptional(TPath(_))]: false;
							 | 
						||
| 
								 | 
							
													default: true;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												var argStr = args.map(printComplexType).join(", ");
							 | 
						||
| 
								 | 
							
												(wrapArgumentsInParentheses ? '($argStr)' : argStr) + " -> " + (switch ret {
							 | 
						||
| 
								 | 
							
													// wrap return type in parentheses if it's also a function
							 | 
						||
| 
								 | 
							
													case TFunction(_): '(${printComplexType(ret)})';
							 | 
						||
| 
								 | 
							
													default: (printComplexType(ret): String);
							 | 
						||
| 
								 | 
							
												});
							 | 
						||
| 
								 | 
							
											case TAnonymous(fields): "{ " + [for (f in fields) printField(f) + "; "].join("") + "}";
							 | 
						||
| 
								 | 
							
											case TParent(ct): "(" + printComplexType(ct) + ")";
							 | 
						||
| 
								 | 
							
											case TOptional(ct): "?" + printComplexType(ct);
							 | 
						||
| 
								 | 
							
											case TNamed(n, ct): n + ":" + printComplexType(ct);
							 | 
						||
| 
								 | 
							
											case TExtend(tpl, fields):
							 | 
						||
| 
								 | 
							
												var types = [for (t in tpl) "> " + printTypePath(t) + ", "].join("");
							 | 
						||
| 
								 | 
							
												var fields = [for (f in fields) printField(f) + "; "].join("");
							 | 
						||
| 
								 | 
							
												'{${types}${fields}}';
							 | 
						||
| 
								 | 
							
											case TIntersection(tl): tl.map(printComplexType).join(" & ");
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printMetadata(meta:MetadataEntry)
							 | 
						||
| 
								 | 
							
										return '@${meta.name}' + ((meta.params != null && meta.params.length > 0) ? '(${printExprs(meta.params, ", ")})' : "");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printAccess(access:Access)
							 | 
						||
| 
								 | 
							
										return switch (access) {
							 | 
						||
| 
								 | 
							
											case AStatic: "static";
							 | 
						||
| 
								 | 
							
											case APublic: "public";
							 | 
						||
| 
								 | 
							
											case APrivate: "private";
							 | 
						||
| 
								 | 
							
											case AOverride: "override";
							 | 
						||
| 
								 | 
							
											case AInline: "inline";
							 | 
						||
| 
								 | 
							
											case ADynamic: "dynamic";
							 | 
						||
| 
								 | 
							
											case AMacro: "macro";
							 | 
						||
| 
								 | 
							
											case AFinal: "final";
							 | 
						||
| 
								 | 
							
											case AExtern: "extern";
							 | 
						||
| 
								 | 
							
											case AAbstract: "abstract";
							 | 
						||
| 
								 | 
							
											case AOverload: "overload";
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printField(field:Field) {
							 | 
						||
| 
								 | 
							
										inline function orderAccess(access: Array<Access>) {
							 | 
						||
| 
								 | 
							
											// final should always be printed last
							 | 
						||
| 
								 | 
							
											// (does not modify input array)
							 | 
						||
| 
								 | 
							
											return access.has(AFinal) ? access.filter(a -> !a.match(AFinal)).concat([AFinal]) : access;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return (field.doc != null
							 | 
						||
| 
								 | 
							
											&& field.doc != "" ? "/**\n"
							 | 
						||
| 
								 | 
							
												+ tabs
							 | 
						||
| 
								 | 
							
												+ tabString
							 | 
						||
| 
								 | 
							
												+ StringTools.replace(field.doc, "\n", "\n" + tabs + tabString)
							 | 
						||
| 
								 | 
							
												+ "\n"
							 | 
						||
| 
								 | 
							
												+ tabs
							 | 
						||
| 
								 | 
							
												+ "**/\n"
							 | 
						||
| 
								 | 
							
												+ tabs : "")
							 | 
						||
| 
								 | 
							
											+ (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join('\n$tabs') + '\n$tabs' : "")
							 | 
						||
| 
								 | 
							
											+ (field.access != null && field.access.length > 0 ? orderAccess(field.access).map(printAccess).join(" ") + " " : "")
							 | 
						||
| 
								 | 
							
											+ switch (field.kind) {
							 | 
						||
| 
								 | 
							
												case FVar(t, eo): ((field.access != null && field.access.has(AFinal)) ? '' : 'var ') + '${field.name}' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = ");
							 | 
						||
| 
								 | 
							
												case FProp(get, set, t, eo): 'var ${field.name}($get, $set)' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = ");
							 | 
						||
| 
								 | 
							
												case FFun(func): 'function ${field.name}' + printFunction(func);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printTypeParamDecl(tpd:TypeParamDecl)
							 | 
						||
| 
								 | 
							
										return (tpd.meta != null && tpd.meta.length > 0 ? tpd.meta.map(printMetadata).join(" ") + " " : "")
							 | 
						||
| 
								 | 
							
											+ tpd.name
							 | 
						||
| 
								 | 
							
											+ (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
											+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printFunctionArg(arg:FunctionArg)
							 | 
						||
| 
								 | 
							
										return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = ");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printFunction(func:Function, ?kind:FunctionKind) {
							 | 
						||
| 
								 | 
							
										var skipParentheses = switch func.args {
							 | 
						||
| 
								 | 
							
											case [{ type:null }]: kind == FArrow;
							 | 
						||
| 
								 | 
							
											case _: false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return (func.params == null ? "" : func.params.length > 0 ? "<" + func.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
											+ (skipParentheses ? "" : "(")
							 | 
						||
| 
								 | 
							
											+ func.args.map(printFunctionArg).join(", ")
							 | 
						||
| 
								 | 
							
											+ (skipParentheses ? "" : ")")
							 | 
						||
| 
								 | 
							
											+ (kind == FArrow ? " ->" : "")
							 | 
						||
| 
								 | 
							
											+ opt(func.ret, printComplexType, ":")
							 | 
						||
| 
								 | 
							
											+ opt(func.expr, printExpr, " ");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printVar(v:Var) {
							 | 
						||
| 
								 | 
							
										var s = v.name + opt(v.type, printComplexType, ":") + opt(v.expr, printExpr, " = ");
							 | 
						||
| 
								 | 
							
										return switch v.meta {
							 | 
						||
| 
								 | 
							
											case null|[]: s;
							 | 
						||
| 
								 | 
							
											case meta: meta.map(printMetadata).join(" ") + " " + s;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printObjectFieldKey(of:ObjectField) {
							 | 
						||
| 
								 | 
							
										return switch (of.quotes) {
							 | 
						||
| 
								 | 
							
											case null | Unquoted: of.field;
							 | 
						||
| 
								 | 
							
											case Quoted: '"${of.field}"'; // TODO: Have to escape that?
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printObjectField(of:ObjectField) {
							 | 
						||
| 
								 | 
							
										return '${printObjectFieldKey(of)} : ${printExpr(of.expr)}';
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printExpr(e:Expr)
							 | 
						||
| 
								 | 
							
										return e == null ? "#NULL" : switch (e.expr) {
							 | 
						||
| 
								 | 
							
											case EConst(c): printConstant(c);
							 | 
						||
| 
								 | 
							
											case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
							 | 
						||
| 
								 | 
							
											case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
							 | 
						||
| 
								 | 
							
											case EField(e1, n): '${printExpr(e1)}.$n';
							 | 
						||
| 
								 | 
							
											case EParenthesis(e1): '(${printExpr(e1)})';
							 | 
						||
| 
								 | 
							
											case EObjectDecl(fl):
							 | 
						||
| 
								 | 
							
												"{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
							 | 
						||
| 
								 | 
							
											case EArrayDecl(el): '[${printExprs(el, ", ")}]';
							 | 
						||
| 
								 | 
							
											case ECall(e1, el): '${printExpr(e1)}(${printExprs(el, ", ")})';
							 | 
						||
| 
								 | 
							
											case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el, ", ")})';
							 | 
						||
| 
								 | 
							
											case EUnop(op, true, e1): printExpr(e1) + printUnop(op);
							 | 
						||
| 
								 | 
							
											case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
							 | 
						||
| 
								 | 
							
											case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
							 | 
						||
| 
								 | 
							
											case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind);
							 | 
						||
| 
								 | 
							
											case EVars(vl): "var " + vl.map(printVar).join(", ");
							 | 
						||
| 
								 | 
							
											case EBlock([]): '{ }';
							 | 
						||
| 
								 | 
							
											case EBlock(el):
							 | 
						||
| 
								 | 
							
												var old = tabs;
							 | 
						||
| 
								 | 
							
												tabs += tabString;
							 | 
						||
| 
								 | 
							
												var s = '{\n$tabs' + printExprs(el, ';\n$tabs');
							 | 
						||
| 
								 | 
							
												tabs = old;
							 | 
						||
| 
								 | 
							
												s + ';\n$tabs}';
							 | 
						||
| 
								 | 
							
											case EFor(e1, e2): 'for (${printExpr(e1)}) ${printExpr(e2)}';
							 | 
						||
| 
								 | 
							
											case EIf(econd, eif, null): 'if (${printExpr(econd)}) ${printExpr(eif)}';
							 | 
						||
| 
								 | 
							
											case EIf(econd, eif, eelse): 'if (${printExpr(econd)}) ${printExpr(eif)} else ${printExpr(eelse)}';
							 | 
						||
| 
								 | 
							
											case EWhile(econd, e1, true): 'while (${printExpr(econd)}) ${printExpr(e1)}';
							 | 
						||
| 
								 | 
							
											case EWhile(econd, e1, false): 'do ${printExpr(e1)} while (${printExpr(econd)})';
							 | 
						||
| 
								 | 
							
											case ESwitch(e1, cl, edef):
							 | 
						||
| 
								 | 
							
												var old = tabs;
							 | 
						||
| 
								 | 
							
												tabs += tabString;
							 | 
						||
| 
								 | 
							
												var s = 'switch ${printExpr(e1)} {\n$tabs'
							 | 
						||
| 
								 | 
							
													+ cl.map(function(c) return 'case ${printExprs(c.values, ", ")}' + (c.guard != null ? ' if (${printExpr(c.guard)}):' : ":")
							 | 
						||
| 
								 | 
							
														+ (c.expr != null ? (opt(c.expr, printExpr)) + ";" : ""))
							 | 
						||
| 
								 | 
							
														.join('\n$tabs');
							 | 
						||
| 
								 | 
							
												if (edef != null)
							 | 
						||
| 
								 | 
							
													s += '\n${tabs}default:' + (edef.expr == null ? "" : printExpr(edef) + ";");
							 | 
						||
| 
								 | 
							
												tabs = old;
							 | 
						||
| 
								 | 
							
												s + '\n$tabs}';
							 | 
						||
| 
								 | 
							
											case ETry(e1, cl):
							 | 
						||
| 
								 | 
							
												'try ${printExpr(e1)}' + cl.map(function(c) return ' catch(${c.name}${c.type == null ? '' : (':' + printComplexType(c.type))}) ${printExpr(c.expr)}').join("");
							 | 
						||
| 
								 | 
							
											case EReturn(eo): "return" + opt(eo, printExpr, " ");
							 | 
						||
| 
								 | 
							
											case EBreak: "break";
							 | 
						||
| 
								 | 
							
											case EContinue: "continue";
							 | 
						||
| 
								 | 
							
											case EUntyped(e1): "untyped " + printExpr(e1);
							 | 
						||
| 
								 | 
							
											case EThrow(e1): "throw " + printExpr(e1);
							 | 
						||
| 
								 | 
							
											case ECast(e1, cto) if (cto != null): 'cast(${printExpr(e1)}, ${printComplexType(cto)})';
							 | 
						||
| 
								 | 
							
											case ECast(e1, _): "cast " + printExpr(e1);
							 | 
						||
| 
								 | 
							
											case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
							 | 
						||
| 
								 | 
							
											case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
							 | 
						||
| 
								 | 
							
											case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})';
							 | 
						||
| 
								 | 
							
											case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
							 | 
						||
| 
								 | 
							
											case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})';
							 | 
						||
| 
								 | 
							
											case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1);
							 | 
						||
| 
								 | 
							
											case EMeta(meta, e1): printMetadata(meta) + " " + printExpr(e1);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printExprs(el:Array<Expr>, sep:String) {
							 | 
						||
| 
								 | 
							
										return el.map(printExpr).join(sep);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function printExtension(tpl:Array<TypePath>, fields:Array<Field>) {
							 | 
						||
| 
								 | 
							
										return '{\n$tabs>'
							 | 
						||
| 
								 | 
							
											+ tpl.map(printTypePath).join(',\n$tabs>')
							 | 
						||
| 
								 | 
							
											+ ","
							 | 
						||
| 
								 | 
							
											+ (fields.length > 0 ? ('\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}") : ("\n}"));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function printStructure(fields:Array<Field>) {
							 | 
						||
| 
								 | 
							
										return fields.length == 0 ? "{ }" : '{\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}";
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printTypeDefinition(t:TypeDefinition, printPackage = true):String {
							 | 
						||
| 
								 | 
							
										var old = tabs;
							 | 
						||
| 
								 | 
							
										tabs = tabString;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var str = t == null ? "#NULL" : (printPackage && t.pack.length > 0 && t.pack[0] != "" ? "package " + t.pack.join(".") + ";\n" : "")
							 | 
						||
| 
								 | 
							
											+ (t.doc != null && t.doc != "" ? "/**\n" + tabString + StringTools.replace(t.doc, "\n", "\n" + tabString) + "\n**/\n" : "")
							 | 
						||
| 
								 | 
							
											+ (t.meta != null && t.meta.length > 0 ? t.meta.map(printMetadata).join(" ") + " " : "")
							 | 
						||
| 
								 | 
							
											+ (t.isExtern ? "extern " : "")
							 | 
						||
| 
								 | 
							
											+ switch (t.kind) {
							 | 
						||
| 
								 | 
							
												case TDEnum:
							 | 
						||
| 
								 | 
							
													"enum "
							 | 
						||
| 
								 | 
							
													+ t.name
							 | 
						||
| 
								 | 
							
													+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
													+ " {\n"
							 | 
						||
| 
								 | 
							
													+ [
							 | 
						||
| 
								 | 
							
														for (field in t.fields)
							 | 
						||
| 
								 | 
							
															tabs
							 | 
						||
| 
								 | 
							
															+ (field.doc != null
							 | 
						||
| 
								 | 
							
																&& field.doc != "" ? "/**\n"
							 | 
						||
| 
								 | 
							
																	+ tabs
							 | 
						||
| 
								 | 
							
																	+ tabString
							 | 
						||
| 
								 | 
							
																	+ StringTools.replace(field.doc, "\n", "\n" + tabs + tabString)
							 | 
						||
| 
								 | 
							
																	+ "\n"
							 | 
						||
| 
								 | 
							
																	+ tabs
							 | 
						||
| 
								 | 
							
																	+ "**/\n"
							 | 
						||
| 
								 | 
							
																	+ tabs : "")
							 | 
						||
| 
								 | 
							
															+ (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join(" ") + " " : "")
							 | 
						||
| 
								 | 
							
															+ (switch (field.kind) {
							 | 
						||
| 
								 | 
							
																case FVar(t, _): field.name + opt(t, printComplexType, ":");
							 | 
						||
| 
								 | 
							
																case FProp(_, _, _, _): throw "FProp is invalid for TDEnum.";
							 | 
						||
| 
								 | 
							
																case FFun(func): field.name + printFunction(func);
							 | 
						||
| 
								 | 
							
															})
							 | 
						||
| 
								 | 
							
															+ ";"].join("\n")
							 | 
						||
| 
								 | 
							
													+ "\n}";
							 | 
						||
| 
								 | 
							
												case TDStructure:
							 | 
						||
| 
								 | 
							
													"typedef "
							 | 
						||
| 
								 | 
							
													+ t.name
							 | 
						||
| 
								 | 
							
													+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
													+ " = {\n"
							 | 
						||
| 
								 | 
							
													+ [
							 | 
						||
| 
								 | 
							
														for (f in t.fields) {
							 | 
						||
| 
								 | 
							
															tabs + printField(f) + ";";
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													].join("\n")
							 | 
						||
| 
								 | 
							
													+ "\n}";
							 | 
						||
| 
								 | 
							
												case TDClass(superClass, interfaces, isInterface, isFinal, isAbstract):
							 | 
						||
| 
								 | 
							
													(isFinal ? "final " : "")
							 | 
						||
| 
								 | 
							
														+ (isAbstract ? "abstract " : "")
							 | 
						||
| 
								 | 
							
														+ (isInterface ? "interface " : "class ")
							 | 
						||
| 
								 | 
							
														+ t.name
							 | 
						||
| 
								 | 
							
														+ (t.params != null && t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
														+ (superClass != null ? " extends " + printTypePath(superClass) : "")
							 | 
						||
| 
								 | 
							
														+ (interfaces != null ? (isInterface ? [for (tp in interfaces) " extends " + printTypePath(tp)] : [
							 | 
						||
| 
								 | 
							
															for (tp in interfaces)
							 | 
						||
| 
								 | 
							
																" implements " + printTypePath(tp)
							 | 
						||
| 
								 | 
							
														]).join("") : "")
							 | 
						||
| 
								 | 
							
														+ " {\n"
							 | 
						||
| 
								 | 
							
														+ [
							 | 
						||
| 
								 | 
							
															for (f in t.fields) {
							 | 
						||
| 
								 | 
							
																tabs + printFieldWithDelimiter(f);
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
														].join("\n")
							 | 
						||
| 
								 | 
							
														+ "\n}";
							 | 
						||
| 
								 | 
							
												case TDAlias(ct):
							 | 
						||
| 
								 | 
							
													"typedef "
							 | 
						||
| 
								 | 
							
													+ t.name
							 | 
						||
| 
								 | 
							
													+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
													+ " = "
							 | 
						||
| 
								 | 
							
													+ (switch (ct) {
							 | 
						||
| 
								 | 
							
														case TExtend(tpl, fields): printExtension(tpl, fields);
							 | 
						||
| 
								 | 
							
														case TAnonymous(fields): printStructure(fields);
							 | 
						||
| 
								 | 
							
														case _: printComplexType(ct);
							 | 
						||
| 
								 | 
							
													})
							 | 
						||
| 
								 | 
							
													+ ";";
							 | 
						||
| 
								 | 
							
												case TDAbstract(tthis, from, to):
							 | 
						||
| 
								 | 
							
													"abstract "
							 | 
						||
| 
								 | 
							
													+ t.name
							 | 
						||
| 
								 | 
							
													+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
							 | 
						||
| 
								 | 
							
													+ (tthis == null ? "" : "(" + printComplexType(tthis) + ")")
							 | 
						||
| 
								 | 
							
													+ (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join(""))
							 | 
						||
| 
								 | 
							
													+ (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join(""))
							 | 
						||
| 
								 | 
							
													+ " {\n"
							 | 
						||
| 
								 | 
							
													+ [
							 | 
						||
| 
								 | 
							
														for (f in t.fields) {
							 | 
						||
| 
								 | 
							
															tabs + printFieldWithDelimiter(f);
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													].join("\n")
							 | 
						||
| 
								 | 
							
													+ "\n}";
							 | 
						||
| 
								 | 
							
												case TDField(kind, access):
							 | 
						||
| 
								 | 
							
													tabs = old;
							 | 
						||
| 
								 | 
							
													(access != null && access.length > 0 ? access.map(printAccess).join(" ") + " " : "")
							 | 
						||
| 
								 | 
							
													+ switch (kind) {
							 | 
						||
| 
								 | 
							
														case FVar(type, eo): ((access != null && access.has(AFinal)) ? '' : 'var ') + '${t.name}' + opt(type, printComplexType, " : ") + opt(eo, printExpr, " = ") + ";";
							 | 
						||
| 
								 | 
							
														case FProp(get, set, type, eo): 'var ${t.name}($get, $set)' + opt(type, printComplexType, " : ") + opt(eo, printExpr, " = ") + ";";
							 | 
						||
| 
								 | 
							
														case FFun(func): 'function ${t.name}' + printFunction(func) + switch func.expr { case {expr: EBlock(_)}: ""; case _: ";"; };
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
											} tabs = old;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return str;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function printFieldWithDelimiter(f:Field):String {
							 | 
						||
| 
								 | 
							
										return printField(f) + switch (f.kind) {
							 | 
						||
| 
								 | 
							
											case FVar(_, _), FProp(_, _, _, _): ";";
							 | 
						||
| 
								 | 
							
											case FFun({expr: null}): ";";
							 | 
						||
| 
								 | 
							
											case FFun({expr: {expr: EBlock(_)}}): "";
							 | 
						||
| 
								 | 
							
											case FFun(_): ";";
							 | 
						||
| 
								 | 
							
											case _: "";
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function opt<T>(v:T, f:T->String, prefix = "")
							 | 
						||
| 
								 | 
							
										return v == null ? "" : (prefix + f(v));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function printExprWithPositions(e:Expr) {
							 | 
						||
| 
								 | 
							
										var buffer = new StringBuf();
							 | 
						||
| 
								 | 
							
										function format4(i:Int) {
							 | 
						||
| 
								 | 
							
											return StringTools.lpad(Std.string(i), " ", 4);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										function loop(tabs:String, e:Expr) {
							 | 
						||
| 
								 | 
							
											function add(s:String, ?p = null) {
							 | 
						||
| 
								 | 
							
												if (p == null) {
							 | 
						||
| 
								 | 
							
													p = e.pos;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												var p = #if macro haxe.macro.Context.getPosInfos(p) #else e.pos #end;
							 | 
						||
| 
								 | 
							
												buffer.add('${format4(p.min)}-${format4(p.max)} $tabs$s\n');
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											function loopI(e:Expr)
							 | 
						||
| 
								 | 
							
												loop(tabs + tabString, e);
							 | 
						||
| 
								 | 
							
											switch (e.expr) {
							 | 
						||
| 
								 | 
							
												case EConst(c):
							 | 
						||
| 
								 | 
							
													add(printConstant(c));
							 | 
						||
| 
								 | 
							
												case EArray(e1, e2):
							 | 
						||
| 
								 | 
							
													add("EArray");
							 | 
						||
| 
								 | 
							
													loopI(e1);
							 | 
						||
| 
								 | 
							
													loopI(e2);
							 | 
						||
| 
								 | 
							
												case EBinop(op, e1, e2):
							 | 
						||
| 
								 | 
							
													add("EBinop " + printBinop(op));
							 | 
						||
| 
								 | 
							
													loopI(e1);
							 | 
						||
| 
								 | 
							
													loopI(e2);
							 | 
						||
| 
								 | 
							
												case EField(e, field):
							 | 
						||
| 
								 | 
							
													add("EField " + field);
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EParenthesis(e):
							 | 
						||
| 
								 | 
							
													add("EParenthesis");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EObjectDecl(fields):
							 | 
						||
| 
								 | 
							
													add("EObjectDecl");
							 | 
						||
| 
								 | 
							
													for (field in fields) {
							 | 
						||
| 
								 | 
							
														add(field.field); // TODO: we don't have the field pos?
							 | 
						||
| 
								 | 
							
														loopI(field.expr);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EArrayDecl(values):
							 | 
						||
| 
								 | 
							
													add("EArrayDecl");
							 | 
						||
| 
								 | 
							
													values.iter(loopI);
							 | 
						||
| 
								 | 
							
												case ECall(e, params):
							 | 
						||
| 
								 | 
							
													add("ECall");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
													params.iter(loopI);
							 | 
						||
| 
								 | 
							
												case ENew(tp, params):
							 | 
						||
| 
								 | 
							
													add("ENew " + printTypePath(tp));
							 | 
						||
| 
								 | 
							
													params.iter(loopI);
							 | 
						||
| 
								 | 
							
												case EUnop(op, postFix, e):
							 | 
						||
| 
								 | 
							
													add("EUnop " + printUnop(op));
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EVars(vars):
							 | 
						||
| 
								 | 
							
													add("EVars");
							 | 
						||
| 
								 | 
							
													for (v in vars) {
							 | 
						||
| 
								 | 
							
														if (v.expr != null) {
							 | 
						||
| 
								 | 
							
															add(v.name);
							 | 
						||
| 
								 | 
							
															loopI(v.expr);
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EFunction(_, f):
							 | 
						||
| 
								 | 
							
													add("EFunction");
							 | 
						||
| 
								 | 
							
													if (f.expr != null) {
							 | 
						||
| 
								 | 
							
														loopI(f.expr);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EBlock(exprs):
							 | 
						||
| 
								 | 
							
													add("EBlock");
							 | 
						||
| 
								 | 
							
													exprs.iter(loopI);
							 | 
						||
| 
								 | 
							
												case EFor(it, expr):
							 | 
						||
| 
								 | 
							
													add("EFor");
							 | 
						||
| 
								 | 
							
													loopI(it);
							 | 
						||
| 
								 | 
							
													loopI(expr);
							 | 
						||
| 
								 | 
							
												case EIf(econd, eif, eelse):
							 | 
						||
| 
								 | 
							
													add("EIf");
							 | 
						||
| 
								 | 
							
													loopI(econd);
							 | 
						||
| 
								 | 
							
													loopI(eif);
							 | 
						||
| 
								 | 
							
													if (eelse != null) {
							 | 
						||
| 
								 | 
							
														loopI(eelse);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EWhile(econd, e, normalWhile):
							 | 
						||
| 
								 | 
							
													add("EWhile");
							 | 
						||
| 
								 | 
							
													loopI(econd);
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case ESwitch(e, cases, edef):
							 | 
						||
| 
								 | 
							
													add("ESwitch");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
													for (c in cases) {
							 | 
						||
| 
								 | 
							
														for (pat in c.values) {
							 | 
						||
| 
								 | 
							
															loop(tabs + tabString + tabString, pat);
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
														if (c.expr != null) {
							 | 
						||
| 
								 | 
							
															loop(tabs + tabString + tabString + tabString, c.expr);
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													if (edef != null) {
							 | 
						||
| 
								 | 
							
														loop(tabs + tabString + tabString + tabString, edef);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case ETry(e, catches):
							 | 
						||
| 
								 | 
							
													add("ETry");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
													for (c in catches) {
							 | 
						||
| 
								 | 
							
														loop(tabs + tabString + tabString, c.expr);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EReturn(e):
							 | 
						||
| 
								 | 
							
													add("EReturn");
							 | 
						||
| 
								 | 
							
													if (e != null) {
							 | 
						||
| 
								 | 
							
														loopI(e);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												case EBreak:
							 | 
						||
| 
								 | 
							
													add("EBreak");
							 | 
						||
| 
								 | 
							
												case EContinue:
							 | 
						||
| 
								 | 
							
													add("EContinue");
							 | 
						||
| 
								 | 
							
												case EUntyped(e):
							 | 
						||
| 
								 | 
							
													add("EUntyped");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EThrow(e):
							 | 
						||
| 
								 | 
							
													add("EThrow");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case ECast(e, t):
							 | 
						||
| 
								 | 
							
													add("ECast");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EIs(e, t):
							 | 
						||
| 
								 | 
							
													add("EIs");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EDisplay(e, displayKind):
							 | 
						||
| 
								 | 
							
													add("EDisplay");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EDisplayNew(t):
							 | 
						||
| 
								 | 
							
													add("EDisplayNew");
							 | 
						||
| 
								 | 
							
												case ETernary(econd, eif, eelse):
							 | 
						||
| 
								 | 
							
													add("ETernary");
							 | 
						||
| 
								 | 
							
													loopI(econd);
							 | 
						||
| 
								 | 
							
													loopI(eif);
							 | 
						||
| 
								 | 
							
													loopI(eelse);
							 | 
						||
| 
								 | 
							
												case ECheckType(e, t):
							 | 
						||
| 
								 | 
							
													add("ECheckType");
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
												case EMeta(s, e):
							 | 
						||
| 
								 | 
							
													add("EMeta " + printMetadata(s));
							 | 
						||
| 
								 | 
							
													loopI(e);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										loop("", e);
							 | 
						||
| 
								 | 
							
										return buffer.toString();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |