| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of js_ast; | 5 part of js_ast; |
| 6 | 6 |
| 7 | |
| 8 class JavaScriptPrintingOptions { | 7 class JavaScriptPrintingOptions { |
| 9 final bool shouldCompressOutput; | 8 final bool shouldCompressOutput; |
| 10 final bool minifyLocalVariables; | 9 final bool minifyLocalVariables; |
| 11 final bool preferSemicolonToNewlineInMinifiedOutput; | 10 final bool preferSemicolonToNewlineInMinifiedOutput; |
| 12 final bool emitTypes; | 11 final bool emitTypes; |
| 13 final bool allowSingleLineIfStatements; | 12 final bool allowSingleLineIfStatements; |
| 14 | 13 |
| 15 /// True to allow keywords in properties, such as `obj.var` or `obj.function` | 14 /// True to allow keywords in properties, such as `obj.var` or `obj.function` |
| 16 /// Modern JS engines support this. | 15 /// Modern JS engines support this. |
| 17 final bool allowKeywordsInProperties; | 16 final bool allowKeywordsInProperties; |
| 18 | 17 |
| 19 JavaScriptPrintingOptions( | 18 JavaScriptPrintingOptions( |
| 20 {this.shouldCompressOutput: false, | 19 {this.shouldCompressOutput: false, |
| 21 this.minifyLocalVariables: false, | 20 this.minifyLocalVariables: false, |
| 22 this.preferSemicolonToNewlineInMinifiedOutput: false, | 21 this.preferSemicolonToNewlineInMinifiedOutput: false, |
| 23 this.emitTypes: false, | 22 this.emitTypes: false, |
| 24 this.allowKeywordsInProperties: false, | 23 this.allowKeywordsInProperties: false, |
| 25 this.allowSingleLineIfStatements: false}); | 24 this.allowSingleLineIfStatements: false}); |
| 26 } | 25 } |
| 27 | 26 |
| 28 | |
| 29 /// An environment in which JavaScript printing is done. Provides emitting of | 27 /// An environment in which JavaScript printing is done. Provides emitting of |
| 30 /// text and pre- and post-visit callbacks. | 28 /// text and pre- and post-visit callbacks. |
| 31 abstract class JavaScriptPrintingContext { | 29 abstract class JavaScriptPrintingContext { |
| 32 /// Signals an error. This should happen only for serious internal errors. | 30 /// Signals an error. This should happen only for serious internal errors. |
| 33 void error(String message) { throw message; } | 31 void error(String message) { |
| 32 throw message; |
| 33 } |
| 34 | 34 |
| 35 /// Adds [string] to the output. | 35 /// Adds [string] to the output. |
| 36 void emit(String string); | 36 void emit(String string); |
| 37 | 37 |
| 38 /// Callback immediately before printing [node]. Whitespace may be printed | 38 /// Callback immediately before printing [node]. Whitespace may be printed |
| 39 /// after this callback before the first non-whitespace character for [node]. | 39 /// after this callback before the first non-whitespace character for [node]. |
| 40 void enterNode(Node node) {} | 40 void enterNode(Node node) {} |
| 41 |
| 41 /// Callback after printing the last character representing [node]. | 42 /// Callback after printing the last character representing [node]. |
| 42 void exitNode(Node node) {} | 43 void exitNode(Node node) {} |
| 43 } | 44 } |
| 44 | 45 |
| 45 /// A simple implementation of [JavaScriptPrintingContext] suitable for tests. | 46 /// A simple implementation of [JavaScriptPrintingContext] suitable for tests. |
| 46 class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext { | 47 class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext { |
| 47 final StringBuffer buffer = new StringBuffer(); | 48 final StringBuffer buffer = new StringBuffer(); |
| 48 | 49 |
| 49 void emit(String string) { | 50 void emit(String string) { |
| 50 buffer.write(string); | 51 buffer.write(string); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 65 bool inForInit = false; | 66 bool inForInit = false; |
| 66 bool atStatementBegin = false; | 67 bool atStatementBegin = false; |
| 67 bool inNewTarget = false; | 68 bool inNewTarget = false; |
| 68 bool pendingSemicolon = false; | 69 bool pendingSemicolon = false; |
| 69 bool pendingSpace = false; | 70 bool pendingSpace = false; |
| 70 | 71 |
| 71 // The current indentation level. | 72 // The current indentation level. |
| 72 int _indentLevel = 0; | 73 int _indentLevel = 0; |
| 73 // A cache of all indentation strings used so far. | 74 // A cache of all indentation strings used so far. |
| 74 List<String> _indentList = <String>[""]; | 75 List<String> _indentList = <String>[""]; |
| 76 |
| 75 /// Whether the next call to [indent] should just be a no-op. | 77 /// Whether the next call to [indent] should just be a no-op. |
| 76 bool _skipNextIndent = false; | 78 bool _skipNextIndent = false; |
| 77 | 79 |
| 78 static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]'); | 80 static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]'); |
| 79 static final expressionContinuationRegExp = new RegExp(r'^[-+([]'); | 81 static final expressionContinuationRegExp = new RegExp(r'^[-+([]'); |
| 80 | 82 |
| 81 Printer(JavaScriptPrintingOptions options, | 83 Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context, |
| 82 JavaScriptPrintingContext context, | 84 {LocalNamer localNamer}) |
| 83 {LocalNamer localNamer}) | |
| 84 : options = options, | 85 : options = options, |
| 85 context = context, | 86 context = context, |
| 86 shouldCompressOutput = options.shouldCompressOutput, | 87 shouldCompressOutput = options.shouldCompressOutput, |
| 87 danglingElseVisitor = new DanglingElseVisitor(context), | 88 danglingElseVisitor = new DanglingElseVisitor(context), |
| 88 localNamer = determineRenamer(localNamer, options); | 89 localNamer = determineRenamer(localNamer, options); |
| 89 | 90 |
| 90 static LocalNamer determineRenamer(LocalNamer localNamer, | 91 static LocalNamer determineRenamer( |
| 91 JavaScriptPrintingOptions options) { | 92 LocalNamer localNamer, JavaScriptPrintingOptions options) { |
| 92 if (localNamer != null) return localNamer; | 93 if (localNamer != null) return localNamer; |
| 93 return (options.shouldCompressOutput && options.minifyLocalVariables) | 94 return (options.shouldCompressOutput && options.minifyLocalVariables) |
| 94 ? new MinifyRenamer() : new IdentityNamer(); | 95 ? new MinifyRenamer() |
| 96 : new IdentityNamer(); |
| 95 } | 97 } |
| 96 | 98 |
| 97 | |
| 98 // The current indentation string. | 99 // The current indentation string. |
| 99 String get indentation { | 100 String get indentation { |
| 100 // Lazily add new indentation strings as required. | 101 // Lazily add new indentation strings as required. |
| 101 while (_indentList.length <= _indentLevel) { | 102 while (_indentList.length <= _indentLevel) { |
| 102 _indentList.add(_indentList.last + " "); | 103 _indentList.add(_indentList.last + " "); |
| 103 } | 104 } |
| 104 return _indentList[_indentLevel]; | 105 return _indentList[_indentLevel]; |
| 105 } | 106 } |
| 106 | 107 |
| 107 void indentMore() { | 108 void indentMore() { |
| 108 _indentLevel++; | 109 _indentLevel++; |
| 109 } | 110 } |
| 110 | 111 |
| 111 void indentLess() { | 112 void indentLess() { |
| 112 _indentLevel--; | 113 _indentLevel--; |
| 113 } | 114 } |
| 114 | 115 |
| 115 | |
| 116 /// Always emit a newline, even under `enableMinification`. | 116 /// Always emit a newline, even under `enableMinification`. |
| 117 void forceLine() { | 117 void forceLine() { |
| 118 out("\n"); | 118 out("\n"); |
| 119 } | 119 } |
| 120 |
| 120 /// Emits a newline for readability. | 121 /// Emits a newline for readability. |
| 121 void lineOut() { | 122 void lineOut() { |
| 122 if (!shouldCompressOutput) forceLine(); | 123 if (!shouldCompressOutput) forceLine(); |
| 123 } | 124 } |
| 125 |
| 124 void spaceOut() { | 126 void spaceOut() { |
| 125 if (!shouldCompressOutput) out(" "); | 127 if (!shouldCompressOutput) out(" "); |
| 126 } | 128 } |
| 127 | 129 |
| 128 String lastAddedString = null; | 130 String lastAddedString = null; |
| 129 int get lastCharCode { | 131 int get lastCharCode { |
| 130 if (lastAddedString == null) return 0; | 132 if (lastAddedString == null) return 0; |
| 131 assert(lastAddedString.length != ""); | 133 assert(lastAddedString.length != ""); |
| 132 return lastAddedString.codeUnitAt(lastAddedString.length - 1); | 134 return lastAddedString.codeUnitAt(lastAddedString.length - 1); |
| 133 } | 135 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 | 177 |
| 176 void outSemicolonLn() { | 178 void outSemicolonLn() { |
| 177 if (shouldCompressOutput) { | 179 if (shouldCompressOutput) { |
| 178 pendingSemicolon = true; | 180 pendingSemicolon = true; |
| 179 } else { | 181 } else { |
| 180 out(";"); | 182 out(";"); |
| 181 forceLine(); | 183 forceLine(); |
| 182 } | 184 } |
| 183 } | 185 } |
| 184 | 186 |
| 185 void outIndent(String str) { indent(); out(str); } | 187 void outIndent(String str) { |
| 186 void outIndentLn(String str) { indent(); outLn(str); } | 188 indent(); |
| 189 out(str); |
| 190 } |
| 191 |
| 192 void outIndentLn(String str) { |
| 193 indent(); |
| 194 outLn(str); |
| 195 } |
| 187 | 196 |
| 188 void skipNextIndent() { | 197 void skipNextIndent() { |
| 189 _skipNextIndent = true; | 198 _skipNextIndent = true; |
| 190 } | 199 } |
| 191 | 200 |
| 192 void indent() { | 201 void indent() { |
| 193 if (_skipNextIndent) { | 202 if (_skipNextIndent) { |
| 194 _skipNextIndent = false; | 203 _skipNextIndent = false; |
| 195 return; | 204 return; |
| 196 } | 205 } |
| 197 if (!shouldCompressOutput) { | 206 if (!shouldCompressOutput) { |
| 198 out(indentation); | 207 out(indentation); |
| 199 } | 208 } |
| 200 } | 209 } |
| 201 | 210 |
| 202 visit(Node node) { | 211 visit(Node node) { |
| 203 context.enterNode(node); | 212 context.enterNode(node); |
| 204 node.accept(this); | 213 node.accept(this); |
| 205 context.exitNode(node); | 214 context.exitNode(node); |
| 206 } | 215 } |
| 207 | 216 |
| 208 visitCommaSeparated(List<Node> nodes, int hasRequiredType, | 217 visitCommaSeparated(List<Node> nodes, int hasRequiredType, |
| 209 {bool newInForInit, bool newAtStatementBegin}) { | 218 {bool newInForInit, bool newAtStatementBegin}) { |
| 210 for (int i = 0; i < nodes.length; i++) { | 219 for (int i = 0; i < nodes.length; i++) { |
| 211 if (i != 0) { | 220 if (i != 0) { |
| 212 atStatementBegin = false; | 221 atStatementBegin = false; |
| 213 out(","); | 222 out(","); |
| 214 spaceOut(); | 223 spaceOut(); |
| 215 } | 224 } |
| 216 visitNestedExpression(nodes[i], hasRequiredType, | 225 visitNestedExpression(nodes[i], hasRequiredType, |
| 217 newInForInit: newInForInit, | 226 newInForInit: newInForInit, newAtStatementBegin: newAtStatementBegin); |
| 218 newAtStatementBegin: newAtStatementBegin); | |
| 219 } | 227 } |
| 220 } | 228 } |
| 221 | 229 |
| 222 visitAll(List<Node> nodes) { | 230 visitAll(List<Node> nodes) { |
| 223 nodes.forEach(visit); | 231 nodes.forEach(visit); |
| 224 } | 232 } |
| 225 | 233 |
| 226 visitProgram(Program program) { | 234 visitProgram(Program program) { |
| 227 if (program.scriptTag != null) { | 235 if (program.scriptTag != null) { |
| 228 out('#!${program.scriptTag}\n'); | 236 out('#!${program.scriptTag}\n'); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 } | 283 } |
| 276 | 284 |
| 277 visitBlock(Block block) { | 285 visitBlock(Block block) { |
| 278 blockOut(block, true, true); | 286 blockOut(block, true, true); |
| 279 } | 287 } |
| 280 | 288 |
| 281 visitExpressionStatement(ExpressionStatement expressionStatement) { | 289 visitExpressionStatement(ExpressionStatement expressionStatement) { |
| 282 indent(); | 290 indent(); |
| 283 outClosureAnnotation(expressionStatement); | 291 outClosureAnnotation(expressionStatement); |
| 284 visitNestedExpression(expressionStatement.expression, EXPRESSION, | 292 visitNestedExpression(expressionStatement.expression, EXPRESSION, |
| 285 newInForInit: false, newAtStatementBegin: true); | 293 newInForInit: false, newAtStatementBegin: true); |
| 286 outSemicolonLn(); | 294 outSemicolonLn(); |
| 287 } | 295 } |
| 288 | 296 |
| 289 visitEmptyStatement(EmptyStatement nop) { | 297 visitEmptyStatement(EmptyStatement nop) { |
| 290 outIndentLn(";"); | 298 outIndentLn(";"); |
| 291 } | 299 } |
| 292 | 300 |
| 293 void ifOut(If node, bool shouldIndent) { | 301 void ifOut(If node, bool shouldIndent) { |
| 294 Node then = node.then; | 302 Node then = node.then; |
| 295 Node elsePart = node.otherwise; | 303 Node elsePart = node.otherwise; |
| 296 bool hasElse = node.hasElse; | 304 bool hasElse = node.hasElse; |
| 297 | 305 |
| 298 // Handle dangling elses and a work-around for Android 4.0 stock browser. | 306 // Handle dangling elses and a work-around for Android 4.0 stock browser. |
| 299 // Android 4.0 requires braces for a single do-while in the `then` branch. | 307 // Android 4.0 requires braces for a single do-while in the `then` branch. |
| 300 // See issue 10923. | 308 // See issue 10923. |
| 301 if (hasElse) { | 309 if (hasElse) { |
| 302 bool needsBraces = node.then.accept(danglingElseVisitor) || then is Do; | 310 bool needsBraces = node.then.accept(danglingElseVisitor) || then is Do; |
| 303 if (needsBraces) { | 311 if (needsBraces) { |
| 304 then = new Block(<Statement>[then]); | 312 then = new Block(<Statement>[then]); |
| 305 } | 313 } |
| 306 } | 314 } |
| 307 if (shouldIndent) indent(); | 315 if (shouldIndent) indent(); |
| 308 out("if"); | 316 out("if"); |
| 309 spaceOut(); | 317 spaceOut(); |
| 310 out("("); | 318 out("("); |
| 311 visitNestedExpression(node.condition, EXPRESSION, | 319 visitNestedExpression(node.condition, EXPRESSION, |
| 312 newInForInit: false, newAtStatementBegin: false); | 320 newInForInit: false, newAtStatementBegin: false); |
| 313 out(")"); | 321 out(")"); |
| 314 bool thenWasBlock; | 322 bool thenWasBlock; |
| 315 if (options.allowSingleLineIfStatements && !hasElse && then is! Block) { | 323 if (options.allowSingleLineIfStatements && !hasElse && then is! Block) { |
| 316 thenWasBlock = false; | 324 thenWasBlock = false; |
| 317 spaceOut(); | 325 spaceOut(); |
| 318 skipNextIndent(); | 326 skipNextIndent(); |
| 319 visit(then); | 327 visit(then); |
| 320 } else { | 328 } else { |
| 321 thenWasBlock = | 329 thenWasBlock = |
| 322 blockBody(then, needsSeparation: false, needsNewline: !hasElse); | 330 blockBody(then, needsSeparation: false, needsNewline: !hasElse); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 340 visitIf(If node) { | 348 visitIf(If node) { |
| 341 ifOut(node, true); | 349 ifOut(node, true); |
| 342 } | 350 } |
| 343 | 351 |
| 344 visitFor(For loop) { | 352 visitFor(For loop) { |
| 345 outIndent("for"); | 353 outIndent("for"); |
| 346 spaceOut(); | 354 spaceOut(); |
| 347 out("("); | 355 out("("); |
| 348 if (loop.init != null) { | 356 if (loop.init != null) { |
| 349 visitNestedExpression(loop.init, EXPRESSION, | 357 visitNestedExpression(loop.init, EXPRESSION, |
| 350 newInForInit: true, newAtStatementBegin: false); | 358 newInForInit: true, newAtStatementBegin: false); |
| 351 } | 359 } |
| 352 out(";"); | 360 out(";"); |
| 353 if (loop.condition != null) { | 361 if (loop.condition != null) { |
| 354 spaceOut(); | 362 spaceOut(); |
| 355 visitNestedExpression(loop.condition, EXPRESSION, | 363 visitNestedExpression(loop.condition, EXPRESSION, |
| 356 newInForInit: false, newAtStatementBegin: false); | 364 newInForInit: false, newAtStatementBegin: false); |
| 357 } | 365 } |
| 358 out(";"); | 366 out(";"); |
| 359 if (loop.update != null) { | 367 if (loop.update != null) { |
| 360 spaceOut(); | 368 spaceOut(); |
| 361 visitNestedExpression(loop.update, EXPRESSION, | 369 visitNestedExpression(loop.update, EXPRESSION, |
| 362 newInForInit: false, newAtStatementBegin: false); | 370 newInForInit: false, newAtStatementBegin: false); |
| 363 } | 371 } |
| 364 out(")"); | 372 out(")"); |
| 365 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 373 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
| 366 } | 374 } |
| 367 | 375 |
| 368 visitForIn(ForIn loop) { | 376 visitForIn(ForIn loop) { |
| 369 outIndent("for"); | 377 outIndent("for"); |
| 370 spaceOut(); | 378 spaceOut(); |
| 371 out("("); | 379 out("("); |
| 372 visitNestedExpression(loop.leftHandSide, EXPRESSION, | 380 visitNestedExpression(loop.leftHandSide, EXPRESSION, |
| 373 newInForInit: true, newAtStatementBegin: false); | 381 newInForInit: true, newAtStatementBegin: false); |
| 374 out(" in"); | 382 out(" in"); |
| 375 pendingSpace = true; | 383 pendingSpace = true; |
| 376 visitNestedExpression(loop.object, EXPRESSION, | 384 visitNestedExpression(loop.object, EXPRESSION, |
| 377 newInForInit: false, newAtStatementBegin: false); | 385 newInForInit: false, newAtStatementBegin: false); |
| 378 out(")"); | 386 out(")"); |
| 379 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 387 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
| 380 } | 388 } |
| 381 | 389 |
| 382 visitForOf(ForOf loop) { | 390 visitForOf(ForOf loop) { |
| 383 outIndent("for"); | 391 outIndent("for"); |
| 384 spaceOut(); | 392 spaceOut(); |
| 385 out("("); | 393 out("("); |
| 386 visitNestedExpression(loop.leftHandSide, EXPRESSION, | 394 visitNestedExpression(loop.leftHandSide, EXPRESSION, |
| 387 newInForInit: true, newAtStatementBegin: false); | 395 newInForInit: true, newAtStatementBegin: false); |
| 388 out(" of"); | 396 out(" of"); |
| 389 pendingSpace = true; | 397 pendingSpace = true; |
| 390 visitNestedExpression(loop.iterable, EXPRESSION, | 398 visitNestedExpression(loop.iterable, EXPRESSION, |
| 391 newInForInit: false, newAtStatementBegin: false); | 399 newInForInit: false, newAtStatementBegin: false); |
| 392 out(")"); | 400 out(")"); |
| 393 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 401 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
| 394 } | 402 } |
| 395 | 403 |
| 396 visitWhile(While loop) { | 404 visitWhile(While loop) { |
| 397 outIndent("while"); | 405 outIndent("while"); |
| 398 spaceOut(); | 406 spaceOut(); |
| 399 out("("); | 407 out("("); |
| 400 visitNestedExpression(loop.condition, EXPRESSION, | 408 visitNestedExpression(loop.condition, EXPRESSION, |
| 401 newInForInit: false, newAtStatementBegin: false); | 409 newInForInit: false, newAtStatementBegin: false); |
| 402 out(")"); | 410 out(")"); |
| 403 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 411 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
| 404 } | 412 } |
| 405 | 413 |
| 406 visitDo(Do loop) { | 414 visitDo(Do loop) { |
| 407 outIndent("do"); | 415 outIndent("do"); |
| 408 if (blockBody(loop.body, needsSeparation: true, needsNewline: false)) { | 416 if (blockBody(loop.body, needsSeparation: true, needsNewline: false)) { |
| 409 spaceOut(); | 417 spaceOut(); |
| 410 } else { | 418 } else { |
| 411 indent(); | 419 indent(); |
| 412 } | 420 } |
| 413 out("while"); | 421 out("while"); |
| 414 spaceOut(); | 422 spaceOut(); |
| 415 out("("); | 423 out("("); |
| 416 visitNestedExpression(loop.condition, EXPRESSION, | 424 visitNestedExpression(loop.condition, EXPRESSION, |
| 417 newInForInit: false, newAtStatementBegin: false); | 425 newInForInit: false, newAtStatementBegin: false); |
| 418 out(")"); | 426 out(")"); |
| 419 outSemicolonLn(); | 427 outSemicolonLn(); |
| 420 } | 428 } |
| 421 | 429 |
| 422 visitContinue(Continue node) { | 430 visitContinue(Continue node) { |
| 423 if (node.targetLabel == null) { | 431 if (node.targetLabel == null) { |
| 424 outIndent("continue"); | 432 outIndent("continue"); |
| 425 } else { | 433 } else { |
| 426 outIndent("continue ${node.targetLabel}"); | 434 outIndent("continue ${node.targetLabel}"); |
| 427 } | 435 } |
| 428 outSemicolonLn(); | 436 outSemicolonLn(); |
| 429 } | 437 } |
| 430 | 438 |
| 431 visitBreak(Break node) { | 439 visitBreak(Break node) { |
| 432 if (node.targetLabel == null) { | 440 if (node.targetLabel == null) { |
| 433 outIndent("break"); | 441 outIndent("break"); |
| 434 } else { | 442 } else { |
| 435 outIndent("break ${node.targetLabel}"); | 443 outIndent("break ${node.targetLabel}"); |
| 436 } | 444 } |
| 437 outSemicolonLn(); | 445 outSemicolonLn(); |
| 438 } | 446 } |
| 439 | 447 |
| 440 visitReturn(Return node) { | 448 visitReturn(Return node) { |
| 441 if (node.value == null) { | 449 if (node.value == null) { |
| 442 outIndent("return"); | 450 outIndent("return"); |
| 443 } else { | 451 } else { |
| 444 outIndent("return"); | 452 outIndent("return"); |
| 445 pendingSpace = true; | 453 pendingSpace = true; |
| 446 visitNestedExpression(node.value, EXPRESSION, | 454 visitNestedExpression(node.value, EXPRESSION, |
| 447 newInForInit: false, newAtStatementBegin: false); | 455 newInForInit: false, newAtStatementBegin: false); |
| 448 } | 456 } |
| 449 outSemicolonLn(); | 457 outSemicolonLn(); |
| 450 } | 458 } |
| 451 | 459 |
| 452 visitDartYield(DartYield node) { | 460 visitDartYield(DartYield node) { |
| 453 if (node.hasStar) { | 461 if (node.hasStar) { |
| 454 outIndent("yield*"); | 462 outIndent("yield*"); |
| 455 } else { | 463 } else { |
| 456 outIndent("yield"); | 464 outIndent("yield"); |
| 457 } | 465 } |
| 458 pendingSpace = true; | 466 pendingSpace = true; |
| 459 visitNestedExpression(node.expression, EXPRESSION, | 467 visitNestedExpression(node.expression, EXPRESSION, |
| 460 newInForInit: false, newAtStatementBegin: false); | 468 newInForInit: false, newAtStatementBegin: false); |
| 461 outSemicolonLn(); | 469 outSemicolonLn(); |
| 462 } | 470 } |
| 463 | 471 |
| 464 | |
| 465 visitThrow(Throw node) { | 472 visitThrow(Throw node) { |
| 466 outIndent("throw"); | 473 outIndent("throw"); |
| 467 pendingSpace = true; | 474 pendingSpace = true; |
| 468 visitNestedExpression(node.expression, EXPRESSION, | 475 visitNestedExpression(node.expression, EXPRESSION, |
| 469 newInForInit: false, newAtStatementBegin: false); | 476 newInForInit: false, newAtStatementBegin: false); |
| 470 outSemicolonLn(); | 477 outSemicolonLn(); |
| 471 } | 478 } |
| 472 | 479 |
| 473 visitTry(Try node) { | 480 visitTry(Try node) { |
| 474 outIndent("try"); | 481 outIndent("try"); |
| 475 blockBody(node.body, needsSeparation: true, needsNewline: false); | 482 blockBody(node.body, needsSeparation: true, needsNewline: false); |
| 476 if (node.catchPart != null) { | 483 if (node.catchPart != null) { |
| 477 visit(node.catchPart); | 484 visit(node.catchPart); |
| 478 } | 485 } |
| 479 if (node.finallyPart != null) { | 486 if (node.finallyPart != null) { |
| 480 spaceOut(); | 487 spaceOut(); |
| 481 out("finally"); | 488 out("finally"); |
| 482 blockBody(node.finallyPart, needsSeparation: true, needsNewline: true); | 489 blockBody(node.finallyPart, needsSeparation: true, needsNewline: true); |
| 483 } else { | 490 } else { |
| 484 lineOut(); | 491 lineOut(); |
| 485 } | 492 } |
| 486 } | 493 } |
| 487 | 494 |
| 488 visitCatch(Catch node) { | 495 visitCatch(Catch node) { |
| 489 spaceOut(); | 496 spaceOut(); |
| 490 out("catch"); | 497 out("catch"); |
| 491 spaceOut(); | 498 spaceOut(); |
| 492 out("("); | 499 out("("); |
| 493 visitNestedExpression(node.declaration, EXPRESSION, | 500 visitNestedExpression(node.declaration, EXPRESSION, |
| 494 newInForInit: false, newAtStatementBegin: false); | 501 newInForInit: false, newAtStatementBegin: false); |
| 495 out(")"); | 502 out(")"); |
| 496 blockBody(node.body, needsSeparation: false, needsNewline: true); | 503 blockBody(node.body, needsSeparation: false, needsNewline: true); |
| 497 } | 504 } |
| 498 | 505 |
| 499 visitSwitch(Switch node) { | 506 visitSwitch(Switch node) { |
| 500 outIndent("switch"); | 507 outIndent("switch"); |
| 501 spaceOut(); | 508 spaceOut(); |
| 502 out("("); | 509 out("("); |
| 503 visitNestedExpression(node.key, EXPRESSION, | 510 visitNestedExpression(node.key, EXPRESSION, |
| 504 newInForInit: false, newAtStatementBegin: false); | 511 newInForInit: false, newAtStatementBegin: false); |
| 505 out(")"); | 512 out(")"); |
| 506 spaceOut(); | 513 spaceOut(); |
| 507 outLn("{"); | 514 outLn("{"); |
| 508 indentMore(); | 515 indentMore(); |
| 509 visitAll(node.cases); | 516 visitAll(node.cases); |
| 510 indentLess(); | 517 indentLess(); |
| 511 outIndentLn("}"); | 518 outIndentLn("}"); |
| 512 } | 519 } |
| 513 | 520 |
| 514 visitCase(Case node) { | 521 visitCase(Case node) { |
| 515 outIndent("case"); | 522 outIndent("case"); |
| 516 pendingSpace = true; | 523 pendingSpace = true; |
| 517 visitNestedExpression(node.expression, EXPRESSION, | 524 visitNestedExpression(node.expression, EXPRESSION, |
| 518 newInForInit: false, newAtStatementBegin: false); | 525 newInForInit: false, newAtStatementBegin: false); |
| 519 outLn(":"); | 526 outLn(":"); |
| 520 if (!node.body.statements.isEmpty) { | 527 if (!node.body.statements.isEmpty) { |
| 521 blockOut(node.body, true, true); | 528 blockOut(node.body, true, true); |
| 522 } | 529 } |
| 523 } | 530 } |
| 524 | 531 |
| 525 visitDefault(Default node) { | 532 visitDefault(Default node) { |
| 526 outIndentLn("default:"); | 533 outIndentLn("default:"); |
| 527 if (!node.body.statements.isEmpty) { | 534 if (!node.body.statements.isEmpty) { |
| 528 blockOut(node.body, true, true); | 535 blockOut(node.body, true, true); |
| 529 } | 536 } |
| 530 } | 537 } |
| 531 | 538 |
| 532 visitLabeledStatement(LabeledStatement node) { | 539 visitLabeledStatement(LabeledStatement node) { |
| 533 outIndent("${node.label}:"); | 540 outIndent("${node.label}:"); |
| 534 blockBody(node.body, needsSeparation: false, needsNewline: true); | 541 blockBody(node.body, needsSeparation: false, needsNewline: true); |
| 535 } | 542 } |
| 536 | 543 |
| 537 void functionOut(Fun fun, Node name) { | 544 void functionOut(Fun fun, Node name) { |
| 538 out("function"); | 545 out("function"); |
| 539 if (fun.isGenerator) out("*"); | 546 if (fun.isGenerator) out("*"); |
| 540 if (name != null) { | 547 if (name != null) { |
| 541 out(" "); | 548 out(" "); |
| 542 // Name must be a [Decl]. Therefore only test for primary expressions. | 549 // Name must be a [Decl]. Therefore only test for primary expressions. |
| 543 visitNestedExpression(name, PRIMARY, | 550 visitNestedExpression(name, PRIMARY, |
| 544 newInForInit: false, newAtStatementBegin: false); | 551 newInForInit: false, newAtStatementBegin: false); |
| 545 } | 552 } |
| 546 localNamer.enterScope(fun); | 553 localNamer.enterScope(fun); |
| 547 outTypeParams(fun.typeParams); | 554 outTypeParams(fun.typeParams); |
| 548 out("("); | 555 out("("); |
| 549 if (fun.params != null) { | 556 if (fun.params != null) { |
| 550 visitCommaSeparated(fun.params, PRIMARY, | 557 visitCommaSeparated(fun.params, PRIMARY, |
| 551 newInForInit: false, newAtStatementBegin: false); | 558 newInForInit: false, newAtStatementBegin: false); |
| 552 } | 559 } |
| 553 out(")"); | 560 out(")"); |
| 554 outTypeAnnotation(fun.returnType); | 561 outTypeAnnotation(fun.returnType); |
| 555 switch (fun.asyncModifier) { | 562 switch (fun.asyncModifier) { |
| 556 case const AsyncModifier.sync(): | 563 case const AsyncModifier.sync(): |
| 557 break; | 564 break; |
| 558 case const AsyncModifier.async(): | 565 case const AsyncModifier.async(): |
| 559 out(' async'); | 566 out(' async'); |
| 560 break; | 567 break; |
| 561 case const AsyncModifier.syncStar(): | 568 case const AsyncModifier.syncStar(): |
| 562 out(' sync*'); | 569 out(' sync*'); |
| 563 break; | 570 break; |
| 564 case const AsyncModifier.asyncStar(): | 571 case const AsyncModifier.asyncStar(): |
| 565 out(' async*'); | 572 out(' async*'); |
| 566 break; | 573 break; |
| 567 } | 574 } |
| 568 blockBody(fun.body, needsSeparation: false, needsNewline: false); | 575 blockBody(fun.body, needsSeparation: false, needsNewline: false); |
| 569 localNamer.leaveScope(); | 576 localNamer.leaveScope(); |
| 570 } | 577 } |
| 571 | 578 |
| 572 visitFunctionDeclaration(FunctionDeclaration declaration) { | 579 visitFunctionDeclaration(FunctionDeclaration declaration) { |
| 573 indent(); | 580 indent(); |
| 574 outClosureAnnotation(declaration); | 581 outClosureAnnotation(declaration); |
| 575 functionOut(declaration.function, declaration.name); | 582 functionOut(declaration.function, declaration.name); |
| 576 lineOut(); | 583 lineOut(); |
| 577 } | 584 } |
| 578 | 585 |
| 579 visitNestedExpression(Expression node, int requiredPrecedence, | 586 visitNestedExpression(Expression node, int requiredPrecedence, |
| 580 {bool newInForInit, bool newAtStatementBegin}) { | 587 {bool newInForInit, bool newAtStatementBegin}) { |
| 581 int nodePrecedence = node.precedenceLevel; | 588 int nodePrecedence = node.precedenceLevel; |
| 582 bool needsParentheses = | 589 bool needsParentheses = |
| 583 // a - (b + c). | 590 // a - (b + c). |
| 584 (requiredPrecedence != EXPRESSION && | 591 (requiredPrecedence != EXPRESSION && |
| 585 nodePrecedence < requiredPrecedence) || | 592 nodePrecedence < requiredPrecedence) || |
| 586 // for (a = (x in o); ... ; ... ) { ... } | 593 // for (a = (x in o); ... ; ... ) { ... } |
| 587 (newInForInit && node is Binary && node.op == "in") || | 594 (newInForInit && node is Binary && node.op == "in") || |
| 588 // (function() { ... })(). | 595 // (function() { ... })(). |
| 589 // ({a: 2, b: 3}.toString()). | 596 // ({a: 2, b: 3}.toString()). |
| 590 (newAtStatementBegin && (node is NamedFunction || | 597 (newAtStatementBegin && |
| 591 node is FunctionExpression || | 598 (node is NamedFunction || |
| 592 node is ObjectInitializer)); | 599 node is FunctionExpression || |
| 600 node is ObjectInitializer)); |
| 593 if (needsParentheses) { | 601 if (needsParentheses) { |
| 594 inForInit = false; | 602 inForInit = false; |
| 595 atStatementBegin = false; | 603 atStatementBegin = false; |
| 596 inNewTarget = false; | 604 inNewTarget = false; |
| 597 out("("); | 605 out("("); |
| 598 visit(node); | 606 visit(node); |
| 599 out(")"); | 607 out(")"); |
| 600 } else { | 608 } else { |
| 601 inForInit = newInForInit; | 609 inForInit = newInForInit; |
| 602 atStatementBegin = newAtStatementBegin; | 610 atStatementBegin = newAtStatementBegin; |
| 603 visit(node); | 611 visit(node); |
| 604 } | 612 } |
| 605 } | 613 } |
| 606 | 614 |
| 607 visitVariableDeclarationList(VariableDeclarationList list) { | 615 visitVariableDeclarationList(VariableDeclarationList list) { |
| 608 outClosureAnnotation(list); | 616 outClosureAnnotation(list); |
| 609 // Note: keyword can be null for non-static field declarations. | 617 // Note: keyword can be null for non-static field declarations. |
| 610 if (list.keyword != null) { | 618 if (list.keyword != null) { |
| 611 out(list.keyword); | 619 out(list.keyword); |
| 612 out(" "); | 620 out(" "); |
| 613 } | 621 } |
| 614 visitCommaSeparated(list.declarations, ASSIGNMENT, | 622 visitCommaSeparated(list.declarations, ASSIGNMENT, |
| 615 newInForInit: inForInit, newAtStatementBegin: false); | 623 newInForInit: inForInit, newAtStatementBegin: false); |
| 616 } | 624 } |
| 617 | 625 |
| 618 visitArrayBindingPattern(ArrayBindingPattern node) { | 626 visitArrayBindingPattern(ArrayBindingPattern node) { |
| 619 out("["); | 627 out("["); |
| 620 visitCommaSeparated(node.variables, EXPRESSION, | 628 visitCommaSeparated(node.variables, EXPRESSION, |
| 621 newInForInit: false, newAtStatementBegin: false); | 629 newInForInit: false, newAtStatementBegin: false); |
| 622 out("]"); | 630 out("]"); |
| 623 } | 631 } |
| 632 |
| 624 visitObjectBindingPattern(ObjectBindingPattern node) { | 633 visitObjectBindingPattern(ObjectBindingPattern node) { |
| 625 out("{"); | 634 out("{"); |
| 626 visitCommaSeparated(node.variables, EXPRESSION, | 635 visitCommaSeparated(node.variables, EXPRESSION, |
| 627 newInForInit: false, newAtStatementBegin: false); | 636 newInForInit: false, newAtStatementBegin: false); |
| 628 out("}"); | 637 out("}"); |
| 629 } | 638 } |
| 630 | 639 |
| 631 visitDestructuredVariable(DestructuredVariable node) { | 640 visitDestructuredVariable(DestructuredVariable node) { |
| 632 var name = node.name; | 641 var name = node.name; |
| 633 var hasName = name != null; | 642 var hasName = name != null; |
| 634 if (hasName) { | 643 if (hasName) { |
| 635 if (name is LiteralString) { | 644 if (name is LiteralString) { |
| 636 out("["); | 645 out("["); |
| 637 out(name.value); | 646 out(name.value); |
| 638 out("]"); | 647 out("]"); |
| 639 } else { | 648 } else { |
| 640 visit(name); | 649 visit(name); |
| 641 } | 650 } |
| 642 } | 651 } |
| 643 if (node.structure != null) { | 652 if (node.structure != null) { |
| 644 if (hasName) { | 653 if (hasName) { |
| 645 out(":"); | 654 out(":"); |
| 646 spaceOut(); | 655 spaceOut(); |
| 647 } | 656 } |
| 648 visit(node.structure); | 657 visit(node.structure); |
| 649 } | 658 } |
| 650 outTypeAnnotation(node.type); | 659 outTypeAnnotation(node.type); |
| 651 if (node.defaultValue != null) { | 660 if (node.defaultValue != null) { |
| 652 spaceOut(); | 661 spaceOut(); |
| 653 out("="); | 662 out("="); |
| 654 spaceOut(); | 663 spaceOut(); |
| 655 visitNestedExpression(node.defaultValue, EXPRESSION, | 664 visitNestedExpression(node.defaultValue, EXPRESSION, |
| 656 newInForInit: false, newAtStatementBegin: false); | 665 newInForInit: false, newAtStatementBegin: false); |
| 657 } | 666 } |
| 658 } | 667 } |
| 659 | 668 |
| 660 visitSimpleBindingPattern(SimpleBindingPattern node) { | 669 visitSimpleBindingPattern(SimpleBindingPattern node) { |
| 661 visit(node.name); | 670 visit(node.name); |
| 662 } | 671 } |
| 663 | 672 |
| 664 visitAssignment(Assignment assignment) { | 673 visitAssignment(Assignment assignment) { |
| 665 visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, | 674 visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, |
| 666 newInForInit: inForInit, | 675 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 667 newAtStatementBegin: atStatementBegin); | |
| 668 if (assignment.value != null) { | 676 if (assignment.value != null) { |
| 669 spaceOut(); | 677 spaceOut(); |
| 670 String op = assignment.op; | 678 String op = assignment.op; |
| 671 if (op != null) out(op); | 679 if (op != null) out(op); |
| 672 out("="); | 680 out("="); |
| 673 spaceOut(); | 681 spaceOut(); |
| 674 visitNestedExpression(assignment.value, ASSIGNMENT, | 682 visitNestedExpression(assignment.value, ASSIGNMENT, |
| 675 newInForInit: inForInit, | 683 newInForInit: inForInit, newAtStatementBegin: false); |
| 676 newAtStatementBegin: false); | |
| 677 } | 684 } |
| 678 } | 685 } |
| 679 | 686 |
| 680 visitVariableInitialization(VariableInitialization initialization) { | 687 visitVariableInitialization(VariableInitialization initialization) { |
| 681 outClosureAnnotation(initialization); | 688 outClosureAnnotation(initialization); |
| 682 visitAssignment(initialization); | 689 visitAssignment(initialization); |
| 683 } | 690 } |
| 684 | 691 |
| 685 visitConditional(Conditional cond) { | 692 visitConditional(Conditional cond) { |
| 686 visitNestedExpression(cond.condition, LOGICAL_OR, | 693 visitNestedExpression(cond.condition, LOGICAL_OR, |
| 687 newInForInit: inForInit, | 694 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 688 newAtStatementBegin: atStatementBegin); | |
| 689 spaceOut(); | 695 spaceOut(); |
| 690 out("?"); | 696 out("?"); |
| 691 spaceOut(); | 697 spaceOut(); |
| 692 // The then part is allowed to have an 'in'. | 698 // The then part is allowed to have an 'in'. |
| 693 visitNestedExpression(cond.then, ASSIGNMENT, | 699 visitNestedExpression(cond.then, ASSIGNMENT, |
| 694 newInForInit: false, newAtStatementBegin: false); | 700 newInForInit: false, newAtStatementBegin: false); |
| 695 spaceOut(); | 701 spaceOut(); |
| 696 out(":"); | 702 out(":"); |
| 697 spaceOut(); | 703 spaceOut(); |
| 698 visitNestedExpression(cond.otherwise, ASSIGNMENT, | 704 visitNestedExpression(cond.otherwise, ASSIGNMENT, |
| 699 newInForInit: inForInit, newAtStatementBegin: false); | 705 newInForInit: inForInit, newAtStatementBegin: false); |
| 700 } | 706 } |
| 701 | 707 |
| 702 visitNew(New node) { | 708 visitNew(New node) { |
| 703 out("new "); | 709 out("new "); |
| 704 inNewTarget = true; | 710 inNewTarget = true; |
| 705 visitNestedExpression(node.target, ACCESS, | 711 visitNestedExpression(node.target, ACCESS, |
| 706 newInForInit: inForInit, newAtStatementBegin: false); | 712 newInForInit: inForInit, newAtStatementBegin: false); |
| 707 inNewTarget = false; | 713 inNewTarget = false; |
| 708 out("("); | 714 out("("); |
| 709 visitCommaSeparated(node.arguments, SPREAD, | 715 visitCommaSeparated(node.arguments, SPREAD, |
| 710 newInForInit: false, newAtStatementBegin: false); | 716 newInForInit: false, newAtStatementBegin: false); |
| 711 out(")"); | 717 out(")"); |
| 712 } | 718 } |
| 713 | 719 |
| 714 visitCall(Call call) { | 720 visitCall(Call call) { |
| 715 visitNestedExpression(call.target, LEFT_HAND_SIDE, | 721 visitNestedExpression(call.target, LEFT_HAND_SIDE, |
| 716 newInForInit: inForInit, | 722 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 717 newAtStatementBegin: atStatementBegin); | |
| 718 out("("); | 723 out("("); |
| 719 visitCommaSeparated(call.arguments, SPREAD, | 724 visitCommaSeparated(call.arguments, SPREAD, |
| 720 newInForInit: false, newAtStatementBegin: false); | 725 newInForInit: false, newAtStatementBegin: false); |
| 721 out(")"); | 726 out(")"); |
| 722 } | 727 } |
| 723 | 728 |
| 724 visitBinary(Binary binary) { | 729 visitBinary(Binary binary) { |
| 725 Expression left = binary.left; | 730 Expression left = binary.left; |
| 726 Expression right = binary.right; | 731 Expression right = binary.right; |
| 727 String op = binary.op; | 732 String op = binary.op; |
| 728 int leftPrecedenceRequirement; | 733 int leftPrecedenceRequirement; |
| 729 int rightPrecedenceRequirement; | 734 int rightPrecedenceRequirement; |
| 730 bool leftSpace = true; // left<HERE>op right | 735 bool leftSpace = true; // left<HERE>op right |
| 731 switch (op) { | 736 switch (op) { |
| 732 case ',': | 737 case ',': |
| 733 // x, (y, z) <=> (x, y), z. | 738 // x, (y, z) <=> (x, y), z. |
| 734 leftPrecedenceRequirement = EXPRESSION; | 739 leftPrecedenceRequirement = EXPRESSION; |
| 735 rightPrecedenceRequirement = EXPRESSION; | 740 rightPrecedenceRequirement = EXPRESSION; |
| 736 leftSpace = false; | 741 leftSpace = false; |
| 737 break; | 742 break; |
| 738 case "||": | 743 case "||": |
| 739 leftPrecedenceRequirement = LOGICAL_OR; | 744 leftPrecedenceRequirement = LOGICAL_OR; |
| 740 // x || (y || z) <=> (x || y) || z. | 745 // x || (y || z) <=> (x || y) || z. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 case "%": | 802 case "%": |
| 798 leftPrecedenceRequirement = MULTIPLICATIVE; | 803 leftPrecedenceRequirement = MULTIPLICATIVE; |
| 799 // We cannot remove parenthesis for "*" because of precision issues. | 804 // We cannot remove parenthesis for "*" because of precision issues. |
| 800 rightPrecedenceRequirement = UNARY; | 805 rightPrecedenceRequirement = UNARY; |
| 801 break; | 806 break; |
| 802 default: | 807 default: |
| 803 context.error("Forgot operator: $op"); | 808 context.error("Forgot operator: $op"); |
| 804 } | 809 } |
| 805 | 810 |
| 806 visitNestedExpression(left, leftPrecedenceRequirement, | 811 visitNestedExpression(left, leftPrecedenceRequirement, |
| 807 newInForInit: inForInit, | 812 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 808 newAtStatementBegin: atStatementBegin); | |
| 809 | 813 |
| 810 if (op == "in" || op == "instanceof") { | 814 if (op == "in" || op == "instanceof") { |
| 811 // There are cases where the space is not required but without further | 815 // There are cases where the space is not required but without further |
| 812 // analysis we cannot know. | 816 // analysis we cannot know. |
| 813 out(" "); | 817 out(" "); |
| 814 out(op); | 818 out(op); |
| 815 out(" "); | 819 out(" "); |
| 816 } else { | 820 } else { |
| 817 if (leftSpace) spaceOut(); | 821 if (leftSpace) spaceOut(); |
| 818 out(op); | 822 out(op); |
| 819 spaceOut(); | 823 spaceOut(); |
| 820 } | 824 } |
| 821 visitNestedExpression(right, rightPrecedenceRequirement, | 825 visitNestedExpression(right, rightPrecedenceRequirement, |
| 822 newInForInit: inForInit, | 826 newInForInit: inForInit, newAtStatementBegin: false); |
| 823 newAtStatementBegin: false); | |
| 824 } | 827 } |
| 825 | 828 |
| 826 visitPrefix(Prefix unary) { | 829 visitPrefix(Prefix unary) { |
| 827 String op = unary.op; | 830 String op = unary.op; |
| 828 switch (op) { | 831 switch (op) { |
| 829 case "delete": | 832 case "delete": |
| 830 case "void": | 833 case "void": |
| 831 case "typeof": | 834 case "typeof": |
| 832 // There are cases where the space is not required but without further | 835 // There are cases where the space is not required but without further |
| 833 // analysis we cannot know. | 836 // analysis we cannot know. |
| 834 out(op); | 837 out(op); |
| 835 out(" "); | 838 out(" "); |
| 836 break; | 839 break; |
| 837 case "+": | 840 case "+": |
| 838 case "++": | 841 case "++": |
| 839 if (lastCharCode == charCodes.$PLUS) out(" "); | 842 if (lastCharCode == charCodes.$PLUS) out(" "); |
| 840 out(op); | 843 out(op); |
| 841 break; | 844 break; |
| 842 case "-": | 845 case "-": |
| 843 case "--": | 846 case "--": |
| 844 if (lastCharCode == charCodes.$MINUS) out(" "); | 847 if (lastCharCode == charCodes.$MINUS) out(" "); |
| 845 out(op); | 848 out(op); |
| 846 break; | 849 break; |
| 847 default: | 850 default: |
| 848 out(op); | 851 out(op); |
| 849 } | 852 } |
| 850 visitNestedExpression(unary.argument, unary.precedenceLevel, | 853 visitNestedExpression(unary.argument, unary.precedenceLevel, |
| 851 newInForInit: inForInit, newAtStatementBegin: false); | 854 newInForInit: inForInit, newAtStatementBegin: false); |
| 852 } | 855 } |
| 853 | 856 |
| 854 visitSpread(Spread unary) => visitPrefix(unary); | 857 visitSpread(Spread unary) => visitPrefix(unary); |
| 855 | 858 |
| 856 visitYield(Yield yield) { | 859 visitYield(Yield yield) { |
| 857 out(yield.star ? "yield*" : "yield"); | 860 out(yield.star ? "yield*" : "yield"); |
| 858 if (yield.value == null) return; | 861 if (yield.value == null) return; |
| 859 out(" "); | 862 out(" "); |
| 860 visitNestedExpression(yield.value, yield.precedenceLevel, | 863 visitNestedExpression(yield.value, yield.precedenceLevel, |
| 861 newInForInit: inForInit, newAtStatementBegin: false); | 864 newInForInit: inForInit, newAtStatementBegin: false); |
| 862 } | 865 } |
| 863 | 866 |
| 864 visitPostfix(Postfix postfix) { | 867 visitPostfix(Postfix postfix) { |
| 865 visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, | 868 visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, |
| 866 newInForInit: inForInit, | 869 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 867 newAtStatementBegin: atStatementBegin); | |
| 868 out(postfix.op); | 870 out(postfix.op); |
| 869 } | 871 } |
| 870 | 872 |
| 871 visitThis(This node) { | 873 visitThis(This node) { |
| 872 out("this"); | 874 out("this"); |
| 873 } | 875 } |
| 874 | 876 |
| 875 visitSuper(Super node) { | 877 visitSuper(Super node) { |
| 876 out("super"); | 878 out("super"); |
| 877 } | 879 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 890 return charCodes.$0 <= charCode && charCode <= charCodes.$9; | 892 return charCodes.$0 <= charCode && charCode <= charCodes.$9; |
| 891 } | 893 } |
| 892 | 894 |
| 893 bool isValidJavaScriptId(String field) { | 895 bool isValidJavaScriptId(String field) { |
| 894 if (field.length < 3) return false; | 896 if (field.length < 3) return false; |
| 895 // Ignore the leading and trailing string-delimiter. | 897 // Ignore the leading and trailing string-delimiter. |
| 896 for (int i = 1; i < field.length - 1; i++) { | 898 for (int i = 1; i < field.length - 1; i++) { |
| 897 // TODO(floitsch): allow more characters. | 899 // TODO(floitsch): allow more characters. |
| 898 int charCode = field.codeUnitAt(i); | 900 int charCode = field.codeUnitAt(i); |
| 899 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || | 901 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || |
| 900 charCodes.$A <= charCode && charCode <= charCodes.$Z || | 902 charCodes.$A <= charCode && charCode <= charCodes.$Z || |
| 901 charCode == charCodes.$$ || | 903 charCode == charCodes.$$ || |
| 902 charCode == charCodes.$_ || | 904 charCode == charCodes.$_ || |
| 903 i != 1 && isDigit(charCode))) { | 905 i != 1 && isDigit(charCode))) { |
| 904 return false; | 906 return false; |
| 905 } | 907 } |
| 906 } | 908 } |
| 907 | 909 |
| 908 // TODO(floitsch): normally we should also check that the field is not a | 910 // TODO(floitsch): normally we should also check that the field is not a |
| 909 // reserved word. We don't generate fields with reserved word names except | 911 // reserved word. We don't generate fields with reserved word names except |
| 910 // for 'super'. | 912 // for 'super'. |
| 911 return options.allowKeywordsInProperties || field != '"super"'; | 913 return options.allowKeywordsInProperties || field != '"super"'; |
| 912 } | 914 } |
| 913 | 915 |
| 914 visitAccess(PropertyAccess access) { | 916 visitAccess(PropertyAccess access) { |
| 915 // Normally we can omit parens on the receiver if it is a Call, even though | 917 // Normally we can omit parens on the receiver if it is a Call, even though |
| 916 // Call expressions have lower precedence. However this optimization doesn't | 918 // Call expressions have lower precedence. However this optimization doesn't |
| 917 // work inside New expressions: | 919 // work inside New expressions: |
| 918 // | 920 // |
| 919 // new obj.foo().bar() | 921 // new obj.foo().bar() |
| 920 // | 922 // |
| 921 // This will be parsed as: | 923 // This will be parsed as: |
| 922 // | 924 // |
| 923 // (new obj.foo()).bar() | 925 // (new obj.foo()).bar() |
| 924 // | 926 // |
| 925 // Which is incorrect. So we must have parenthesis in this case: | 927 // Which is incorrect. So we must have parenthesis in this case: |
| 926 // | 928 // |
| 927 // new (obj.foo()).bar() | 929 // new (obj.foo()).bar() |
| 928 // | 930 // |
| 929 int precedence = inNewTarget ? ACCESS : CALL; | 931 int precedence = inNewTarget ? ACCESS : CALL; |
| 930 | 932 |
| 931 visitNestedExpression(access.receiver, precedence, | 933 visitNestedExpression(access.receiver, precedence, |
| 932 newInForInit: inForInit, | 934 newInForInit: inForInit, newAtStatementBegin: atStatementBegin); |
| 933 newAtStatementBegin: atStatementBegin); | |
| 934 propertyNameOut(access.selector, inAccess: true); | 935 propertyNameOut(access.selector, inAccess: true); |
| 935 } | 936 } |
| 936 | 937 |
| 937 visitNamedFunction(NamedFunction namedFunction) { | 938 visitNamedFunction(NamedFunction namedFunction) { |
| 938 functionOut(namedFunction.function, namedFunction.name); | 939 functionOut(namedFunction.function, namedFunction.name); |
| 939 } | 940 } |
| 940 | 941 |
| 941 visitFun(Fun fun) { | 942 visitFun(Fun fun) { |
| 942 functionOut(fun, null); | 943 functionOut(fun, null); |
| 943 } | 944 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 // and [1,,] (array with 1 and a hole) would become [1,] = [1]. | 1009 // and [1,,] (array with 1 and a hole) would become [1,] = [1]. |
| 1009 out(","); | 1010 out(","); |
| 1010 continue; | 1011 continue; |
| 1011 } | 1012 } |
| 1012 if (i != 0 && !multiline) spaceOut(); | 1013 if (i != 0 && !multiline) spaceOut(); |
| 1013 if (multiline) { | 1014 if (multiline) { |
| 1014 forceLine(); | 1015 forceLine(); |
| 1015 indent(); | 1016 indent(); |
| 1016 } | 1017 } |
| 1017 visitNestedExpression(element, ASSIGNMENT, | 1018 visitNestedExpression(element, ASSIGNMENT, |
| 1018 newInForInit: false, newAtStatementBegin: false); | 1019 newInForInit: false, newAtStatementBegin: false); |
| 1019 // We can skip the trailing "," for the last element (since it's not | 1020 // We can skip the trailing "," for the last element (since it's not |
| 1020 // an array hole). | 1021 // an array hole). |
| 1021 if (i != elements.length - 1) out(","); | 1022 if (i != elements.length - 1) out(","); |
| 1022 } | 1023 } |
| 1023 indentLess(); | 1024 indentLess(); |
| 1024 if (multiline) { | 1025 if (multiline) { |
| 1025 lineOut(); | 1026 lineOut(); |
| 1026 indent(); | 1027 indent(); |
| 1027 } | 1028 } |
| 1028 out("]"); | 1029 out("]"); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1055 indent(); | 1056 indent(); |
| 1056 } | 1057 } |
| 1057 out("}"); | 1058 out("}"); |
| 1058 } | 1059 } |
| 1059 | 1060 |
| 1060 visitProperty(Property node) { | 1061 visitProperty(Property node) { |
| 1061 propertyNameOut(node.name); | 1062 propertyNameOut(node.name); |
| 1062 out(":"); | 1063 out(":"); |
| 1063 spaceOut(); | 1064 spaceOut(); |
| 1064 visitNestedExpression(node.value, ASSIGNMENT, | 1065 visitNestedExpression(node.value, ASSIGNMENT, |
| 1065 newInForInit: false, newAtStatementBegin: false); | 1066 newInForInit: false, newAtStatementBegin: false); |
| 1066 } | 1067 } |
| 1067 | 1068 |
| 1068 visitRegExpLiteral(RegExpLiteral node) { | 1069 visitRegExpLiteral(RegExpLiteral node) { |
| 1069 out(node.pattern); | 1070 out(node.pattern); |
| 1070 } | 1071 } |
| 1071 | 1072 |
| 1072 visitTemplateString(TemplateString node) { | 1073 visitTemplateString(TemplateString node) { |
| 1073 out('`'); | 1074 out('`'); |
| 1074 for (var element in node.elements) { | 1075 for (var element in node.elements) { |
| 1075 if (element is String) { | 1076 if (element is String) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1177 if (node != null && node.closureAnnotation != null) { | 1178 if (node != null && node.closureAnnotation != null) { |
| 1178 String comment = node.closureAnnotation.toString(indentation); | 1179 String comment = node.closureAnnotation.toString(indentation); |
| 1179 if (comment.isNotEmpty) { | 1180 if (comment.isNotEmpty) { |
| 1180 out(comment); | 1181 out(comment); |
| 1181 lineOut(); | 1182 lineOut(); |
| 1182 indent(); | 1183 indent(); |
| 1183 } | 1184 } |
| 1184 } | 1185 } |
| 1185 } | 1186 } |
| 1186 | 1187 |
| 1187 void propertyNameOut(Expression node, {bool inMethod: false, | 1188 void propertyNameOut(Expression node, |
| 1188 bool inAccess: false}) { | 1189 {bool inMethod: false, bool inAccess: false}) { |
| 1189 | |
| 1190 if (node is LiteralNumber) { | 1190 if (node is LiteralNumber) { |
| 1191 LiteralNumber nameNumber = node; | 1191 LiteralNumber nameNumber = node; |
| 1192 if (inAccess) out('['); | 1192 if (inAccess) out('['); |
| 1193 out(nameNumber.value); | 1193 out(nameNumber.value); |
| 1194 if (inAccess) out(']'); | 1194 if (inAccess) out(']'); |
| 1195 } else { | 1195 } else { |
| 1196 if (node is LiteralString) { | 1196 if (node is LiteralString) { |
| 1197 if (isValidJavaScriptId(node.value)) { | 1197 if (isValidJavaScriptId(node.value)) { |
| 1198 if (inAccess) out('.'); | 1198 if (inAccess) out('.'); |
| 1199 out(node.valueWithoutQuotes); | 1199 out(node.valueWithoutQuotes); |
| 1200 } else { | 1200 } else { |
| 1201 if (inMethod || inAccess) out("["); | 1201 if (inMethod || inAccess) out("["); |
| 1202 out(node.value); | 1202 out(node.value); |
| 1203 if (inMethod || inAccess) out("]"); | 1203 if (inMethod || inAccess) out("]"); |
| 1204 } | 1204 } |
| 1205 } else { | 1205 } else { |
| 1206 // ComputedPropertyName | 1206 // ComputedPropertyName |
| 1207 out("["); | 1207 out("["); |
| 1208 visitNestedExpression(node, EXPRESSION, | 1208 visitNestedExpression(node, EXPRESSION, |
| 1209 newInForInit: false, newAtStatementBegin: false); | 1209 newInForInit: false, newAtStatementBegin: false); |
| 1210 out("]"); | 1210 out("]"); |
| 1211 } | 1211 } |
| 1212 } | 1212 } |
| 1213 } | 1213 } |
| 1214 | 1214 |
| 1215 visitImportDeclaration(ImportDeclaration node) { | 1215 visitImportDeclaration(ImportDeclaration node) { |
| 1216 indent(); | 1216 indent(); |
| 1217 out('import '); | 1217 out('import '); |
| 1218 if (node.defaultBinding != null) { | 1218 if (node.defaultBinding != null) { |
| 1219 visit(node.defaultBinding); | 1219 visit(node.defaultBinding); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 } | 1388 } |
| 1389 } | 1389 } |
| 1390 | 1390 |
| 1391 // Collects all the var declarations in the function. We need to do this in a | 1391 // Collects all the var declarations in the function. We need to do this in a |
| 1392 // separate pass because JS vars are lifted to the top of the function. | 1392 // separate pass because JS vars are lifted to the top of the function. |
| 1393 class VarCollector extends BaseVisitor { | 1393 class VarCollector extends BaseVisitor { |
| 1394 bool nested; | 1394 bool nested; |
| 1395 final Set<String> vars; | 1395 final Set<String> vars; |
| 1396 final Set<String> params; | 1396 final Set<String> params; |
| 1397 | 1397 |
| 1398 VarCollector() : nested = false, | 1398 VarCollector() |
| 1399 vars = new Set<String>(), | 1399 : nested = false, |
| 1400 params = new Set<String>(); | 1400 vars = new Set<String>(), |
| 1401 params = new Set<String>(); |
| 1401 | 1402 |
| 1402 void forEachVar(void fn(String v)) => vars.forEach(fn); | 1403 void forEachVar(void fn(String v)) => vars.forEach(fn); |
| 1403 void forEachParam(void fn(String p)) => params.forEach(fn); | 1404 void forEachParam(void fn(String p)) => params.forEach(fn); |
| 1404 | 1405 |
| 1405 void collectVarsInFunction(FunctionExpression fun) { | 1406 void collectVarsInFunction(FunctionExpression fun) { |
| 1406 if (!nested) { | 1407 if (!nested) { |
| 1407 nested = true; | 1408 nested = true; |
| 1408 if (fun.params != null) { | 1409 if (fun.params != null) { |
| 1409 for (var param in fun.params) { | 1410 for (var param in fun.params) { |
| 1410 // TODO(jmesserly): add ES6 support. Currently not needed because | 1411 // TODO(jmesserly): add ES6 support. Currently not needed because |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 void visitVariableInitialization(VariableInitialization node) { | 1454 void visitVariableInitialization(VariableInitialization node) { |
| 1454 declareVariable(node.declaration); | 1455 declareVariable(node.declaration); |
| 1455 if (node.value != null) node.value.accept(this); | 1456 if (node.value != null) node.value.accept(this); |
| 1456 } | 1457 } |
| 1457 | 1458 |
| 1458 void declareVariable(Identifier decl) { | 1459 void declareVariable(Identifier decl) { |
| 1459 if (decl.allowRename) vars.add(decl.name); | 1460 if (decl.allowRename) vars.add(decl.name); |
| 1460 } | 1461 } |
| 1461 } | 1462 } |
| 1462 | 1463 |
| 1463 | |
| 1464 /** | 1464 /** |
| 1465 * Returns true, if the given node must be wrapped into braces when used | 1465 * Returns true, if the given node must be wrapped into braces when used |
| 1466 * as then-statement in an [If] that has an else branch. | 1466 * as then-statement in an [If] that has an else branch. |
| 1467 */ | 1467 */ |
| 1468 class DanglingElseVisitor extends BaseVisitor<bool> { | 1468 class DanglingElseVisitor extends BaseVisitor<bool> { |
| 1469 JavaScriptPrintingContext context; | 1469 JavaScriptPrintingContext context; |
| 1470 | 1470 |
| 1471 DanglingElseVisitor(this.context); | 1471 DanglingElseVisitor(this.context); |
| 1472 | 1472 |
| 1473 bool visitProgram(Program node) => false; | 1473 bool visitProgram(Program node) => false; |
| 1474 | 1474 |
| 1475 bool visitNode(Node node) { | 1475 bool visitNode(Node node) { |
| 1476 context.error("Forgot node: $node"); | 1476 context.error("Forgot node: $node"); |
| 1477 return null; | 1477 return null; |
| 1478 } | 1478 } |
| 1479 | 1479 |
| 1480 bool visitBlock(Block node) => false; | 1480 bool visitBlock(Block node) => false; |
| 1481 bool visitExpressionStatement(ExpressionStatement node) => false; | 1481 bool visitExpressionStatement(ExpressionStatement node) => false; |
| 1482 bool visitEmptyStatement(EmptyStatement node) => false; | 1482 bool visitEmptyStatement(EmptyStatement node) => false; |
| 1483 bool visitIf(If node) { | 1483 bool visitIf(If node) { |
| 1484 if (!node.hasElse) return true; | 1484 if (!node.hasElse) return true; |
| 1485 return node.otherwise.accept(this); | 1485 return node.otherwise.accept(this); |
| 1486 } | 1486 } |
| 1487 |
| 1487 bool visitFor(For node) => node.body.accept(this); | 1488 bool visitFor(For node) => node.body.accept(this); |
| 1488 bool visitForIn(ForIn node) => node.body.accept(this); | 1489 bool visitForIn(ForIn node) => node.body.accept(this); |
| 1489 bool visitForOf(ForOf node) => node.body.accept(this); | 1490 bool visitForOf(ForOf node) => node.body.accept(this); |
| 1490 bool visitWhile(While node) => node.body.accept(this); | 1491 bool visitWhile(While node) => node.body.accept(this); |
| 1491 bool visitDo(Do node) => false; | 1492 bool visitDo(Do node) => false; |
| 1492 bool visitContinue(Continue node) => false; | 1493 bool visitContinue(Continue node) => false; |
| 1493 bool visitBreak(Break node) => false; | 1494 bool visitBreak(Break node) => false; |
| 1494 bool visitReturn(Return node) => false; | 1495 bool visitReturn(Return node) => false; |
| 1495 bool visitThrow(Throw node) => false; | 1496 bool visitThrow(Throw node) => false; |
| 1496 bool visitTry(Try node) { | 1497 bool visitTry(Try node) { |
| 1497 if (node.finallyPart != null) { | 1498 if (node.finallyPart != null) { |
| 1498 return node.finallyPart.accept(this); | 1499 return node.finallyPart.accept(this); |
| 1499 } else { | 1500 } else { |
| 1500 return node.catchPart.accept(this); | 1501 return node.catchPart.accept(this); |
| 1501 } | 1502 } |
| 1502 } | 1503 } |
| 1504 |
| 1503 bool visitCatch(Catch node) => node.body.accept(this); | 1505 bool visitCatch(Catch node) => node.body.accept(this); |
| 1504 bool visitSwitch(Switch node) => false; | 1506 bool visitSwitch(Switch node) => false; |
| 1505 bool visitCase(Case node) => false; | 1507 bool visitCase(Case node) => false; |
| 1506 bool visitDefault(Default node) => false; | 1508 bool visitDefault(Default node) => false; |
| 1507 bool visitFunctionDeclaration(FunctionDeclaration node) => false; | 1509 bool visitFunctionDeclaration(FunctionDeclaration node) => false; |
| 1508 bool visitLabeledStatement(LabeledStatement node) | 1510 bool visitLabeledStatement(LabeledStatement node) => node.body.accept(this); |
| 1509 => node.body.accept(this); | |
| 1510 bool visitLiteralStatement(LiteralStatement node) => true; | 1511 bool visitLiteralStatement(LiteralStatement node) => true; |
| 1511 bool visitClassDeclaration(ClassDeclaration node) => false; | 1512 bool visitClassDeclaration(ClassDeclaration node) => false; |
| 1512 | 1513 |
| 1513 bool visitExpression(Expression node) => false; | 1514 bool visitExpression(Expression node) => false; |
| 1514 } | 1515 } |
| 1515 | 1516 |
| 1516 | |
| 1517 abstract class LocalNamer { | 1517 abstract class LocalNamer { |
| 1518 String getName(Identifier node); | 1518 String getName(Identifier node); |
| 1519 void enterScope(FunctionExpression node); | 1519 void enterScope(FunctionExpression node); |
| 1520 void leaveScope(); | 1520 void leaveScope(); |
| 1521 } | 1521 } |
| 1522 | 1522 |
| 1523 | |
| 1524 class IdentityNamer implements LocalNamer { | 1523 class IdentityNamer implements LocalNamer { |
| 1525 String getName(Identifier node) => node.name; | 1524 String getName(Identifier node) => node.name; |
| 1526 void enterScope(FunctionExpression node) {} | 1525 void enterScope(FunctionExpression node) {} |
| 1527 void leaveScope() {} | 1526 void leaveScope() {} |
| 1528 } | 1527 } |
| 1529 | 1528 |
| 1530 | |
| 1531 class MinifyRenamer implements LocalNamer { | 1529 class MinifyRenamer implements LocalNamer { |
| 1532 final List<Map<String, String>> maps = []; | 1530 final List<Map<String, String>> maps = []; |
| 1533 final List<int> parameterNumberStack = []; | 1531 final List<int> parameterNumberStack = []; |
| 1534 final List<int> variableNumberStack = []; | 1532 final List<int> variableNumberStack = []; |
| 1535 int parameterNumber = 0; | 1533 int parameterNumber = 0; |
| 1536 int variableNumber = 0; | 1534 int variableNumber = 0; |
| 1537 | 1535 |
| 1538 void enterScope(FunctionExpression node) { | 1536 void enterScope(FunctionExpression node) { |
| 1539 var vars = new VarCollector(); | 1537 var vars = new VarCollector(); |
| 1540 node.accept(vars); | 1538 node.accept(vars); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1560 if (replacement != null) return replacement; | 1558 if (replacement != null) return replacement; |
| 1561 } | 1559 } |
| 1562 return oldName; | 1560 return oldName; |
| 1563 } | 1561 } |
| 1564 | 1562 |
| 1565 static const LOWER_CASE_LETTERS = 26; | 1563 static const LOWER_CASE_LETTERS = 26; |
| 1566 static const LETTERS = LOWER_CASE_LETTERS; | 1564 static const LETTERS = LOWER_CASE_LETTERS; |
| 1567 static const DIGITS = 10; | 1565 static const DIGITS = 10; |
| 1568 | 1566 |
| 1569 static int nthLetter(int n) { | 1567 static int nthLetter(int n) { |
| 1570 return (n < LOWER_CASE_LETTERS) ? | 1568 return (n < LOWER_CASE_LETTERS) |
| 1571 charCodes.$a + n : | 1569 ? charCodes.$a + n |
| 1572 charCodes.$A + n - LOWER_CASE_LETTERS; | 1570 : charCodes.$A + n - LOWER_CASE_LETTERS; |
| 1573 } | 1571 } |
| 1574 | 1572 |
| 1575 // Parameters go from a to z and variables go from z to a. This makes each | 1573 // Parameters go from a to z and variables go from z to a. This makes each |
| 1576 // argument list and each top-of-function var declaration look similar and | 1574 // argument list and each top-of-function var declaration look similar and |
| 1577 // helps gzip compress the file. If we have more than 26 arguments and | 1575 // helps gzip compress the file. If we have more than 26 arguments and |
| 1578 // variables then we meet somewhere in the middle of the alphabet. After | 1576 // variables then we meet somewhere in the middle of the alphabet. After |
| 1579 // that we give up trying to be nice to the compression algorithm and just | 1577 // that we give up trying to be nice to the compression algorithm and just |
| 1580 // use the same namespace for arguments and variables, starting with A, and | 1578 // use the same namespace for arguments and variables, starting with A, and |
| 1581 // moving on to a0, a1, etc. | 1579 // moving on to a0, a1, etc. |
| 1582 String declareVariable(String oldName) { | 1580 String declareVariable(String oldName) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1654 /// [visitIdentifier] otherwise. | 1652 /// [visitIdentifier] otherwise. |
| 1655 abstract class VariableDeclarationVisitor<T> extends BaseVisitor<T> { | 1653 abstract class VariableDeclarationVisitor<T> extends BaseVisitor<T> { |
| 1656 declare(Identifier node); | 1654 declare(Identifier node); |
| 1657 | 1655 |
| 1658 visitFunctionExpression(FunctionExpression node) { | 1656 visitFunctionExpression(FunctionExpression node) { |
| 1659 node.params.forEach(_scanVariableBinding); | 1657 node.params.forEach(_scanVariableBinding); |
| 1660 node.body.accept(this); | 1658 node.body.accept(this); |
| 1661 } | 1659 } |
| 1662 | 1660 |
| 1663 _scanVariableBinding(VariableBinding d) { | 1661 _scanVariableBinding(VariableBinding d) { |
| 1664 if (d is Identifier) declare(d); | 1662 if (d is Identifier) |
| 1665 else d.accept(this); | 1663 declare(d); |
| 1664 else |
| 1665 d.accept(this); |
| 1666 } | 1666 } |
| 1667 | 1667 |
| 1668 visitRestParameter(RestParameter node) { | 1668 visitRestParameter(RestParameter node) { |
| 1669 _scanVariableBinding(node.parameter); | 1669 _scanVariableBinding(node.parameter); |
| 1670 super.visitRestParameter(node); | 1670 super.visitRestParameter(node); |
| 1671 } | 1671 } |
| 1672 | 1672 |
| 1673 visitDestructuredVariable(DestructuredVariable node) { | 1673 visitDestructuredVariable(DestructuredVariable node) { |
| 1674 var name = node.name; | 1674 var name = node.name; |
| 1675 if (name is Identifier) _scanVariableBinding(name); | 1675 if (name is Identifier) _scanVariableBinding(name); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1700 declare(node.name); | 1700 declare(node.name); |
| 1701 node.function.accept(this); | 1701 node.function.accept(this); |
| 1702 } | 1702 } |
| 1703 | 1703 |
| 1704 visitClassExpression(ClassExpression node) { | 1704 visitClassExpression(ClassExpression node) { |
| 1705 declare(node.name); | 1705 declare(node.name); |
| 1706 if (node.heritage != null) node.heritage.accept(this); | 1706 if (node.heritage != null) node.heritage.accept(this); |
| 1707 for (Method element in node.methods) element.accept(this); | 1707 for (Method element in node.methods) element.accept(this); |
| 1708 } | 1708 } |
| 1709 } | 1709 } |
| OLD | NEW |