| 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 |