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 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'; |
| 11 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | |
| 11 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 12 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 12 import 'package:analyzer/src/generated/scanner.dart' | 13 import 'package:analyzer/src/generated/scanner.dart' |
| 13 show StringToken, Token, TokenType; | 14 show StringToken, Token, TokenType; |
| 14 import 'package:analyzer/src/generated/type_system.dart' | 15 import 'package:analyzer/src/generated/type_system.dart' |
| 15 show StrongTypeSystemImpl; | 16 show StrongTypeSystemImpl; |
| 16 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; | 17 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; |
| 17 | 18 |
| 18 import 'ast_builder.dart' show AstBuilder; | 19 import 'ast_builder.dart' show AstBuilder; |
| 19 import 'reify_coercions.dart' show CoercionReifier, Tuple2; | 20 import 'reify_coercions.dart' show CoercionReifier, Tuple2; |
| 20 | 21 |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 } else if (member is MethodDeclaration) { | 422 } else if (member is MethodDeclaration) { |
| 422 methods.add(member); | 423 methods.add(member); |
| 423 } | 424 } |
| 424 } | 425 } |
| 425 | 426 |
| 426 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 427 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), |
| 427 _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); | 428 _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); |
| 428 | 429 |
| 429 String jsPeerName; | 430 String jsPeerName; |
| 430 var jsPeer = findAnnotation(classElem, isJsPeerInterface); | 431 var jsPeer = findAnnotation(classElem, isJsPeerInterface); |
| 432 // Only look at "Native" annotations on registered extension types. | |
| 433 // E.g., we're current ignoring the ones in dart:html. | |
| 434 if (jsPeer == null && _extensionTypes.contains(classElem)) { | |
| 435 jsPeer = findAnnotation(classElem, isNativeAnnotation); | |
| 436 } | |
| 431 if (jsPeer != null) { | 437 if (jsPeer != null) { |
| 432 jsPeerName = | 438 jsPeerName = |
| 433 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); | 439 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); |
| 440 if (jsPeerName.contains(',')) { | |
| 441 jsPeerName = jsPeerName.split(',')[0]; | |
| 442 } | |
| 434 } | 443 } |
| 435 | 444 |
| 436 var body = _finishClassMembers(classElem, classExpr, ctors, fields, | 445 var body = _finishClassMembers(classElem, classExpr, ctors, fields, |
| 437 staticFields, methods, node.metadata, jsPeerName); | 446 staticFields, methods, node.metadata, jsPeerName); |
| 438 | 447 |
| 439 var result = _finishClassDef(type, body); | 448 var result = _finishClassDef(type, body); |
| 440 | 449 |
| 441 if (jsPeerName != null) { | 450 if (jsPeerName != null) { |
| 442 // This class isn't allowed to be lazy, because we need to set up | 451 // This class isn't allowed to be lazy, because we need to set up |
| 443 // the native JS type eagerly at this point. | 452 // the native JS type eagerly at this point. |
| (...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1267 | 1276 |
| 1268 JS.Expression _defaultParamValue(FormalParameter param) { | 1277 JS.Expression _defaultParamValue(FormalParameter param) { |
| 1269 if (param is DefaultFormalParameter && param.defaultValue != null) { | 1278 if (param is DefaultFormalParameter && param.defaultValue != null) { |
| 1270 return _visit(param.defaultValue); | 1279 return _visit(param.defaultValue); |
| 1271 } else { | 1280 } else { |
| 1272 return new JS.LiteralNull(); | 1281 return new JS.LiteralNull(); |
| 1273 } | 1282 } |
| 1274 } | 1283 } |
| 1275 | 1284 |
| 1276 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { | 1285 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { |
| 1277 if (node.isAbstract || _externalOrNative(node)) { | 1286 if (node.isAbstract) { |
| 1278 return null; | 1287 return null; |
| 1279 } | 1288 } |
| 1280 | 1289 |
| 1281 var params = _visit(node.parameters) as List<JS.Parameter>; | 1290 var params = _visit(node.parameters) as List<JS.Parameter>; |
| 1282 if (params == null) params = <JS.Parameter>[]; | 1291 if (params == null) params = <JS.Parameter>[]; |
| 1283 | 1292 |
| 1284 JS.Fun fn = _emitFunctionBody(params, node.body); | 1293 JS.Fun fn; |
| 1294 if (_externalOrNative(node)) { | |
| 1295 if (node.isStatic) { | |
|
Jennifer Messerly
2016/02/10 00:20:30
Perhaps factor this out into _emitNativeFunctionBo
vsm
2016/02/11 22:36:06
Done.
| |
| 1296 // TODO(vsm): Do we need to handle this case? | |
| 1297 return null; | |
| 1298 } | |
| 1299 | |
| 1300 String name = node.name.name; | |
| 1301 var annotation = findAnnotation(node.element, isJsName); | |
| 1302 if (annotation != null) { | |
| 1303 name = getConstantField(annotation, 'name', types.stringType) | |
| 1304 ?.toStringValue(); | |
| 1305 } | |
| 1306 if (node.isGetter) { | |
| 1307 fn = new JS.Fun(params, js.statement('{ return this.#; }', [name])); | |
| 1308 } else if (node.isSetter) { | |
| 1309 fn = new JS.Fun( | |
| 1310 params, js.statement('{ this.# = #; }', [name, params.last])); | |
| 1311 } else { | |
| 1312 fn = new JS.Fun( | |
| 1313 params, js.statement('{ return this.#(#); }', [name, params])); | |
| 1314 } | |
| 1315 } else { | |
| 1316 fn = _emitFunctionBody(params, node.body); | |
| 1317 } | |
| 1318 | |
| 1285 if (node.operatorKeyword != null && | 1319 if (node.operatorKeyword != null && |
| 1286 node.name.name == '[]=' && | 1320 node.name.name == '[]=' && |
| 1287 params.isNotEmpty) { | 1321 params.isNotEmpty) { |
| 1288 // []= methods need to return the value. We could also address this at | 1322 // []= methods need to return the value. We could also address this at |
| 1289 // call sites, but it's cleaner to instead transform the operator method. | 1323 // call sites, but it's cleaner to instead transform the operator method. |
| 1290 var returnValue = new JS.Return(params.last); | 1324 var returnValue = new JS.Return(params.last); |
| 1291 var body = fn.body; | 1325 var body = fn.body; |
| 1292 if (JS.Return.foundIn(fn)) { | 1326 if (JS.Return.foundIn(fn)) { |
| 1293 // If a return is inside body, transform `(params) { body }` to | 1327 // If a return is inside body, transform `(params) { body }` to |
| 1294 // `(params) { (() => { body })(); return value; }`. | 1328 // `(params) { (() => { body })(); return value; }`. |
| (...skipping 2253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3548 } else if (type is InterfaceType && type.element == expectedType.element) { | 3582 } else if (type is InterfaceType && type.element == expectedType.element) { |
| 3549 return type.typeArguments[0]; | 3583 return type.typeArguments[0]; |
| 3550 } else { | 3584 } else { |
| 3551 // TODO(leafp): The above only handles the case where the return type | 3585 // TODO(leafp): The above only handles the case where the return type |
| 3552 // is exactly Future/Stream/Iterable. Handle the subtype case. | 3586 // is exactly Future/Stream/Iterable. Handle the subtype case. |
| 3553 return DynamicTypeImpl.instance; | 3587 return DynamicTypeImpl.instance; |
| 3554 } | 3588 } |
| 3555 } | 3589 } |
| 3556 } | 3590 } |
| 3557 | 3591 |
| 3558 class JSGenerator extends CodeGenerator { | 3592 class _ExtensionFinder extends GeneralizingElementVisitor { |
| 3559 final _extensionTypes = new HashSet<ClassElement>(); | 3593 final AnalysisContext _context; |
| 3594 final HashSet<ClassElement> _extensionTypes; | |
| 3560 final TypeProvider _types; | 3595 final TypeProvider _types; |
| 3561 JSGenerator(AbstractCompiler compiler) | 3596 |
| 3562 : _types = compiler.context.typeProvider, | 3597 _ExtensionFinder(this._context, this._extensionTypes, this._types); |
| 3563 super(compiler) { | 3598 |
| 3564 // TODO(jacobr): determine the the set of types with extension methods from | 3599 visitClassElement(ClassElement element) { |
| 3565 // the annotations rather than hard coding the list once the analyzer | 3600 if (findAnnotation(element, isJsPeerInterface) != null || |
| 3566 // supports summaries. | 3601 findAnnotation(element, isNativeAnnotation) != null) { |
| 3567 var context = compiler.context; | 3602 _addExtensionType(element.type); |
| 3568 var src = context.sourceFactory.forUri('dart:_interceptors'); | |
| 3569 var interceptors = context.computeLibraryElement(src); | |
| 3570 for (var t in ['JSArray', 'JSString', 'JSNumber', 'JSBool']) { | |
| 3571 _addExtensionType(interceptors.getType(t).type); | |
| 3572 } | 3603 } |
| 3573 // TODO(jmesserly): manually add `int` and `double` | |
| 3574 // Unfortunately our current analyzer rejects "implements int". | |
| 3575 // Fix was landed, so we can remove this hack once we're updated: | |
| 3576 // https://github.com/dart-lang/sdk/commit/d7cd11f86a02f55269fc8d9843e7758eb eeb81c8 | |
| 3577 _addExtensionType(_types.intType); | |
| 3578 _addExtensionType(_types.doubleType); | |
| 3579 } | 3604 } |
| 3580 | 3605 |
| 3581 void _addExtensionType(InterfaceType t) { | 3606 void _addExtensionType(InterfaceType t) { |
| 3582 if (t.isObject || !_extensionTypes.add(t.element)) return; | 3607 if (t.isObject || !_extensionTypes.add(t.element)) return; |
| 3583 t = fillDynamicTypeArgs(t, _types) as InterfaceType; | 3608 t = fillDynamicTypeArgs(t, _types) as InterfaceType; |
| 3584 t.interfaces.forEach(_addExtensionType); | 3609 t.interfaces.forEach(_addExtensionType); |
| 3585 t.mixins.forEach(_addExtensionType); | 3610 t.mixins.forEach(_addExtensionType); |
| 3586 _addExtensionType(t.superclass); | 3611 _addExtensionType(t.superclass); |
| 3587 } | 3612 } |
| 3588 | 3613 |
| 3614 void _addExtensionTypes(String libraryUri) { | |
| 3615 var sourceFactory = _context.sourceFactory.forUri(libraryUri); | |
| 3616 var library = _context.computeLibraryElement(sourceFactory); | |
| 3617 visitLibraryElement(library); | |
| 3618 } | |
| 3619 } | |
| 3620 | |
| 3621 class JSGenerator extends CodeGenerator { | |
| 3622 final _extensionTypes = new HashSet<ClassElement>(); | |
| 3623 final TypeProvider _types; | |
| 3624 | |
| 3625 JSGenerator(AbstractCompiler compiler) | |
| 3626 : _types = compiler.context.typeProvider, | |
| 3627 super(compiler) { | |
| 3628 // TODO(vsm): Eventually, we want to make this extensible - i.e., find | |
| 3629 // annotations in user code as well. It would need to be summarized in | |
| 3630 // the element model - not searched this way on every compile. | |
| 3631 var finder = new _ExtensionFinder(context, _extensionTypes, _types); | |
| 3632 finder._addExtensionTypes('dart:_interceptors'); | |
| 3633 finder._addExtensionTypes('dart:_native_typed_data'); | |
| 3634 | |
| 3635 // TODO(vsm): If we're analyzing against the main SDK, those | |
| 3636 // types are not explicitly annotated. | |
| 3637 finder._addExtensionType(_types.intType); | |
| 3638 finder._addExtensionType(_types.doubleType); | |
| 3639 finder._addExtensionType(_types.boolType); | |
| 3640 finder._addExtensionType(_types.stringType); | |
| 3641 } | |
| 3642 | |
| 3589 String generateLibrary(LibraryUnit unit) { | 3643 String generateLibrary(LibraryUnit unit) { |
| 3590 // Clone the AST first, so we can mutate it. | 3644 // Clone the AST first, so we can mutate it. |
| 3591 unit = unit.clone(); | 3645 unit = unit.clone(); |
| 3592 var library = unit.library.element.library; | 3646 var library = unit.library.element.library; |
| 3593 var fields = findFieldsNeedingStorage(unit, _extensionTypes); | 3647 var fields = findFieldsNeedingStorage(unit, _extensionTypes); |
| 3594 var rules = new StrongTypeSystemImpl(); | 3648 var rules = new StrongTypeSystemImpl(); |
| 3595 var codegen = | 3649 var codegen = |
| 3596 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields); | 3650 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields); |
| 3597 var module = codegen.emitLibrary(unit); | 3651 var module = codegen.emitLibrary(unit); |
| 3598 var out = compiler.getOutputPath(library.source.uri); | 3652 var out = compiler.getOutputPath(library.source.uri); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 3624 | 3678 |
| 3625 /// A special kind of element created by the compiler, signifying a temporary | 3679 /// A special kind of element created by the compiler, signifying a temporary |
| 3626 /// variable. These objects use instance equality, and should be shared | 3680 /// variable. These objects use instance equality, and should be shared |
| 3627 /// everywhere in the tree where they are treated as the same variable. | 3681 /// everywhere in the tree where they are treated as the same variable. |
| 3628 class TemporaryVariableElement extends LocalVariableElementImpl { | 3682 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3629 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3683 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3630 | 3684 |
| 3631 int get hashCode => identityHashCode(this); | 3685 int get hashCode => identityHashCode(this); |
| 3632 bool operator ==(Object other) => identical(this, other); | 3686 bool operator ==(Object other) => identical(this, other); |
| 3633 } | 3687 } |
| OLD | NEW |