Chromium Code Reviews| Index: pkg/js_ast/lib/src/printer.dart |
| diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart |
| index f362be5646b37857287498760cd5c6115d57283e..f6f0324408e11309e36c06395a663ba163710d72 100644 |
| --- a/pkg/js_ast/lib/src/printer.dart |
| +++ b/pkg/js_ast/lib/src/printer.dart |
| @@ -26,11 +26,24 @@ abstract class JavaScriptPrintingContext { |
| /// Adds [string] to the output. |
| void emit(String string); |
| - /// Callback immediately before printing [node]. Whitespace may be printed |
| - /// after this callback before the first non-whitespace character for [node]. |
| - void enterNode(Node node) {} |
| - /// Callback after printing the last character representing [node]. |
| - void exitNode(Node node) {} |
| + /// Callback for the start of printing of [node]. [startPosition] is the |
| + /// position of the first non-whitespace character of [node]. |
| + /// |
| + /// [enterNode] is called in pre-traversal order. |
| + void enterNode(Node node, int startPosition) {} |
| + |
| + /// Callback for the end of printing of [node]. [startPosition] is the |
| + /// position of the first non-whitespace character of [node] (also provided |
| + /// in the [enterNode] callback), [endPosition] is the position immediately |
| + /// following the last character of [node]. [delimiterPosition] is the |
| + /// position of the ending delimiter of [node]. This is only provided for |
| + /// [Fun] nodes and is `null` otherwise. |
| + /// |
| + /// [enterNode] is called in post-traversal order. |
| + void exitNode(Node node, |
| + int startPosition, |
| + int endPosition, |
| + int delimiterPosition) {} |
|
sra1
2015/04/14 21:54:44
Perhaps call this 'closingPosition' (throughout)
'
Johnni Winther
2015/04/15 11:15:28
Done.
|
| } |
| /// A simple implementation of [JavaScriptPrintingContext] suitable for tests. |
| @@ -52,6 +65,7 @@ class Printer implements NodeVisitor { |
| final DanglingElseVisitor danglingElseVisitor; |
| final LocalNamer localNamer; |
| + int _charCount = 0; |
| bool inForInit = false; |
| bool atStatementBegin = false; |
| bool pendingSemicolon = false; |
| @@ -98,31 +112,33 @@ class Printer implements NodeVisitor { |
| _indentLevel--; |
| } |
| - |
| /// Always emit a newline, even under `enableMinification`. |
| void forceLine() { |
| - out("\n"); |
| + out("\n", isWhitespace: true); |
| } |
| + |
| /// Emits a newline for readability. |
| void lineOut() { |
| if (!shouldCompressOutput) forceLine(); |
| } |
| + |
| void spaceOut() { |
| - if (!shouldCompressOutput) out(" "); |
| + if (!shouldCompressOutput) out(" ", isWhitespace: true); |
| } |
| String lastAddedString = null; |
| + |
| int get lastCharCode { |
| if (lastAddedString == null) return 0; |
| assert(lastAddedString.length != ""); |
| return lastAddedString.codeUnitAt(lastAddedString.length - 1); |
| } |
| - void out(String str) { |
| + void out(String str, {bool isWhitespace: false}) { |
| if (str != "") { |
| if (pendingSemicolon) { |
| if (!shouldCompressOutput) { |
| - context.emit(";"); |
| + _emit(";"); |
| } else if (str != "}") { |
| // We want to output newline instead of semicolon because it makes |
| // the raw stack traces much easier to read and it also makes line- |
| @@ -137,19 +153,22 @@ class Printer implements NodeVisitor { |
| // than newlines because the former doesn't need escaping. |
| if (options.preferSemicolonToNewlineInMinifiedOutput || |
| expressionContinuationRegExp.hasMatch(str)) { |
| - context.emit(";"); |
| + _emit(";"); |
| } else { |
| - context.emit("\n"); |
| + _emit("\n"); |
| } |
| } |
| } |
| if (pendingSpace && |
| (!shouldCompressOutput || identifierCharacterRegExp.hasMatch(str))) { |
| - context.emit(" "); |
| + _emit(" "); |
| } |
| pendingSpace = false; |
| pendingSemicolon = false; |
| - context.emit(str); |
| + if (!isWhitespace) { |
| + enterNode(); |
| + } |
| + _emit(str); |
| lastAddedString = str; |
| } |
| } |
| @@ -168,22 +187,49 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - void outIndent(String str) { indent(); out(str); } |
| - void outIndentLn(String str) { indent(); outLn(str); } |
| + void outIndent(String str) { |
| + indent(); out(str); |
|
sra1
2015/04/14 19:14:00
two lines
Johnni Winther
2015/04/15 11:15:28
Done.
|
| + } |
| + |
| + void outIndentLn(String str) { |
| + indent(); outLn(str); |
| + } |
| + |
| void indent() { |
| if (!shouldCompressOutput) { |
| - out(indentation); |
| + out(indentation, isWhitespace: true); |
| } |
| } |
| - visit(Node node) { |
| - context.enterNode(node); |
| + EnterExitNode currentNode; |
| + |
| + void _emit(String text) { |
| + context.emit(text); |
| + _charCount += text.length; |
| + } |
| + |
| + void startNode(Node node) { |
| + currentNode = new EnterExitNode(currentNode, node); |
| + } |
| + |
| + void enterNode() { |
| + currentNode.enterNode(context, _charCount); |
| + } |
| + |
| + void endNode(Node node) { |
| + //print('currentNode.node=${currentNode.node} node=$node'); |
|
floitsch
2015/04/14 15:09:31
debugprint.
Johnni Winther
2015/04/15 11:15:28
Removed.
|
| + assert(currentNode.node == node); |
| + currentNode = currentNode.exitNode(context, _charCount); |
| + } |
| + |
| + void visit(Node node) { |
| + startNode(node); |
| node.accept(this); |
| - context.exitNode(node); |
| + endNode(node); |
| } |
| - visitCommaSeparated(List<Node> nodes, int hasRequiredType, |
| - {bool newInForInit, bool newAtStatementBegin}) { |
| + void visitCommaSeparated(List<Node> nodes, int hasRequiredType, |
| + {bool newInForInit, bool newAtStatementBegin}) { |
| for (int i = 0; i < nodes.length; i++) { |
| if (i != 0) { |
| atStatementBegin = false; |
| @@ -196,12 +242,15 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitAll(List<Node> nodes) { |
| + void visitAll(List<Node> nodes) { |
| nodes.forEach(visit); |
| } |
| - visitProgram(Program program) { |
| - visitAll(program.body); |
| + @override |
| + void visitProgram(Program program) { |
| + if (program.body.isNotEmpty) { |
| + visitAll(program.body); |
| + } |
| } |
| Statement unwrapBlockIfSingleStatement(Statement body) { |
| @@ -223,7 +272,7 @@ class Printer implements NodeVisitor { |
| if (shouldCompressOutput && needsSeparation) { |
| // If [shouldCompressOutput] is false, then the 'lineOut' will insert |
| // the separation. |
| - out(" "); |
| + out(" ", isWhitespace: true); |
| } else { |
| lineOut(); |
| } |
| @@ -235,18 +284,18 @@ class Printer implements NodeVisitor { |
| void blockOutWithoutBraces(Node node) { |
| if (node is Block) { |
| - context.enterNode(node); |
| + startNode(node); |
| Block block = node; |
| block.statements.forEach(blockOutWithoutBraces); |
| - context.exitNode(node); |
| + endNode(node); |
| } else { |
| visit(node); |
| } |
| } |
| - void blockOut(Block node, {bool shouldIndent, bool needsNewline}) { |
| + int blockOut(Block node, {bool shouldIndent, bool needsNewline}) { |
| if (shouldIndent) indent(); |
| - context.enterNode(node); |
| + startNode(node); |
| out("{"); |
| lineOut(); |
| indentMore(); |
| @@ -254,22 +303,27 @@ class Printer implements NodeVisitor { |
| indentLess(); |
| indent(); |
| out("}"); |
| - context.exitNode(node); |
| + int delimiterPosition = _charCount - 1; |
| + endNode(node); |
| if (needsNewline) lineOut(); |
| + return delimiterPosition; |
| } |
| - visitBlock(Block block) { |
| + @override |
| + void visitBlock(Block block) { |
| blockOut(block, shouldIndent: true, needsNewline: true); |
| } |
| - visitExpressionStatement(ExpressionStatement expressionStatement) { |
| + @override |
| + void visitExpressionStatement(ExpressionStatement node) { |
| indent(); |
| - visitNestedExpression(expressionStatement.expression, EXPRESSION, |
| + visitNestedExpression(node.expression, EXPRESSION, |
| newInForInit: false, newAtStatementBegin: true); |
| outSemicolonLn(); |
| } |
| - visitEmptyStatement(EmptyStatement nop) { |
| + @override |
| + void visitEmptyStatement(EmptyStatement node) { |
| outIndentLn(";"); |
| } |
| @@ -313,11 +367,13 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitIf(If node) { |
| + @override |
| + void visitIf(If node) { |
| ifOut(node, true); |
| } |
| - visitFor(For loop) { |
| + @override |
| + void visitFor(For loop) { |
| outIndent("for"); |
| spaceOut(); |
| out("("); |
| @@ -342,7 +398,8 @@ class Printer implements NodeVisitor { |
| needsSeparation: false, needsNewline: true); |
| } |
| - visitForIn(ForIn loop) { |
| + @override |
| + void visitForIn(ForIn loop) { |
| outIndent("for"); |
| spaceOut(); |
| out("("); |
| @@ -357,7 +414,8 @@ class Printer implements NodeVisitor { |
| needsSeparation: false, needsNewline: true); |
| } |
| - visitWhile(While loop) { |
| + @override |
| + void visitWhile(While loop) { |
| outIndent("while"); |
| spaceOut(); |
| out("("); |
| @@ -368,7 +426,8 @@ class Printer implements NodeVisitor { |
| needsSeparation: false, needsNewline: true); |
| } |
| - visitDo(Do loop) { |
| + @override |
| + void visitDo(Do loop) { |
| outIndent("do"); |
| if (blockBody(unwrapBlockIfSingleStatement(loop.body), |
| needsSeparation: true, needsNewline: false)) { |
| @@ -385,7 +444,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - visitContinue(Continue node) { |
| + @override |
| + void visitContinue(Continue node) { |
| if (node.targetLabel == null) { |
| outIndent("continue"); |
| } else { |
| @@ -394,7 +454,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - visitBreak(Break node) { |
| + @override |
| + void visitBreak(Break node) { |
| if (node.targetLabel == null) { |
| outIndent("break"); |
| } else { |
| @@ -403,7 +464,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - visitReturn(Return node) { |
| + @override |
| + void visitReturn(Return node) { |
| if (node.value == null) { |
| outIndent("return"); |
| } else { |
| @@ -415,7 +477,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - visitDartYield(DartYield node) { |
| + @override |
| + void visitDartYield(DartYield node) { |
| if (node.hasStar) { |
| outIndent("yield*"); |
| } else { |
| @@ -427,8 +490,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - |
| - visitThrow(Throw node) { |
| + @override |
| + void visitThrow(Throw node) { |
| outIndent("throw"); |
| pendingSpace = true; |
| visitNestedExpression(node.expression, EXPRESSION, |
| @@ -436,7 +499,8 @@ class Printer implements NodeVisitor { |
| outSemicolonLn(); |
| } |
| - visitTry(Try node) { |
| + @override |
| + void visitTry(Try node) { |
| outIndent("try"); |
| blockBody(node.body, needsSeparation: true, needsNewline: false); |
| if (node.catchPart != null) { |
| @@ -451,7 +515,8 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitCatch(Catch node) { |
| + @override |
| + void visitCatch(Catch node) { |
| spaceOut(); |
| out("catch"); |
| spaceOut(); |
| @@ -462,7 +527,8 @@ class Printer implements NodeVisitor { |
| blockBody(node.body, needsSeparation: false, needsNewline: false); |
| } |
| - visitSwitch(Switch node) { |
| + @override |
| + void visitSwitch(Switch node) { |
| outIndent("switch"); |
| spaceOut(); |
| out("("); |
| @@ -477,7 +543,8 @@ class Printer implements NodeVisitor { |
| outIndentLn("}"); |
| } |
| - visitCase(Case node) { |
| + @override |
| + void visitCase(Case node) { |
| outIndent("case"); |
| pendingSpace = true; |
| visitNestedExpression(node.expression, EXPRESSION, |
| @@ -490,7 +557,8 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitDefault(Default node) { |
| + @override |
| + void visitDefault(Default node) { |
| outIndentLn("default:"); |
| if (!node.body.statements.isEmpty) { |
| indentMore(); |
| @@ -499,7 +567,8 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitLabeledStatement(LabeledStatement node) { |
| + @override |
| + void visitLabeledStatement(LabeledStatement node) { |
| Statement body = unwrapBlockIfSingleStatement(node.body); |
| // `label: break label;` |
| // Does not work on IE. The statement is a nop, so replace it by an empty |
| @@ -514,7 +583,7 @@ class Printer implements NodeVisitor { |
| blockBody(body, needsSeparation: false, needsNewline: true); |
| } |
| - void functionOut(Fun fun, Node name, VarCollector vars) { |
| + int functionOut(Fun fun, Node name, VarCollector vars) { |
| out("function"); |
| if (name != null) { |
| out(" "); |
| @@ -533,19 +602,24 @@ class Printer implements NodeVisitor { |
| case const AsyncModifier.sync(): |
| break; |
| case const AsyncModifier.async(): |
| - out(' async'); |
| + out(' ', isWhitespace: true); out('async'); |
|
sra1
2015/04/14 19:14:00
multiple lines
Johnni Winther
2015/04/15 11:15:28
Done.
|
| break; |
| case const AsyncModifier.syncStar(): |
| - out(' sync*'); |
| + out(' ', isWhitespace: true); out('sync*'); |
| break; |
| case const AsyncModifier.asyncStar(): |
| - out(' async*'); |
| + out(' ', isWhitespace: true); out('async*'); |
| break; |
| } |
| - blockBody(fun.body, needsSeparation: false, needsNewline: false); |
| + spaceOut(); |
| + int delimiterPosition = |
| + blockOut(fun.body, shouldIndent: false, needsNewline: false); |
| localNamer.leaveScope(); |
| + return delimiterPosition; |
| + |
| } |
| + @override |
| visitFunctionDeclaration(FunctionDeclaration declaration) { |
| VarCollector vars = new VarCollector(); |
| vars.visitFunctionDeclaration(declaration); |
| @@ -580,12 +654,14 @@ class Printer implements NodeVisitor { |
| } |
| } |
| + @override |
| visitVariableDeclarationList(VariableDeclarationList list) { |
| out("var "); |
| visitCommaSeparated(list.declarations, ASSIGNMENT, |
| newInForInit: inForInit, newAtStatementBegin: false); |
| } |
| + @override |
| visitAssignment(Assignment assignment) { |
| visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, |
| newInForInit: inForInit, |
| @@ -602,10 +678,12 @@ class Printer implements NodeVisitor { |
| } |
| } |
| + @override |
| visitVariableInitialization(VariableInitialization initialization) { |
| visitAssignment(initialization); |
| } |
| + @override |
| visitConditional(Conditional cond) { |
| visitNestedExpression(cond.condition, LOGICAL_OR, |
| newInForInit: inForInit, |
| @@ -623,6 +701,7 @@ class Printer implements NodeVisitor { |
| newInForInit: inForInit, newAtStatementBegin: false); |
| } |
| + @override |
| visitNew(New node) { |
| out("new "); |
| visitNestedExpression(node.target, CALL, |
| @@ -633,6 +712,7 @@ class Printer implements NodeVisitor { |
| out(")"); |
| } |
| + @override |
| visitCall(Call call) { |
| visitNestedExpression(call.target, LEFT_HAND_SIDE, |
| newInForInit: inForInit, |
| @@ -643,7 +723,8 @@ class Printer implements NodeVisitor { |
| out(")"); |
| } |
| - visitBinary(Binary binary) { |
| + @override |
| + void visitBinary(Binary binary) { |
| Expression left = binary.left; |
| Expression right = binary.right; |
| String op = binary.op; |
| @@ -732,9 +813,9 @@ class Printer implements NodeVisitor { |
| if (op == "in" || op == "instanceof") { |
| // There are cases where the space is not required but without further |
| // analysis we cannot know. |
| - out(" "); |
| + out(" ", isWhitespace: true); |
| out(op); |
| - out(" "); |
| + out(" ", isWhitespace: true); |
| } else { |
| if (leftSpace) spaceOut(); |
| out(op); |
| @@ -745,7 +826,8 @@ class Printer implements NodeVisitor { |
| newAtStatementBegin: false); |
| } |
| - visitPrefix(Prefix unary) { |
| + @override |
| + void visitPrefix(Prefix unary) { |
| String op = unary.op; |
| switch (op) { |
| case "delete": |
| @@ -754,16 +836,16 @@ class Printer implements NodeVisitor { |
| // There are cases where the space is not required but without further |
| // analysis we cannot know. |
| out(op); |
| - out(" "); |
| + out(" ", isWhitespace: true); |
| break; |
| case "+": |
| case "++": |
| - if (lastCharCode == charCodes.$PLUS) out(" "); |
| + if (lastCharCode == charCodes.$PLUS) out(" ", isWhitespace: true); |
| out(op); |
| break; |
| case "-": |
| case "--": |
| - if (lastCharCode == charCodes.$MINUS) out(" "); |
| + if (lastCharCode == charCodes.$MINUS) out(" ", isWhitespace: true); |
| out(op); |
| break; |
| default: |
| @@ -773,26 +855,31 @@ class Printer implements NodeVisitor { |
| newInForInit: inForInit, newAtStatementBegin: false); |
| } |
| - visitPostfix(Postfix postfix) { |
| + @override |
| + void visitPostfix(Postfix postfix) { |
| visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, |
| newInForInit: inForInit, |
| newAtStatementBegin: atStatementBegin); |
| out(postfix.op); |
| } |
| - visitVariableUse(VariableUse ref) { |
| + @override |
| + void visitVariableUse(VariableUse ref) { |
| out(localNamer.getName(ref.name)); |
| } |
| - visitThis(This node) { |
| + @override |
| + void visitThis(This node) { |
| out("this"); |
| } |
| - visitVariableDeclaration(VariableDeclaration decl) { |
| + @override |
| + void visitVariableDeclaration(VariableDeclaration decl) { |
| out(localNamer.getName(decl.name)); |
| } |
| - visitParameter(Parameter param) { |
| + @override |
| + void visitParameter(Parameter param) { |
| out(localNamer.getName(param.name)); |
| } |
| @@ -821,7 +908,8 @@ class Printer implements NodeVisitor { |
| return true; |
| } |
| - visitAccess(PropertyAccess access) { |
| + @override |
| + void visitAccess(PropertyAccess access) { |
| visitNestedExpression(access.receiver, CALL, |
| newInForInit: inForInit, |
| newAtStatementBegin: atStatementBegin); |
| @@ -830,7 +918,7 @@ class Printer implements NodeVisitor { |
| LiteralString selectorString = selector; |
| String fieldWithQuotes = selectorString.value; |
| if (isValidJavaScriptId(fieldWithQuotes)) { |
| - if (access.receiver is LiteralNumber) out(" "); |
| + if (access.receiver is LiteralNumber) out(" ", isWhitespace: true); |
| out("."); |
| out(fieldWithQuotes.substring(1, fieldWithQuotes.length - 1)); |
| return; |
| @@ -842,39 +930,49 @@ class Printer implements NodeVisitor { |
| out("]"); |
| } |
| - visitNamedFunction(NamedFunction namedFunction) { |
| + @override |
| + void visitNamedFunction(NamedFunction namedFunction) { |
| VarCollector vars = new VarCollector(); |
| vars.visitNamedFunction(namedFunction); |
| - functionOut(namedFunction.function, namedFunction.name, vars); |
| + startNode(namedFunction.function); |
| + currentNode.delimiterPosition = |
| + functionOut(namedFunction.function, namedFunction.name, vars); |
| + endNode(namedFunction.function); |
| } |
| - visitFun(Fun fun) { |
| + @override |
| + void visitFun(Fun fun) { |
| VarCollector vars = new VarCollector(); |
| vars.visitFun(fun); |
| - functionOut(fun, null, vars); |
| + currentNode.delimiterPosition = functionOut(fun, null, vars); |
| } |
| - visitLiteralBool(LiteralBool node) { |
| + @override |
| + void visitLiteralBool(LiteralBool node) { |
| out(node.value ? "true" : "false"); |
| } |
| - visitLiteralString(LiteralString node) { |
| + @override |
| + void visitLiteralString(LiteralString node) { |
| out(node.value); |
| } |
| - visitLiteralNumber(LiteralNumber node) { |
| + @override |
| + void visitLiteralNumber(LiteralNumber node) { |
| int charCode = node.value.codeUnitAt(0); |
| if (charCode == charCodes.$MINUS && lastCharCode == charCodes.$MINUS) { |
| - out(" "); |
| + out(" ", isWhitespace: true); |
| } |
| out(node.value); |
| } |
| - visitLiteralNull(LiteralNull node) { |
| + @override |
| + void visitLiteralNull(LiteralNull node) { |
| out("null"); |
| } |
| - visitArrayInitializer(ArrayInitializer node) { |
| + @override |
| + void visitArrayInitializer(ArrayInitializer node) { |
| out("["); |
| List<Expression> elements = node.elements; |
| for (int i = 0; i < elements.length; i++) { |
| @@ -897,11 +995,13 @@ class Printer implements NodeVisitor { |
| out("]"); |
| } |
| - visitArrayHole(ArrayHole node) { |
| + @override |
| + void visitArrayHole(ArrayHole node) { |
| throw "Unreachable"; |
| } |
| - visitObjectInitializer(ObjectInitializer node) { |
| + @override |
| + void visitObjectInitializer(ObjectInitializer node) { |
| // Print all the properties on one line until we see a function-valued |
| // property. Ideally, we would use a proper pretty-printer to make the |
| // decision based on layout. |
| @@ -928,7 +1028,8 @@ class Printer implements NodeVisitor { |
| out("}"); |
| } |
| - visitProperty(Property node) { |
| + @override |
| + void visitProperty(Property node) { |
| if (node.name is LiteralString) { |
| LiteralString nameString = node.name; |
| String name = nameString.value; |
| @@ -948,11 +1049,13 @@ class Printer implements NodeVisitor { |
| newInForInit: false, newAtStatementBegin: false); |
| } |
| - visitRegExpLiteral(RegExpLiteral node) { |
| + @override |
| + void visitRegExpLiteral(RegExpLiteral node) { |
| out(node.pattern); |
| } |
| - visitLiteralExpression(LiteralExpression node) { |
| + @override |
| + void visitLiteralExpression(LiteralExpression node) { |
| String template = node.template; |
| List<Expression> inputs = node.inputs; |
| @@ -970,34 +1073,42 @@ class Printer implements NodeVisitor { |
| } |
| } |
| - visitLiteralStatement(LiteralStatement node) { |
| + @override |
| + void visitLiteralStatement(LiteralStatement node) { |
| outLn(node.code); |
| } |
| - visitInterpolatedNode(InterpolatedNode node) { |
| + void visitInterpolatedNode(InterpolatedNode node) { |
| out('#${node.nameOrPosition}'); |
| } |
| - visitInterpolatedExpression(InterpolatedExpression node) => |
| + @override |
| + void visitInterpolatedExpression(InterpolatedExpression node) => |
| visitInterpolatedNode(node); |
| - visitInterpolatedLiteral(InterpolatedLiteral node) => |
| + @override |
| + void visitInterpolatedLiteral(InterpolatedLiteral node) => |
| visitInterpolatedNode(node); |
| - visitInterpolatedParameter(InterpolatedParameter node) => |
| + @override |
| + void visitInterpolatedParameter(InterpolatedParameter node) => |
| visitInterpolatedNode(node); |
| - visitInterpolatedSelector(InterpolatedSelector node) => |
| + @override |
| + void visitInterpolatedSelector(InterpolatedSelector node) => |
| visitInterpolatedNode(node); |
| - visitInterpolatedStatement(InterpolatedStatement node) { |
| + @override |
| + void visitInterpolatedStatement(InterpolatedStatement node) { |
| outLn('#${node.nameOrPosition}'); |
| } |
| - visitInterpolatedDeclaration(InterpolatedDeclaration node) { |
| + @override |
| + void visitInterpolatedDeclaration(InterpolatedDeclaration node) { |
| visitInterpolatedNode(node); |
| } |
| + @override |
| void visitComment(Comment node) { |
| if (shouldCompressOutput) return; |
| String comment = node.comment.trim(); |
| @@ -1011,6 +1122,7 @@ class Printer implements NodeVisitor { |
| } |
| } |
| + @override |
| void visitAwait(Await node) { |
| out("await "); |
| visit(node.expression); |
| @@ -1025,8 +1137,8 @@ class OrderedSet<T> { |
| OrderedSet() : set = new Set<T>(), list = <T>[]; |
| void add(T x) { |
| - if (!set.contains(x)) { |
| - set.add(x); |
| + if (set.add(x)) { |
| + // [Set.add] returns `true` if 'x' was added. |
| list.add(x); |
| } |
| } |
| @@ -1274,3 +1386,31 @@ class MinifyRenamer implements LocalNamer { |
| return newName; |
| } |
| } |
| + |
| +/// Information pertaining the enter and exit callbacks for [node]. |
| +class EnterExitNode { |
| + final EnterExitNode parent; |
| + final Node node; |
| + |
| + int startPosition; |
| + int delimiterPosition; |
| + |
| + EnterExitNode(this.parent, this.node); |
| + |
| + void enterNode(JavaScriptPrintingContext context, int position) { |
|
sra1
2015/04/14 19:14:00
Perhaps 'addToNode' is a better name.
On an If nod
Johnni Winther
2015/04/15 11:15:28
Done.
|
| + if (parent != null) { |
| + parent.enterNode(context, position); |
|
sra1
2015/04/14 19:14:00
This multiplies the cost of printing by the tree h
sra1
2015/04/14 21:54:44
I ran this command 5 times in a row. Emitting is
Johnni Winther
2015/04/15 11:15:28
Moved the parent call under the `startPosition ==
|
| + } |
| + if (startPosition == null) { |
| + startPosition = position; |
| + context.enterNode(node, position); |
| + } |
| + } |
| + |
| + EnterExitNode exitNode(JavaScriptPrintingContext context, int position) { |
| + // Enter must happen before exit. |
| + enterNode(context, position); |
| + context.exitNode(node, startPosition, position, delimiterPosition); |
| + return parent; |
| + } |
| +} |