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; |
11 import 'package:analyzer/src/generated/constant.dart'; | 11 import 'package:analyzer/src/generated/constant.dart'; |
12 import 'package:analyzer/src/generated/element.dart'; | 12 import 'package:analyzer/src/generated/element.dart'; |
13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
14 import 'package:analyzer/src/generated/scanner.dart' | 14 import 'package:analyzer/src/generated/scanner.dart' |
15 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
16 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; | 16 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; |
17 | 17 |
18 import 'ast_builder.dart' show AstBuilder; | 18 import 'ast_builder.dart' show AstBuilder; |
19 import 'reify_coercions.dart' show CoercionReifier; | 19 import 'reify_coercions.dart' show CoercionReifier, Tuple2; |
20 | 20 |
21 // TODO(jmesserly): import from its own package | 21 // TODO(jmesserly): import from its own package |
22 import '../js/js_ast.dart' as JS; | 22 import '../js/js_ast.dart' as JS; |
23 import '../js/js_ast.dart' show js; | 23 import '../js/js_ast.dart' show js; |
24 | 24 |
25 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 25 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
26 import '../compiler.dart' show AbstractCompiler; | 26 import '../compiler.dart' show AbstractCompiler; |
27 import '../checker/rules.dart'; | 27 import '../checker/rules.dart'; |
28 import '../info.dart'; | 28 import '../info.dart'; |
29 import '../options.dart' show CodegenOptions; | 29 import '../options.dart' show CodegenOptions; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 JS.TemporaryId _asyncStarController; | 75 JS.TemporaryId _asyncStarController; |
76 | 76 |
77 /// Imported libraries, and the temporaries used to refer to them. | 77 /// Imported libraries, and the temporaries used to refer to them. |
78 final _imports = new Map<LibraryElement, JS.TemporaryId>(); | 78 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
79 final _exports = new Set<String>(); | 79 final _exports = new Set<String>(); |
80 final _lazyFields = <VariableDeclaration>[]; | 80 final _lazyFields = <VariableDeclaration>[]; |
81 final _properties = <FunctionDeclaration>[]; | 81 final _properties = <FunctionDeclaration>[]; |
82 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 82 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
83 final _moduleItems = <JS.Statement>[]; | 83 final _moduleItems = <JS.Statement>[]; |
84 final _temps = new HashMap<Element, JS.TemporaryId>(); | 84 final _temps = new HashMap<Element, JS.TemporaryId>(); |
85 final _qualifiedIds = new HashMap<Element, JS.MaybeQualifiedId>(); | 85 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); |
86 final _qualifiedGenericIds = new HashMap<Element, JS.MaybeQualifiedId>(); | |
87 | 86 |
88 /// The name for the library's exports inside itself. | 87 /// The name for the library's exports inside itself. |
89 /// `exports` was chosen as the most similar to ES module patterns. | 88 /// `exports` was chosen as the most similar to ES module patterns. |
90 final _dartxVar = new JS.Identifier('dartx'); | 89 final _dartxVar = new JS.Identifier('dartx'); |
91 final _exportsVar = new JS.TemporaryId('exports'); | 90 final _exportsVar = new JS.TemporaryId('exports'); |
92 final _runtimeLibVar = new JS.Identifier('dart'); | 91 final _runtimeLibVar = new JS.Identifier('dart'); |
93 final _namedArgTemp = new JS.TemporaryId('opts'); | 92 final _namedArgTemp = new JS.TemporaryId('opts'); |
94 | 93 |
95 ConstFieldVisitor _constField; | 94 ConstFieldVisitor _constField; |
96 | 95 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 } | 161 } |
163 } | 162 } |
164 } | 163 } |
165 | 164 |
166 // Flush any unwritten fields/properties. | 165 // Flush any unwritten fields/properties. |
167 _flushLazyFields(_moduleItems); | 166 _flushLazyFields(_moduleItems); |
168 _flushLibraryProperties(_moduleItems); | 167 _flushLibraryProperties(_moduleItems); |
169 | 168 |
170 // Mark all qualified names as qualified or not, depending on if they need | 169 // Mark all qualified names as qualified or not, depending on if they need |
171 // to be loaded lazily or not. | 170 // to be loaded lazily or not. |
172 unqualifyIfNeeded(Element e, JS.MaybeQualifiedId id) { | 171 for (var elementIdPairs in _qualifiedIds) { |
173 id.setQualified(!_loader.isLoaded(e)); | 172 var element = elementIdPairs.e0; |
| 173 var id = elementIdPairs.e1; |
| 174 id.setQualified(!_loader.isLoaded(element)); |
174 } | 175 } |
175 _qualifiedIds.forEach(unqualifyIfNeeded); | |
176 _qualifiedGenericIds.forEach(unqualifyIfNeeded); | |
177 | 176 |
178 if (_exports.isNotEmpty) _moduleItems.add(js.comment('Exports:')); | 177 if (_exports.isNotEmpty) _moduleItems.add(js.comment('Exports:')); |
179 | 178 |
180 // TODO(jmesserly): make these immutable in JS? | 179 // TODO(jmesserly): make these immutable in JS? |
181 for (var name in _exports) { | 180 for (var name in _exports) { |
182 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); | 181 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); |
183 } | 182 } |
184 | 183 |
185 var jsPath = compiler.getModuleName(currentLibrary.source.uri); | 184 var jsPath = compiler.getModuleName(currentLibrary.source.uri); |
186 | 185 |
(...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1473 // type literal | 1472 // type literal |
1474 if (element is ClassElement || | 1473 if (element is ClassElement || |
1475 element is DynamicElementImpl || | 1474 element is DynamicElementImpl || |
1476 element is FunctionTypeAliasElement) { | 1475 element is FunctionTypeAliasElement) { |
1477 return _emitTypeName( | 1476 return _emitTypeName( |
1478 fillDynamicTypeArgs((element as dynamic).type, types)); | 1477 fillDynamicTypeArgs((element as dynamic).type, types)); |
1479 } | 1478 } |
1480 | 1479 |
1481 // library member | 1480 // library member |
1482 if (element.enclosingElement is CompilationUnitElement) { | 1481 if (element.enclosingElement is CompilationUnitElement) { |
1483 return _maybeQualifiedName( | 1482 return _maybeQualifiedName(element); |
1484 element, _emitMemberName(name, isStatic: true)); | |
1485 } | 1483 } |
1486 | 1484 |
1487 // Unqualified class member. This could mean implicit-this, or implicit | 1485 // Unqualified class member. This could mean implicit-this, or implicit |
1488 // call to a static from the same class. | 1486 // call to a static from the same class. |
1489 if (element is ClassMemberElement && element is! ConstructorElement) { | 1487 if (element is ClassMemberElement && element is! ConstructorElement) { |
1490 bool isStatic = element.isStatic; | 1488 bool isStatic = element.isStatic; |
1491 var type = element.enclosingElement.type; | 1489 var type = element.enclosingElement.type; |
1492 var member = _emitMemberName(name, isStatic: isStatic, type: type); | 1490 var member = _emitMemberName(name, isStatic: isStatic, type: type); |
1493 | 1491 |
1494 // For static methods, we add the raw type name, without generics or | 1492 // For static methods, we add the raw type name, without generics or |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 Iterable jsArgs = null; | 1632 Iterable jsArgs = null; |
1635 if (args.any((a) => a != types.dynamicType)) { | 1633 if (args.any((a) => a != types.dynamicType)) { |
1636 jsArgs = args.map(_emitTypeName); | 1634 jsArgs = args.map(_emitTypeName); |
1637 } else if (lowerGeneric || isCurrentClass) { | 1635 } else if (lowerGeneric || isCurrentClass) { |
1638 // When creating a `new S<dynamic>` we try and use the raw form | 1636 // When creating a `new S<dynamic>` we try and use the raw form |
1639 // `new S()`, but this does not work if we're inside the same class, | 1637 // `new S()`, but this does not work if we're inside the same class, |
1640 // because `S` refers to the current S<T> we are generating. | 1638 // because `S` refers to the current S<T> we are generating. |
1641 jsArgs = []; | 1639 jsArgs = []; |
1642 } | 1640 } |
1643 if (jsArgs != null) { | 1641 if (jsArgs != null) { |
1644 var genericName = _maybeQualifiedName( | 1642 var genericName = _maybeQualifiedName(element, '$name\$'); |
1645 element, _propertyName('$name\$'), _qualifiedGenericIds); | |
1646 return js.call('#(#)', [genericName, jsArgs]); | 1643 return js.call('#(#)', [genericName, jsArgs]); |
1647 } | 1644 } |
1648 } | 1645 } |
1649 | 1646 |
1650 return _maybeQualifiedName(element, _propertyName(name)); | 1647 return _maybeQualifiedName(element); |
1651 } | 1648 } |
1652 | 1649 |
1653 JS.Expression _maybeQualifiedName(Element e, JS.Expression name, | 1650 JS.Expression _maybeQualifiedName(Element e, [String name]) { |
1654 [Map<Element, JS.MaybeQualifiedId> idTable]) { | |
1655 var libName = _libraryName(e.library); | 1651 var libName = _libraryName(e.library); |
1656 if (idTable == null) idTable = _qualifiedIds; | 1652 var nameExpr = _propertyName(name ?? e.name); |
1657 | 1653 |
1658 // Mutable top-level fields should always be qualified. | 1654 // Always qualify: |
| 1655 // * mutable top-level fields |
| 1656 // * elements from other libraries |
1659 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; | 1657 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; |
1660 if (e.library != currentLibrary || mutableTopLevel) { | 1658 bool fromAnotherLibrary = e.library != currentLibrary; |
1661 return new JS.PropertyAccess(libName, name); | 1659 if (mutableTopLevel || fromAnotherLibrary) { |
| 1660 return new JS.PropertyAccess(libName, nameExpr); |
1662 } | 1661 } |
1663 | 1662 |
1664 return idTable.putIfAbsent(e, () => new JS.MaybeQualifiedId(libName, name)); | 1663 var id = new JS.MaybeQualifiedId(libName, nameExpr); |
| 1664 _qualifiedIds.add(new Tuple2(e, id)); |
| 1665 return id; |
1665 } | 1666 } |
1666 | 1667 |
1667 @override | 1668 @override |
1668 JS.Expression visitAssignmentExpression(AssignmentExpression node) { | 1669 JS.Expression visitAssignmentExpression(AssignmentExpression node) { |
1669 var left = node.leftHandSide; | 1670 var left = node.leftHandSide; |
1670 var right = node.rightHandSide; | 1671 var right = node.rightHandSide; |
1671 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); | 1672 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); |
1672 var op = node.operator.lexeme; | 1673 var op = node.operator.lexeme; |
1673 assert(op.endsWith('=')); | 1674 assert(op.endsWith('=')); |
1674 op = op.substring(0, op.length - 1); // remove trailing '=' | 1675 op = op.substring(0, op.length - 1); // remove trailing '=' |
(...skipping 1646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3321 | 3322 |
3322 /// A special kind of element created by the compiler, signifying a temporary | 3323 /// A special kind of element created by the compiler, signifying a temporary |
3323 /// variable. These objects use instance equality, and should be shared | 3324 /// variable. These objects use instance equality, and should be shared |
3324 /// everywhere in the tree where they are treated as the same variable. | 3325 /// everywhere in the tree where they are treated as the same variable. |
3325 class TemporaryVariableElement extends LocalVariableElementImpl { | 3326 class TemporaryVariableElement extends LocalVariableElementImpl { |
3326 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3327 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3327 | 3328 |
3328 int get hashCode => identityHashCode(this); | 3329 int get hashCode => identityHashCode(this); |
3329 bool operator ==(Object other) => identical(this, other); | 3330 bool operator ==(Object other) => identical(this, other); |
3330 } | 3331 } |
OLD | NEW |