| 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 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 5 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 8 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/src/generated/constant.dart'; | 9 import 'package:analyzer/src/generated/constant.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 JS.TemporaryId _asyncStarController; | 79 JS.TemporaryId _asyncStarController; |
| 80 | 80 |
| 81 /// Imported libraries, and the temporaries used to refer to them. | 81 /// Imported libraries, and the temporaries used to refer to them. |
| 82 final _imports = new Map<LibraryElement, JS.TemporaryId>(); | 82 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
| 83 final _exports = <String, String>{}; | 83 final _exports = <String, String>{}; |
| 84 final _properties = <FunctionDeclaration>[]; | 84 final _properties = <FunctionDeclaration>[]; |
| 85 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 85 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
| 86 final _moduleItems = <JS.Statement>[]; | 86 final _moduleItems = <JS.Statement>[]; |
| 87 final _temps = new HashMap<Element, JS.TemporaryId>(); | 87 final _temps = new HashMap<Element, JS.TemporaryId>(); |
| 88 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); | 88 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); |
| 89 final _topLevelExtensionNames = new Set<String>(); |
| 89 | 90 |
| 90 /// The name for the library's exports inside itself. | 91 /// The name for the library's exports inside itself. |
| 91 /// `exports` was chosen as the most similar to ES module patterns. | 92 /// `exports` was chosen as the most similar to ES module patterns. |
| 92 final _dartxVar = new JS.Identifier('dartx'); | 93 final _dartxVar = new JS.Identifier('dartx'); |
| 93 final _exportsVar = new JS.TemporaryId('exports'); | 94 final _exportsVar = new JS.TemporaryId('exports'); |
| 94 final _runtimeLibVar = new JS.Identifier('dart'); | 95 final _runtimeLibVar = new JS.Identifier('dart'); |
| 95 final _namedArgTemp = new JS.TemporaryId('opts'); | 96 final _namedArgTemp = new JS.TemporaryId('opts'); |
| 96 | 97 |
| 97 final TypeProvider _types; | 98 final TypeProvider _types; |
| 98 | 99 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 if (decl is TopLevelVariableDeclaration) { | 162 if (decl is TopLevelVariableDeclaration) { |
| 162 visitTopLevelVariableDeclaration(decl); | 163 visitTopLevelVariableDeclaration(decl); |
| 163 } else { | 164 } else { |
| 164 _loader.loadDeclaration(decl, decl.element); | 165 _loader.loadDeclaration(decl, decl.element); |
| 165 } | 166 } |
| 166 } | 167 } |
| 167 } | 168 } |
| 168 | 169 |
| 169 // Flush any unwritten fields/properties. | 170 // Flush any unwritten fields/properties. |
| 170 _flushLibraryProperties(_moduleItems); | 171 _flushLibraryProperties(_moduleItems); |
| 172 // TODO(ochafik): Refactor to merge this with the dartxNames codepath. |
| 173 if (_topLevelExtensionNames.isNotEmpty) { |
| 174 _moduleItems.add(_emitExtensionNamesDeclaration( |
| 175 _topLevelExtensionNames.map(js.string).toList())); |
| 176 } |
| 171 | 177 |
| 172 // Mark all qualified names as qualified or not, depending on if they need | 178 // Mark all qualified names as qualified or not, depending on if they need |
| 173 // to be loaded lazily or not. | 179 // to be loaded lazily or not. |
| 174 for (var elementIdPairs in _qualifiedIds) { | 180 for (var elementIdPairs in _qualifiedIds) { |
| 175 var element = elementIdPairs.e0; | 181 var element = elementIdPairs.e0; |
| 176 var id = elementIdPairs.e1; | 182 var id = elementIdPairs.e1; |
| 177 id.setQualified(!_loader.isLoaded(element)); | 183 id.setQualified(!_loader.isLoaded(element)); |
| 178 } | 184 } |
| 179 | 185 |
| 180 var moduleBuilder = new ModuleBuilder(options.moduleFormat); | 186 var moduleBuilder = new ModuleBuilder(options.moduleFormat); |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 JS.Expression _instantiateAnnotation(Annotation node) { | 673 JS.Expression _instantiateAnnotation(Annotation node) { |
| 668 var element = node.element; | 674 var element = node.element; |
| 669 if (element is ConstructorElement) { | 675 if (element is ConstructorElement) { |
| 670 return _emitInstanceCreationExpression(element, element.returnType, | 676 return _emitInstanceCreationExpression(element, element.returnType, |
| 671 node.constructorName, node.arguments, true); | 677 node.constructorName, node.arguments, true); |
| 672 } else { | 678 } else { |
| 673 return _visit(node.name); | 679 return _visit(node.name); |
| 674 } | 680 } |
| 675 } | 681 } |
| 676 | 682 |
| 683 JS.Statement _emitExtensionNamesDeclaration(List<JS.Expression> names) => |
| 684 js.statement('dart.defineExtensionNames(#)', |
| 685 [new JS.ArrayInitializer(names.toList(), multiline: true)]); |
| 686 |
| 687 JS.Expression _emitExtensionName(String name) => |
| 688 js.call('dartx.#', _propertyName(name)); |
| 689 |
| 677 /// Emit class members that need to come after the class declaration, such | 690 /// Emit class members that need to come after the class declaration, such |
| 678 /// as static fields. See [_emitClassMethods] for things that are emitted | 691 /// as static fields. See [_emitClassMethods] for things that are emitted |
| 679 /// inside the ES6 `class { ... }` node. | 692 /// inside the ES6 `class { ... }` node. |
| 680 JS.Statement _finishClassMembers( | 693 JS.Statement _finishClassMembers( |
| 681 ClassElement classElem, | 694 ClassElement classElem, |
| 682 JS.ClassExpression cls, | 695 JS.ClassExpression cls, |
| 683 List<ConstructorDeclaration> ctors, | 696 List<ConstructorDeclaration> ctors, |
| 684 List<FieldDeclaration> fields, | 697 List<FieldDeclaration> fields, |
| 685 List<FieldDeclaration> staticFields, | 698 List<FieldDeclaration> staticFields, |
| 686 List<MethodDeclaration> methods, | 699 List<MethodDeclaration> methods, |
| 687 List<Annotation> metadata, | 700 List<Annotation> metadata, |
| 688 String jsPeerName) { | 701 String jsPeerName) { |
| 689 var name = classElem.name; | 702 var name = classElem.name; |
| 690 var body = <JS.Statement>[]; | 703 var body = <JS.Statement>[]; |
| 691 | 704 |
| 692 if (_extensionTypes.contains(classElem)) { | 705 if (_extensionTypes.contains(classElem)) { |
| 693 var dartxNames = <JS.Expression>[]; | 706 var dartxNames = <JS.Expression>[]; |
| 694 for (var m in methods) { | 707 for (var m in methods) { |
| 695 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 708 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 696 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); | 709 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); |
| 697 } | 710 } |
| 698 } | 711 } |
| 699 if (dartxNames.isNotEmpty) { | 712 if (dartxNames.isNotEmpty) { |
| 700 body.add(js.statement('dart.defineExtensionNames(#)', | 713 body.add(_emitExtensionNamesDeclaration(dartxNames)); |
| 701 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | |
| 702 } | 714 } |
| 703 } | 715 } |
| 704 | 716 |
| 705 body.add(new JS.ClassDeclaration(cls)); | 717 body.add(new JS.ClassDeclaration(cls)); |
| 706 | 718 |
| 707 // TODO(jmesserly): we should really just extend native Array. | 719 // TODO(jmesserly): we should really just extend native Array. |
| 708 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { | 720 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { |
| 709 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', | 721 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', |
| 710 [classElem.name, _propertyName(jsPeerName)])); | 722 [classElem.name, _propertyName(jsPeerName)])); |
| 711 } | 723 } |
| (...skipping 1518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2230 assert(element.isStatic); | 2242 assert(element.isStatic); |
| 2231 | 2243 |
| 2232 _loader.startCheckingReferences(); | 2244 _loader.startCheckingReferences(); |
| 2233 JS.Expression jsInit = _visitInitializer(field); | 2245 JS.Expression jsInit = _visitInitializer(field); |
| 2234 bool isLoaded = _loader.finishCheckingReferences(); | 2246 bool isLoaded = _loader.finishCheckingReferences(); |
| 2235 | 2247 |
| 2236 bool eagerInit = | 2248 bool eagerInit = |
| 2237 isLoaded && (field.isConst || _constField.isFieldInitConstant(field)); | 2249 isLoaded && (field.isConst || _constField.isFieldInitConstant(field)); |
| 2238 | 2250 |
| 2239 var fieldName = field.name.name; | 2251 var fieldName = field.name.name; |
| 2240 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { | 2252 if (eagerInit && !JS.invalidStaticFieldName(fieldName, options)) { |
| 2241 return annotateVariable( | 2253 return annotateVariable( |
| 2242 js.statement('#.# = #;', [ | 2254 js.statement('#.# = #;', [ |
| 2243 classElem.name, | 2255 classElem.name, |
| 2244 _emitMemberName(fieldName, isStatic: true), | 2256 _emitMemberName(fieldName, isStatic: true), |
| 2245 jsInit | 2257 jsInit |
| 2246 ]), | 2258 ]), |
| 2247 field.element); | 2259 field.element); |
| 2248 } | 2260 } |
| 2249 | 2261 |
| 2250 // This means it should be treated as a lazy field. | 2262 // This means it should be treated as a lazy field. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2290 // anything they depend on first. | 2302 // anything they depend on first. |
| 2291 | 2303 |
| 2292 if (isPublic(fieldName)) _addExport(fieldName, exportName); | 2304 if (isPublic(fieldName)) _addExport(fieldName, exportName); |
| 2293 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2305 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
| 2294 return annotateVariable( | 2306 return annotateVariable( |
| 2295 js.statement( | 2307 js.statement( |
| 2296 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), | 2308 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), |
| 2297 field.element); | 2309 field.element); |
| 2298 } | 2310 } |
| 2299 | 2311 |
| 2300 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { | 2312 if (eagerInit && !JS.invalidStaticFieldName(fieldName, options)) { |
| 2301 return annotateVariable( | 2313 return annotateVariable( |
| 2302 js.statement('# = #;', [_visit(field.name), jsInit]), field.element); | 2314 js.statement('# = #;', [_visit(field.name), jsInit]), field.element); |
| 2303 } | 2315 } |
| 2304 | 2316 |
| 2305 return _emitLazyFields(currentLibrary, [field]); | 2317 return _emitLazyFields(currentLibrary, [field]); |
| 2306 } | 2318 } |
| 2307 | 2319 |
| 2308 JS.Expression _visitInitializer(VariableDeclaration node) { | 2320 JS.Expression _visitInitializer(VariableDeclaration node) { |
| 2309 var value = _visit(node.initializer); | 2321 var value = _visit(node.initializer); |
| 2310 // explicitly initialize to null, to avoid getting `undefined`. | 2322 // explicitly initialize to null, to avoid getting `undefined`. |
| (...skipping 1053 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3364 /// for this transformation to happen, otherwise binary minus is assumed. | 3376 /// for this transformation to happen, otherwise binary minus is assumed. |
| 3365 /// | 3377 /// |
| 3366 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 3378 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
| 3367 /// helper, that checks for null. The user defined method is called '=='. | 3379 /// helper, that checks for null. The user defined method is called '=='. |
| 3368 /// | 3380 /// |
| 3369 JS.Expression _emitMemberName(String name, | 3381 JS.Expression _emitMemberName(String name, |
| 3370 {DartType type, | 3382 {DartType type, |
| 3371 bool unary: false, | 3383 bool unary: false, |
| 3372 bool isStatic: false, | 3384 bool isStatic: false, |
| 3373 bool allowExtensions: true}) { | 3385 bool allowExtensions: true}) { |
| 3374 // Static members skip the rename steps. | 3386 // Static members skip the rename steps, except for Function properties. |
| 3375 if (isStatic) return _propertyName(name); | 3387 if (isStatic) { |
| 3388 // Avoid colliding with names on Function that are disallowed in ES6, |
| 3389 // or where we need to work around transpilers. |
| 3390 if (invalidStaticFieldName(name, options)) { |
| 3391 _topLevelExtensionNames.add(name); |
| 3392 return _emitExtensionName(name); |
| 3393 } else { |
| 3394 return _propertyName(name); |
| 3395 } |
| 3396 } |
| 3376 | 3397 |
| 3377 if (name.startsWith('_')) { | 3398 if (name.startsWith('_')) { |
| 3378 return _privateNames.putIfAbsent( | 3399 return _privateNames.putIfAbsent( |
| 3379 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); | 3400 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); |
| 3380 } | 3401 } |
| 3381 | 3402 |
| 3382 if (name == '[]') { | 3403 if (name == '[]') { |
| 3383 name = 'get'; | 3404 name = 'get'; |
| 3384 } else if (name == '[]=') { | 3405 } else if (name == '[]=') { |
| 3385 name = 'set'; | 3406 name = 'set'; |
| 3386 } else if (name == '-' && unary) { | 3407 } else if (name == '-' && unary) { |
| 3387 name = 'unary-'; | 3408 name = 'unary-'; |
| 3388 } else if (name == 'constructor' || name == 'prototype') { | 3409 } else if (name == 'constructor' || name == 'prototype') { |
| 3389 // This uses an illegal (in Dart) character for a member, avoiding the | 3410 // This uses an illegal (in Dart) character for a member, avoiding the |
| 3390 // conflict. We could use practically any character for this. | 3411 // conflict. We could use practically any character for this. |
| 3391 name = '+$name'; | 3412 name = '+$name'; |
| 3392 } | 3413 } |
| 3393 | 3414 |
| 3394 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 3415 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
| 3395 var baseType = type; | 3416 var baseType = type; |
| 3396 while (baseType is TypeParameterType) { | 3417 while (baseType is TypeParameterType) { |
| 3397 baseType = baseType.element.bound; | 3418 baseType = baseType.element.bound; |
| 3398 } | 3419 } |
| 3399 if (allowExtensions && | 3420 if (allowExtensions && |
| 3400 _extensionTypes.contains(baseType.element) && | 3421 _extensionTypes.contains(baseType.element) && |
| 3401 !_isObjectProperty(name)) { | 3422 !_isObjectProperty(name)) { |
| 3402 return js.call('dartx.#', _propertyName(name)); | 3423 return _emitExtensionName(name); |
| 3403 } | 3424 } |
| 3404 | 3425 |
| 3405 return _propertyName(name); | 3426 return _propertyName(name); |
| 3406 } | 3427 } |
| 3407 | 3428 |
| 3408 bool _externalOrNative(node) => | 3429 bool _externalOrNative(node) => |
| 3409 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3430 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 3410 | 3431 |
| 3411 FunctionBody _functionBody(node) => | 3432 FunctionBody _functionBody(node) => |
| 3412 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 3433 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3589 | 3610 |
| 3590 /// A special kind of element created by the compiler, signifying a temporary | 3611 /// A special kind of element created by the compiler, signifying a temporary |
| 3591 /// variable. These objects use instance equality, and should be shared | 3612 /// variable. These objects use instance equality, and should be shared |
| 3592 /// everywhere in the tree where they are treated as the same variable. | 3613 /// everywhere in the tree where they are treated as the same variable. |
| 3593 class TemporaryVariableElement extends LocalVariableElementImpl { | 3614 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3594 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3615 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3595 | 3616 |
| 3596 int get hashCode => identityHashCode(this); | 3617 int get hashCode => identityHashCode(this); |
| 3597 bool operator ==(Object other) => identical(this, other); | 3618 bool operator ==(Object other) => identical(this, other); |
| 3598 } | 3619 } |
| OLD | NEW |