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 dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
284 if (hide != null) { | 284 if (hide != null) { |
285 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); | 285 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); |
286 } | 286 } |
287 args.add(new JS.ArrayInitializer(shownNames)); | 287 args.add(new JS.ArrayInitializer(shownNames)); |
288 args.add(new JS.ArrayInitializer(hiddenNames)); | 288 args.add(new JS.ArrayInitializer(hiddenNames)); |
289 } | 289 } |
290 _moduleItems.add(js.statement('dart.export(#);', [args])); | 290 _moduleItems.add(js.statement('dart.export(#);', [args])); |
291 } | 291 } |
292 | 292 |
293 JS.Identifier _initSymbol(JS.Identifier id) { | 293 JS.Identifier _initSymbol(JS.Identifier id) { |
294 var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); | 294 var s = js.statement('let # = Symbol(#);', [id, js.string(id.name, "'")]); |
295 _moduleItems.add(s); | 295 _moduleItems.add(s); |
296 return id; | 296 return id; |
297 } | 297 } |
298 | 298 |
299 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, | |
300 // until we have better name tracking. | |
301 String get _SYMBOL { | |
302 var name = currentLibrary.name; | |
303 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol'; | |
304 return 'Symbol'; | |
305 } | |
306 | |
307 bool isPublic(String name) => !name.startsWith('_'); | 299 bool isPublic(String name) => !name.startsWith('_'); |
308 | 300 |
309 @override | 301 @override |
310 visitAsExpression(AsExpression node) { | 302 visitAsExpression(AsExpression node) { |
311 var from = getStaticType(node.expression); | 303 var from = getStaticType(node.expression); |
312 var to = node.type.type; | 304 var to = node.type.type; |
313 | 305 |
314 // Skip the cast if it's not needed. | 306 // Skip the cast if it's not needed. |
315 if (rules.isSubTypeOf(from, to)) return _visit(node.expression); | 307 if (rules.isSubTypeOf(from, to)) return _visit(node.expression); |
316 | 308 |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
544 return js.statement( | 536 return js.statement( |
545 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', | 537 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', |
546 [genericDef, _exportsVar, _propertyName(name), genericName]); | 538 [genericDef, _exportsVar, _propertyName(name), genericName]); |
547 } | 539 } |
548 | 540 |
549 return js.statement( | 541 return js.statement( |
550 'dart.defineLazyClass(#, { get #() { #; return #; } });', | 542 'dart.defineLazyClass(#, { get #() { #; return #; } });', |
551 [_exportsVar, _propertyName(name), body, name]); | 543 [_exportsVar, _propertyName(name), body, name]); |
552 } | 544 } |
553 | 545 |
554 if (isPublic(name)) _addExport(name); | |
555 | |
556 if (genericDef != null) { | 546 if (genericDef != null) { |
557 var dynType = fillDynamicTypeArgs(type, types); | 547 var dynType = fillDynamicTypeArgs(type, types); |
558 var genericInst = _emitTypeName(dynType, lowerGeneric: true); | 548 var genericInst = _emitTypeName(dynType, lowerGeneric: true); |
559 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 549 |
550 if (_isJsBuiltinName(name)) { | |
ochafik
2015/09/15 18:05:17
nit: store as a var above for reuse below?
| |
551 genericInst = js.statement('#.# = #;', | |
552 [_libraryName(type.element.library), name, genericInst]); | |
ochafik
2015/09/15 18:05:17
nit: isn't this guaranteed to be currentLibrary?
| |
553 } else { | |
554 if (isPublic(name)) _addExport(name); | |
555 genericInst = js.statement('let # = #;', [name, genericInst]); | |
556 } | |
557 | |
558 return new JS.Block([genericDef, genericInst]); | |
560 } | 559 } |
560 | |
561 if (_isJsBuiltinName(name)) { | |
562 var typeName = _emitTypeName(type) as JS.PropertyAccess; | |
563 | |
564 // TODO(jmesserly): we could generate something cleaner, but since it only | |
565 // affects 3 types, doesn't seem like a big concern. | |
566 var classExpr = new JS.Call( | |
567 new JS.ArrowFun([], js.statement('{ #; return #; }', [body, name])), | |
568 []); | |
569 return new JS.Assignment(typeName, classExpr).toStatement(); | |
570 } else if (isPublic(name)) { | |
571 _addExport(name); | |
572 } | |
573 | |
561 return body; | 574 return body; |
562 } | 575 } |
563 | 576 |
564 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { | 577 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { |
565 var name = type.name; | 578 var name = type.name; |
566 var genericName = '$name\$'; | 579 var genericName = '$name\$'; |
567 var typeParams = type.typeParameters.map((p) => p.name); | 580 var typeParams = type.typeParameters.map((p) => p.name); |
568 if (isPublic(name)) _exports.add(genericName); | 581 if (isPublic(name)) _exports.add(genericName); |
569 return js.statement('let # = dart.generic(function(#) { #; return #; });', | 582 return js.statement('let # = dart.generic(function(#) { #; return #; });', |
570 [genericName, typeParams, body, name]); | 583 [genericName, typeParams, body, name]); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
648 // Iterable, we know the adapter is already there, so we can skip it as a | 661 // Iterable, we know the adapter is already there, so we can skip it as a |
649 // simple code size optimization. | 662 // simple code size optimization. |
650 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); | 663 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); |
651 if (parent != null) return null; | 664 if (parent != null) return null; |
652 var parentType = findSupertype(t, _implementsIterable); | 665 var parentType = findSupertype(t, _implementsIterable); |
653 if (parentType != null) return null; | 666 if (parentType != null) return null; |
654 | 667 |
655 // Otherwise, emit the adapter method, which wraps the Dart iterator in | 668 // Otherwise, emit the adapter method, which wraps the Dart iterator in |
656 // an ES6 iterator. | 669 // an ES6 iterator. |
657 return new JS.Method( | 670 return new JS.Method( |
658 js.call('$_SYMBOL.iterator'), | 671 js.call('Symbol.iterator'), |
659 js.call('function() { return new dart.JsIterator(this.#); }', | 672 js.call('function() { return new dart.JsIterator(this.#); }', |
660 [_emitMemberName('iterator', type: t)]) as JS.Fun); | 673 [_emitMemberName('iterator', type: t)]) as JS.Fun); |
661 } | 674 } |
662 | 675 |
663 JS.Expression _instantiateAnnotation(Annotation node) { | 676 JS.Expression _instantiateAnnotation(Annotation node) { |
664 var element = node.element; | 677 var element = node.element; |
665 if (element is ConstructorElement) { | 678 if (element is ConstructorElement) { |
666 return _emitInstanceCreationExpression(element, element.returnType, | 679 return _emitInstanceCreationExpression(element, element.returnType, |
667 node.constructorName, node.arguments, true); | 680 node.constructorName, node.arguments, true); |
668 } else { | 681 } else { |
(...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1648 return _maybeQualifiedName(element, _propertyName(name)); | 1661 return _maybeQualifiedName(element, _propertyName(name)); |
1649 } | 1662 } |
1650 | 1663 |
1651 JS.Expression _maybeQualifiedName(Element e, JS.Expression name, | 1664 JS.Expression _maybeQualifiedName(Element e, JS.Expression name, |
1652 [Map<Element, JS.MaybeQualifiedId> idTable]) { | 1665 [Map<Element, JS.MaybeQualifiedId> idTable]) { |
1653 var libName = _libraryName(e.library); | 1666 var libName = _libraryName(e.library); |
1654 if (idTable == null) idTable = _qualifiedIds; | 1667 if (idTable == null) idTable = _qualifiedIds; |
1655 | 1668 |
1656 // Mutable top-level fields should always be qualified. | 1669 // Mutable top-level fields should always be qualified. |
1657 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; | 1670 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; |
1658 if (e.library != currentLibrary || mutableTopLevel) { | 1671 if (e.library != currentLibrary || |
1672 mutableTopLevel || | |
1673 _isJsBuiltinName(e.name)) { | |
ochafik
2015/09/15 18:05:17
I think that check alone (in the context of "exten
| |
1659 return new JS.PropertyAccess(libName, name); | 1674 return new JS.PropertyAccess(libName, name); |
1660 } | 1675 } |
1661 | 1676 |
1662 return idTable.putIfAbsent(e, () => new JS.MaybeQualifiedId(libName, name)); | 1677 return idTable.putIfAbsent(e, () => new JS.MaybeQualifiedId(libName, name)); |
1663 } | 1678 } |
1664 | 1679 |
1680 /// Returns true if this name is Object, Error, or Symbol. | |
1681 /// | |
1682 /// We avoid using those names as locals so we don't shadow the global JS | |
1683 /// names. While we could technically deal with this, it confuses other tools | |
1684 /// like JS Compiler. | |
1685 bool _isJsBuiltinName(String name) { | |
1686 switch (name) { | |
1687 case 'Object': | |
1688 case 'Error': | |
1689 case 'Symbol': | |
ochafik
2015/09/15 16:58:33
Presumably also Map, Set, TypeError, RangeError, R
Jennifer Messerly
2015/09/15 17:06:09
Maybe I need to step back, I honestly don't have a
ochafik
2015/09/15 18:05:17
Right now it's just to avoid errors in Closure wit
Jennifer Messerly
2015/09/15 18:34:23
ah, we try and qualify the minimum possible. In fa
| |
1690 return true; | |
1691 } | |
1692 return false; | |
1693 } | |
1694 | |
1665 @override | 1695 @override |
1666 JS.Expression visitAssignmentExpression(AssignmentExpression node) { | 1696 JS.Expression visitAssignmentExpression(AssignmentExpression node) { |
1667 var left = node.leftHandSide; | 1697 var left = node.leftHandSide; |
1668 var right = node.rightHandSide; | 1698 var right = node.rightHandSide; |
1669 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); | 1699 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); |
1670 var op = node.operator.lexeme; | 1700 var op = node.operator.lexeme; |
1671 assert(op.endsWith('=')); | 1701 assert(op.endsWith('=')); |
1672 op = op.substring(0, op.length - 1); // remove trailing '=' | 1702 op = op.substring(0, op.length - 1); // remove trailing '=' |
1673 return _emitOpAssign(left, right, op, node.staticElement, context: node); | 1703 return _emitOpAssign(left, right, op, node.staticElement, context: node); |
1674 } | 1704 } |
(...skipping 1636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3311 | 3341 |
3312 /// A special kind of element created by the compiler, signifying a temporary | 3342 /// A special kind of element created by the compiler, signifying a temporary |
3313 /// variable. These objects use instance equality, and should be shared | 3343 /// variable. These objects use instance equality, and should be shared |
3314 /// everywhere in the tree where they are treated as the same variable. | 3344 /// everywhere in the tree where they are treated as the same variable. |
3315 class TemporaryVariableElement extends LocalVariableElementImpl { | 3345 class TemporaryVariableElement extends LocalVariableElementImpl { |
3316 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3346 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3317 | 3347 |
3318 int get hashCode => identityHashCode(this); | 3348 int get hashCode => identityHashCode(this); |
3319 bool operator ==(Object other) => identical(this, other); | 3349 bool operator ==(Object other) => identical(this, other); |
3320 } | 3350 } |
OLD | NEW |