Chromium Code Reviews| 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 printTypes; | |
|
Jennifer Messerly
2016/02/09 01:21:33
this sounds like a method name. Maybe "shouldPrint
ochafik
2016/02/10 18:12:45
Thanks, went for 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.printTypes: 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 13 matching lines...) Expand all Loading... | |
| 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 |
| 55 class Printer implements NodeVisitor { | 57 class Printer extends TypeScriptTypePrinter implements NodeVisitor { |
|
Jennifer Messerly
2016/02/09 01:21:34
Hmmm. I haven't seen the other class yet, but this
ochafik
2016/02/10 18:12:45
Good point, left a TODO for when/if we drop Closur
| |
| 56 final JavaScriptPrintingOptions options; | 58 final JavaScriptPrintingOptions options; |
| 57 final JavaScriptPrintingContext context; | 59 final JavaScriptPrintingContext context; |
| 58 final bool shouldCompressOutput; | 60 final bool shouldCompressOutput; |
| 59 final DanglingElseVisitor danglingElseVisitor; | 61 final DanglingElseVisitor danglingElseVisitor; |
| 60 final LocalNamer localNamer; | 62 final LocalNamer localNamer; |
| 61 | 63 |
| 62 bool inForInit = false; | 64 bool inForInit = false; |
| 63 bool atStatementBegin = false; | 65 bool atStatementBegin = false; |
| 64 bool inNewTarget = false; | 66 bool inNewTarget = false; |
| 65 bool pendingSemicolon = false; | 67 bool pendingSemicolon = false; |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 534 void functionOut(Fun fun, Node name) { | 536 void functionOut(Fun fun, Node name) { |
| 535 out("function"); | 537 out("function"); |
| 536 if (fun.isGenerator) out("*"); | 538 if (fun.isGenerator) out("*"); |
| 537 if (name != null) { | 539 if (name != null) { |
| 538 out(" "); | 540 out(" "); |
| 539 // Name must be a [Decl]. Therefore only test for primary expressions. | 541 // Name must be a [Decl]. Therefore only test for primary expressions. |
| 540 visitNestedExpression(name, PRIMARY, | 542 visitNestedExpression(name, PRIMARY, |
| 541 newInForInit: false, newAtStatementBegin: false); | 543 newInForInit: false, newAtStatementBegin: false); |
| 542 } | 544 } |
| 543 localNamer.enterScope(fun); | 545 localNamer.enterScope(fun); |
| 546 outTypeArgs(fun.typeArgs); | |
| 544 out("("); | 547 out("("); |
| 545 if (fun.params != null) { | 548 if (fun.params != null) { |
| 546 visitCommaSeparated(fun.params, PRIMARY, | 549 visitCommaSeparated(fun.params, PRIMARY, |
| 547 newInForInit: false, newAtStatementBegin: false); | 550 newInForInit: false, newAtStatementBegin: false); |
| 548 } | 551 } |
| 549 out(")"); | 552 out(")"); |
| 553 outTypeAnnotation(fun.returnType); | |
| 550 switch (fun.asyncModifier) { | 554 switch (fun.asyncModifier) { |
| 551 case const AsyncModifier.sync(): | 555 case const AsyncModifier.sync(): |
| 552 break; | 556 break; |
| 553 case const AsyncModifier.async(): | 557 case const AsyncModifier.async(): |
| 554 out(' async'); | 558 out(' async'); |
| 555 break; | 559 break; |
| 556 case const AsyncModifier.syncStar(): | 560 case const AsyncModifier.syncStar(): |
| 557 out(' sync*'); | 561 out(' sync*'); |
| 558 break; | 562 break; |
| 559 case const AsyncModifier.asyncStar(): | 563 case const AsyncModifier.asyncStar(): |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 594 out(")"); | 598 out(")"); |
| 595 } else { | 599 } else { |
| 596 inForInit = newInForInit; | 600 inForInit = newInForInit; |
| 597 atStatementBegin = newAtStatementBegin; | 601 atStatementBegin = newAtStatementBegin; |
| 598 visit(node); | 602 visit(node); |
| 599 } | 603 } |
| 600 } | 604 } |
| 601 | 605 |
| 602 visitVariableDeclarationList(VariableDeclarationList list) { | 606 visitVariableDeclarationList(VariableDeclarationList list) { |
| 603 outClosureAnnotation(list); | 607 outClosureAnnotation(list); |
| 604 out(list.keyword); | 608 // Note: keyword can be null for non-static field declarations. |
| 605 out(" "); | 609 if (list.keyword != null) { |
| 610 out(list.keyword); | |
| 611 out(" "); | |
| 612 } | |
| 606 visitCommaSeparated(list.declarations, ASSIGNMENT, | 613 visitCommaSeparated(list.declarations, ASSIGNMENT, |
| 607 newInForInit: inForInit, newAtStatementBegin: false); | 614 newInForInit: inForInit, newAtStatementBegin: false); |
| 608 } | 615 } |
| 609 | 616 |
| 610 visitArrayBindingPattern(ArrayBindingPattern node) { | 617 visitArrayBindingPattern(ArrayBindingPattern node) { |
| 611 out("["); | 618 out("["); |
| 612 visitCommaSeparated(node.variables, EXPRESSION, | 619 visitCommaSeparated(node.variables, EXPRESSION, |
| 613 newInForInit: false, newAtStatementBegin: false); | 620 newInForInit: false, newAtStatementBegin: false); |
| 614 out("]"); | 621 out("]"); |
| 615 } | 622 } |
| 616 visitObjectBindingPattern(ObjectBindingPattern node) { | 623 visitObjectBindingPattern(ObjectBindingPattern node) { |
| 617 out("{"); | 624 out("{"); |
| 618 visitCommaSeparated(node.variables, EXPRESSION, | 625 visitCommaSeparated(node.variables, EXPRESSION, |
| 619 newInForInit: false, newAtStatementBegin: false); | 626 newInForInit: false, newAtStatementBegin: false); |
| 620 out("}"); | 627 out("}"); |
| 621 } | 628 } |
| 622 | 629 |
| 623 visitDestructuredVariable(DestructuredVariable node) { | 630 visitDestructuredVariable(DestructuredVariable node) { |
| 624 var hasName = node.name != null; | 631 var hasName = node.name != null; |
| 625 if (hasName) visit(node.name); | 632 if (hasName) visit(node.name); |
| 626 if (node.structure != null) { | 633 if (node.structure != null) { |
| 627 if (hasName) { | 634 if (hasName) { |
| 628 out(":"); | 635 out(":"); |
| 629 spaceOut(); | 636 spaceOut(); |
| 630 } | 637 } |
| 631 visit(node.structure); | 638 visit(node.structure); |
| 632 } | 639 } |
| 640 outTypeAnnotation(node.type); | |
| 633 if (node.defaultValue != null) { | 641 if (node.defaultValue != null) { |
| 634 spaceOut(); | 642 spaceOut(); |
| 635 out("="); | 643 out("="); |
| 636 spaceOut(); | 644 spaceOut(); |
| 637 visitNestedExpression(node.defaultValue, EXPRESSION, | 645 visitNestedExpression(node.defaultValue, EXPRESSION, |
| 638 newInForInit: false, newAtStatementBegin: false); | 646 newInForInit: false, newAtStatementBegin: false); |
| 639 } | 647 } |
| 640 } | 648 } |
| 641 | 649 |
| 642 visitAssignment(Assignment assignment) { | 650 visitAssignment(Assignment assignment) { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 849 visitThis(This node) { | 857 visitThis(This node) { |
| 850 out("this"); | 858 out("this"); |
| 851 } | 859 } |
| 852 | 860 |
| 853 visitSuper(Super node) { | 861 visitSuper(Super node) { |
| 854 out("super"); | 862 out("super"); |
| 855 } | 863 } |
| 856 | 864 |
| 857 visitIdentifier(Identifier node) { | 865 visitIdentifier(Identifier node) { |
| 858 out(localNamer.getName(node)); | 866 out(localNamer.getName(node)); |
| 867 outTypeAnnotation(node.type); | |
| 859 } | 868 } |
| 860 | 869 |
| 861 visitRestParameter(RestParameter node) { | 870 visitRestParameter(RestParameter node) { |
| 862 out('...'); | 871 out('...'); |
| 863 visitIdentifier(node.parameter); | 872 visitIdentifier(node.parameter); |
| 864 } | 873 } |
| 865 | 874 |
| 866 bool isDigit(int charCode) { | 875 bool isDigit(int charCode) { |
| 867 return charCodes.$0 <= charCode && charCode <= charCodes.$9; | 876 return charCodes.$0 <= charCode && charCode <= charCodes.$9; |
| 868 } | 877 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 visitNamedFunction(NamedFunction namedFunction) { | 923 visitNamedFunction(NamedFunction namedFunction) { |
| 915 functionOut(namedFunction.function, namedFunction.name); | 924 functionOut(namedFunction.function, namedFunction.name); |
| 916 } | 925 } |
| 917 | 926 |
| 918 visitFun(Fun fun) { | 927 visitFun(Fun fun) { |
| 919 functionOut(fun, null); | 928 functionOut(fun, null); |
| 920 } | 929 } |
| 921 | 930 |
| 922 visitArrowFun(ArrowFun fun) { | 931 visitArrowFun(ArrowFun fun) { |
| 923 localNamer.enterScope(fun); | 932 localNamer.enterScope(fun); |
| 924 if (fun.params.length == 1) { | 933 if (fun.params.length == 1 && |
| 934 (fun.params.single.type == null || !options.printTypes)) { | |
| 925 visitNestedExpression(fun.params.single, SPREAD, | 935 visitNestedExpression(fun.params.single, SPREAD, |
| 926 newInForInit: false, newAtStatementBegin: false); | 936 newInForInit: false, newAtStatementBegin: false); |
| 927 } else { | 937 } else { |
| 928 out("("); | 938 out("("); |
| 929 visitCommaSeparated(fun.params, SPREAD, | 939 visitCommaSeparated(fun.params, SPREAD, |
| 930 newInForInit: false, newAtStatementBegin: false); | 940 newInForInit: false, newAtStatementBegin: false); |
| 931 out(")"); | 941 out(")"); |
| 932 } | 942 } |
| 943 outTypeAnnotation(fun.returnType); | |
| 933 spaceOut(); | 944 spaceOut(); |
| 934 out("=>"); | 945 out("=>"); |
| 935 if (fun.body is Expression) { | 946 if (fun.body is Expression) { |
| 936 spaceOut(); | 947 spaceOut(); |
| 937 // Object initializers require parenthesis to disambiguate | 948 // Object initializers require parenthesis to disambiguate |
| 938 // AssignmentExpression from FunctionBody. See: | 949 // AssignmentExpression from FunctionBody. See: |
| 939 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio n-definitions | 950 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio n-definitions |
| 940 var needsParen = fun.body is ObjectInitializer; | 951 var needsParen = fun.body is ObjectInitializer; |
| 941 if (needsParen) out("("); | 952 if (needsParen) out("("); |
| 942 visitNestedExpression(fun.body, ASSIGNMENT, | 953 visitNestedExpression(fun.body, ASSIGNMENT, |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1061 visit(node.tag); | 1072 visit(node.tag); |
| 1062 visit(node.template); | 1073 visit(node.template); |
| 1063 } | 1074 } |
| 1064 | 1075 |
| 1065 visitClassDeclaration(ClassDeclaration node) { | 1076 visitClassDeclaration(ClassDeclaration node) { |
| 1066 indent(); | 1077 indent(); |
| 1067 visit(node.classExpr); | 1078 visit(node.classExpr); |
| 1068 lineOut(); | 1079 lineOut(); |
| 1069 } | 1080 } |
| 1070 | 1081 |
| 1082 outTypeArgs(List<Identifier> typeArgs) { | |
| 1083 if (options.printTypes && typeArgs != null && typeArgs.isNotEmpty) { | |
|
Jennifer Messerly
2016/02/09 01:21:33
null check on variable/param is probably fastest,
ochafik
2016/02/10 18:12:45
Done.
| |
| 1084 out("<"); | |
|
Jennifer Messerly
2016/02/09 01:21:33
does typescript have any cases where precedence co
ochafik
2016/02/10 18:12:45
It *looks* fine in TS (since the : would announce
| |
| 1085 var first = true; | |
| 1086 for (var typeParam in typeArgs) { | |
| 1087 if (!first) out(", "); | |
| 1088 first = false; | |
| 1089 visit(typeParam); | |
| 1090 } | |
| 1091 out(">"); | |
| 1092 } | |
| 1093 } | |
| 1094 | |
| 1071 visitClassExpression(ClassExpression node) { | 1095 visitClassExpression(ClassExpression node) { |
| 1072 out('class '); | 1096 out('class '); |
| 1073 visit(node.name); | 1097 visit(node.name); |
| 1098 outTypeArgs(node.typeArgs); | |
| 1074 if (node.heritage != null) { | 1099 if (node.heritage != null) { |
| 1075 out(' extends '); | 1100 out(' extends '); |
| 1076 visit(node.heritage); | 1101 visit(node.heritage); |
| 1077 } | 1102 } |
| 1078 spaceOut(); | 1103 spaceOut(); |
| 1079 if (node.methods.isNotEmpty) { | 1104 if (node.methods.isNotEmpty) { |
| 1080 out('{'); | 1105 out('{'); |
| 1081 lineOut(); | 1106 lineOut(); |
| 1082 indentMore(); | 1107 indentMore(); |
| 1108 if (options.printTypes) { | |
| 1109 for (var field in node.fields) { | |
| 1110 indent(); | |
| 1111 visit(field); | |
| 1112 out(";"); | |
| 1113 lineOut(); | |
| 1114 } | |
| 1115 } | |
| 1083 for (var method in node.methods) { | 1116 for (var method in node.methods) { |
| 1084 indent(); | 1117 indent(); |
| 1085 visit(method); | 1118 visit(method); |
| 1086 lineOut(); | 1119 lineOut(); |
| 1087 } | 1120 } |
| 1088 indentLess(); | 1121 indentLess(); |
| 1089 indent(); | 1122 indent(); |
| 1090 out('}'); | 1123 out('}'); |
| 1091 } else { | 1124 } else { |
| 1092 out('{}'); | 1125 out('{}'); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1304 } else { | 1337 } else { |
| 1305 out('/* $comment */'); | 1338 out('/* $comment */'); |
| 1306 } | 1339 } |
| 1307 visit(node.expression); | 1340 visit(node.expression); |
| 1308 } | 1341 } |
| 1309 | 1342 |
| 1310 void visitAwait(Await node) { | 1343 void visitAwait(Await node) { |
| 1311 out("await "); | 1344 out("await "); |
| 1312 visit(node.expression); | 1345 visit(node.expression); |
| 1313 } | 1346 } |
| 1347 | |
| 1348 void outTypeAnnotation(TypeRef node) { | |
| 1349 if (!options.printTypes || node == null || node.isUnknown) return; | |
|
Jennifer Messerly
2016/02/09 01:21:33
silly micro opt: check null first
ochafik
2016/02/10 18:12:45
Done.
| |
| 1350 | |
| 1351 if (node is OptionalTypeRef) { | |
| 1352 out("?: "); | |
| 1353 visit(node.type); | |
| 1354 } else { | |
| 1355 out(": "); | |
| 1356 visit(node); | |
| 1357 } | |
| 1358 } | |
| 1314 } | 1359 } |
| 1315 | 1360 |
| 1316 // Collects all the var declarations in the function. We need to do this in a | 1361 // Collects all the var declarations in the function. We need to do this in a |
| 1317 // separate pass because JS vars are lifted to the top of the function. | 1362 // separate pass because JS vars are lifted to the top of the function. |
| 1318 class VarCollector extends BaseVisitor { | 1363 class VarCollector extends BaseVisitor { |
| 1319 bool nested; | 1364 bool nested; |
| 1320 final Set<String> vars; | 1365 final Set<String> vars; |
| 1321 final Set<String> params; | 1366 final Set<String> params; |
| 1322 | 1367 |
| 1323 VarCollector() : nested = false, | 1368 VarCollector() : nested = false, |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1613 declare(node.name); | 1658 declare(node.name); |
| 1614 node.function.accept(this); | 1659 node.function.accept(this); |
| 1615 } | 1660 } |
| 1616 | 1661 |
| 1617 visitClassExpression(ClassExpression node) { | 1662 visitClassExpression(ClassExpression node) { |
| 1618 declare(node.name); | 1663 declare(node.name); |
| 1619 if (node.heritage != null) node.heritage.accept(this); | 1664 if (node.heritage != null) node.heritage.accept(this); |
| 1620 for (Method element in node.methods) element.accept(this); | 1665 for (Method element in node.methods) element.accept(this); |
| 1621 } | 1666 } |
| 1622 } | 1667 } |
| OLD | NEW |