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 |