| OLD | NEW |
| 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, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| (...skipping 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 if (needsTagging) { | 1314 if (needsTagging) { |
| 1315 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) | 1315 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) |
| 1316 .toStatement()); | 1316 .toStatement()); |
| 1317 } | 1317 } |
| 1318 | 1318 |
| 1319 if (isPublic(name)) _addExport(name); | 1319 if (isPublic(name)) _addExport(name); |
| 1320 return _statement(body); | 1320 return _statement(body); |
| 1321 } | 1321 } |
| 1322 | 1322 |
| 1323 bool _isInlineJSFunction(FunctionExpression functionExpression) { | 1323 bool _isInlineJSFunction(FunctionExpression functionExpression) { |
| 1324 bool isJsInvocation(Expression expr) => | |
| 1325 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement); | |
| 1326 | |
| 1327 var body = functionExpression.body; | 1324 var body = functionExpression.body; |
| 1328 if (body is ExpressionFunctionBody) { | 1325 if (body is ExpressionFunctionBody) { |
| 1329 return isJsInvocation(body.expression); | 1326 return _isJSInvocation(body.expression); |
| 1330 } else if (body is BlockFunctionBody) { | 1327 } else if (body is BlockFunctionBody) { |
| 1331 if (body.block.statements.length == 1) { | 1328 if (body.block.statements.length == 1) { |
| 1332 var stat = body.block.statements.single; | 1329 var stat = body.block.statements.single; |
| 1333 if (stat is ReturnStatement) { | 1330 if (stat is ReturnStatement) { |
| 1334 return isJsInvocation(stat.expression); | 1331 return _isJSInvocation(stat.expression); |
| 1335 } | 1332 } |
| 1336 } | 1333 } |
| 1337 } | 1334 } |
| 1338 return false; | 1335 return false; |
| 1339 } | 1336 } |
| 1340 | 1337 |
| 1338 bool _isJSInvocation(Expression expr) => |
| 1339 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement); |
| 1340 |
| 1341 // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`. | 1341 // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`. |
| 1342 // Note: we don't check if the top-level args match the ones passed through | 1342 // Note: we don't check if the top-level args match the ones passed through |
| 1343 // the arrow function, which allows silently passing args through to the | 1343 // the arrow function, which allows silently passing args through to the |
| 1344 // body (which only works if we don't do weird renamings of Dart params). | 1344 // body (which only works if we don't do weird renamings of Dart params). |
| 1345 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) { | 1345 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) { |
| 1346 String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null; | 1346 String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null; |
| 1347 List<String> getIdents(List params) => | 1347 List<String> getIdents(List params) => |
| 1348 params.map(getIdent).toList(growable: false); | 1348 params.map(getIdent).toList(growable: false); |
| 1349 | 1349 |
| 1350 if (fn.body is JS.Block && fn.body.statements.length == 1) { | 1350 if (fn.body is JS.Block && fn.body.statements.length == 1) { |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1737 return _maybeQualifiedName(element); | 1737 return _maybeQualifiedName(element); |
| 1738 } | 1738 } |
| 1739 | 1739 |
| 1740 JS.Expression _maybeQualifiedName(Element e, [String name]) { | 1740 JS.Expression _maybeQualifiedName(Element e, [String name]) { |
| 1741 var libName = _libraryName(e.library); | 1741 var libName = _libraryName(e.library); |
| 1742 var nameExpr = _propertyName(name ?? e.name); | 1742 var nameExpr = _propertyName(name ?? e.name); |
| 1743 | 1743 |
| 1744 // Always qualify: | 1744 // Always qualify: |
| 1745 // * mutable top-level fields | 1745 // * mutable top-level fields |
| 1746 // * elements from other libraries | 1746 // * elements from other libraries |
| 1747 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; | 1747 bool mutableTopLevel = e is TopLevelVariableElement && |
| 1748 !e.isConst && |
| 1749 !_isFinalJSDecl(e.computeNode()); |
| 1748 bool fromAnotherLibrary = e.library != currentLibrary; | 1750 bool fromAnotherLibrary = e.library != currentLibrary; |
| 1749 if (mutableTopLevel || fromAnotherLibrary) { | 1751 if (mutableTopLevel || fromAnotherLibrary) { |
| 1750 return new JS.PropertyAccess(libName, nameExpr); | 1752 return new JS.PropertyAccess(libName, nameExpr); |
| 1751 } | 1753 } |
| 1752 | 1754 |
| 1753 var id = new JS.MaybeQualifiedId(libName, nameExpr); | 1755 var id = new JS.MaybeQualifiedId(libName, nameExpr); |
| 1754 _qualifiedIds.add(new Tuple2(e, id)); | 1756 _qualifiedIds.add(new Tuple2(e, id)); |
| 1755 return id; | 1757 return id; |
| 1756 } | 1758 } |
| 1757 | 1759 |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2083 } | 2085 } |
| 2084 | 2086 |
| 2085 @override | 2087 @override |
| 2086 visitVariableDeclaration(VariableDeclaration node) { | 2088 visitVariableDeclaration(VariableDeclaration node) { |
| 2087 if (node.element is PropertyInducingElement) return _emitStaticField(node); | 2089 if (node.element is PropertyInducingElement) return _emitStaticField(node); |
| 2088 | 2090 |
| 2089 var name = new JS.Identifier(node.name.name); | 2091 var name = new JS.Identifier(node.name.name); |
| 2090 return new JS.VariableInitialization(name, _visitInitializer(node)); | 2092 return new JS.VariableInitialization(name, _visitInitializer(node)); |
| 2091 } | 2093 } |
| 2092 | 2094 |
| 2095 bool _isFinalJSDecl(AstNode field) => field is VariableDeclaration && |
| 2096 field.isFinal && |
| 2097 _isJSInvocation(field.initializer); |
| 2098 |
| 2093 /// Emits a static or top-level field. | 2099 /// Emits a static or top-level field. |
| 2094 JS.Statement _emitStaticField(VariableDeclaration field) { | 2100 JS.Statement _emitStaticField(VariableDeclaration field) { |
| 2095 PropertyInducingElement element = field.element; | 2101 PropertyInducingElement element = field.element; |
| 2096 assert(element.isStatic); | 2102 assert(element.isStatic); |
| 2097 | 2103 |
| 2098 bool eagerInit; | 2104 bool eagerInit; |
| 2099 JS.Expression jsInit; | 2105 JS.Expression jsInit; |
| 2100 if (field.isConst || _constField.isFieldInitConstant(field)) { | 2106 if (field.isConst || _constField.isFieldInitConstant(field)) { |
| 2101 // If the field is constant, try and generate it at the top level. | 2107 // If the field is constant, try and generate it at the top level. |
| 2102 _loader.startTopLevel(element); | 2108 _loader.startTopLevel(element); |
| 2103 jsInit = _visitInitializer(field); | 2109 jsInit = _visitInitializer(field); |
| 2104 _loader.finishTopLevel(element); | 2110 _loader.finishTopLevel(element); |
| 2105 eagerInit = _loader.isLoaded(element); | 2111 eagerInit = _loader.isLoaded(element); |
| 2106 } else { | 2112 } else { |
| 2107 jsInit = _visitInitializer(field); | 2113 jsInit = _visitInitializer(field); |
| 2108 eagerInit = false; | 2114 eagerInit = false; |
| 2109 } | 2115 } |
| 2110 | 2116 |
| 2117 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile |
| 2118 // runtime helpers. |
| 2119 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); |
| 2120 if (isJSTopLevel) eagerInit = true; |
| 2121 |
| 2111 var fieldName = field.name.name; | 2122 var fieldName = field.name.name; |
| 2112 if (field.isConst && eagerInit && element is TopLevelVariableElement) { | 2123 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || |
| 2124 isJSTopLevel) { |
| 2113 // constant fields don't change, so we can generate them as `let` | 2125 // constant fields don't change, so we can generate them as `let` |
| 2114 // but add them to the module's exports. However, make sure we generate | 2126 // but add them to the module's exports. However, make sure we generate |
| 2115 // anything they depend on first. | 2127 // anything they depend on first. |
| 2116 | 2128 |
| 2117 if (isPublic(fieldName)) _addExport(fieldName); | 2129 if (isPublic(fieldName)) _addExport(fieldName); |
| 2118 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2130 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
| 2119 return annotateVariable( | 2131 return annotateVariable( |
| 2120 js.statement( | 2132 js.statement( |
| 2121 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), | 2133 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), |
| 2122 field.element); | 2134 field.element); |
| (...skipping 1294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3417 | 3429 |
| 3418 /// A special kind of element created by the compiler, signifying a temporary | 3430 /// A special kind of element created by the compiler, signifying a temporary |
| 3419 /// variable. These objects use instance equality, and should be shared | 3431 /// variable. These objects use instance equality, and should be shared |
| 3420 /// everywhere in the tree where they are treated as the same variable. | 3432 /// everywhere in the tree where they are treated as the same variable. |
| 3421 class TemporaryVariableElement extends LocalVariableElementImpl { | 3433 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3422 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3434 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3423 | 3435 |
| 3424 int get hashCode => identityHashCode(this); | 3436 int get hashCode => identityHashCode(this); |
| 3425 bool operator ==(Object other) => identical(this, other); | 3437 bool operator ==(Object other) => identical(this, other); |
| 3426 } | 3438 } |
| OLD | NEW |