| 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 js_codegen; | 5 library 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/dart/ast/token.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 11 import 'package:analyzer/src/generated/constant.dart'; | 12 import 'package:analyzer/src/generated/constant.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; | 13 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 14 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 14 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 15 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 15 import 'package:analyzer/src/generated/scanner.dart' | 16 import 'package:analyzer/src/dart/ast/token.dart' |
| 16 show StringToken, Token, TokenType; | 17 show StringToken, Token, TokenType; |
| 17 import 'package:analyzer/src/generated/type_system.dart' | 18 import 'package:analyzer/src/generated/type_system.dart' |
| 18 show StrongTypeSystemImpl; | 19 show StrongTypeSystemImpl; |
| 19 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; | 20 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; |
| 20 | 21 |
| 21 import 'ast_builder.dart' show AstBuilder; | 22 import 'ast_builder.dart' show AstBuilder; |
| 22 import 'reify_coercions.dart' show CoercionReifier, Tuple2; | 23 import 'reify_coercions.dart' show CoercionReifier, Tuple2; |
| 23 | 24 |
| 24 // TODO(jmesserly): import from its own package | 25 // TODO(jmesserly): import from its own package |
| 25 import '../js/js_ast.dart' as JS; | 26 import '../js/js_ast.dart' as JS; |
| (...skipping 1295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1321 t is ParameterizedType && t.typeArguments.any(_hasUnsoundTypeParameter); | 1322 t is ParameterizedType && t.typeArguments.any(_hasUnsoundTypeParameter); |
| 1322 | 1323 |
| 1323 JS.Expression _defaultParamValue(FormalParameter param) { | 1324 JS.Expression _defaultParamValue(FormalParameter param) { |
| 1324 if (param is DefaultFormalParameter && param.defaultValue != null) { | 1325 if (param is DefaultFormalParameter && param.defaultValue != null) { |
| 1325 return _visit(param.defaultValue); | 1326 return _visit(param.defaultValue); |
| 1326 } else { | 1327 } else { |
| 1327 return new JS.LiteralNull(); | 1328 return new JS.LiteralNull(); |
| 1328 } | 1329 } |
| 1329 } | 1330 } |
| 1330 | 1331 |
| 1331 JS.Fun _emitNativeFunctionBody( | 1332 JS.Fun _emitNativeFunctionBody(List<JS.Parameter> params, |
| 1332 List<JS.Parameter> params, List<JS.Expression> paramRefs, | 1333 List<JS.Expression> paramRefs, MethodDeclaration node) { |
| 1333 MethodDeclaration node) { | |
| 1334 if (node.isStatic) { | 1334 if (node.isStatic) { |
| 1335 // TODO(vsm): Do we need to handle this case? | 1335 // TODO(vsm): Do we need to handle this case? |
| 1336 return null; | 1336 return null; |
| 1337 } | 1337 } |
| 1338 | 1338 |
| 1339 String name = node.name.name; | 1339 String name = node.name.name; |
| 1340 var annotation = findAnnotation(node.element, isJsName); | 1340 var annotation = findAnnotation(node.element, isJsName); |
| 1341 if (annotation != null) { | 1341 if (annotation != null) { |
| 1342 name = getConstantField(annotation, 'name', types.stringType) | 1342 name = getConstantField(annotation, 'name', types.stringType) |
| 1343 ?.toStringValue(); | 1343 ?.toStringValue(); |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1558 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them | 1558 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them |
| 1559 // with regular functions (e.g. `function({a} = {}) { return 1 }`). | 1559 // with regular functions (e.g. `function({a} = {}) { return 1 }`). |
| 1560 // Note that Firefox accepts both syntaxes just fine. | 1560 // Note that Firefox accepts both syntaxes just fine. |
| 1561 // TODO(ochafik): Simplify this code when Chrome Canary catches up. | 1561 // TODO(ochafik): Simplify this code when Chrome Canary catches up. |
| 1562 var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam); | 1562 var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam); |
| 1563 | 1563 |
| 1564 JS.Node jsBody; | 1564 JS.Node jsBody; |
| 1565 var body = node.body; | 1565 var body = node.body; |
| 1566 if (body.isGenerator || body.isAsynchronous) { | 1566 if (body.isGenerator || body.isAsynchronous) { |
| 1567 var paramRefs = _emitParameterReferences(node.parameters); | 1567 var paramRefs = _emitParameterReferences(node.parameters); |
| 1568 jsBody = _emitGeneratorFunctionBody( | 1568 jsBody = |
| 1569 params, paramRefs, body, returnType); | 1569 _emitGeneratorFunctionBody(params, paramRefs, body, returnType); |
| 1570 } else if (body is ExpressionFunctionBody) { | 1570 } else if (body is ExpressionFunctionBody) { |
| 1571 jsBody = _visit(body.expression); | 1571 jsBody = _visit(body.expression); |
| 1572 } else { | 1572 } else { |
| 1573 jsBody = _visit(body); | 1573 jsBody = _visit(body); |
| 1574 } | 1574 } |
| 1575 if (jsBody is JS.Expression && !canUseArrowFun) { | 1575 if (jsBody is JS.Expression && !canUseArrowFun) { |
| 1576 jsBody = js.statement("{ return #; }", [jsBody]); | 1576 jsBody = js.statement("{ return #; }", [jsBody]); |
| 1577 } | 1577 } |
| 1578 var clos = canUseArrowFun | 1578 var clos = canUseArrowFun |
| 1579 ? new JS.ArrowFun(params, jsBody, | 1579 ? new JS.ArrowFun(params, jsBody, |
| 1580 typeParams: typeParams, returnType: returnType) | 1580 typeParams: typeParams, returnType: returnType) |
| 1581 : new JS.Fun(params, jsBody, | 1581 : new JS.Fun(params, jsBody, |
| 1582 typeParams: typeParams, returnType: returnType); | 1582 typeParams: typeParams, returnType: returnType); |
| 1583 if (!inStmt) { | 1583 if (!inStmt) { |
| 1584 var type = getStaticType(node); | 1584 var type = getStaticType(node); |
| 1585 return _emitFunctionTagged(clos, type, | 1585 return _emitFunctionTagged(clos, type, |
| 1586 topLevel: _executesAtTopLevel(node)); | 1586 topLevel: _executesAtTopLevel(node)); |
| 1587 } | 1587 } |
| 1588 return clos; | 1588 return clos; |
| 1589 } | 1589 } |
| 1590 } | 1590 } |
| 1591 | 1591 |
| 1592 JS.Fun _emitFunctionBody(List<JS.Parameter> params, | 1592 JS.Fun _emitFunctionBody( |
| 1593 List<JS.Expression> paramRefs, FunctionBody body, | 1593 List<JS.Parameter> params, |
| 1594 List<JS.Identifier> typeParams, JS.TypeRef returnType) { | 1594 List<JS.Expression> paramRefs, |
| 1595 FunctionBody body, |
| 1596 List<JS.Identifier> typeParams, |
| 1597 JS.TypeRef returnType) { |
| 1595 // sync*, async, async* | 1598 // sync*, async, async* |
| 1596 if (body.isAsynchronous || body.isGenerator) { | 1599 if (body.isAsynchronous || body.isGenerator) { |
| 1597 // TODO(ochafik): Refine params: we don't need default values in the | 1600 // TODO(ochafik): Refine params: we don't need default values in the |
| 1598 // nested function, so we'd need to generate a custom, simpler params | 1601 // nested function, so we'd need to generate a custom, simpler params |
| 1599 // list here. | 1602 // list here. |
| 1600 return new JS.Fun( | 1603 return new JS.Fun( |
| 1601 params, | 1604 params, |
| 1602 js.statement('{ return #; }', [ | 1605 js.statement('{ return #; }', [ |
| 1603 _emitGeneratorFunctionBody(params, paramRefs, body, returnType) | 1606 _emitGeneratorFunctionBody(params, paramRefs, body, returnType) |
| 1604 ]), | 1607 ]), |
| 1605 returnType: returnType); | 1608 returnType: returnType); |
| 1606 } | 1609 } |
| 1607 // normal function (sync) | 1610 // normal function (sync) |
| 1608 return new JS.Fun(params, _visit(body), | 1611 return new JS.Fun(params, _visit(body), |
| 1609 typeParams: typeParams, returnType: returnType); | 1612 typeParams: typeParams, returnType: returnType); |
| 1610 } | 1613 } |
| 1611 | 1614 |
| 1612 JS.Expression _emitGeneratorFunctionBody( | 1615 JS.Expression _emitGeneratorFunctionBody(List<JS.Parameter> params, |
| 1613 List<JS.Parameter> params, List<JS.Expression> paramRefs, | 1616 List<JS.Expression> paramRefs, FunctionBody body, JS.TypeRef returnType) { |
| 1614 FunctionBody body, JS.TypeRef returnType) { | |
| 1615 var kind = body.isSynchronous ? 'sync' : 'async'; | 1617 var kind = body.isSynchronous ? 'sync' : 'async'; |
| 1616 if (body.isGenerator) kind += 'Star'; | 1618 if (body.isGenerator) kind += 'Star'; |
| 1617 | 1619 |
| 1618 // Transforms `sync*` `async` and `async*` function bodies | 1620 // Transforms `sync*` `async` and `async*` function bodies |
| 1619 // using ES6 generators. | 1621 // using ES6 generators. |
| 1620 // | 1622 // |
| 1621 // `sync*` wraps a generator in a Dart Iterable<T>: | 1623 // `sync*` wraps a generator in a Dart Iterable<T>: |
| 1622 // | 1624 // |
| 1623 // function name(<args>) { | 1625 // function name(<args>) { |
| 1624 // return dart.syncStar(function*(<args>) { | 1626 // return dart.syncStar(function*(<args>) { |
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2173 bool _isNamedParam(FormalParameter param) => | 2175 bool _isNamedParam(FormalParameter param) => |
| 2174 param.kind == ParameterKind.NAMED; | 2176 param.kind == ParameterKind.NAMED; |
| 2175 | 2177 |
| 2176 @override | 2178 @override |
| 2177 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => | 2179 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => |
| 2178 _emitFormalParameterList(node); | 2180 _emitFormalParameterList(node); |
| 2179 | 2181 |
| 2180 // TODO(ochafik): Decouple Parameter from Identifier. | 2182 // TODO(ochafik): Decouple Parameter from Identifier. |
| 2181 List<JS.Expression> _emitParameterReferences(FormalParameterList node) => | 2183 List<JS.Expression> _emitParameterReferences(FormalParameterList node) => |
| 2182 node == null | 2184 node == null |
| 2183 ? <JS.Expression>[] | 2185 ? <JS.Expression>[] |
| 2184 : _emitFormalParameterList(node, allowDestructuring: false) | 2186 : _emitFormalParameterList(node, allowDestructuring: false) |
| 2185 .map((JS.Parameter p) { | 2187 .map((JS.Parameter p) { |
| 2186 if (p is JS.RestParameter) return new JS.Spread(p.parameter); | 2188 if (p is JS.RestParameter) return new JS.Spread(p.parameter); |
| 2187 return p as JS.Identifier; | 2189 return p as JS.Identifier; |
| 2188 }) | 2190 }).toList(); |
| 2189 .toList(); | |
| 2190 | 2191 |
| 2191 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, | 2192 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, |
| 2192 {bool allowDestructuring: true}) { | 2193 {bool allowDestructuring: true}) { |
| 2193 var result = <JS.Parameter>[]; | 2194 var result = <JS.Parameter>[]; |
| 2194 | 2195 |
| 2195 var namedVars = <JS.DestructuredVariable>[]; | 2196 var namedVars = <JS.DestructuredVariable>[]; |
| 2196 var destructure = allowDestructuring && options.destructureNamedParams; | 2197 var destructure = allowDestructuring && options.destructureNamedParams; |
| 2197 var hasNamedArgsConflictingWithObjectProperties = false; | 2198 var hasNamedArgsConflictingWithObjectProperties = false; |
| 2198 var needsOpts = false; | 2199 var needsOpts = false; |
| 2199 | 2200 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2214 } | 2215 } |
| 2215 namedVars.add(new JS.DestructuredVariable( | 2216 namedVars.add(new JS.DestructuredVariable( |
| 2216 name: name, | 2217 name: name, |
| 2217 structure: structure, | 2218 structure: structure, |
| 2218 defaultValue: _defaultParamValue(param))); | 2219 defaultValue: _defaultParamValue(param))); |
| 2219 } else { | 2220 } else { |
| 2220 needsOpts = true; | 2221 needsOpts = true; |
| 2221 } | 2222 } |
| 2222 } else { | 2223 } else { |
| 2223 var jsParam = _visit(param); | 2224 var jsParam = _visit(param); |
| 2224 result.add( | 2225 result.add(param is DefaultFormalParameter && destructure |
| 2225 param is DefaultFormalParameter && destructure | 2226 ? new JS.DestructuredVariable( |
| 2226 ? new JS.DestructuredVariable( | 2227 name: jsParam, defaultValue: _defaultParamValue(param)) |
| 2227 name: jsParam, defaultValue: _defaultParamValue(param)) | 2228 : jsParam); |
| 2228 : jsParam); | |
| 2229 } | 2229 } |
| 2230 } | 2230 } |
| 2231 | 2231 |
| 2232 if (needsOpts) { | 2232 if (needsOpts) { |
| 2233 result.add(_namedArgTemp); | 2233 result.add(_namedArgTemp); |
| 2234 } else if (namedVars.isNotEmpty) { | 2234 } else if (namedVars.isNotEmpty) { |
| 2235 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so | 2235 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so |
| 2236 // in case there are conflicting names we create an object without | 2236 // in case there are conflicting names we create an object without |
| 2237 // any prototype. | 2237 // any prototype. |
| 2238 var defaultOpts = hasNamedArgsConflictingWithObjectProperties | 2238 var defaultOpts = hasNamedArgsConflictingWithObjectProperties |
| (...skipping 1540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3779 | 3779 |
| 3780 /// A special kind of element created by the compiler, signifying a temporary | 3780 /// A special kind of element created by the compiler, signifying a temporary |
| 3781 /// variable. These objects use instance equality, and should be shared | 3781 /// variable. These objects use instance equality, and should be shared |
| 3782 /// everywhere in the tree where they are treated as the same variable. | 3782 /// everywhere in the tree where they are treated as the same variable. |
| 3783 class TemporaryVariableElement extends LocalVariableElementImpl { | 3783 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3784 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3784 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3785 | 3785 |
| 3786 int get hashCode => identityHashCode(this); | 3786 int get hashCode => identityHashCode(this); |
| 3787 bool operator ==(Object other) => identical(this, other); | 3787 bool operator ==(Object other) => identical(this, other); |
| 3788 } | 3788 } |
| OLD | NEW |