Chromium Code Reviews| 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 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 = new Set<String>(); | 83 final _exports = new Set<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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 if (decl is TopLevelVariableDeclaration) { | 153 if (decl is TopLevelVariableDeclaration) { |
| 153 visitTopLevelVariableDeclaration(decl); | 154 visitTopLevelVariableDeclaration(decl); |
| 154 } else { | 155 } else { |
| 155 _loader.loadDeclaration(decl, decl.element); | 156 _loader.loadDeclaration(decl, decl.element); |
| 156 } | 157 } |
| 157 } | 158 } |
| 158 } | 159 } |
| 159 | 160 |
| 160 // Flush any unwritten fields/properties. | 161 // Flush any unwritten fields/properties. |
| 161 _flushLibraryProperties(_moduleItems); | 162 _flushLibraryProperties(_moduleItems); |
| 163 if (_topLevelExtensionNames.isNotEmpty) { | |
|
Jennifer Messerly
2016/02/02 00:22:56
I don't think this should be needed at the top-lev
ochafik
2016/02/03 19:58:49
Great point! Leaving todo for follow up refactorin
| |
| 164 _moduleItems.add(_emitExtensionNamesDeclaration( | |
| 165 _topLevelExtensionNames.map(js.string).toList())); | |
| 166 } | |
| 162 | 167 |
| 163 // Mark all qualified names as qualified or not, depending on if they need | 168 // Mark all qualified names as qualified or not, depending on if they need |
| 164 // to be loaded lazily or not. | 169 // to be loaded lazily or not. |
| 165 for (var elementIdPairs in _qualifiedIds) { | 170 for (var elementIdPairs in _qualifiedIds) { |
| 166 var element = elementIdPairs.e0; | 171 var element = elementIdPairs.e0; |
| 167 var id = elementIdPairs.e1; | 172 var id = elementIdPairs.e1; |
| 168 id.setQualified(!_loader.isLoaded(element)); | 173 id.setQualified(!_loader.isLoaded(element)); |
| 169 } | 174 } |
| 170 | 175 |
| 171 var moduleBuilder = new ModuleBuilder(options.moduleFormat); | 176 var moduleBuilder = new ModuleBuilder(options.moduleFormat); |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 651 JS.Expression _instantiateAnnotation(Annotation node) { | 656 JS.Expression _instantiateAnnotation(Annotation node) { |
| 652 var element = node.element; | 657 var element = node.element; |
| 653 if (element is ConstructorElement) { | 658 if (element is ConstructorElement) { |
| 654 return _emitInstanceCreationExpression(element, element.returnType, | 659 return _emitInstanceCreationExpression(element, element.returnType, |
| 655 node.constructorName, node.arguments, true); | 660 node.constructorName, node.arguments, true); |
| 656 } else { | 661 } else { |
| 657 return _visit(node.name); | 662 return _visit(node.name); |
| 658 } | 663 } |
| 659 } | 664 } |
| 660 | 665 |
| 666 JS.Statement _emitExtensionNamesDeclaration(List<JS.Expression> names) => | |
| 667 js.statement('dart.defineExtensionNames(#)', | |
| 668 [new JS.ArrayInitializer(names.toList(), multiline: true)]); | |
| 669 | |
| 670 JS.Expression _emitExtensionName(String name) => | |
| 671 js.call('dartx.#', _propertyName(name)); | |
| 672 | |
| 661 /// Emit class members that need to come after the class declaration, such | 673 /// Emit class members that need to come after the class declaration, such |
| 662 /// as static fields. See [_emitClassMethods] for things that are emitted | 674 /// as static fields. See [_emitClassMethods] for things that are emitted |
| 663 /// inside the ES6 `class { ... }` node. | 675 /// inside the ES6 `class { ... }` node. |
| 664 JS.Statement _finishClassMembers( | 676 JS.Statement _finishClassMembers( |
| 665 ClassElement classElem, | 677 ClassElement classElem, |
| 666 JS.ClassExpression cls, | 678 JS.ClassExpression cls, |
| 667 List<ConstructorDeclaration> ctors, | 679 List<ConstructorDeclaration> ctors, |
| 668 List<FieldDeclaration> fields, | 680 List<FieldDeclaration> fields, |
| 669 List<FieldDeclaration> staticFields, | 681 List<FieldDeclaration> staticFields, |
| 670 List<MethodDeclaration> methods, | 682 List<MethodDeclaration> methods, |
| 671 List<Annotation> metadata, | 683 List<Annotation> metadata, |
| 672 String jsPeerName) { | 684 String jsPeerName) { |
| 673 var name = classElem.name; | 685 var name = classElem.name; |
| 674 var body = <JS.Statement>[]; | 686 var body = <JS.Statement>[]; |
| 675 | 687 |
| 676 if (_extensionTypes.contains(classElem)) { | 688 if (_extensionTypes.contains(classElem)) { |
| 677 var dartxNames = <JS.Expression>[]; | 689 var dartxNames = <JS.Expression>[]; |
| 678 for (var m in methods) { | 690 for (var m in methods) { |
| 679 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 691 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 680 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); | 692 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); |
| 681 } | 693 } |
| 682 } | 694 } |
| 683 if (dartxNames.isNotEmpty) { | 695 if (dartxNames.isNotEmpty) { |
| 684 body.add(js.statement('dart.defineExtensionNames(#)', | 696 body.add(_emitExtensionNamesDeclaration(dartxNames)); |
| 685 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | |
| 686 } | 697 } |
| 687 } | 698 } |
| 688 | 699 |
| 689 body.add(new JS.ClassDeclaration(cls)); | 700 body.add(new JS.ClassDeclaration(cls)); |
| 690 | 701 |
| 691 // TODO(jmesserly): we should really just extend native Array. | 702 // TODO(jmesserly): we should really just extend native Array. |
| 692 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { | 703 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { |
| 693 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', | 704 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', |
| 694 [classElem.name, _propertyName(jsPeerName)])); | 705 [classElem.name, _propertyName(jsPeerName)])); |
| 695 } | 706 } |
| (...skipping 2688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3384 /// for this transformation to happen, otherwise binary minus is assumed. | 3395 /// for this transformation to happen, otherwise binary minus is assumed. |
| 3385 /// | 3396 /// |
| 3386 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 3397 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
| 3387 /// helper, that checks for null. The user defined method is called '=='. | 3398 /// helper, that checks for null. The user defined method is called '=='. |
| 3388 /// | 3399 /// |
| 3389 JS.Expression _emitMemberName(String name, | 3400 JS.Expression _emitMemberName(String name, |
| 3390 {DartType type, | 3401 {DartType type, |
| 3391 bool unary: false, | 3402 bool unary: false, |
| 3392 bool isStatic: false, | 3403 bool isStatic: false, |
| 3393 bool allowExtensions: true}) { | 3404 bool allowExtensions: true}) { |
| 3394 // Static members skip the rename steps. | 3405 // Static members skip the rename steps, except for Function properties. |
| 3395 if (isStatic) return _propertyName(name); | 3406 if (isStatic) { |
| 3407 if (options.closure) { | |
| 3408 // Avoid colliding with Function properties, which might be desirable | |
| 3409 // in general but is critical to work around a Closure ES6->ES5 bug | |
| 3410 // (https://github.com/google/closure-compiler/issues/1460). | |
| 3411 if (invalidStaticFieldName(name, closureCompiler: true)) { | |
|
Jennifer Messerly
2016/01/28 20:03:36
I still don't understand why were are using extens
Jennifer Messerly
2016/02/02 00:22:56
We chatted about this, decided extension method sy
ochafik
2016/02/03 19:58:49
Done.
ochafik
2016/02/03 19:58:49
Acknowledged.
| |
| 3412 _topLevelExtensionNames.add(name); | |
| 3413 return _emitExtensionName(name); | |
| 3414 } | |
| 3415 } | |
| 3416 return _propertyName(name); | |
| 3417 } | |
| 3396 | 3418 |
| 3397 if (name.startsWith('_')) { | 3419 if (name.startsWith('_')) { |
| 3398 return _privateNames.putIfAbsent( | 3420 return _privateNames.putIfAbsent( |
| 3399 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); | 3421 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); |
| 3400 } | 3422 } |
| 3401 | 3423 |
| 3402 if (name == '[]') { | 3424 if (name == '[]') { |
| 3403 name = 'get'; | 3425 name = 'get'; |
| 3404 } else if (name == '[]=') { | 3426 } else if (name == '[]=') { |
| 3405 name = 'set'; | 3427 name = 'set'; |
| 3406 } else if (name == '-' && unary) { | 3428 } else if (name == '-' && unary) { |
| 3407 name = 'unary-'; | 3429 name = 'unary-'; |
| 3408 } else if (name == 'constructor' || name == 'prototype') { | 3430 } else if (name == 'constructor' || name == 'prototype') { |
| 3409 // This uses an illegal (in Dart) character for a member, avoiding the | 3431 // This uses an illegal (in Dart) character for a member, avoiding the |
| 3410 // conflict. We could use practically any character for this. | 3432 // conflict. We could use practically any character for this. |
| 3411 name = '+$name'; | 3433 name = '+$name'; |
| 3412 } | 3434 } |
| 3413 | 3435 |
| 3414 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 3436 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
| 3415 var baseType = type; | 3437 var baseType = type; |
| 3416 while (baseType is TypeParameterType) { | 3438 while (baseType is TypeParameterType) { |
| 3417 baseType = baseType.element.bound; | 3439 baseType = baseType.element.bound; |
| 3418 } | 3440 } |
| 3419 if (allowExtensions && | 3441 if (allowExtensions && |
| 3420 _extensionTypes.contains(baseType.element) && | 3442 _extensionTypes.contains(baseType.element) && |
| 3421 !_isObjectProperty(name)) { | 3443 !_isObjectProperty(name)) { |
| 3422 return js.call('dartx.#', _propertyName(name)); | 3444 return _emitExtensionName(name); |
| 3423 } | 3445 } |
| 3424 | 3446 |
| 3425 return _propertyName(name); | 3447 return _propertyName(name); |
| 3426 } | 3448 } |
| 3427 | 3449 |
| 3428 bool _externalOrNative(node) => | 3450 bool _externalOrNative(node) => |
| 3429 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3451 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 3430 | 3452 |
| 3431 FunctionBody _functionBody(node) => | 3453 FunctionBody _functionBody(node) => |
| 3432 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 3454 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3610 | 3632 |
| 3611 /// A special kind of element created by the compiler, signifying a temporary | 3633 /// A special kind of element created by the compiler, signifying a temporary |
| 3612 /// variable. These objects use instance equality, and should be shared | 3634 /// variable. These objects use instance equality, and should be shared |
| 3613 /// everywhere in the tree where they are treated as the same variable. | 3635 /// everywhere in the tree where they are treated as the same variable. |
| 3614 class TemporaryVariableElement extends LocalVariableElementImpl { | 3636 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3615 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3637 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3616 | 3638 |
| 3617 int get hashCode => identityHashCode(this); | 3639 int get hashCode => identityHashCode(this); |
| 3618 bool operator ==(Object other) => identical(this, other); | 3640 bool operator ==(Object other) => identical(this, other); |
| 3619 } | 3641 } |
| OLD | NEW |