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 | 12 |
13 | |
14 /// True to allow keywords in properties, such as `obj.var` or `obj.function` | 13 /// True to allow keywords in properties, such as `obj.var` or `obj.function` |
15 /// Modern JS engines support this. | 14 /// Modern JS engines support this. |
16 final bool allowKeywordsInProperties; | 15 final bool allowKeywordsInProperties; |
17 | 16 |
| 17 /// Workaround if `this` is not bound in arrow functions. |
| 18 final bool arrowFnBindThisWorkaround; |
| 19 |
18 JavaScriptPrintingOptions( | 20 JavaScriptPrintingOptions( |
19 {this.shouldCompressOutput: false, | 21 {this.shouldCompressOutput: false, |
20 this.minifyLocalVariables: false, | 22 this.minifyLocalVariables: false, |
21 this.preferSemicolonToNewlineInMinifiedOutput: false, | 23 this.preferSemicolonToNewlineInMinifiedOutput: false, |
22 this.allowKeywordsInProperties: false}); | 24 this.allowKeywordsInProperties: false, |
| 25 this.arrowFnBindThisWorkaround: false}); |
23 } | 26 } |
24 | 27 |
25 | 28 |
26 /// An environment in which JavaScript printing is done. Provides emitting of | 29 /// An environment in which JavaScript printing is done. Provides emitting of |
27 /// text and pre- and post-visit callbacks. | 30 /// text and pre- and post-visit callbacks. |
28 abstract class JavaScriptPrintingContext { | 31 abstract class JavaScriptPrintingContext { |
29 /// Signals an error. This should happen only for serious internal errors. | 32 /// Signals an error. This should happen only for serious internal errors. |
30 void error(String message) { throw message; } | 33 void error(String message) { throw message; } |
31 | 34 |
32 /// Adds [string] to the output. | 35 /// Adds [string] to the output. |
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 } | 544 } |
542 | 545 |
543 visitFunctionDeclaration(FunctionDeclaration declaration) { | 546 visitFunctionDeclaration(FunctionDeclaration declaration) { |
544 indent(); | 547 indent(); |
545 functionOut(declaration.function, declaration.name); | 548 functionOut(declaration.function, declaration.name); |
546 lineOut(); | 549 lineOut(); |
547 } | 550 } |
548 | 551 |
549 visitNestedExpression(Expression node, int requiredPrecedence, | 552 visitNestedExpression(Expression node, int requiredPrecedence, |
550 {bool newInForInit, bool newAtStatementBegin}) { | 553 {bool newInForInit, bool newAtStatementBegin}) { |
| 554 int nodePrecedence = node.precedenceLevel; |
| 555 if (options.arrowFnBindThisWorkaround) { |
| 556 if (node is ArrowFun && node.closesOverThis) { |
| 557 nodePrecedence = CALL; |
| 558 } |
| 559 } |
551 bool needsParentheses = | 560 bool needsParentheses = |
552 // a - (b + c). | 561 // a - (b + c). |
553 (requiredPrecedence != EXPRESSION && | 562 (requiredPrecedence != EXPRESSION && |
554 node.precedenceLevel < requiredPrecedence) || | 563 nodePrecedence < requiredPrecedence) || |
555 // for (a = (x in o); ... ; ... ) { ... } | 564 // for (a = (x in o); ... ; ... ) { ... } |
556 (newInForInit && node is Binary && node.op == "in") || | 565 (newInForInit && node is Binary && node.op == "in") || |
557 // (function() { ... })(). | 566 // (function() { ... })(). |
558 // ({a: 2, b: 3}.toString()). | 567 // ({a: 2, b: 3}.toString()). |
559 (newAtStatementBegin && (node is NamedFunction || | 568 (newAtStatementBegin && (node is NamedFunction || |
560 node is FunctionExpression || | 569 node is FunctionExpression || |
561 node is ObjectInitializer)); | 570 node is ObjectInitializer)); |
562 if (needsParentheses) { | 571 if (needsParentheses) { |
563 inForInit = false; | 572 inForInit = false; |
564 atStatementBegin = false; | 573 atStatementBegin = false; |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 | 860 |
852 visitNamedFunction(NamedFunction namedFunction) { | 861 visitNamedFunction(NamedFunction namedFunction) { |
853 functionOut(namedFunction.function, namedFunction.name); | 862 functionOut(namedFunction.function, namedFunction.name); |
854 } | 863 } |
855 | 864 |
856 visitFun(Fun fun) { | 865 visitFun(Fun fun) { |
857 functionOut(fun, null); | 866 functionOut(fun, null); |
858 } | 867 } |
859 | 868 |
860 visitArrowFun(ArrowFun fun) { | 869 visitArrowFun(ArrowFun fun) { |
| 870 bool bindThis = options.arrowFnBindThisWorkaround && fun.closesOverThis; |
| 871 if (bindThis) { |
| 872 out("("); |
| 873 } |
861 localNamer.enterScope(fun); | 874 localNamer.enterScope(fun); |
862 if (fun.params.length == 1) { | 875 if (fun.params.length == 1) { |
863 visitNestedExpression(fun.params.single, SPREAD, | 876 visitNestedExpression(fun.params.single, SPREAD, |
864 newInForInit: false, newAtStatementBegin: false); | 877 newInForInit: false, newAtStatementBegin: false); |
865 } else { | 878 } else { |
866 out("("); | 879 out("("); |
867 visitCommaSeparated(fun.params, SPREAD, | 880 visitCommaSeparated(fun.params, SPREAD, |
868 newInForInit: false, newAtStatementBegin: false); | 881 newInForInit: false, newAtStatementBegin: false); |
869 out(")"); | 882 out(")"); |
870 } | 883 } |
871 spaceOut(); | 884 spaceOut(); |
872 out("=>"); | 885 out("=>"); |
873 if (fun.body is Expression) { | 886 if (fun.body is Expression) { |
874 spaceOut(); | 887 spaceOut(); |
875 // Object initializers require parenthesis to disambiguate | 888 // Object initializers require parenthesis to disambiguate |
876 // AssignmentExpression from FunctionBody. See: | 889 // AssignmentExpression from FunctionBody. See: |
877 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio
n-definitions | 890 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-functio
n-definitions |
878 var needsParen = fun.body is ObjectInitializer; | 891 var needsParen = fun.body is ObjectInitializer; |
879 if (needsParen) out("("); | 892 if (needsParen) out("("); |
880 visitNestedExpression(fun.body, ASSIGNMENT, | 893 visitNestedExpression(fun.body, ASSIGNMENT, |
881 newInForInit: false, newAtStatementBegin: false); | 894 newInForInit: false, newAtStatementBegin: false); |
882 if (needsParen) out(")"); | 895 if (needsParen) out(")"); |
883 } else { | 896 } else { |
884 blockBody(fun.body, needsSeparation: false, needsNewline: false); | 897 blockBody(fun.body, needsSeparation: false, needsNewline: false); |
885 } | 898 } |
886 localNamer.leaveScope(); | 899 localNamer.leaveScope(); |
| 900 if (bindThis) { |
| 901 out(").bind(this)"); |
| 902 } |
887 } | 903 } |
888 | 904 |
889 visitLiteralBool(LiteralBool node) { | 905 visitLiteralBool(LiteralBool node) { |
890 out(node.value ? "true" : "false"); | 906 out(node.value ? "true" : "false"); |
891 } | 907 } |
892 | 908 |
893 visitLiteralString(LiteralString node) { | 909 visitLiteralString(LiteralString node) { |
894 out(node.value); | 910 out(node.value); |
895 } | 911 } |
896 | 912 |
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1460 declare(node.name); | 1476 declare(node.name); |
1461 node.function.accept(this); | 1477 node.function.accept(this); |
1462 } | 1478 } |
1463 | 1479 |
1464 visitClassExpression(ClassExpression node) { | 1480 visitClassExpression(ClassExpression node) { |
1465 declare(node.name); | 1481 declare(node.name); |
1466 if (node.heritage != null) node.heritage.accept(this); | 1482 if (node.heritage != null) node.heritage.accept(this); |
1467 for (Method element in node.methods) element.accept(this); | 1483 for (Method element in node.methods) element.accept(this); |
1468 } | 1484 } |
1469 } | 1485 } |
OLD | NEW |