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 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 4463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4474 | 4474 |
4475 if (op.lexeme == '++' || op.lexeme == '--') { | 4475 if (op.lexeme == '++' || op.lexeme == '--') { |
4476 // Increment or decrement requires expansion. | 4476 // Increment or decrement requires expansion. |
4477 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions | 4477 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions |
4478 // (for example, x is IndexExpression) we evaluate those once. | 4478 // (for example, x is IndexExpression) we evaluate those once. |
4479 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 4479 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
4480 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement, | 4480 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement, |
4481 context: expr); | 4481 context: expr); |
4482 } | 4482 } |
4483 | 4483 |
4484 return _emitSend(expr, op.lexeme[0], []); | 4484 var operatorName = op.lexeme; |
4485 if (operatorName == '-') operatorName = 'unary-'; | |
Bob Nystrom
2016/10/20 21:01:13
Is "unary-" just used as a magic string for _emitM
Jennifer Messerly
2016/10/20 22:45:04
it's not. It's defined by the Dart language spec a
| |
4486 return _emitSend(expr, operatorName, []); | |
4485 } | 4487 } |
4486 | 4488 |
4487 // Cascades can contain [IndexExpression], [MethodInvocation] and | 4489 // Cascades can contain [IndexExpression], [MethodInvocation] and |
4488 // [PropertyAccess]. The code generation for those is handled in their | 4490 // [PropertyAccess]. The code generation for those is handled in their |
4489 // respective visit methods. | 4491 // respective visit methods. |
4490 @override | 4492 @override |
4491 JS.Node visitCascadeExpression(CascadeExpression node) { | 4493 JS.Node visitCascadeExpression(CascadeExpression node) { |
4492 var savedCascadeTemp = _cascadeTarget; | 4494 var savedCascadeTemp = _cascadeTarget; |
4493 | 4495 |
4494 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 4496 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4707 } | 4709 } |
4708 | 4710 |
4709 /// Emits a generic send, like an operator method. | 4711 /// Emits a generic send, like an operator method. |
4710 /// | 4712 /// |
4711 /// **Please note** this function does not support method invocation syntax | 4713 /// **Please note** this function does not support method invocation syntax |
4712 /// `obj.name(args)` because that could be a getter followed by a call. | 4714 /// `obj.name(args)` because that could be a getter followed by a call. |
4713 /// See [visitMethodInvocation]. | 4715 /// See [visitMethodInvocation]. |
4714 JS.Expression _emitSend( | 4716 JS.Expression _emitSend( |
4715 Expression target, String name, List<Expression> args) { | 4717 Expression target, String name, List<Expression> args) { |
4716 var type = getStaticType(target); | 4718 var type = getStaticType(target); |
4717 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); | 4719 var memberName = _emitMemberName(name, type: type); |
4718 if (isDynamicInvoke(target)) { | 4720 if (isDynamicInvoke(target)) { |
4719 if (_inWhitelistCode(target)) { | 4721 if (_inWhitelistCode(target)) { |
4720 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 4722 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
4721 var l = _visit(_bindValue(vars, 'l', target)); | 4723 var l = _visit(_bindValue(vars, 'l', target)); |
4722 return new JS.MetaLet(vars, [ | 4724 return new JS.MetaLet(vars, [ |
4723 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)', | 4725 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)', |
4724 [l, l, memberName, memberName, l, _visitList(args)]) | 4726 [l, l, memberName, memberName, l, _visitList(args)]) |
4725 ]); | 4727 ]); |
4726 } | 4728 } |
4727 // dynamic dispatch | 4729 // dynamic dispatch |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5219 /// directly rather than computing the relevant options for [_emitMemberName]. | 5221 /// directly rather than computing the relevant options for [_emitMemberName]. |
5220 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) { | 5222 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) { |
5221 String name; | 5223 String name; |
5222 if (e is PropertyAccessorElement) { | 5224 if (e is PropertyAccessorElement) { |
5223 name = e.variable.name; | 5225 name = e.variable.name; |
5224 } else { | 5226 } else { |
5225 name = e.name; | 5227 name = e.name; |
5226 } | 5228 } |
5227 return _emitMemberName(name, | 5229 return _emitMemberName(name, |
5228 type: (e.enclosingElement as ClassElement).type, | 5230 type: (e.enclosingElement as ClassElement).type, |
5229 unary: e.parameters.isEmpty, | |
5230 isStatic: e.isStatic, | 5231 isStatic: e.isStatic, |
5231 useExtension: useExtension); | 5232 useExtension: useExtension); |
5232 } | 5233 } |
5233 | 5234 |
5234 /// This handles member renaming for private names and operators. | 5235 /// This handles member renaming for private names and operators. |
5235 /// | 5236 /// |
5236 /// Private names are generated using ES6 symbols: | 5237 /// Private names are generated using ES6 symbols: |
5237 /// | 5238 /// |
5238 /// // At the top of the module: | 5239 /// // At the top of the module: |
5239 /// let _x = Symbol('_x'); | 5240 /// let _x = Symbol('_x'); |
(...skipping 19 matching lines...) Expand all Loading... | |
5259 /// | 5260 /// |
5260 /// There are three exceptions: [], []= and unary -. | 5261 /// There are three exceptions: [], []= and unary -. |
5261 /// The indexing operators we use `get` and `set` instead: | 5262 /// The indexing operators we use `get` and `set` instead: |
5262 /// | 5263 /// |
5263 /// x.get('hi') | 5264 /// x.get('hi') |
5264 /// x.set('hi', 123) | 5265 /// x.set('hi', 123) |
5265 /// | 5266 /// |
5266 /// This follows the same pattern as ECMAScript 6 Map: | 5267 /// This follows the same pattern as ECMAScript 6 Map: |
5267 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> | 5268 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> |
5268 /// | 5269 /// |
5269 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed | 5270 /// Unary minus looks like: `x._negate()`. Note that [unary] must be passed |
Bob Nystrom
2016/10/20 21:01:13
Can you update the part of the doc around "[unary]
Jennifer Messerly
2016/10/20 22:45:04
Done.
| |
5270 /// for this transformation to happen, otherwise binary minus is assumed. | 5271 /// for this transformation to happen, otherwise binary minus is assumed. |
5271 /// | 5272 /// |
5272 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 5273 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
5273 /// helper, that checks for null. The user defined method is called '=='. | 5274 /// helper, that checks for null. The user defined method is called '=='. |
5274 /// | 5275 /// |
5275 JS.Expression _emitMemberName(String name, | 5276 JS.Expression _emitMemberName(String name, |
5276 {DartType type, | 5277 {DartType type, bool isStatic: false, bool useExtension}) { |
5277 bool unary: false, | |
5278 bool isStatic: false, | |
5279 bool useExtension}) { | |
5280 // Static members skip the rename steps. | 5278 // Static members skip the rename steps. |
5281 if (isStatic) return _propertyName(name); | 5279 if (isStatic) return _propertyName(name); |
5282 | 5280 |
5283 if (name.startsWith('_')) { | 5281 if (name.startsWith('_')) { |
5284 return _emitPrivateNameSymbol(currentLibrary, name); | 5282 return _emitPrivateNameSymbol(currentLibrary, name); |
5285 } | 5283 } |
5286 | 5284 |
5285 // When generating synthetic names, we use _ as the prefix, since Dart names | |
5286 // won't have this (eliminated above), nor will static names reach here. | |
5287 if (name == '[]') { | 5287 if (name == '[]') { |
kevmoo
2016/10/20 20:06:03
better as a switch, no?
Jennifer Messerly
2016/10/20 20:12:14
I tend to find Dart's C-style switch clunky, e.g.
Bob Nystrom
2016/10/20 21:01:13
If it was my code, I'd probably use switch () to h
| |
5288 name = 'get'; | 5288 name = '_get'; |
5289 } else if (name == '[]=') { | 5289 } else if (name == '[]=') { |
5290 name = 'set'; | 5290 name = '_set'; |
5291 } else if (name == '-' && unary) { | 5291 } else if (name == 'unary-') { |
5292 name = 'unary-'; | 5292 name = '_negate'; |
5293 } else if (name == 'constructor' || name == 'prototype') { | 5293 } else if (name == 'constructor' || name == 'prototype') { |
5294 // This uses an illegal (in Dart) character for a member, avoiding the | 5294 name = '_$name'; |
5295 // conflict. We could use practically any character for this. | |
5296 name = '+$name'; | |
5297 } | 5295 } |
5298 | 5296 |
5299 var result = _propertyName(name); | 5297 var result = _propertyName(name); |
5300 | 5298 |
5301 if (useExtension == null) { | 5299 if (useExtension == null) { |
5302 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 5300 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
5303 var baseType = type; | 5301 var baseType = type; |
5304 while (baseType is TypeParameterType) { | 5302 while (baseType is TypeParameterType) { |
5305 baseType = (baseType.element as TypeParameterElement).bound; | 5303 baseType = (baseType.element as TypeParameterElement).bound; |
5306 } | 5304 } |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5519 } | 5517 } |
5520 | 5518 |
5521 bool isLibraryPrefix(Expression node) => | 5519 bool isLibraryPrefix(Expression node) => |
5522 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5520 node is SimpleIdentifier && node.staticElement is PrefixElement; |
5523 | 5521 |
5524 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5522 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
5525 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5523 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
5526 | 5524 |
5527 bool _isDartRuntime(LibraryElement l) => | 5525 bool _isDartRuntime(LibraryElement l) => |
5528 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5526 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |