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 avoidKeywordsInIdentifiers; |
12 | 13 |
13 JavaScriptPrintingOptions( | 14 JavaScriptPrintingOptions( |
14 {this.shouldCompressOutput: false, | 15 {this.shouldCompressOutput: false, |
15 this.minifyLocalVariables: false, | 16 this.minifyLocalVariables: false, |
16 this.preferSemicolonToNewlineInMinifiedOutput: false}); | 17 this.preferSemicolonToNewlineInMinifiedOutput: false, |
| 18 this.avoidKeywordsInIdentifiers: false}); |
17 } | 19 } |
18 | 20 |
19 | 21 |
20 /// An environment in which JavaScript printing is done. Provides emitting of | 22 /// An environment in which JavaScript printing is done. Provides emitting of |
21 /// text and pre- and post-visit callbacks. | 23 /// text and pre- and post-visit callbacks. |
22 abstract class JavaScriptPrintingContext { | 24 abstract class JavaScriptPrintingContext { |
23 /// Signals an error. This should happen only for serious internal errors. | 25 /// Signals an error. This should happen only for serious internal errors. |
24 void error(String message) { throw message; } | 26 void error(String message) { throw message; } |
25 | 27 |
26 /// Adds [string] to the output. | 28 /// Adds [string] to the output. |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 visitNestedExpression(loop.leftHandSide, EXPRESSION, | 339 visitNestedExpression(loop.leftHandSide, EXPRESSION, |
338 newInForInit: true, newAtStatementBegin: false); | 340 newInForInit: true, newAtStatementBegin: false); |
339 out(" in"); | 341 out(" in"); |
340 pendingSpace = true; | 342 pendingSpace = true; |
341 visitNestedExpression(loop.object, EXPRESSION, | 343 visitNestedExpression(loop.object, EXPRESSION, |
342 newInForInit: false, newAtStatementBegin: false); | 344 newInForInit: false, newAtStatementBegin: false); |
343 out(")"); | 345 out(")"); |
344 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 346 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
345 } | 347 } |
346 | 348 |
| 349 visitForOf(ForOf loop) { |
| 350 outIndent("for"); |
| 351 spaceOut(); |
| 352 out("("); |
| 353 visitNestedExpression(loop.leftHandSide, EXPRESSION, |
| 354 newInForInit: true, newAtStatementBegin: false); |
| 355 out(" of"); |
| 356 pendingSpace = true; |
| 357 visitNestedExpression(loop.iterable, EXPRESSION, |
| 358 newInForInit: false, newAtStatementBegin: false); |
| 359 out(")"); |
| 360 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
| 361 } |
| 362 |
347 visitWhile(While loop) { | 363 visitWhile(While loop) { |
348 outIndent("while"); | 364 outIndent("while"); |
349 spaceOut(); | 365 spaceOut(); |
350 out("("); | 366 out("("); |
351 visitNestedExpression(loop.condition, EXPRESSION, | 367 visitNestedExpression(loop.condition, EXPRESSION, |
352 newInForInit: false, newAtStatementBegin: false); | 368 newInForInit: false, newAtStatementBegin: false); |
353 out(")"); | 369 out(")"); |
354 blockBody(loop.body, needsSeparation: false, needsNewline: true); | 370 blockBody(loop.body, needsSeparation: false, needsNewline: true); |
355 } | 371 } |
356 | 372 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 {bool newInForInit, bool newAtStatementBegin}) { | 549 {bool newInForInit, bool newAtStatementBegin}) { |
534 bool needsParentheses = | 550 bool needsParentheses = |
535 // a - (b + c). | 551 // a - (b + c). |
536 (requiredPrecedence != EXPRESSION && | 552 (requiredPrecedence != EXPRESSION && |
537 node.precedenceLevel < requiredPrecedence) || | 553 node.precedenceLevel < requiredPrecedence) || |
538 // for (a = (x in o); ... ; ... ) { ... } | 554 // for (a = (x in o); ... ; ... ) { ... } |
539 (newInForInit && node is Binary && node.op == "in") || | 555 (newInForInit && node is Binary && node.op == "in") || |
540 // (function() { ... })(). | 556 // (function() { ... })(). |
541 // ({a: 2, b: 3}.toString()). | 557 // ({a: 2, b: 3}.toString()). |
542 (newAtStatementBegin && (node is NamedFunction || | 558 (newAtStatementBegin && (node is NamedFunction || |
543 node is Fun || | 559 node is FunctionExpression || |
544 node is ObjectInitializer)); | 560 node is ObjectInitializer)); |
545 if (needsParentheses) { | 561 if (needsParentheses) { |
546 inForInit = false; | 562 inForInit = false; |
547 atStatementBegin = false; | 563 atStatementBegin = false; |
548 out("("); | 564 out("("); |
549 visit(node); | 565 visit(node); |
550 out(")"); | 566 out(")"); |
551 } else { | 567 } else { |
552 inForInit = newInForInit; | 568 inForInit = newInForInit; |
553 atStatementBegin = newAtStatementBegin; | 569 atStatementBegin = newAtStatementBegin; |
554 visit(node); | 570 visit(node); |
555 } | 571 } |
556 } | 572 } |
557 | 573 |
558 visitVariableDeclarationList(VariableDeclarationList list) { | 574 visitVariableDeclarationList(VariableDeclarationList list) { |
559 out("var "); | 575 out(list.keyword); |
| 576 out(" "); |
560 visitCommaSeparated(list.declarations, ASSIGNMENT, | 577 visitCommaSeparated(list.declarations, ASSIGNMENT, |
561 newInForInit: inForInit, newAtStatementBegin: false); | 578 newInForInit: inForInit, newAtStatementBegin: false); |
562 } | 579 } |
563 | 580 |
564 visitAssignment(Assignment assignment) { | 581 visitAssignment(Assignment assignment) { |
565 visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, | 582 visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE, |
566 newInForInit: inForInit, | 583 newInForInit: inForInit, |
567 newAtStatementBegin: atStatementBegin); | 584 newAtStatementBegin: atStatementBegin); |
568 if (assignment.value != null) { | 585 if (assignment.value != null) { |
569 spaceOut(); | 586 spaceOut(); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 } | 773 } |
757 | 774 |
758 visitVariableUse(VariableUse ref) { | 775 visitVariableUse(VariableUse ref) { |
759 out(localNamer.getName(ref.name)); | 776 out(localNamer.getName(ref.name)); |
760 } | 777 } |
761 | 778 |
762 visitThis(This node) { | 779 visitThis(This node) { |
763 out("this"); | 780 out("this"); |
764 } | 781 } |
765 | 782 |
| 783 visitSuper(Super node) { |
| 784 out("super"); |
| 785 } |
| 786 |
766 visitVariableDeclaration(VariableDeclaration decl) { | 787 visitVariableDeclaration(VariableDeclaration decl) { |
767 out(localNamer.getName(decl.name)); | 788 out(localNamer.getName(decl.name)); |
768 } | 789 } |
769 | 790 |
770 visitParameter(Parameter param) { | 791 visitParameter(Parameter param) { |
771 out(localNamer.getName(param.name)); | 792 out(localNamer.getName(param.name)); |
772 } | 793 } |
773 | 794 |
774 bool isDigit(int charCode) { | 795 bool isDigit(int charCode) { |
775 return charCodes.$0 <= charCode && charCode <= charCodes.$9; | 796 return charCodes.$0 <= charCode && charCode <= charCodes.$9; |
776 } | 797 } |
777 | 798 |
778 bool isValidJavaScriptId(String field) { | 799 bool isValidJavaScriptId(String field) { |
779 if (field.length < 3) return false; | 800 if (field.length < 3) return false; |
780 // Ignore the leading and trailing string-delimiter. | 801 // Ignore the leading and trailing string-delimiter. |
781 for (int i = 1; i < field.length - 1; i++) { | 802 for (int i = 1; i < field.length - 1; i++) { |
782 // TODO(floitsch): allow more characters. | 803 // TODO(floitsch): allow more characters. |
783 int charCode = field.codeUnitAt(i); | 804 int charCode = field.codeUnitAt(i); |
784 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || | 805 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || |
785 charCodes.$A <= charCode && charCode <= charCodes.$Z || | 806 charCodes.$A <= charCode && charCode <= charCodes.$Z || |
786 charCode == charCodes.$$ || | 807 charCode == charCodes.$$ || |
787 charCode == charCodes.$_ || | 808 charCode == charCodes.$_ || |
788 i != 1 && isDigit(charCode))) { | 809 i != 1 && isDigit(charCode))) { |
789 return false; | 810 return false; |
790 } | 811 } |
791 } | 812 } |
792 // TODO(floitsch): normally we should also check that the field is not a | 813 |
793 // reserved word. We don't generate fields with reserved word names except | 814 if (options.avoidKeywordsInIdentifiers) { |
794 // for 'super'. | 815 return !_isJsKeyword(field.substring(1, field.length - 1)); |
795 if (field == '"super"') return false; | 816 } else { |
796 return true; | 817 // TODO(floitsch): normally we should also check that the field is not a |
| 818 // reserved word. We don't generate fields with reserved word names excep
t |
| 819 // for 'super'. |
| 820 return field != '"super"'; |
| 821 } |
| 822 } |
| 823 |
| 824 static bool _isJsKeyword(String keyword) { |
| 825 switch (keyword) { |
| 826 case "break": |
| 827 case "case": |
| 828 case "catch": |
| 829 case "class": |
| 830 case "const": |
| 831 case "continue": |
| 832 case "debugger": |
| 833 case "default": |
| 834 case "delete": |
| 835 case "do": |
| 836 case "else": |
| 837 case "export": |
| 838 case "extends": |
| 839 case "finally": |
| 840 case "for": |
| 841 case "function": |
| 842 case "if": |
| 843 case "import": |
| 844 case "in": |
| 845 case "instanceof": |
| 846 case "let": |
| 847 case "new": |
| 848 case "return": |
| 849 case "static": |
| 850 case "super": |
| 851 case "switch": |
| 852 case "this": |
| 853 case "throw": |
| 854 case "try": |
| 855 case "typeof": |
| 856 case "var": |
| 857 case "void": |
| 858 case "while": |
| 859 case "with": |
| 860 case "yield": |
| 861 return true; |
| 862 } |
| 863 return false; |
797 } | 864 } |
798 | 865 |
799 visitAccess(PropertyAccess access) { | 866 visitAccess(PropertyAccess access) { |
800 visitNestedExpression(access.receiver, CALL, | 867 visitNestedExpression(access.receiver, CALL, |
801 newInForInit: inForInit, | 868 newInForInit: inForInit, |
802 newAtStatementBegin: atStatementBegin); | 869 newAtStatementBegin: atStatementBegin); |
803 Node selector = access.selector; | 870 Node selector = access.selector; |
804 if (selector is LiteralString) { | 871 if (selector is LiteralString) { |
805 LiteralString selectorString = selector; | 872 LiteralString selectorString = selector; |
806 String fieldWithQuotes = selectorString.value; | 873 String fieldWithQuotes = selectorString.value; |
(...skipping 15 matching lines...) Expand all Loading... |
822 vars.visitNamedFunction(namedFunction); | 889 vars.visitNamedFunction(namedFunction); |
823 functionOut(namedFunction.function, namedFunction.name, vars); | 890 functionOut(namedFunction.function, namedFunction.name, vars); |
824 } | 891 } |
825 | 892 |
826 visitFun(Fun fun) { | 893 visitFun(Fun fun) { |
827 VarCollector vars = new VarCollector(); | 894 VarCollector vars = new VarCollector(); |
828 vars.visitFun(fun); | 895 vars.visitFun(fun); |
829 functionOut(fun, null, vars); | 896 functionOut(fun, null, vars); |
830 } | 897 } |
831 | 898 |
| 899 visitArrowFun(ArrowFun fun) { |
| 900 VarCollector vars = new VarCollector(); |
| 901 vars.visitArrowFun(fun); |
| 902 localNamer.enterScope(vars); |
| 903 out("("); |
| 904 if (fun.params != null) { |
| 905 visitCommaSeparated(fun.params, PRIMARY, |
| 906 newInForInit: false, newAtStatementBegin: false); |
| 907 } |
| 908 out(")"); |
| 909 spaceOut(); |
| 910 out("=>"); |
| 911 if (fun.body is Expression) { |
| 912 spaceOut(); |
| 913 fun.body.accept(this); |
| 914 } else { |
| 915 blockBody(fun.body, needsSeparation: false, needsNewline: false); |
| 916 } |
| 917 localNamer.leaveScope(); |
| 918 } |
| 919 |
832 visitLiteralBool(LiteralBool node) { | 920 visitLiteralBool(LiteralBool node) { |
833 out(node.value ? "true" : "false"); | 921 out(node.value ? "true" : "false"); |
834 } | 922 } |
835 | 923 |
836 visitLiteralString(LiteralString node) { | 924 visitLiteralString(LiteralString node) { |
837 out(node.value); | 925 out(node.value); |
838 } | 926 } |
839 | 927 |
840 visitLiteralNumber(LiteralNumber node) { | 928 visitLiteralNumber(LiteralNumber node) { |
841 int charCode = node.value.codeUnitAt(0); | 929 int charCode = node.value.codeUnitAt(0); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
876 throw "Unreachable"; | 964 throw "Unreachable"; |
877 } | 965 } |
878 | 966 |
879 visitObjectInitializer(ObjectInitializer node) { | 967 visitObjectInitializer(ObjectInitializer node) { |
880 // Print all the properties on one line until we see a function-valued | 968 // Print all the properties on one line until we see a function-valued |
881 // property. Ideally, we would use a proper pretty-printer to make the | 969 // property. Ideally, we would use a proper pretty-printer to make the |
882 // decision based on layout. | 970 // decision based on layout. |
883 List<Property> properties = node.properties; | 971 List<Property> properties = node.properties; |
884 out("{"); | 972 out("{"); |
885 indentMore(); | 973 indentMore(); |
| 974 |
| 975 var isOneLiner = !properties.any((p) => p.value is FunctionExpression); |
886 for (int i = 0; i < properties.length; i++) { | 976 for (int i = 0; i < properties.length; i++) { |
887 Expression value = properties[i].value; | |
888 if (i != 0) { | 977 if (i != 0) { |
889 out(","); | 978 out(","); |
890 if (node.isOneLiner) spaceOut(); | 979 if (isOneLiner) spaceOut(); |
891 } | 980 } |
892 if (!node.isOneLiner) { | 981 if (!isOneLiner) { |
893 forceLine(); | 982 forceLine(); |
894 indent(); | 983 indent(); |
895 } | 984 } |
896 visit(properties[i]); | 985 visit(properties[i]); |
897 } | 986 } |
898 indentLess(); | 987 indentLess(); |
899 if (!node.isOneLiner && !properties.isEmpty) { | 988 if (!isOneLiner) { |
900 lineOut(); | 989 lineOut(); |
901 indent(); | 990 indent(); |
902 } | 991 } |
903 out("}"); | 992 out("}"); |
904 } | 993 } |
905 | 994 |
906 visitProperty(Property node) { | 995 visitProperty(Property node) { |
907 if (node.name is LiteralString) { | 996 propertyNameOut(node.name); |
908 LiteralString nameString = node.name; | |
909 String name = nameString.value; | |
910 if (isValidJavaScriptId(name)) { | |
911 out(name.substring(1, name.length - 1)); | |
912 } else { | |
913 out(name); | |
914 } | |
915 } else { | |
916 assert(node.name is LiteralNumber); | |
917 LiteralNumber nameNumber = node.name; | |
918 out(nameNumber.value); | |
919 } | |
920 out(":"); | 997 out(":"); |
921 spaceOut(); | 998 spaceOut(); |
922 visitNestedExpression(node.value, ASSIGNMENT, | 999 visitNestedExpression(node.value, ASSIGNMENT, |
923 newInForInit: false, newAtStatementBegin: false); | 1000 newInForInit: false, newAtStatementBegin: false); |
924 } | 1001 } |
925 | 1002 |
926 visitRegExpLiteral(RegExpLiteral node) { | 1003 visitRegExpLiteral(RegExpLiteral node) { |
927 out(node.pattern); | 1004 out(node.pattern); |
928 } | 1005 } |
929 | 1006 |
| 1007 visitTemplateString(TemplateString node) { |
| 1008 out('`'); |
| 1009 for (var element in node.elements) { |
| 1010 if (element is String) { |
| 1011 out(element); |
| 1012 } else { |
| 1013 out(r'${'); |
| 1014 visit(element); |
| 1015 out('}'); |
| 1016 } |
| 1017 } |
| 1018 out('`'); |
| 1019 } |
| 1020 |
| 1021 visitTaggedTemplate(TaggedTemplate node) { |
| 1022 visit(node.tag); |
| 1023 visit(node.template); |
| 1024 } |
| 1025 |
| 1026 visitClassDeclaration(ClassDeclaration node) { |
| 1027 indent(); |
| 1028 visit(node.classExpr); |
| 1029 lineOut(); |
| 1030 } |
| 1031 |
| 1032 visitClassExpression(ClassExpression node) { |
| 1033 out('class '); |
| 1034 visit(node.name); |
| 1035 if (node.heritage != null) { |
| 1036 out(' extends '); |
| 1037 visit(node.heritage); |
| 1038 spaceOut(); |
| 1039 } |
| 1040 out('{'); |
| 1041 lineOut(); |
| 1042 indentMore(); |
| 1043 for (var method in node.methods) { |
| 1044 indent(); |
| 1045 visit(method); |
| 1046 lineOut(); |
| 1047 } |
| 1048 indentLess(); |
| 1049 indent(); |
| 1050 out('}'); |
| 1051 } |
| 1052 |
| 1053 visitMethod(Method node) { |
| 1054 if (node.isStatic) { |
| 1055 out('static '); |
| 1056 } |
| 1057 if (node.isGetter) { |
| 1058 out('get '); |
| 1059 } else if (node.isSetter) { |
| 1060 out('set '); |
| 1061 } |
| 1062 var vars = new VarCollector(); |
| 1063 vars.visitMethod(node); |
| 1064 |
| 1065 propertyNameOut(node.name, inMethod: true); |
| 1066 |
| 1067 localNamer.enterScope(vars); |
| 1068 out("("); |
| 1069 var fun = node.function; |
| 1070 if (fun.params != null) { |
| 1071 visitCommaSeparated(fun.params, PRIMARY, |
| 1072 newInForInit: false, newAtStatementBegin: false); |
| 1073 } |
| 1074 out(")"); |
| 1075 // TODO(jmesserly): async modifiers |
| 1076 if (fun.body.statements.isEmpty) { |
| 1077 spaceOut(); |
| 1078 out("{}"); |
| 1079 } else { |
| 1080 blockBody(fun.body, needsSeparation: false, needsNewline: false); |
| 1081 } |
| 1082 localNamer.leaveScope(); |
| 1083 } |
| 1084 |
| 1085 visitPropertyName(PropertyName node) => propertyNameOut(node); |
| 1086 |
| 1087 void propertyNameOut(Expression node, {bool inMethod: false}) { |
| 1088 inForInit = false; |
| 1089 atStatementBegin = false; |
| 1090 |
| 1091 if (node is LiteralNumber) { |
| 1092 LiteralNumber nameNumber = node; |
| 1093 out(nameNumber.value); |
| 1094 } else { |
| 1095 String quotedName; |
| 1096 if (node is PropertyName) { |
| 1097 quotedName = "'${node.name}'"; |
| 1098 } else if (node is LiteralString) { |
| 1099 quotedName = node.value; |
| 1100 } |
| 1101 if (quotedName != null) { |
| 1102 if (isValidJavaScriptId(quotedName)) { |
| 1103 out(quotedName.substring(1, quotedName.length - 1)); |
| 1104 } else { |
| 1105 if (inMethod) out("["); |
| 1106 out(quotedName); |
| 1107 if (inMethod) out("]"); |
| 1108 } |
| 1109 } else { |
| 1110 // ComputedPropertyName |
| 1111 out("["); |
| 1112 visit(node); |
| 1113 out("]"); |
| 1114 } |
| 1115 } |
| 1116 } |
| 1117 |
930 visitLiteralExpression(LiteralExpression node) { | 1118 visitLiteralExpression(LiteralExpression node) { |
931 String template = node.template; | 1119 String template = node.template; |
932 List<Expression> inputs = node.inputs; | 1120 List<Expression> inputs = node.inputs; |
933 | 1121 |
934 List<String> parts = template.split('#'); | 1122 List<String> parts = template.split('#'); |
935 int inputsLength = inputs == null ? 0 : inputs.length; | 1123 int inputsLength = inputs == null ? 0 : inputs.length; |
936 if (parts.length != inputsLength + 1) { | 1124 if (parts.length != inputsLength + 1) { |
937 context.error('Wrong number of arguments for JS: $template'); | 1125 context.error('Wrong number of arguments for JS: $template'); |
938 } | 1126 } |
939 // Code that uses JS must take care of operator precedences, and | 1127 // Code that uses JS must take care of operator precedences, and |
(...skipping 18 matching lines...) Expand all Loading... |
958 | 1146 |
959 visitInterpolatedLiteral(InterpolatedLiteral node) => | 1147 visitInterpolatedLiteral(InterpolatedLiteral node) => |
960 visitInterpolatedNode(node); | 1148 visitInterpolatedNode(node); |
961 | 1149 |
962 visitInterpolatedParameter(InterpolatedParameter node) => | 1150 visitInterpolatedParameter(InterpolatedParameter node) => |
963 visitInterpolatedNode(node); | 1151 visitInterpolatedNode(node); |
964 | 1152 |
965 visitInterpolatedSelector(InterpolatedSelector node) => | 1153 visitInterpolatedSelector(InterpolatedSelector node) => |
966 visitInterpolatedNode(node); | 1154 visitInterpolatedNode(node); |
967 | 1155 |
| 1156 visitInterpolatedPropertyName(InterpolatedPropertyName node) => |
| 1157 visitInterpolatedNode(node); |
| 1158 |
| 1159 visitInterpolatedMethod(InterpolatedMethod node) => |
| 1160 visitInterpolatedNode(node); |
| 1161 |
| 1162 visitInterpolatedVariableDeclaration(InterpolatedVariableDeclaration node) => |
| 1163 visitInterpolatedNode(node); |
| 1164 |
968 visitInterpolatedStatement(InterpolatedStatement node) { | 1165 visitInterpolatedStatement(InterpolatedStatement node) { |
969 outLn('#${node.nameOrPosition}'); | 1166 outLn('#${node.nameOrPosition}'); |
970 } | 1167 } |
971 | 1168 |
972 void visitComment(Comment node) { | 1169 void visitComment(Comment node) { |
973 if (shouldCompressOutput) return; | 1170 if (shouldCompressOutput) return; |
974 String comment = node.comment.trim(); | 1171 String comment = node.comment.trim(); |
975 if (comment.isEmpty) return; | 1172 if (comment.isEmpty) return; |
976 for (var line in comment.split('\n')) { | 1173 for (var line in comment.split('\n')) { |
977 if (comment.startsWith('//')) { | 1174 if (comment.startsWith('//')) { |
978 outIndentLn(line.trim()); | 1175 outIndentLn(line.trim()); |
979 } else { | 1176 } else { |
980 outIndentLn('// ${line.trim()}'); | 1177 outIndentLn('// ${line.trim()}'); |
981 } | 1178 } |
982 } | 1179 } |
983 } | 1180 } |
984 | 1181 |
| 1182 void visitCommentExpression(CommentExpression node) { |
| 1183 if (shouldCompressOutput) return; |
| 1184 String comment = node.comment.trim(); |
| 1185 if (comment.isEmpty) return; |
| 1186 if (comment.startsWith('/*')) { |
| 1187 out(comment); |
| 1188 } else { |
| 1189 out('/* $comment */'); |
| 1190 } |
| 1191 visit(node.expression); |
| 1192 } |
| 1193 |
985 void visitAwait(Await node) { | 1194 void visitAwait(Await node) { |
986 out("await "); | 1195 out("await "); |
987 visit(node.expression); | 1196 visit(node.expression); |
988 } | 1197 } |
989 } | 1198 } |
990 | 1199 |
991 | 1200 |
992 class OrderedSet<T> { | 1201 class OrderedSet<T> { |
993 final Set<T> set; | 1202 final Set<T> set; |
994 final List<T> list; | 1203 final List<T> list; |
(...skipping 19 matching lines...) Expand all Loading... |
1014 final OrderedSet<String> vars; | 1223 final OrderedSet<String> vars; |
1015 final OrderedSet<String> params; | 1224 final OrderedSet<String> params; |
1016 | 1225 |
1017 VarCollector() : nested = false, | 1226 VarCollector() : nested = false, |
1018 vars = new OrderedSet<String>(), | 1227 vars = new OrderedSet<String>(), |
1019 params = new OrderedSet<String>(); | 1228 params = new OrderedSet<String>(); |
1020 | 1229 |
1021 void forEachVar(void fn(String v)) => vars.forEach(fn); | 1230 void forEachVar(void fn(String v)) => vars.forEach(fn); |
1022 void forEachParam(void fn(String p)) => params.forEach(fn); | 1231 void forEachParam(void fn(String p)) => params.forEach(fn); |
1023 | 1232 |
1024 void collectVarsInFunction(Fun fun) { | 1233 void collectVarsInFunction(FunctionExpression fun) { |
1025 if (!nested) { | 1234 if (!nested) { |
1026 nested = true; | 1235 nested = true; |
1027 if (fun.params != null) { | 1236 if (fun.params != null) { |
1028 for (int i = 0; i < fun.params.length; i++) { | 1237 for (int i = 0; i < fun.params.length; i++) { |
1029 params.add(fun.params[i].name); | 1238 params.add(fun.params[i].name); |
1030 } | 1239 } |
1031 } | 1240 } |
1032 visitBlock(fun.body); | 1241 fun.body.accept(this); |
1033 nested = false; | 1242 nested = false; |
1034 } | 1243 } |
1035 } | 1244 } |
1036 | 1245 |
1037 void visitFunctionDeclaration(FunctionDeclaration declaration) { | 1246 void visitFunctionDeclaration(FunctionDeclaration declaration) { |
1038 // Note that we don't bother collecting the name of the function. | 1247 // Note that we don't bother collecting the name of the function. |
1039 collectVarsInFunction(declaration.function); | 1248 collectVarsInFunction(declaration.function); |
1040 } | 1249 } |
1041 | 1250 |
1042 void visitNamedFunction(NamedFunction namedFunction) { | 1251 void visitNamedFunction(NamedFunction namedFunction) { |
1043 // Note that we don't bother collecting the name of the function. | 1252 // Note that we don't bother collecting the name of the function. |
1044 collectVarsInFunction(namedFunction.function); | 1253 collectVarsInFunction(namedFunction.function); |
1045 } | 1254 } |
1046 | 1255 |
| 1256 void visitMethod(Method declaration) { |
| 1257 // Note that we don't bother collecting the name of the function. |
| 1258 collectVarsInFunction(declaration.function); |
| 1259 } |
| 1260 |
1047 void visitFun(Fun fun) { | 1261 void visitFun(Fun fun) { |
1048 collectVarsInFunction(fun); | 1262 collectVarsInFunction(fun); |
1049 } | 1263 } |
1050 | 1264 |
| 1265 void visitArrowFun(ArrowFun fun) { |
| 1266 collectVarsInFunction(fun); |
| 1267 } |
| 1268 |
1051 void visitThis(This node) {} | 1269 void visitThis(This node) {} |
1052 | 1270 |
1053 void visitVariableDeclaration(VariableDeclaration decl) { | 1271 void visitVariableDeclaration(VariableDeclaration decl) { |
1054 if (decl.allowRename) vars.add(decl.name); | 1272 if (decl.allowRename) vars.add(decl.name); |
1055 } | 1273 } |
1056 } | 1274 } |
1057 | 1275 |
1058 | 1276 |
1059 /** | 1277 /** |
1060 * Returns true, if the given node must be wrapped into braces when used | 1278 * Returns true, if the given node must be wrapped into braces when used |
(...skipping 13 matching lines...) Expand all Loading... |
1074 | 1292 |
1075 bool visitBlock(Block node) => false; | 1293 bool visitBlock(Block node) => false; |
1076 bool visitExpressionStatement(ExpressionStatement node) => false; | 1294 bool visitExpressionStatement(ExpressionStatement node) => false; |
1077 bool visitEmptyStatement(EmptyStatement node) => false; | 1295 bool visitEmptyStatement(EmptyStatement node) => false; |
1078 bool visitIf(If node) { | 1296 bool visitIf(If node) { |
1079 if (!node.hasElse) return true; | 1297 if (!node.hasElse) return true; |
1080 return node.otherwise.accept(this); | 1298 return node.otherwise.accept(this); |
1081 } | 1299 } |
1082 bool visitFor(For node) => node.body.accept(this); | 1300 bool visitFor(For node) => node.body.accept(this); |
1083 bool visitForIn(ForIn node) => node.body.accept(this); | 1301 bool visitForIn(ForIn node) => node.body.accept(this); |
| 1302 bool visitForOf(ForOf node) => node.body.accept(this); |
1084 bool visitWhile(While node) => node.body.accept(this); | 1303 bool visitWhile(While node) => node.body.accept(this); |
1085 bool visitDo(Do node) => false; | 1304 bool visitDo(Do node) => false; |
1086 bool visitContinue(Continue node) => false; | 1305 bool visitContinue(Continue node) => false; |
1087 bool visitBreak(Break node) => false; | 1306 bool visitBreak(Break node) => false; |
1088 bool visitReturn(Return node) => false; | 1307 bool visitReturn(Return node) => false; |
1089 bool visitThrow(Throw node) => false; | 1308 bool visitThrow(Throw node) => false; |
1090 bool visitTry(Try node) { | 1309 bool visitTry(Try node) { |
1091 if (node.finallyPart != null) { | 1310 if (node.finallyPart != null) { |
1092 return node.finallyPart.accept(this); | 1311 return node.finallyPart.accept(this); |
1093 } else { | 1312 } else { |
1094 return node.catchPart.accept(this); | 1313 return node.catchPart.accept(this); |
1095 } | 1314 } |
1096 } | 1315 } |
1097 bool visitCatch(Catch node) => node.body.accept(this); | 1316 bool visitCatch(Catch node) => node.body.accept(this); |
1098 bool visitSwitch(Switch node) => false; | 1317 bool visitSwitch(Switch node) => false; |
1099 bool visitCase(Case node) => false; | 1318 bool visitCase(Case node) => false; |
1100 bool visitDefault(Default node) => false; | 1319 bool visitDefault(Default node) => false; |
1101 bool visitFunctionDeclaration(FunctionDeclaration node) => false; | 1320 bool visitFunctionDeclaration(FunctionDeclaration node) => false; |
1102 bool visitLabeledStatement(LabeledStatement node) | 1321 bool visitLabeledStatement(LabeledStatement node) |
1103 => node.body.accept(this); | 1322 => node.body.accept(this); |
1104 bool visitLiteralStatement(LiteralStatement node) => true; | 1323 bool visitLiteralStatement(LiteralStatement node) => true; |
| 1324 bool visitClassDeclaration(ClassDeclaration) => false; |
1105 | 1325 |
1106 bool visitExpression(Expression node) => false; | 1326 bool visitExpression(Expression node) => false; |
1107 } | 1327 } |
1108 | 1328 |
1109 | 1329 |
1110 abstract class LocalNamer { | 1330 abstract class LocalNamer { |
1111 String getName(String oldName); | 1331 String getName(String oldName); |
1112 String declareVariable(String oldName); | 1332 String declareVariable(String oldName); |
1113 String declareParameter(String oldName); | 1333 String declareParameter(String oldName); |
1114 void enterScope(VarCollector vars); | 1334 void enterScope(VarCollector vars); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1238 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); | 1458 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); |
1239 } | 1459 } |
1240 codes.add(charCodes.$0 + digit); | 1460 codes.add(charCodes.$0 + digit); |
1241 newName = new String.fromCharCodes(codes); | 1461 newName = new String.fromCharCodes(codes); |
1242 } | 1462 } |
1243 assert(new RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); | 1463 assert(new RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); |
1244 maps.last[oldName] = newName; | 1464 maps.last[oldName] = newName; |
1245 return newName; | 1465 return newName; |
1246 } | 1466 } |
1247 } | 1467 } |
OLD | NEW |