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/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 // want to support construction of instances with generic types other | 459 // want to support construction of instances with generic types other |
460 // than dynamic. See issue #154 for Array and List<E> related bug. | 460 // than dynamic. See issue #154 for Array and List<E> related bug. |
461 var copyMembers = js.statement( | 461 var copyMembers = js.statement( |
462 'dart.registerExtension(dart.global.#, #);', | 462 'dart.registerExtension(dart.global.#, #);', |
463 [_propertyName(jsPeerName), classElem.name]); | 463 [_propertyName(jsPeerName), classElem.name]); |
464 return _statement([result, copyMembers]); | 464 return _statement([result, copyMembers]); |
465 } | 465 } |
466 return result; | 466 return result; |
467 } | 467 } |
468 | 468 |
469 Iterable<JS.Identifier> _emitTypeParams(TypeParameterizedElement e) sync* { | 469 Iterable<JS.TypeParameter> _emitTypeParams(TypeParameterizedElement e) sync* { |
470 if (!options.closure) return; | 470 if (!options.closure) return; |
471 for (var typeParam in e.typeParameters) { | 471 for (var typeParam in e.typeParameters) { |
472 yield new JS.Identifier(typeParam.name); | 472 yield new JS.TypeParameter( |
| 473 new JS.Identifier(typeParam.name), |
| 474 bound: emitTypeRef(typeParam.bound)); |
473 } | 475 } |
474 } | 476 } |
475 | 477 |
476 /// Emit field declarations for TypeScript & Closure's ES6_TYPED | 478 /// Emit field declarations for TypeScript & Closure's ES6_TYPED |
477 /// (e.g. `class Foo { i: string; }`) | 479 /// (e.g. `class Foo { i: string; }`) |
478 Iterable<JS.VariableDeclarationList> _emitFieldDeclarations( | 480 Iterable<JS.VariableDeclarationList> _emitFieldDeclarations( |
479 ClassElement classElem, | 481 ClassElement classElem, |
480 List<FieldDeclaration> fields, | 482 List<FieldDeclaration> fields, |
481 List<FieldDeclaration> staticFields) sync* { | 483 List<FieldDeclaration> staticFields) sync* { |
482 if (!options.closure) return; | 484 if (!options.closure) return; |
483 | 485 |
484 makeInitialization(VariableDeclaration decl) => | 486 makeInitialization(VariableDeclaration decl) => |
485 new JS.VariableInitialization( | 487 new JS.VariableInitialization( |
486 new JS.Identifier( | 488 // TODO(ochafik): use a refactored _emitMemberName instead. |
487 // TODO(ochafik): use a refactored _emitMemberName instead. | 489 new JS.Identifier(decl.name.name), |
488 decl.name.name, | 490 null, |
489 type: emitTypeRef(decl.element.type)), | 491 type: emitTypeRef(decl.element.type)); |
490 null); | |
491 | 492 |
492 for (var field in fields) { | 493 for (var field in fields) { |
493 yield new JS.VariableDeclarationList( | 494 yield new JS.VariableDeclarationList( |
494 null, field.fields.variables.map(makeInitialization).toList()); | 495 null, field.fields.variables.map(makeInitialization).toList()); |
495 } | 496 } |
496 for (var field in staticFields) { | 497 for (var field in staticFields) { |
497 yield new JS.VariableDeclarationList( | 498 yield new JS.VariableDeclarationList( |
498 'static', field.fields.variables.map(makeInitialization).toList()); | 499 'static', field.fields.variables.map(makeInitialization).toList()); |
499 } | 500 } |
500 } | 501 } |
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1204 fields[element as FieldElement] = _visitInitializer(fieldNode); | 1205 fields[element as FieldElement] = _visitInitializer(fieldNode); |
1205 } | 1206 } |
1206 } | 1207 } |
1207 } | 1208 } |
1208 | 1209 |
1209 // Initialize fields from `this.fieldName` parameters. | 1210 // Initialize fields from `this.fieldName` parameters. |
1210 if (ctor != null) { | 1211 if (ctor != null) { |
1211 for (var p in ctor.parameters.parameters) { | 1212 for (var p in ctor.parameters.parameters) { |
1212 var element = p.element; | 1213 var element = p.element; |
1213 if (element is FieldFormalParameterElement) { | 1214 if (element is FieldFormalParameterElement) { |
1214 fields[element.field] = _emitFormalParameter(p, allowType: false); | 1215 fields[element.field] = _visit(p.identifier); |
1215 } | 1216 } |
1216 } | 1217 } |
1217 | 1218 |
1218 // Run constructor field initializers such as `: foo = bar.baz` | 1219 // Run constructor field initializers such as `: foo = bar.baz` |
1219 for (var init in ctor.initializers) { | 1220 for (var init in ctor.initializers) { |
1220 if (init is ConstructorFieldInitializer) { | 1221 if (init is ConstructorFieldInitializer) { |
1221 fields[init.fieldName.staticElement as FieldElement] = | 1222 fields[init.fieldName.staticElement as FieldElement] = |
1222 _visit(init.expression); | 1223 _visit(init.expression); |
1223 } | 1224 } |
1224 } | 1225 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1262 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { | 1263 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { |
1263 // Constructor argument initializers are emitted earlier in the code, rather | 1264 // Constructor argument initializers are emitted earlier in the code, rather |
1264 // than always when we visit the function body, so we control it explicitly. | 1265 // than always when we visit the function body, so we control it explicitly. |
1265 if (node is ConstructorDeclaration != constructor) return null; | 1266 if (node is ConstructorDeclaration != constructor) return null; |
1266 | 1267 |
1267 var parameters = _parametersOf(node); | 1268 var parameters = _parametersOf(node); |
1268 if (parameters == null) return null; | 1269 if (parameters == null) return null; |
1269 | 1270 |
1270 var body = <JS.Statement>[]; | 1271 var body = <JS.Statement>[]; |
1271 for (var param in parameters.parameters) { | 1272 for (var param in parameters.parameters) { |
1272 var jsParam = _emitSimpleIdentifier(param.identifier, allowType: false); | 1273 var jsParam = _visit(param.identifier); |
1273 | 1274 |
1274 if (param.kind == ParameterKind.NAMED) { | 1275 if (param.kind == ParameterKind.NAMED) { |
1275 if (!options.destructureNamedParams) { | 1276 if (!options.destructureNamedParams) { |
1276 // Parameters will be passed using their real names, not the (possibly | 1277 // Parameters will be passed using their real names, not the (possibly |
1277 // renamed) local variable. | 1278 // renamed) local variable. |
1278 var paramName = js.string(param.identifier.name, "'"); | 1279 var paramName = js.string(param.identifier.name, "'"); |
1279 | 1280 |
1280 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. | 1281 // TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming. |
1281 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 1282 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
1282 jsParam, | 1283 jsParam, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 if (params == null) params = <JS.Parameter>[]; | 1330 if (params == null) params = <JS.Parameter>[]; |
1330 | 1331 |
1331 var typeParams = _emitTypeParams(node.element).toList(); | 1332 var typeParams = _emitTypeParams(node.element).toList(); |
1332 var returnType = emitTypeRef(node.element.returnType); | 1333 var returnType = emitTypeRef(node.element.returnType); |
1333 JS.Fun fn = _emitFunctionBody(params, node.body, typeParams, returnType); | 1334 JS.Fun fn = _emitFunctionBody(params, node.body, typeParams, returnType); |
1334 if (node.operatorKeyword != null && | 1335 if (node.operatorKeyword != null && |
1335 node.name.name == '[]=' && | 1336 node.name.name == '[]=' && |
1336 params.isNotEmpty) { | 1337 params.isNotEmpty) { |
1337 // []= methods need to return the value. We could also address this at | 1338 // []= methods need to return the value. We could also address this at |
1338 // call sites, but it's cleaner to instead transform the operator method. | 1339 // call sites, but it's cleaner to instead transform the operator method. |
1339 var returnValue = new JS.Return(params.last); | 1340 // TODO(ochafik): How do we ensure this is an expression and not a destruc
ting pattern? |
| 1341 var returnValue = new JS.Return(params.last.binding as JS.Expression); |
1340 var body = fn.body; | 1342 var body = fn.body; |
1341 if (JS.Return.foundIn(fn)) { | 1343 if (JS.Return.foundIn(fn)) { |
1342 // If a return is inside body, transform `(params) { body }` to | 1344 // If a return is inside body, transform `(params) { body }` to |
1343 // `(params) { (() => { body })(); return value; }`. | 1345 // `(params) { (() => { body })(); return value; }`. |
1344 // TODO(jmesserly): we could instead generate the return differently, | 1346 // TODO(jmesserly): we could instead generate the return differently, |
1345 // and avoid the immediately invoked function. | 1347 // and avoid the immediately invoked function. |
1346 body = new JS.Call(new JS.ArrowFun([], fn.body), []).toStatement(); | 1348 body = new JS.Call(new JS.ArrowFun([], fn.body), []).toStatement(); |
1347 } | 1349 } |
1348 // Rewrite the function to include the return. | 1350 // Rewrite the function to include the return. |
1349 fn = new JS.Fun(fn.params, new JS.Block([body, returnValue]), | 1351 fn = new JS.Fun(fn.params, new JS.Block([body, returnValue]), |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1536 if (!inStmt) { | 1538 if (!inStmt) { |
1537 var type = getStaticType(node); | 1539 var type = getStaticType(node); |
1538 return _emitFunctionTagged(clos, type, | 1540 return _emitFunctionTagged(clos, type, |
1539 topLevel: _executesAtTopLevel(node)); | 1541 topLevel: _executesAtTopLevel(node)); |
1540 } | 1542 } |
1541 return clos; | 1543 return clos; |
1542 } | 1544 } |
1543 } | 1545 } |
1544 | 1546 |
1545 JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body, | 1547 JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body, |
1546 List<JS.Identifier> typeParams, JS.TypeRef returnType) { | 1548 List<JS.TypeParameter> typeParams, JS.TypeRef returnType) { |
1547 // sync*, async, async* | 1549 // sync*, async, async* |
1548 if (body.isAsynchronous || body.isGenerator) { | 1550 if (body.isAsynchronous || body.isGenerator) { |
1549 return new JS.Fun( | 1551 return new JS.Fun( |
1550 params, | 1552 params, |
1551 js.statement('{ return #; }', | 1553 js.statement('{ return #; }', |
1552 [_emitGeneratorFunctionBody(params, body, returnType)]), | 1554 [_emitGeneratorFunctionBody(params, body, returnType)]), |
1553 returnType: returnType); | 1555 returnType: returnType); |
1554 } | 1556 } |
1555 // normal function (sync) | 1557 // normal function (sync) |
1556 return new JS.Fun(params, _visit(body), | 1558 return new JS.Fun(params, _visit(body), |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 declareFn = new JS.FunctionDeclaration(name, fn); | 1636 declareFn = new JS.FunctionDeclaration(name, fn); |
1635 } | 1637 } |
1636 declareFn = annotate(declareFn, node, node.functionDeclaration.element); | 1638 declareFn = annotate(declareFn, node, node.functionDeclaration.element); |
1637 | 1639 |
1638 return new JS.Block([ | 1640 return new JS.Block([ |
1639 declareFn, | 1641 declareFn, |
1640 _emitFunctionTagged(name, func.element.type).toStatement() | 1642 _emitFunctionTagged(name, func.element.type).toStatement() |
1641 ]); | 1643 ]); |
1642 } | 1644 } |
1643 | 1645 |
1644 @override | |
1645 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) => | |
1646 _emitSimpleIdentifier(node); | |
1647 | |
1648 /// Writes a simple identifier. This can handle implicit `this` as well as | 1646 /// Writes a simple identifier. This can handle implicit `this` as well as |
1649 /// going through the qualified library name if necessary. | 1647 /// going through the qualified library name if necessary. |
1650 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node, | 1648 @override |
1651 {bool allowType: false}) { | 1649 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
1652 var accessor = node.staticElement; | 1650 var accessor = node.staticElement; |
1653 if (accessor == null) { | 1651 if (accessor == null) { |
1654 return js.commentExpression( | 1652 return js.commentExpression( |
1655 'Unimplemented unknown name', new JS.Identifier(node.name)); | 1653 'Unimplemented unknown name', new JS.Identifier(node.name)); |
1656 } | 1654 } |
1657 | 1655 |
1658 // Get the original declaring element. If we had a property accessor, this | 1656 // Get the original declaring element. If we had a property accessor, this |
1659 // indirects back to a (possibly synthetic) field. | 1657 // indirects back to a (possibly synthetic) field. |
1660 var element = accessor; | 1658 var element = accessor; |
1661 if (accessor is PropertyAccessorElement) element = accessor.variable; | 1659 if (accessor is PropertyAccessorElement) element = accessor.variable; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1710 } | 1708 } |
1711 | 1709 |
1712 if (element is TemporaryVariableElement) { | 1710 if (element is TemporaryVariableElement) { |
1713 if (name[0] == '#') { | 1711 if (name[0] == '#') { |
1714 return new JS.InterpolatedExpression(name.substring(1)); | 1712 return new JS.InterpolatedExpression(name.substring(1)); |
1715 } else { | 1713 } else { |
1716 return _getTemp(element, name); | 1714 return _getTemp(element, name); |
1717 } | 1715 } |
1718 } | 1716 } |
1719 | 1717 |
1720 return annotate( | 1718 return annotate(new JS.Identifier(name), node); |
1721 new JS.Identifier(name, | |
1722 type: allowType ? emitTypeRef(node.bestType) : null), | |
1723 node); | |
1724 } | 1719 } |
1725 | 1720 |
1726 JS.TemporaryId _getTemp(Element key, String name) => | 1721 JS.TemporaryId _getTemp(Element key, String name) => |
1727 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); | 1722 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); |
1728 | 1723 |
1729 List<Annotation> _parameterMetadata(FormalParameter p) => | 1724 List<Annotation> _parameterMetadata(FormalParameter p) => |
1730 (p is NormalFormalParameter) | 1725 (p is NormalFormalParameter) |
1731 ? p.metadata | 1726 ? p.metadata |
1732 : (p as DefaultFormalParameter).parameter.metadata; | 1727 : (p as DefaultFormalParameter).parameter.metadata; |
1733 | 1728 |
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 code = '#(#)'; | 2083 code = '#(#)'; |
2089 } | 2084 } |
2090 return js.call(code, [_visit(node.function), _visit(node.argumentList)]); | 2085 return js.call(code, [_visit(node.function), _visit(node.argumentList)]); |
2091 } | 2086 } |
2092 | 2087 |
2093 @override | 2088 @override |
2094 List<JS.Expression> visitArgumentList(ArgumentList node) { | 2089 List<JS.Expression> visitArgumentList(ArgumentList node) { |
2095 var args = <JS.Expression>[]; | 2090 var args = <JS.Expression>[]; |
2096 var named = <JS.Property>[]; | 2091 var named = <JS.Property>[]; |
2097 for (var arg in node.arguments) { | 2092 for (var arg in node.arguments) { |
| 2093 var jsArg = _visit(arg); |
2098 if (arg is NamedExpression) { | 2094 if (arg is NamedExpression) { |
2099 named.add(_visit(arg)); | 2095 named.add(jsArg); |
2100 } else if (arg is MethodInvocation && isJsSpreadInvocation(arg)) { | 2096 } else if (arg is MethodInvocation && isJsSpreadInvocation(arg)) { |
2101 args.add( | 2097 args.add(new JS.Spread(jsArg)); |
2102 new JS.RestParameter(_visit(arg.argumentList.arguments.single))); | |
2103 } else { | 2098 } else { |
2104 args.add(_visit(arg)); | 2099 args.add(jsArg); |
2105 } | 2100 } |
2106 } | 2101 } |
2107 if (named.isNotEmpty) { | 2102 if (named.isNotEmpty) { |
2108 args.add(new JS.ObjectInitializer(named)); | 2103 args.add(new JS.ObjectInitializer(named)); |
2109 } | 2104 } |
2110 return args; | 2105 return args; |
2111 } | 2106 } |
2112 | 2107 |
2113 @override | 2108 @override |
2114 JS.Property visitNamedExpression(NamedExpression node) { | 2109 JS.Property visitNamedExpression(NamedExpression node) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 name = _visit(param.identifier); | 2144 name = _visit(param.identifier); |
2150 } | 2145 } |
2151 namedVars.add(new JS.DestructuredVariable( | 2146 namedVars.add(new JS.DestructuredVariable( |
2152 name: name, | 2147 name: name, |
2153 structure: structure, | 2148 structure: structure, |
2154 defaultValue: _defaultParamValue(param))); | 2149 defaultValue: _defaultParamValue(param))); |
2155 } else { | 2150 } else { |
2156 needsOpts = true; | 2151 needsOpts = true; |
2157 } | 2152 } |
2158 } else { | 2153 } else { |
2159 var jsParam = _visit(param); | 2154 result.add(_visit(param)); |
2160 result.add( | |
2161 param is DefaultFormalParameter && options.destructureNamedParams | |
2162 ? new JS.DestructuredVariable( | |
2163 name: jsParam, defaultValue: _defaultParamValue(param)) | |
2164 : jsParam); | |
2165 } | 2155 } |
2166 } | 2156 } |
2167 | 2157 |
2168 if (needsOpts) { | 2158 if (needsOpts) { |
2169 result.add(_namedArgTemp); | 2159 result.add(new JS.Parameter(_namedArgTemp)); |
2170 } else if (namedVars.isNotEmpty) { | 2160 } else if (namedVars.isNotEmpty) { |
2171 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so | 2161 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so |
2172 // in case there are conflicting names we create an object without | 2162 // in case there are conflicting names we create an object without |
2173 // any prototype. | 2163 // any prototype. |
2174 var defaultOpts = hasNamedArgsConflictingWithObjectProperties | 2164 var defaultOpts = hasNamedArgsConflictingWithObjectProperties |
2175 ? js.call('Object.create(null)') | 2165 ? js.call('Object.create(null)') |
2176 : js.call('{}'); | 2166 : js.call('{}'); |
2177 result.add(new JS.DestructuredVariable( | 2167 result.add(new JS.Parameter( |
2178 structure: new JS.ObjectBindingPattern(namedVars), | 2168 new JS.ObjectBindingPattern(namedVars), |
2179 type: emitNamedParamsArgType(node.parameterElements), | 2169 type: emitNamedParamsArgType(node.parameterElements), |
2180 defaultValue: defaultOpts)); | 2170 defaultValue: defaultOpts)); |
2181 } | 2171 } |
2182 return result; | 2172 return result; |
2183 } | 2173 } |
2184 | 2174 |
2185 /// See ES6 spec (and `Object.getOwnPropertyNames(Object.prototype)`): | 2175 /// See ES6 spec (and `Object.getOwnPropertyNames(Object.prototype)`): |
2186 /// http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-obje
ct-prototype-object | 2176 /// http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-obje
ct-prototype-object |
2187 /// http://www.ecma-international.org/ecma-262/6.0/#sec-additional-properties-
of-the-object.prototype-object | 2177 /// http://www.ecma-international.org/ecma-262/6.0/#sec-additional-properties-
of-the-object.prototype-object |
2188 static final Set<String> _jsObjectProperties = new Set<String>() | 2178 static final Set<String> _jsObjectProperties = new Set<String>() |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2301 } | 2291 } |
2302 | 2292 |
2303 @override | 2293 @override |
2304 visitVariableDeclaration(VariableDeclaration node) { | 2294 visitVariableDeclaration(VariableDeclaration node) { |
2305 if (node.element is PropertyInducingElement) { | 2295 if (node.element is PropertyInducingElement) { |
2306 // Static and instance fields are handled elsewhere. | 2296 // Static and instance fields are handled elsewhere. |
2307 assert(node.element is TopLevelVariableElement); | 2297 assert(node.element is TopLevelVariableElement); |
2308 return _emitTopLevelField(node); | 2298 return _emitTopLevelField(node); |
2309 } | 2299 } |
2310 | 2300 |
2311 var name = | 2301 var name = new JS.Identifier(node.name.name); |
2312 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type)); | 2302 return new JS.VariableInitialization(name, _visitInitializer(node), |
2313 return new JS.VariableInitialization(name, _visitInitializer(node)); | 2303 type: emitTypeRef(node.element.type)); |
2314 } | 2304 } |
2315 | 2305 |
2316 bool _isFinalJSDecl(AstNode field) => | 2306 bool _isFinalJSDecl(AstNode field) => |
2317 field is VariableDeclaration && | 2307 field is VariableDeclaration && |
2318 field.isFinal && | 2308 field.isFinal && |
2319 _isJSInvocation(field.initializer); | 2309 _isJSInvocation(field.initializer); |
2320 | 2310 |
2321 /// Try to emit a constant static field. | 2311 /// Try to emit a constant static field. |
2322 /// | 2312 /// |
2323 /// If the field's initializer does not cause side effects, and if all of | 2313 /// If the field's initializer does not cause side effects, and if all of |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2396 // constant fields don't change, so we can generate them as `let` | 2386 // constant fields don't change, so we can generate them as `let` |
2397 // but add them to the module's exports. However, make sure we generate | 2387 // but add them to the module's exports. However, make sure we generate |
2398 // anything they depend on first. | 2388 // anything they depend on first. |
2399 | 2389 |
2400 if (isPublic(fieldName)) _addExport(fieldName, exportName); | 2390 if (isPublic(fieldName)) _addExport(fieldName, exportName); |
2401 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2391 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
2402 return js.statement('#;', [ | 2392 return js.statement('#;', [ |
2403 annotate( | 2393 annotate( |
2404 new JS.VariableDeclarationList(declKeyword, [ | 2394 new JS.VariableDeclarationList(declKeyword, [ |
2405 new JS.VariableInitialization( | 2395 new JS.VariableInitialization( |
2406 new JS.Identifier(fieldName, | 2396 new JS.Identifier(fieldName), |
2407 type: emitTypeRef(field.element.type)), | 2397 jsInit, |
2408 jsInit) | 2398 type: emitTypeRef(field.element.type)) |
2409 ]), | 2399 ]), |
2410 field, | 2400 field, |
2411 field.element) | 2401 field.element) |
2412 ]); | 2402 ]); |
2413 } | 2403 } |
2414 | 2404 |
2415 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { | 2405 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { |
2416 return annotate(js.statement('# = #;', [_visit(field.name), jsInit]), | 2406 return annotate(js.statement('# = #;', [_visit(field.name), jsInit]), |
2417 field, field.element); | 2407 field, field.element); |
2418 } | 2408 } |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2830 _cascadeTarget = savedCascadeTemp; | 2820 _cascadeTarget = savedCascadeTemp; |
2831 return result; | 2821 return result; |
2832 } | 2822 } |
2833 | 2823 |
2834 @override | 2824 @override |
2835 visitParenthesizedExpression(ParenthesizedExpression node) => | 2825 visitParenthesizedExpression(ParenthesizedExpression node) => |
2836 // The printer handles precedence so we don't need to. | 2826 // The printer handles precedence so we don't need to. |
2837 _visit(node.expression); | 2827 _visit(node.expression); |
2838 | 2828 |
2839 @override | 2829 @override |
2840 visitFormalParameter(FormalParameter node) => _emitFormalParameter(node); | 2830 visitFormalParameter(FormalParameter node) { |
2841 | 2831 var defaultValue = |
2842 _emitFormalParameter(FormalParameter node, {bool allowType: true}) { | 2832 node is DefaultFormalParameter && options.destructureNamedParams |
2843 var id = _emitSimpleIdentifier(node.identifier, allowType: allowType); | 2833 ? _defaultParamValue(node) : null; |
2844 | 2834 return new JS.Parameter( |
2845 var isRestArg = findAnnotation(node.element, isJsRestAnnotation) != null; | 2835 _visit(node.identifier), |
2846 return isRestArg ? new JS.RestParameter(id) : id; | 2836 type: emitTypeRef(node.element.type), |
| 2837 defaultValue: defaultValue, |
| 2838 isRest: findAnnotation(node.element, isJsRestAnnotation) != null); |
2847 } | 2839 } |
2848 | 2840 |
2849 @override | 2841 @override |
2850 JS.This visitThisExpression(ThisExpression node) => new JS.This(); | 2842 JS.This visitThisExpression(ThisExpression node) => new JS.This(); |
2851 | 2843 |
2852 @override | 2844 @override |
2853 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); | 2845 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); |
2854 | 2846 |
2855 @override | 2847 @override |
2856 visitPrefixedIdentifier(PrefixedIdentifier node) { | 2848 visitPrefixedIdentifier(PrefixedIdentifier node) { |
(...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3689 | 3681 |
3690 /// A special kind of element created by the compiler, signifying a temporary | 3682 /// A special kind of element created by the compiler, signifying a temporary |
3691 /// variable. These objects use instance equality, and should be shared | 3683 /// variable. These objects use instance equality, and should be shared |
3692 /// everywhere in the tree where they are treated as the same variable. | 3684 /// everywhere in the tree where they are treated as the same variable. |
3693 class TemporaryVariableElement extends LocalVariableElementImpl { | 3685 class TemporaryVariableElement extends LocalVariableElementImpl { |
3694 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3686 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3695 | 3687 |
3696 int get hashCode => identityHashCode(this); | 3688 int get hashCode => identityHashCode(this); |
3697 bool operator ==(Object other) => identical(this, other); | 3689 bool operator ==(Object other) => identical(this, other); |
3698 } | 3690 } |
OLD | NEW |