Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1052693004: move => bind this workaround to js_ast (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/runtime/dart/isolate.js ('k') | lib/src/js/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap; 7 import 'dart:collection' show HashSet, HashMap;
8 import 'dart:io' show Directory, File; 8 import 'dart:io' show Directory, File;
9 9
10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
(...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 } 906 }
907 907
908 @override 908 @override
909 JS.Expression visitFunctionExpression(FunctionExpression node) { 909 JS.Expression visitFunctionExpression(FunctionExpression node) {
910 var params = _visit(node.parameters); 910 var params = _visit(node.parameters);
911 if (params == null) params = []; 911 if (params == null) params = [];
912 912
913 if (node.parent is FunctionDeclaration) { 913 if (node.parent is FunctionDeclaration) {
914 return new JS.Fun(params, _visit(node.body)); 914 return new JS.Fun(params, _visit(node.body));
915 } else { 915 } else {
916 var bindThis = _maybeBindThis(node.body);
917
918 String code; 916 String code;
919 AstNode body; 917 AstNode body;
920 var nodeBody = node.body; 918 var nodeBody = node.body;
921 if (nodeBody is ExpressionFunctionBody) { 919 if (nodeBody is ExpressionFunctionBody) {
922 code = '(#) => #'; 920 code = '(#) => #';
923 body = nodeBody.expression; 921 body = nodeBody.expression;
924 } else { 922 } else {
925 code = '(#) => { #; }'; 923 code = '(#) => { #; }';
926 body = nodeBody; 924 body = nodeBody;
927 } 925 }
928 return js.call('($code)$bindThis', [params, _visit(body)]); 926 return js.call(code, [params, _visit(body)]);
929 } 927 }
930 } 928 }
931 929
932 @override 930 @override
933 JS.Statement visitFunctionDeclarationStatement( 931 JS.Statement visitFunctionDeclarationStatement(
934 FunctionDeclarationStatement node) { 932 FunctionDeclarationStatement node) {
935 var func = node.functionDeclaration; 933 var func = node.functionDeclaration;
936 if (func.isGetter || func.isSetter) { 934 if (func.isGetter || func.isSetter) {
937 return js.comment('Unimplemented function get/set statement: $node'); 935 return js.comment('Unimplemented function get/set statement: $node');
938 } 936 }
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after
1524 bool _canUsePrimitiveEquality(Expression left, Expression right) { 1522 bool _canUsePrimitiveEquality(Expression left, Expression right) {
1525 if (_isNull(left) || _isNull(right)) return true; 1523 if (_isNull(left) || _isNull(right)) return true;
1526 1524
1527 var leftType = _canonicalizeNumTypes(rules.getStaticType(left)); 1525 var leftType = _canonicalizeNumTypes(rules.getStaticType(left));
1528 var rightType = _canonicalizeNumTypes(rules.getStaticType(right)); 1526 var rightType = _canonicalizeNumTypes(rules.getStaticType(right));
1529 return _isJSBuiltinType(leftType) && leftType == rightType; 1527 return _isJSBuiltinType(leftType) && leftType == rightType;
1530 } 1528 }
1531 1529
1532 bool _isNull(Expression expr) => expr is NullLiteral; 1530 bool _isNull(Expression expr) => expr is NullLiteral;
1533 1531
1534 // TODO(jmesserly, vsm): Refactor this logic.
1535 SimpleIdentifier _createTemporary(String name, DartType type) { 1532 SimpleIdentifier _createTemporary(String name, DartType type) {
1536 // We use an invalid source location to signal that this is a temporary. 1533 // We use an invalid source location to signal that this is a temporary.
1537 // See [_isTemporary]. 1534 // See [_isTemporary].
1538 // TODO(jmesserly): alternatives are 1535 // TODO(jmesserly): alternatives are
1539 // * (ab)use Element.isSynthetic, which isn't currently used for 1536 // * (ab)use Element.isSynthetic, which isn't currently used for
1540 // LocalVariableElementImpl, so we could repurpose to mean "temp". 1537 // LocalVariableElementImpl, so we could repurpose to mean "temp".
1541 // * add a new property to LocalVariableElementImpl. 1538 // * add a new property to LocalVariableElementImpl.
1542 // * create a new subtype of LocalVariableElementImpl to mark a temp. 1539 // * create a new subtype of LocalVariableElementImpl to mark a temp.
1543 var id = 1540 var id =
1544 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); 1541 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1));
1545 id.staticElement = new LocalVariableElementImpl.forNode(id); 1542 id.staticElement = new LocalVariableElementImpl.forNode(id);
1546 id.staticType = type; 1543 id.staticType = type;
1547 return id; 1544 return id;
1548 } 1545 }
1549 1546
1550 bool _isTemporary(Element node) => node.nameOffset == -1; 1547 bool _isTemporary(Element node) => node.nameOffset == -1;
1551 1548
1552 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { 1549 JS.Expression _emitPostfixIncrement(Expression expr, Token op) {
1553 var type = rules.getStaticType(expr); 1550 var type = rules.getStaticType(expr);
1554 assert(type != null); 1551 assert(type != null);
1555 var tmp = _createTemporary('x', type); 1552 var tmp = _createTemporary('x', type);
1556 1553
1557 // Increment and write 1554 // Increment and write
1558 var one = AstBuilder.integerLiteral(1); 1555 var one = AstBuilder.integerLiteral(1);
1559 one.staticType = rules.provider.intType; 1556 one.staticType = rules.provider.intType;
1560 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); 1557 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one);
1561 increment.staticType = type; 1558 increment.staticType = type;
1562 var write = _emitAssignment(expr, increment); 1559 var write = _emitAssignment(expr, increment);
1563 1560
1564 var bindThis = _maybeBindThis(expr); 1561 return js.call(
1565 return js.call("((#) => (#, #))$bindThis(#)", [ 1562 "((#) => (#, #))(#)", [_visit(tmp), write, _visit(tmp), _visit(expr)]);
1566 _visit(tmp),
1567 write,
1568 _visit(tmp),
1569 _visit(expr)
1570 ]);
1571 } 1563 }
1572 1564
1573 @override 1565 @override
1574 JS.Expression visitPostfixExpression(PostfixExpression node) { 1566 JS.Expression visitPostfixExpression(PostfixExpression node) {
1575 var op = node.operator; 1567 var op = node.operator;
1576 var expr = node.operand; 1568 var expr = node.operand;
1577 1569
1578 if (node.parent is Statement) { 1570 if (node.parent is Statement) {
1579 // Prefix code is simpler. If the expr result isn't used, fall to that. 1571 // Prefix code is simpler. If the expr result isn't used, fall to that.
1580 return _emitPrefixExpression(op, expr); 1572 return _emitPrefixExpression(op, expr);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1655 } else { 1647 } else {
1656 // Use comma expression. For example: 1648 // Use comma expression. For example:
1657 // (sb.write(1), sb.write(2), sb) 1649 // (sb.write(1), sb.write(2), sb)
1658 var sections = _visitListToBinary(node.cascadeSections, ','); 1650 var sections = _visitListToBinary(node.cascadeSections, ',');
1659 result = new JS.Binary(',', sections, _visit(_cascadeTarget)); 1651 result = new JS.Binary(',', sections, _visit(_cascadeTarget));
1660 } 1652 }
1661 } else { 1653 } else {
1662 // In the general case we need to capture the target expression into 1654 // In the general case we need to capture the target expression into
1663 // a temporary. This uses a lambda to get a temporary scope, and it also 1655 // a temporary. This uses a lambda to get a temporary scope, and it also
1664 // remains valid in an expression context. 1656 // remains valid in an expression context.
1665 // TODO(jmesserly): need a better way to handle temps.
1666 // TODO(jmesserly): special case for parent is ExpressionStatement?
1667 _cascadeTarget = _createTemporary('_', node.target.staticType); 1657 _cascadeTarget = _createTemporary('_', node.target.staticType);
1668 1658
1669 var body = _visitList(node.cascadeSections); 1659 var body = _visitList(node.cascadeSections);
1670 if (node.parent is! ExpressionStatement) { 1660 if (node.parent is! ExpressionStatement) {
1671 body.add(js.statement('return #;', _visit(_cascadeTarget))); 1661 body.add(js.statement('return #;', _visit(_cascadeTarget)));
1672 } 1662 }
1673 1663
1674 var bindThis = _maybeBindThis(node.cascadeSections); 1664 result = js.call('((#) => { # })(#)', [
1675 result = js.call('((#) => { # })$bindThis(#)', [
1676 _visit(_cascadeTarget), 1665 _visit(_cascadeTarget),
1677 body, 1666 body,
1678 _visit(node.target) 1667 _visit(node.target)
1679 ]); 1668 ]);
1680 } 1669 }
1681 1670
1682 _cascadeTarget = savedCascadeTemp; 1671 _cascadeTarget = savedCascadeTemp;
1683 return result; 1672 return result;
1684 } 1673 }
1685 1674
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after
2170 node is FunctionDeclaration ? node.functionExpression.body : node.body; 2159 node is FunctionDeclaration ? node.functionExpression.body : node.body;
2171 2160
2172 /// Choose a canonical name from the library element. 2161 /// Choose a canonical name from the library element.
2173 /// This never uses the library's name (the identifier in the `library` 2162 /// This never uses the library's name (the identifier in the `library`
2174 /// declaration) as it doesn't have any meaningful rules enforced. 2163 /// declaration) as it doesn't have any meaningful rules enforced.
2175 JS.Identifier _libraryName(LibraryElement library) { 2164 JS.Identifier _libraryName(LibraryElement library) {
2176 if (library == libraryInfo.library) return _exportsVar; 2165 if (library == libraryInfo.library) return _exportsVar;
2177 return new JS.Identifier(jsLibraryName(library)); 2166 return new JS.Identifier(jsLibraryName(library));
2178 } 2167 }
2179 2168
2180 String _maybeBindThis(node) {
2181 if (currentClass == null) return '';
2182 var visitor = _BindThisVisitor._instance;
2183 visitor._bindThis = false;
2184 node.accept(visitor);
2185 return visitor._bindThis ? '.bind(this)' : '';
2186 }
2187
2188 static bool _needsImplicitThis(Element e) => 2169 static bool _needsImplicitThis(Element e) =>
2189 e is PropertyAccessorElement && !e.variable.isStatic || 2170 e is PropertyAccessorElement && !e.variable.isStatic ||
2190 e is ClassMemberElement && !e.isStatic && e is! ConstructorElement; 2171 e is ClassMemberElement && !e.isStatic && e is! ConstructorElement;
2191 } 2172 }
2192 2173
2193 /// Returns true if the local variable is potentially mutated within [context]. 2174 /// Returns true if the local variable is potentially mutated within [context].
2194 /// This accounts for closures that may have been created outside of [context]. 2175 /// This accounts for closures that may have been created outside of [context].
2195 bool _isPotentiallyMutated(VariableElementImpl e, [AstNode context]) { 2176 bool _isPotentiallyMutated(VariableElementImpl e, [AstNode context]) {
2196 if (e.isPotentiallyMutatedInClosure) { 2177 if (e.isPotentiallyMutatedInClosure) {
2197 // TODO(jmesserly): this returns true incorrectly in some cases, because 2178 // TODO(jmesserly): this returns true incorrectly in some cases, because
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2232 identical(parent.methodName, node)) return; 2213 identical(parent.methodName, node)) return;
2233 if (parent is ConstructorName) return; 2214 if (parent is ConstructorName) return;
2234 if (parent is Label) return; 2215 if (parent is Label) return;
2235 2216
2236 if (node.inSetterContext() && node.staticElement == _variable) { 2217 if (node.inSetterContext() && node.staticElement == _variable) {
2237 _potentiallyMutated = true; 2218 _potentiallyMutated = true;
2238 } 2219 }
2239 } 2220 }
2240 } 2221 }
2241 2222
2242 /// This is a workaround for V8 arrow function bindings being not yet
2243 /// implemented. See issue #43
2244 // TODO(jmesserly): cleaner to handle this workaround on the JS side.
2245 class _BindThisVisitor extends RecursiveAstVisitor {
2246 static _BindThisVisitor _instance = new _BindThisVisitor();
2247 bool _bindThis = false;
2248
2249 @override
2250 visitSimpleIdentifier(SimpleIdentifier node) {
2251 if (JSCodegenVisitor._needsImplicitThis(node.staticElement)) {
2252 _bindThis = true;
2253 }
2254 }
2255
2256 @override
2257 visitThisExpression(ThisExpression node) {
2258 _bindThis = true;
2259 }
2260 }
2261
2262 class JSGenerator extends CodeGenerator { 2223 class JSGenerator extends CodeGenerator {
2263 final JSCodeOptions options; 2224 final JSCodeOptions options;
2264 2225
2265 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) 2226 JSGenerator(String outDir, Uri root, TypeRules rules, this.options)
2266 : super(outDir, root, rules); 2227 : super(outDir, root, rules);
2267 2228
2268 String generateLibrary( 2229 String generateLibrary(
2269 LibraryUnit unit, LibraryInfo info, CheckerReporter reporter) { 2230 LibraryUnit unit, LibraryInfo info, CheckerReporter reporter) {
2270 var jsTree = new JSCodegenVisitor(info, rules, reporter).emitLibrary(unit); 2231 var jsTree = new JSCodegenVisitor(info, rules, reporter).emitLibrary(unit);
2271 2232
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
2384 2345
2385 // TODO(jmesserly): in many cases marking the end will be unncessary. 2346 // TODO(jmesserly): in many cases marking the end will be unncessary.
2386 printer.mark(_location(node.end)); 2347 printer.mark(_location(node.end));
2387 } 2348 }
2388 2349
2389 String _getIdentifier(AstNode node) { 2350 String _getIdentifier(AstNode node) {
2390 if (node is SimpleIdentifier) return node.name; 2351 if (node is SimpleIdentifier) return node.name;
2391 return null; 2352 return null;
2392 } 2353 }
2393 } 2354 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/isolate.js ('k') | lib/src/js/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698