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 1276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1287 } | 1287 } |
1288 | 1288 |
1289 return annotate( | 1289 return annotate( |
1290 new JS.Method(_elementMemberName(node.element), fn, | 1290 new JS.Method(_elementMemberName(node.element), fn, |
1291 isGetter: node.isGetter, | 1291 isGetter: node.isGetter, |
1292 isSetter: node.isSetter, | 1292 isSetter: node.isSetter, |
1293 isStatic: node.isStatic), | 1293 isStatic: node.isStatic), |
1294 node.element); | 1294 node.element); |
1295 } | 1295 } |
1296 | 1296 |
1297 /// Returns the name value of the `JSExportName` annotation (when compiling | |
1298 /// the SDK), or `null` if there's none. This is used to control the name | |
1299 /// under which functions are compiled and exported. | |
1300 String _getJSExportName(Element e) { | |
1301 if (e is! FunctionElement || !currentLibrary.source.isInSystemLibrary) { | |
1302 return null; | |
1303 } | |
1304 var jsName = findAnnotation(e, isJSExportNameAnnotation); | |
1305 return getConstantField(jsName, 'name', types.stringType)?.toStringValue(); | |
1306 } | |
1307 | |
1297 @override | 1308 @override |
1298 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 1309 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
1299 assert(node.parent is CompilationUnit); | 1310 assert(node.parent is CompilationUnit); |
1300 | 1311 |
1301 if (_externalOrNative(node)) return null; | 1312 if (_externalOrNative(node)) return null; |
1302 | 1313 |
1303 if (node.isGetter || node.isSetter) { | 1314 if (node.isGetter || node.isSetter) { |
1304 // Add these later so we can use getter/setter syntax. | 1315 // Add these later so we can use getter/setter syntax. |
1305 _properties.add(node); | 1316 _properties.add(node); |
1306 return null; | 1317 return null; |
1307 } | 1318 } |
1308 | 1319 |
1309 var body = <JS.Statement>[]; | 1320 var body = <JS.Statement>[]; |
1310 _flushLibraryProperties(body); | 1321 _flushLibraryProperties(body); |
1311 | 1322 |
1312 var name = node.name.name; | 1323 var name = _getJSExportName(node.element) ?? node.name.name; |
1313 | 1324 |
1314 var fn = _visit(node.functionExpression); | 1325 var fn = _visit(node.functionExpression); |
1315 bool needsTagging = true; | 1326 bool needsTagging = true; |
1316 | 1327 |
1317 if (currentLibrary.source.isInSystemLibrary && | 1328 if (currentLibrary.source.isInSystemLibrary && |
1318 _isInlineJSFunction(node.functionExpression)) { | 1329 _isInlineJSFunction(node.functionExpression)) { |
1319 fn = _simplifyPassThroughArrowFunCallBody(fn); | 1330 fn = _simplifyPassThroughArrowFunCallBody(fn); |
1320 needsTagging = !_isDartUtils; | 1331 needsTagging = !_isDartUtils; |
1321 } | 1332 } |
1322 | 1333 |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1568 } | 1579 } |
1569 | 1580 |
1570 // Get the original declaring element. If we had a property accessor, this | 1581 // Get the original declaring element. If we had a property accessor, this |
1571 // indirects back to a (possibly synthetic) field. | 1582 // indirects back to a (possibly synthetic) field. |
1572 var element = accessor; | 1583 var element = accessor; |
1573 if (accessor is PropertyAccessorElement) element = accessor.variable; | 1584 if (accessor is PropertyAccessorElement) element = accessor.variable; |
1574 if (accessor is FunctionMember) element = accessor.baseElement; | 1585 if (accessor is FunctionMember) element = accessor.baseElement; |
1575 | 1586 |
1576 _loader.declareBeforeUse(element); | 1587 _loader.declareBeforeUse(element); |
1577 | 1588 |
1578 var name = element.name; | |
1579 | |
1580 // type literal | 1589 // type literal |
1581 if (element is ClassElement || | 1590 if (element is ClassElement || |
1582 element is DynamicElementImpl || | 1591 element is DynamicElementImpl || |
1583 element is FunctionTypeAliasElement) { | 1592 element is FunctionTypeAliasElement) { |
1584 return _emitTypeName( | 1593 return _emitTypeName( |
1585 fillDynamicTypeArgs((element as dynamic).type, types)); | 1594 fillDynamicTypeArgs((element as dynamic).type, types)); |
1586 } | 1595 } |
1587 | 1596 |
1588 // library member | 1597 // library member |
1589 if (element.enclosingElement is CompilationUnitElement) { | 1598 if (element.enclosingElement is CompilationUnitElement) { |
1590 return _maybeQualifiedName(element); | 1599 return _emitTopLevelName(element); |
Jennifer Messerly
2016/01/13 17:43:59
nice! it's funny how a name change makes such a di
ochafik
2016/01/13 18:51:29
Yeah, *sounds* so much more deterministic now ;-)
| |
1591 } | 1600 } |
1592 | 1601 |
1602 var name = element.name; | |
1603 | |
1593 // Unqualified class member. This could mean implicit-this, or implicit | 1604 // Unqualified class member. This could mean implicit-this, or implicit |
1594 // call to a static from the same class. | 1605 // call to a static from the same class. |
1595 if (element is ClassMemberElement && element is! ConstructorElement) { | 1606 if (element is ClassMemberElement && element is! ConstructorElement) { |
1596 bool isStatic = element.isStatic; | 1607 bool isStatic = element.isStatic; |
1597 var type = element.enclosingElement.type; | 1608 var type = element.enclosingElement.type; |
1598 var member = _emitMemberName(name, isStatic: isStatic, type: type); | 1609 var member = _emitMemberName(name, isStatic: isStatic, type: type); |
1599 | 1610 |
1600 // For static methods, we add the raw type name, without generics or | 1611 // For static methods, we add the raw type name, without generics or |
1601 // library prefix. We don't need those because static calls can't use | 1612 // library prefix. We don't need those because static calls can't use |
1602 // the generic type. | 1613 // the generic type. |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1750 if (args | 1761 if (args |
1751 .any((a) => a != types.dynamicType && !_isGenericTypeParameter(a))) { | 1762 .any((a) => a != types.dynamicType && !_isGenericTypeParameter(a))) { |
1752 jsArgs = args.map(_emitTypeName); | 1763 jsArgs = args.map(_emitTypeName); |
1753 } else if (lowerGeneric || isCurrentClass) { | 1764 } else if (lowerGeneric || isCurrentClass) { |
1754 // When creating a `new S<dynamic>` we try and use the raw form | 1765 // When creating a `new S<dynamic>` we try and use the raw form |
1755 // `new S()`, but this does not work if we're inside the same class, | 1766 // `new S()`, but this does not work if we're inside the same class, |
1756 // because `S` refers to the current S<T> we are generating. | 1767 // because `S` refers to the current S<T> we are generating. |
1757 jsArgs = []; | 1768 jsArgs = []; |
1758 } | 1769 } |
1759 if (jsArgs != null) { | 1770 if (jsArgs != null) { |
1760 var genericName = _maybeQualifiedName(element, '$name\$'); | 1771 var genericName = _emitTopLevelName(element, '$name\$'); |
1761 return js.call('#(#)', [genericName, jsArgs]); | 1772 return js.call('#(#)', [genericName, jsArgs]); |
1762 } | 1773 } |
1763 } | 1774 } |
1764 | 1775 |
1765 return _maybeQualifiedName(element); | 1776 return _emitTopLevelName(element); |
1766 } | 1777 } |
1767 | 1778 |
1768 JS.Expression _maybeQualifiedName(Element e, [String name]) { | 1779 JS.Expression _emitTopLevelName(Element e, [String name]) { |
1769 var libName = _libraryName(e.library); | 1780 var libName = _libraryName(e.library); |
1770 var nameExpr = _propertyName(name ?? e.name); | 1781 var nameExpr = _propertyName(name ?? _getJSExportName(e) ?? e.name); |
Jennifer Messerly
2016/01/13 17:44:00
oh wow, the [name] optional parameter--which was p
ochafik
2016/01/13 18:51:29
Cool! Done.
| |
1771 | 1782 |
1772 // Always qualify: | 1783 // Always qualify: |
1773 // * mutable top-level fields | 1784 // * mutable top-level fields |
1774 // * elements from other libraries | 1785 // * elements from other libraries |
1775 bool mutableTopLevel = e is TopLevelVariableElement && | 1786 bool mutableTopLevel = e is TopLevelVariableElement && |
1776 !e.isConst && | 1787 !e.isConst && |
1777 !_isFinalJSDecl(e.computeNode()); | 1788 !_isFinalJSDecl(e.computeNode()); |
1778 bool fromAnotherLibrary = e.library != currentLibrary; | 1789 bool fromAnotherLibrary = e.library != currentLibrary; |
1779 if (mutableTopLevel || fromAnotherLibrary) { | 1790 if (mutableTopLevel || fromAnotherLibrary) { |
1780 return new JS.PropertyAccess(libName, nameExpr); | 1791 return new JS.PropertyAccess(libName, nameExpr); |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2223 } else { | 2234 } else { |
2224 jsInit = _visitInitializer(field); | 2235 jsInit = _visitInitializer(field); |
2225 eagerInit = false; | 2236 eagerInit = false; |
2226 } | 2237 } |
2227 | 2238 |
2228 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile | 2239 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile |
2229 // runtime helpers. | 2240 // runtime helpers. |
2230 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); | 2241 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); |
2231 if (isJSTopLevel) eagerInit = true; | 2242 if (isJSTopLevel) eagerInit = true; |
2232 | 2243 |
2233 var fieldName = field.name.name; | 2244 var fieldName = _getJSExportName(element) ?? field.name.name; |
Jennifer Messerly
2016/01/13 17:43:59
So for top-level fields, I think this works.
I wo
ochafik
2016/01/13 18:51:29
Aaaah, absolutely, thanks!
| |
2234 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || | 2245 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || |
2235 isJSTopLevel) { | 2246 isJSTopLevel) { |
2236 // constant fields don't change, so we can generate them as `let` | 2247 // constant fields don't change, so we can generate them as `let` |
2237 // but add them to the module's exports. However, make sure we generate | 2248 // but add them to the module's exports. However, make sure we generate |
2238 // anything they depend on first. | 2249 // anything they depend on first. |
2239 | 2250 |
2240 if (isPublic(fieldName)) _addExport(fieldName); | 2251 if (isPublic(fieldName)) _addExport(fieldName); |
2241 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2252 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
2242 return annotateVariable( | 2253 return annotateVariable( |
2243 js.statement( | 2254 js.statement( |
(...skipping 1376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3620 | 3631 |
3621 /// A special kind of element created by the compiler, signifying a temporary | 3632 /// A special kind of element created by the compiler, signifying a temporary |
3622 /// variable. These objects use instance equality, and should be shared | 3633 /// variable. These objects use instance equality, and should be shared |
3623 /// everywhere in the tree where they are treated as the same variable. | 3634 /// everywhere in the tree where they are treated as the same variable. |
3624 class TemporaryVariableElement extends LocalVariableElementImpl { | 3635 class TemporaryVariableElement extends LocalVariableElementImpl { |
3625 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3636 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3626 | 3637 |
3627 int get hashCode => identityHashCode(this); | 3638 int get hashCode => identityHashCode(this); |
3628 bool operator ==(Object other) => identical(this, other); | 3639 bool operator ==(Object other) => identical(this, other); |
3629 } | 3640 } |
OLD | NEW |