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();
|
|
}
|
|
}
|