| 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/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
| 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/constant.dart'; | 10 import 'package:analyzer/src/generated/constant.dart'; |
| 11 import 'package:analyzer/src/generated/element.dart'; | 11 import 'package:analyzer/src/generated/element.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 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/dart/ast/token.dart' | 14 import 'package:analyzer/src/dart/ast/token.dart' |
| 15 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
| 16 import 'package:analyzer/src/generated/type_system.dart' | 16 import 'package:analyzer/src/generated/type_system.dart' |
| 17 show StrongTypeSystemImpl; | 17 show StrongTypeSystemImpl; |
| 18 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; | |
| 19 | 18 |
| 20 import 'ast_builder.dart' show AstBuilder; | 19 import 'ast_builder.dart' show AstBuilder; |
| 21 import 'reify_coercions.dart' show CoercionReifier, Tuple2; | 20 import 'reify_coercions.dart' show CoercionReifier, Tuple2; |
| 22 | 21 |
| 23 import '../js/js_ast.dart' as JS; | 22 import '../js/js_ast.dart' as JS; |
| 24 import '../js/js_ast.dart' show js; | 23 import '../js/js_ast.dart' show js; |
| 25 | 24 |
| 26 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 25 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
| 27 import '../compiler.dart' | 26 import '../compiler.dart' |
| 28 show AbstractCompiler, corelibOrder, getCorelibModuleName; | 27 show AbstractCompiler, corelibOrder, getCorelibModuleName; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 | 98 |
| 100 final TypeProvider _types; | 99 final TypeProvider _types; |
| 101 | 100 |
| 102 ConstFieldVisitor _constField; | 101 ConstFieldVisitor _constField; |
| 103 | 102 |
| 104 ModuleItemLoadOrder _loader; | 103 ModuleItemLoadOrder _loader; |
| 105 | 104 |
| 106 /// _interceptors.JSArray<E>, used for List literals. | 105 /// _interceptors.JSArray<E>, used for List literals. |
| 107 ClassElement _jsArray; | 106 ClassElement _jsArray; |
| 108 | 107 |
| 108 /// The current function body being compiled. |
| 109 FunctionBody _currentFunction; |
| 110 |
| 109 /// The default value of the module object. See [visitLibraryDirective]. | 111 /// The default value of the module object. See [visitLibraryDirective]. |
| 110 String _jsModuleValue; | 112 String _jsModuleValue; |
| 111 | 113 |
| 112 bool _isDartRuntime; | 114 bool _isDartRuntime; |
| 113 | 115 |
| 114 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, | 116 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, |
| 115 this._extensionTypes, this._fieldsNeedingStorage) | 117 this._extensionTypes, this._fieldsNeedingStorage) |
| 116 : compiler = compiler, | 118 : compiler = compiler, |
| 117 options = compiler.options.codegenOptions, | 119 options = compiler.options.codegenOptions, |
| 118 _types = compiler.context.typeProvider { | 120 _types = compiler.context.typeProvider { |
| 119 _loader = new ModuleItemLoadOrder(_emitModuleItem); | 121 _loader = new ModuleItemLoadOrder(_emitModuleItem); |
| 120 | 122 |
| 121 var context = compiler.context; | 123 var context = compiler.context; |
| 122 var src = context.sourceFactory.forUri('dart:_interceptors'); | 124 var src = context.sourceFactory.forUri('dart:_interceptors'); |
| 123 var interceptors = context.computeLibraryElement(src); | 125 var interceptors = context.computeLibraryElement(src); |
| 124 _jsArray = interceptors.getType('JSArray'); | 126 _jsArray = interceptors.getType('JSArray'); |
| 125 _isDartRuntime = currentLibrary.source.uri.toString() == 'dart:_runtime'; | 127 _isDartRuntime = currentLibrary.source.uri.toString() == 'dart:_runtime'; |
| 126 } | 128 } |
| 127 | 129 |
| 128 TypeProvider get types => _types; | 130 TypeProvider get types => _types; |
| 129 | 131 |
| 130 JS.Program emitLibrary(LibraryUnit library) { | 132 JS.Program emitLibrary(LibraryUnit library) { |
| 131 // Modify the AST to make coercions explicit. | 133 // Modify the AST to make coercions explicit. |
| 132 new CoercionReifier(library, rules).reify(); | 134 new CoercionReifier(library, rules).reify(); |
| 133 | 135 |
| 134 // Build the public namespace for this library. This allows us to do | |
| 135 // constant time lookups (contrast with `Element.getChild(name)`). | |
| 136 if (currentLibrary.publicNamespace == null) { | |
| 137 (currentLibrary as LibraryElementImpl).publicNamespace = | |
| 138 new PublicNamespaceBuilder().build(currentLibrary); | |
| 139 } | |
| 140 | |
| 141 library.library.directives.forEach(_visit); | 136 library.library.directives.forEach(_visit); |
| 142 | 137 |
| 143 var units = library.partsThenLibrary; | 138 var units = library.partsThenLibrary; |
| 144 | 139 |
| 145 // Rather than directly visit declarations, we instead use [_loader] to | 140 // Rather than directly visit declarations, we instead use [_loader] to |
| 146 // visit them. It has the ability to sort elements on demand, so | 141 // visit them. It has the ability to sort elements on demand, so |
| 147 // dependencies between top level items are handled with a minimal | 142 // dependencies between top level items are handled with a minimal |
| 148 // reordering of the user's input code. The loader will call back into | 143 // reordering of the user's input code. The loader will call back into |
| 149 // this visitor via [_emitModuleItem] when it's ready to visit the item | 144 // this visitor via [_emitModuleItem] when it's ready to visit the item |
| 150 // for real. | 145 // for real. |
| (...skipping 952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 // Mark the parameter as no-rename. | 1098 // Mark the parameter as no-rename. |
| 1104 body = js.statement('''{ | 1099 body = js.statement('''{ |
| 1105 // Get the class name for this instance. | 1100 // Get the class name for this instance. |
| 1106 let name = this.constructor.name; | 1101 let name = this.constructor.name; |
| 1107 // Call the default constructor. | 1102 // Call the default constructor. |
| 1108 let result = void 0; | 1103 let result = void 0; |
| 1109 if (name in this) result = this[name](...arguments); | 1104 if (name in this) result = this[name](...arguments); |
| 1110 return result === void 0 ? this : result; | 1105 return result === void 0 ? this : result; |
| 1111 }''') as JS.Block; | 1106 }''') as JS.Block; |
| 1112 } else { | 1107 } else { |
| 1108 var savedFunction = _currentFunction; |
| 1109 _currentFunction = node.body; |
| 1113 body = _emitConstructorBody(node, fields); | 1110 body = _emitConstructorBody(node, fields); |
| 1111 _currentFunction = savedFunction; |
| 1114 } | 1112 } |
| 1115 | 1113 |
| 1116 // We generate constructors as initializer methods in the class; | 1114 // We generate constructors as initializer methods in the class; |
| 1117 // this allows use of `super` for instance methods/properties. | 1115 // this allows use of `super` for instance methods/properties. |
| 1118 // It also avoids V8 restrictions on `super` in default constructors. | 1116 // It also avoids V8 restrictions on `super` in default constructors. |
| 1119 return annotate( | 1117 return annotate( |
| 1120 new JS.Method(name, new JS.Fun(params, body, returnType: returnType)), | 1118 new JS.Method(name, new JS.Fun(params, body, returnType: returnType)), |
| 1121 node, | 1119 node, |
| 1122 node.element); | 1120 node.element); |
| 1123 } | 1121 } |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 /// Contrast with [_emitFunction]. | 1581 /// Contrast with [_emitFunction]. |
| 1584 @override | 1582 @override |
| 1585 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1583 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 1586 assert(node.parent is! FunctionDeclaration && | 1584 assert(node.parent is! FunctionDeclaration && |
| 1587 node.parent is! MethodDeclaration); | 1585 node.parent is! MethodDeclaration); |
| 1588 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 1586 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
| 1589 topLevel: _executesAtTopLevel(node)); | 1587 topLevel: _executesAtTopLevel(node)); |
| 1590 } | 1588 } |
| 1591 | 1589 |
| 1592 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 1590 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
| 1593 List<JS.Parameter> params; | 1591 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); |
| 1592 var body = f.body; |
| 1594 | 1593 |
| 1595 var body = node.body; | 1594 // Simplify `=> { return e; }` to `=> e` |
| 1596 var type = node.element.type; | 1595 if (body is JS.Block) { |
| 1597 | 1596 JS.Block block = body; |
| 1598 JS.Node jsBody; | 1597 if (block.statements.length == 1) { |
| 1599 if (body.isGenerator || body.isAsynchronous) { | 1598 JS.Statement s = block.statements[0]; |
| 1600 params = visitFormalParameterList(node.parameters, destructure: false); | 1599 if (s is JS.Return) body = s.value; |
| 1601 jsBody = _emitGeneratorFunctionBody(node.element, node.parameters, body); | |
| 1602 } else { | |
| 1603 params = visitFormalParameterList(node.parameters); | |
| 1604 | |
| 1605 // Chrome Canary does not accept default values with destructuring in | |
| 1606 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them | |
| 1607 // with regular functions (e.g. `function({a} = {}) { return 1 }`). | |
| 1608 // Note that Firefox accepts both syntaxes just fine. | |
| 1609 // TODO(ochafik): Simplify this code when Chrome Canary catches up. | |
| 1610 bool destructureNamed = params.any((p) => | |
| 1611 p is JS.DestructuredVariable && | |
| 1612 p.structure is JS.ObjectBindingPattern); | |
| 1613 | |
| 1614 if (body is ExpressionFunctionBody && !destructureNamed) { | |
| 1615 // An arrow function can use the expression directly. | |
| 1616 jsBody = _visit(body.expression); | |
| 1617 } else { | |
| 1618 jsBody = _visit(body); | |
| 1619 } | 1600 } |
| 1620 } | 1601 } |
| 1621 | 1602 |
| 1622 var fn = new JS.ArrowFun(params, jsBody, | 1603 // Convert `function(...) { ... }` to `(...) => ...` |
| 1623 typeParams: _emitTypeFormals(type.typeFormals), | 1604 // This is for readability, but it also ensures correct `this` binding. |
| 1624 returnType: emitTypeRef(type.returnType)); | 1605 return annotate( |
| 1625 return annotate(fn, node); | 1606 new JS.ArrowFun(f.params, body, |
| 1607 typeParams: f.typeParams, returnType: f.returnType), |
| 1608 node); |
| 1626 } | 1609 } |
| 1627 | 1610 |
| 1628 /// Emits a non-arrow FunctionExpression node. | 1611 /// Emits a non-arrow FunctionExpression node. |
| 1629 /// | 1612 /// |
| 1630 /// This should be used for all places in Dart's AST where FunctionExpression | 1613 /// This should be used for all places in Dart's AST where FunctionExpression |
| 1631 /// appears but the function is not actually in an Expression context, such | 1614 /// appears but the function is not actually in an Expression context, such |
| 1632 /// as methods, properties, and top-level functions. | 1615 /// as methods, properties, and top-level functions. |
| 1633 /// | 1616 /// |
| 1634 /// Contrast with [visitFunctionExpression]. | 1617 /// Contrast with [visitFunctionExpression]. |
| 1635 JS.Fun _emitFunction(FunctionExpression node) { | 1618 JS.Fun _emitFunction(FunctionExpression node) { |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2067 // or when one of the expressions is stateless, which seems common. | 2050 // or when one of the expressions is stateless, which seems common. |
| 2068 var vars = <String, JS.Expression>{}; | 2051 var vars = <String, JS.Expression>{}; |
| 2069 var left = _bindValue(vars, 'l', node.target); | 2052 var left = _bindValue(vars, 'l', node.target); |
| 2070 var body = js.call('# == null ? null : #', | 2053 var body = js.call('# == null ? null : #', |
| 2071 [_visit(left), _emitSet(_stripNullAwareOp(node, left), right)]); | 2054 [_visit(left), _emitSet(_stripNullAwareOp(node, left), right)]); |
| 2072 return new JS.MetaLet(vars, [body]); | 2055 return new JS.MetaLet(vars, [body]); |
| 2073 } | 2056 } |
| 2074 | 2057 |
| 2075 @override | 2058 @override |
| 2076 JS.Block visitExpressionFunctionBody(ExpressionFunctionBody node) { | 2059 JS.Block visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 2060 var savedFunction = _currentFunction; |
| 2061 _currentFunction = node; |
| 2077 var initArgs = _emitArgumentInitializers(node.parent); | 2062 var initArgs = _emitArgumentInitializers(node.parent); |
| 2078 var ret = new JS.Return(_visit(node.expression)); | 2063 var ret = new JS.Return(_visit(node.expression)); |
| 2064 _currentFunction = savedFunction; |
| 2079 return new JS.Block(initArgs != null ? [initArgs, ret] : [ret]); | 2065 return new JS.Block(initArgs != null ? [initArgs, ret] : [ret]); |
| 2080 } | 2066 } |
| 2081 | 2067 |
| 2082 @override | 2068 @override |
| 2083 JS.Block visitEmptyFunctionBody(EmptyFunctionBody node) => new JS.Block([]); | 2069 JS.Block visitEmptyFunctionBody(EmptyFunctionBody node) => new JS.Block([]); |
| 2084 | 2070 |
| 2085 @override | 2071 @override |
| 2086 JS.Block visitBlockFunctionBody(BlockFunctionBody node) { | 2072 JS.Block visitBlockFunctionBody(BlockFunctionBody node) { |
| 2073 var savedFunction = _currentFunction; |
| 2074 _currentFunction = node; |
| 2087 var initArgs = _emitArgumentInitializers(node.parent); | 2075 var initArgs = _emitArgumentInitializers(node.parent); |
| 2088 var stmts = _visitList(node.block.statements) as List<JS.Statement>; | 2076 var stmts = _visitList(node.block.statements) as List<JS.Statement>; |
| 2089 if (initArgs != null) stmts.insert(0, initArgs); | 2077 if (initArgs != null) stmts.insert(0, initArgs); |
| 2078 _currentFunction = savedFunction; |
| 2090 return new JS.Block(stmts); | 2079 return new JS.Block(stmts); |
| 2091 } | 2080 } |
| 2092 | 2081 |
| 2093 @override | 2082 @override |
| 2094 JS.Block visitBlock(Block node) => | 2083 JS.Block visitBlock(Block node) => |
| 2095 new JS.Block(_visitList(node.statements) as List<JS.Statement>, | 2084 new JS.Block(_visitList(node.statements) as List<JS.Statement>, |
| 2096 isScope: true); | 2085 isScope: true); |
| 2097 | 2086 |
| 2098 @override | 2087 @override |
| 2099 visitMethodInvocation(MethodInvocation node) { | 2088 visitMethodInvocation(MethodInvocation node) { |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2814 /// | 2803 /// |
| 2815 /// If the expression does not end up using `x` more than once, or if those | 2804 /// If the expression does not end up using `x` more than once, or if those |
| 2816 /// expressions can be treated as stateless (e.g. they are non-mutated | 2805 /// expressions can be treated as stateless (e.g. they are non-mutated |
| 2817 /// variables), then the resulting code will be simplified automatically. | 2806 /// variables), then the resulting code will be simplified automatically. |
| 2818 /// | 2807 /// |
| 2819 /// [scope] will be mutated to contain the new temporary's initialization. | 2808 /// [scope] will be mutated to contain the new temporary's initialization. |
| 2820 Expression _bindValue( | 2809 Expression _bindValue( |
| 2821 Map<String, JS.Expression> scope, String name, Expression expr, | 2810 Map<String, JS.Expression> scope, String name, Expression expr, |
| 2822 {Expression context}) { | 2811 {Expression context}) { |
| 2823 // No need to do anything for stateless expressions. | 2812 // No need to do anything for stateless expressions. |
| 2824 if (isStateless(expr, context)) return expr; | 2813 if (isStateless(_currentFunction, expr, context)) return expr; |
| 2825 | 2814 |
| 2826 var t = _createTemporary('#$name', getStaticType(expr)); | 2815 var t = _createTemporary('#$name', getStaticType(expr)); |
| 2827 scope[name] = _visit(expr); | 2816 scope[name] = _visit(expr); |
| 2828 return t; | 2817 return t; |
| 2829 } | 2818 } |
| 2830 | 2819 |
| 2831 /// Desugars postfix increment. | 2820 /// Desugars postfix increment. |
| 2832 /// | 2821 /// |
| 2833 /// In the general case [expr] can be one of [IndexExpression], | 2822 /// In the general case [expr] can be one of [IndexExpression], |
| 2834 /// [PrefixExpression] or [PropertyAccess] and we need to | 2823 /// [PrefixExpression] or [PropertyAccess] and we need to |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3400 return _emitConst(emitSymbol); | 3389 return _emitConst(emitSymbol); |
| 3401 } | 3390 } |
| 3402 | 3391 |
| 3403 @override | 3392 @override |
| 3404 visitListLiteral(ListLiteral node) { | 3393 visitListLiteral(ListLiteral node) { |
| 3405 JS.Expression emitList() { | 3394 JS.Expression emitList() { |
| 3406 JS.Expression list = new JS.ArrayInitializer( | 3395 JS.Expression list = new JS.ArrayInitializer( |
| 3407 _visitList(node.elements) as List<JS.Expression>); | 3396 _visitList(node.elements) as List<JS.Expression>); |
| 3408 ParameterizedType type = node.staticType; | 3397 ParameterizedType type = node.staticType; |
| 3409 var elementType = type.typeArguments.single; | 3398 var elementType = type.typeArguments.single; |
| 3410 if (elementType != types.dynamicType) { | 3399 // TODO(jmesserly): analyzer will usually infer `List<Object>` because |
| 3400 // that is the least upper bound of the element types. So we rarely |
| 3401 // generate a plain `List<dynamic>` anymore. |
| 3402 if (!elementType.isDynamic) { |
| 3411 // dart.list helper internally depends on _interceptors.JSArray. | 3403 // dart.list helper internally depends on _interceptors.JSArray. |
| 3412 _loader.declareBeforeUse(_jsArray); | 3404 _loader.declareBeforeUse(_jsArray); |
| 3413 list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]); | 3405 list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]); |
| 3414 } | 3406 } |
| 3415 return list; | 3407 return list; |
| 3416 } | 3408 } |
| 3417 if (node.constKeyword != null) return _emitConst(emitList); | 3409 if (node.constKeyword != null) return _emitConst(emitList); |
| 3418 return emitList(); | 3410 return emitList(); |
| 3419 } | 3411 } |
| 3420 | 3412 |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3851 | 3843 |
| 3852 /// A special kind of element created by the compiler, signifying a temporary | 3844 /// A special kind of element created by the compiler, signifying a temporary |
| 3853 /// variable. These objects use instance equality, and should be shared | 3845 /// variable. These objects use instance equality, and should be shared |
| 3854 /// everywhere in the tree where they are treated as the same variable. | 3846 /// everywhere in the tree where they are treated as the same variable. |
| 3855 class TemporaryVariableElement extends LocalVariableElementImpl { | 3847 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3856 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3848 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3857 | 3849 |
| 3858 int get hashCode => identityHashCode(this); | 3850 int get hashCode => identityHashCode(this); |
| 3859 bool operator ==(Object other) => identical(this, other); | 3851 bool operator ==(Object other) => identical(this, other); |
| 3860 } | 3852 } |
| OLD | NEW |