| 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 | 7 |
| 8 class JavaScriptPrintingOptions { | 8 class JavaScriptPrintingOptions { |
| 9 final bool shouldCompressOutput; | 9 final bool shouldCompressOutput; |
| 10 final bool minifyLocalVariables; | 10 final bool minifyLocalVariables; |
| 11 final bool preferSemicolonToNewlineInMinifiedOutput; | 11 final bool preferSemicolonToNewlineInMinifiedOutput; |
| 12 final bool shouldEmitTypes; |
| 12 final bool allowSingleLineIfStatements; | 13 final bool allowSingleLineIfStatements; |
| 13 | 14 |
| 14 /// True to allow keywords in properties, such as `obj.var` or `obj.function` | 15 /// True to allow keywords in properties, such as `obj.var` or `obj.function` |
| 15 /// Modern JS engines support this. | 16 /// Modern JS engines support this. |
| 16 final bool allowKeywordsInProperties; | 17 final bool allowKeywordsInProperties; |
| 17 | 18 |
| 18 JavaScriptPrintingOptions( | 19 JavaScriptPrintingOptions( |
| 19 {this.shouldCompressOutput: false, | 20 {this.shouldCompressOutput: false, |
| 20 this.minifyLocalVariables: false, | 21 this.minifyLocalVariables: false, |
| 21 this.preferSemicolonToNewlineInMinifiedOutput: false, | 22 this.preferSemicolonToNewlineInMinifiedOutput: false, |
| 23 this.shouldEmitTypes: false, |
| 22 this.allowKeywordsInProperties: false, | 24 this.allowKeywordsInProperties: false, |
| 23 this.allowSingleLineIfStatements: false}); | 25 this.allowSingleLineIfStatements: false}); |
| 24 } | 26 } |
| 25 | 27 |
| 26 | 28 |
| 27 /// An environment in which JavaScript printing is done. Provides emitting of | 29 /// An environment in which JavaScript printing is done. Provides emitting of |
| 28 /// text and pre- and post-visit callbacks. | 30 /// text and pre- and post-visit callbacks. |
| 29 abstract class JavaScriptPrintingContext { | 31 abstract class JavaScriptPrintingContext { |
| 30 /// Signals an error. This should happen only for serious internal errors. | 32 /// Signals an error. This should happen only for serious internal errors. |
| 31 void error(String message) { throw message; } | 33 void error(String message) { throw message; } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 44 class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext { | 46 class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext { |
| 45 final StringBuffer buffer = new StringBuffer(); | 47 final StringBuffer buffer = new StringBuffer(); |
| 46 | 48 |
| 47 void emit(String string) { | 49 void emit(String string) { |
| 48 buffer.write(string); | 50 buffer.write(string); |
| 49 } | 51 } |
| 50 | 52 |
| 51 String getText() => buffer.toString(); | 53 String getText() => buffer.toString(); |
| 52 } | 54 } |
| 53 | 55 |
| 54 | 56 // TODO(ochafik): Inline the body of [TypeScriptTypePrinter] here if/when it no |
| 55 class Printer implements NodeVisitor { | 57 // longer needs to share utils with [ClosureTypePrinter]. |
| 58 class Printer extends TypeScriptTypePrinter implements NodeVisitor { |
| 56 final JavaScriptPrintingOptions options; | 59 final JavaScriptPrintingOptions options; |
| 57 final JavaScriptPrintingContext context; | 60 final JavaScriptPrintingContext context; |
| 58 final bool shouldCompressOutput; | 61 final bool shouldCompressOutput; |
| 59 final DanglingElseVisitor danglingElseVisitor; | 62 final DanglingElseVisitor danglingElseVisitor; |
| 60 final LocalNamer localNamer; | 63 final LocalNamer localNamer; |
| 61 | 64 |
| 62 bool inForInit = false; | 65 bool inForInit = false; |
| 63 bool atStatementBegin = false; | 66 bool atStatementBegin = false; |
| 64 bool inNewTarget = false; | 67 bool inNewTarget = false; |
| 65 bool pendingSemicolon = false; | 68 bool pendingSemicolon = false; |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 void functionOut(Fun fun, Node name) { | 537 void functionOut(Fun fun, Node name) { |
| 535 out("function"); | 538 out("function"); |
| 536 if (fun.isGenerator) out("*"); | 539 if (fun.isGenerator) out("*"); |
| 537 if (name != null) { | 540 if (name != null) { |
| 538 out(" "); | 541 out(" "); |
| 539 // Name must be a [Decl]. Therefore only test for primary expressions. | 542 // Name must be a [Decl]. Therefore only test for primary expressions. |
| 540 visitNestedExpression(name, PRIMARY, | 543 visitNestedExpression(name, PRIMARY, |
| 541 newInForInit: false, newAtStatementBegin: false); | 544 newInForInit: false, newAtStatementBegin: false); |
| 542 } | 545 } |
| 543 localNamer.enterScope(fun); | 546 localNamer.enterScope(fun); |
| 547 outTypeParams(fun.typeParams); |
| 544 out("("); | 548 out("("); |
| 545 if (fun.params != null) { | 549 if (fun.params != null) { |
| 546 visitCommaSeparated(fun.params, PRIMARY, | 550 visitCommaSeparated(fun.params, PRIMARY, |
| 547 newInForInit: false, newAtStatementBegin: false); | 551 newInForInit: false, newAtStatementBegin: false); |
| 548 } | 552 } |
| 549 out(")"); | 553 out(")"); |
| 554 outTypeAnnotation(fun.returnType); |
| 550 switch (fun.asyncModifier) { | 555 switch (fun.asyncModifier) { |
| 551 case const AsyncModifier.sync(): | 556 case const AsyncModifier.sync(): |
| 552 break; | 557 break; |
| 553 case const AsyncModifier.async(): | 558 case const AsyncModifier.async(): |
| 554 out(' async'); | 559 out(' async'); |
| 555 break; | 560 break; |
| 556 case const AsyncModifier.syncStar(): | 561 case const AsyncModifier.syncStar(): |
| 557 out(' sync*'); | 562 out(' sync*'); |
| 558 break; | 563 break; |
| 559 case const AsyncModifier.asyncStar(): | 564 case const AsyncModifier.asyncStar(): |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 out(")"); | 599 out(")"); |
| 595 } else { | 600 } else { |
| 596 inForInit = newInForInit; | 601 inForInit = newInForInit; |
| 597 atStatementBegin = newAtStatementBegin; | 602 atStatementBegin = newAtStatementBegin; |
| 598 visit(node); | 603 visit(node); |
| 599 } | 604 } |
| 600 } | 605 } |
| 601 | 606 |
| 602 visitVariableDeclarationList(VariableDeclarationList list) { | 607 visitVariableDeclarationList(VariableDeclarationList list) { |
| 603 outClosureAnnotation(list); | 608 outClosureAnnotation(list); |
| 604 out(list.keyword); | 609 // Note: keyword can be null for non-static field declarations. |
| 605 out(" "); | 610 if (list.keyword != null) { |
| 611 out(list.keyword); |
| 612 out(" "); |
| 613 } |
| 606 visitCommaSeparated(list.declarations, ASSIGNMENT, | 614 visitCommaSeparated(list.declarations, ASSIGNMENT, |
| 607 newInForInit: inForInit, newAtStatementBegin: false); | 615 newInForInit: inForInit, newAtStatementBegin: false); |
| 608 } | 616 } |
| 609 | 617 |
| 610 visitArrayBindingPattern(ArrayBindingPattern node) { | 618 visitArrayBindingPattern(ArrayBindingPattern node) { |
| 611 out("["); | 619 out("["); |
| 612 visitCommaSeparated(node.variables, EXPRESSION, | 620 visitCommaSeparated(node.variables, EXPRESSION, |
| 613 newInForInit: false, newAtStatementBegin: false); | 621 newInForInit: false, newAtStatementBegin: false); |
| 614 out("]"); | 622 out("]"); |
| 615 } | 623 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 632 visit(name); | 640 visit(name); |
| 633 } | 641 } |
| 634 } | 642 } |
| 635 if (node.structure != null) { | 643 if (node.structure != null) { |
| 636 if (hasName) { | 644 if (hasName) { |
| 637 out(":"); | 645 out(":"); |
| 638 spaceOut(); | 646 spaceOut(); |
| 639 } | 647 } |
| 640 visit(node.structure); | 648 visit(node.structure); |
| 641 } | 649 } |
| 650 outTypeAnnotation(node.type); |
| 642 if (node.defaultValue != null) { | 651 if (node.defaultValue != null) { |
| 643 spaceOut(); | 652 spaceOut(); |
| 644 out("="); | 653 out("="); |
| 645 spaceOut(); | 654 spaceOut(); |
| 646 visitNestedExpression(node.defaultValue, EXPRESSION, | 655 visitNestedExpression(node.defaultValue, EXPRESSION, |
| 647 newInForInit: false, newAtStatementBegin: false); | 656 newInForInit: false, newAtStatementBegin: false); |
| 648 } | 657 } |
| 649 } | 658 } |
| 650 | 659 |
| 651 visitSimpleBindingPattern(SimpleBindingPattern node) { | 660 visitSimpleBindingPattern(SimpleBindingPattern node) { |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 visitThis(This node) { | 871 visitThis(This node) { |
| 863 out("this"); | 872 out("this"); |
| 864 } | 873 } |
| 865 | 874 |
| 866 visitSuper(Super node) { | 875 visitSuper(Super node) { |
| 867 out("super"); | 876 out("super"); |
| 868 } | 877 } |
| 869 | 878 |
| 870 visitIdentifier(Identifier node) { | 879 visitIdentifier(Identifier node) { |
| 871 out(localNamer.getName(node)); | 880 out(localNamer.getName(node)); |
| 881 outTypeAnnotation(node.type); |
| 872 } | 882 } |
| 873 | 883 |
| 874 visitRestParameter(RestParameter node) { | 884 visitRestParameter(RestParameter node) { |
| 875 out('...'); | 885 out('...'); |
| 876 visitIdentifier(node.parameter); | 886 visitIdentifier(node.parameter); |
| 877 } | 887 } |
| 878 | 888 |
| 879 bool isDigit(int charCode) { | 889 bool isDigit(int charCode) { |
| 880 return charCodes.$0 <= charCode && charCode <= charCodes.$9; | 890 return charCodes.$0 <= charCode && charCode <= charCodes.$9; |
| 881 } | 891 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 visitNamedFunction(NamedFunction namedFunction) { | 937 visitNamedFunction(NamedFunction namedFunction) { |
| 928 functionOut(namedFunction.function, namedFunction.name); | 938 functionOut(namedFunction.function, namedFunction.name); |
| 929 } | 939 } |
| 930 | 940 |
| 931 visitFun(Fun fun) { | 941 visitFun(Fun fun) { |
| 932 functionOut(fun, null); | 942 functionOut(fun, null); |
| 933 } | 943 } |
| 934 | 944 |
| 935 visitArrowFun(ArrowFun fun) { | 945 visitArrowFun(ArrowFun fun) { |
| 936 localNamer.enterScope(fun); | 946 localNamer.enterScope(fun); |
| 937 if (fun.params.length == 1) { | 947 if (fun.params.length == 1 && |
| 948 (fun.params.single.type == null || !options.shouldEmitTypes)) { |
| 938 visitNestedExpression(fun.params.single, SPREAD, | 949 visitNestedExpression(fun.params.single, SPREAD, |
| 939 newInForInit: false, newAtStatementBegin: false); | 950 newInForInit: false, newAtStatementBegin: false); |
| 940 } else { | 951 } else { |
| 941 out("("); | 952 out("("); |
| 942 visitCommaSeparated(fun.params, SPREAD, | 953 visitCommaSeparated(fun.params, SPREAD, |
| 943 newInForInit: false, newAtStatementBegin: false); | 954 newInForInit: false, newAtStatementBegin: false); |
| 944 out(")"); | 955 out(")"); |
| 945 } | 956 } |
| 957 outTypeAnnotation(fun.returnType); |
| 946 spaceOut(); | 958 spaceOut(); |
| 947 out("=>"); | 959 out("=>"); |
| 948 if (fun.body is Expression) { | 960 if (fun.body is Expression) { |
| 949 spaceOut(); | 961 spaceOut(); |
| 950 // Object initializers require parenthesis to disambiguate | 962 // Object initializers require parenthesis to disambiguate |
| 951 // AssignmentExpression from FunctionBody. See: | 963 // AssignmentExpression from FunctionBody. See: |
| 952 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio
n-definitions | 964 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio
n-definitions |
| 953 var needsParen = fun.body is ObjectInitializer; | 965 var needsParen = fun.body is ObjectInitializer; |
| 954 if (needsParen) out("("); | 966 if (needsParen) out("("); |
| 955 visitNestedExpression(fun.body, ASSIGNMENT, | 967 visitNestedExpression(fun.body, ASSIGNMENT, |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 visit(node.tag); | 1086 visit(node.tag); |
| 1075 visit(node.template); | 1087 visit(node.template); |
| 1076 } | 1088 } |
| 1077 | 1089 |
| 1078 visitClassDeclaration(ClassDeclaration node) { | 1090 visitClassDeclaration(ClassDeclaration node) { |
| 1079 indent(); | 1091 indent(); |
| 1080 visit(node.classExpr); | 1092 visit(node.classExpr); |
| 1081 lineOut(); | 1093 lineOut(); |
| 1082 } | 1094 } |
| 1083 | 1095 |
| 1096 void outTypeParams(Iterable<Identifier> typeParams) { |
| 1097 if (typeParams != null && options.shouldEmitTypes && typeParams.isNotEmpty)
{ |
| 1098 out("<"); |
| 1099 var first = true; |
| 1100 for (var typeParam in typeParams) { |
| 1101 if (!first) out(", "); |
| 1102 first = false; |
| 1103 visit(typeParam); |
| 1104 } |
| 1105 out(">"); |
| 1106 } |
| 1107 } |
| 1108 |
| 1084 visitClassExpression(ClassExpression node) { | 1109 visitClassExpression(ClassExpression node) { |
| 1085 out('class '); | 1110 out('class '); |
| 1086 visit(node.name); | 1111 visit(node.name); |
| 1112 outTypeParams(node.typeParams); |
| 1087 if (node.heritage != null) { | 1113 if (node.heritage != null) { |
| 1088 out(' extends '); | 1114 out(' extends '); |
| 1089 visit(node.heritage); | 1115 visit(node.heritage); |
| 1090 } | 1116 } |
| 1091 spaceOut(); | 1117 spaceOut(); |
| 1092 if (node.methods.isNotEmpty) { | 1118 if (node.methods.isNotEmpty) { |
| 1093 out('{'); | 1119 out('{'); |
| 1094 lineOut(); | 1120 lineOut(); |
| 1095 indentMore(); | 1121 indentMore(); |
| 1122 if (options.shouldEmitTypes && node.fields != null) { |
| 1123 for (var field in node.fields) { |
| 1124 indent(); |
| 1125 visit(field); |
| 1126 out(";"); |
| 1127 lineOut(); |
| 1128 } |
| 1129 } |
| 1096 for (var method in node.methods) { | 1130 for (var method in node.methods) { |
| 1097 indent(); | 1131 indent(); |
| 1098 visit(method); | 1132 visit(method); |
| 1099 lineOut(); | 1133 lineOut(); |
| 1100 } | 1134 } |
| 1101 indentLess(); | 1135 indentLess(); |
| 1102 indent(); | 1136 indent(); |
| 1103 out('}'); | 1137 out('}'); |
| 1104 } else { | 1138 } else { |
| 1105 out('{}'); | 1139 out('{}'); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 } else { | 1351 } else { |
| 1318 out('/* $comment */'); | 1352 out('/* $comment */'); |
| 1319 } | 1353 } |
| 1320 visit(node.expression); | 1354 visit(node.expression); |
| 1321 } | 1355 } |
| 1322 | 1356 |
| 1323 void visitAwait(Await node) { | 1357 void visitAwait(Await node) { |
| 1324 out("await "); | 1358 out("await "); |
| 1325 visit(node.expression); | 1359 visit(node.expression); |
| 1326 } | 1360 } |
| 1361 |
| 1362 void outTypeAnnotation(TypeRef node) { |
| 1363 if (node == null || !options.shouldEmitTypes || node.isUnknown) return; |
| 1364 |
| 1365 if (node is OptionalTypeRef) { |
| 1366 out("?: "); |
| 1367 visit(node.type); |
| 1368 } else { |
| 1369 out(": "); |
| 1370 visit(node); |
| 1371 } |
| 1372 } |
| 1327 } | 1373 } |
| 1328 | 1374 |
| 1329 // Collects all the var declarations in the function. We need to do this in a | 1375 // Collects all the var declarations in the function. We need to do this in a |
| 1330 // separate pass because JS vars are lifted to the top of the function. | 1376 // separate pass because JS vars are lifted to the top of the function. |
| 1331 class VarCollector extends BaseVisitor { | 1377 class VarCollector extends BaseVisitor { |
| 1332 bool nested; | 1378 bool nested; |
| 1333 final Set<String> vars; | 1379 final Set<String> vars; |
| 1334 final Set<String> params; | 1380 final Set<String> params; |
| 1335 | 1381 |
| 1336 VarCollector() : nested = false, | 1382 VarCollector() : nested = false, |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 declare(node.name); | 1682 declare(node.name); |
| 1637 node.function.accept(this); | 1683 node.function.accept(this); |
| 1638 } | 1684 } |
| 1639 | 1685 |
| 1640 visitClassExpression(ClassExpression node) { | 1686 visitClassExpression(ClassExpression node) { |
| 1641 declare(node.name); | 1687 declare(node.name); |
| 1642 if (node.heritage != null) node.heritage.accept(this); | 1688 if (node.heritage != null) node.heritage.accept(this); |
| 1643 for (Method element in node.methods) element.accept(this); | 1689 for (Method element in node.methods) element.accept(this); |
| 1644 } | 1690 } |
| 1645 } | 1691 } |
| OLD | NEW |