Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1059583002: Extension method support to move us closer to a valid List implementation. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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; 7 import 'dart:collection' show HashSet, HashMap;
8 import 'dart:io' show Directory, File; 8 import 'dart:io' show Directory, File;
9 9
10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
(...skipping 24 matching lines...) Expand all
35 35
36 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; 36 bool _isAnnotationType(Annotation m, String name) => m.name.name == name;
37 37
38 Annotation _getAnnotation(AnnotatedNode node, String name) => node.metadata 38 Annotation _getAnnotation(AnnotatedNode node, String name) => node.metadata
39 .firstWhere((annotation) => _isAnnotationType(annotation, name), 39 .firstWhere((annotation) => _isAnnotationType(annotation, name),
40 orElse: () => null); 40 orElse: () => null);
41 41
42 Annotation _getJsNameAnnotation(AnnotatedNode node) => 42 Annotation _getJsNameAnnotation(AnnotatedNode node) =>
43 _getAnnotation(node, "JsName"); 43 _getAnnotation(node, "JsName");
44 44
45 // TODO(jacobr): we would like to do something like the following
46 // but we don't have summary support yet.
47 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
48 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
49
50
45 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { 51 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
46 final LibraryInfo libraryInfo; 52 final LibraryInfo libraryInfo;
47 final TypeRules rules; 53 final TypeRules rules;
48 54
49 // TODO(jmesserly): this is needed because RestrictedTypeRules can send 55 // TODO(jmesserly): this is needed because RestrictedTypeRules can send
50 // messages to CheckerReporter, for things like missing types. 56 // messages to CheckerReporter, for things like missing types.
51 // We should probably refactor so this can't happen, as codegen would be too 57 // We should probably refactor so this can't happen, as codegen would be too
52 // late to be issuing these messages. 58 // late to be issuing these messages.
53 final CheckerReporter _checkerReporter; 59 final CheckerReporter _checkerReporter;
54 60
55 /// The variable for the target of the current `..` cascade expression. 61 /// The variable for the target of the current `..` cascade expression.
56 SimpleIdentifier _cascadeTarget; 62 SimpleIdentifier _cascadeTarget;
57 /// The variable for the current catch clause 63 /// The variable for the current catch clause
58 SimpleIdentifier _catchParameter; 64 SimpleIdentifier _catchParameter;
59 65
60 ClassDeclaration currentClass; 66 ClassDeclaration currentClass;
61 ConstantEvaluator _constEvaluator; 67 ConstantEvaluator _constEvaluator;
62 68
63 final _exports = <String>[]; 69 final _exports = <String>[];
64 final _lazyFields = <VariableDeclaration>[]; 70 final _lazyFields = <VariableDeclaration>[];
65 final _properties = <FunctionDeclaration>[]; 71 final _properties = <FunctionDeclaration>[];
66 final _privateNames = new HashSet<String>(); 72 final _privateNames = new HashSet<String>();
67 final _pendingPrivateNames = <String>[]; 73 final _pendingPrivateNames = <String>[];
74 final _extensionMethodNames = new HashSet<String>();
75 final _pendingExtensionMethodNames = <String>[];
76
77 // TODO(jacobr): determine the the set of types with extension methods from
78 // the annotations rather than hard coding the list once the analyzer
79 // supports summaries.
80
81 List<InterfaceType> get _JsExtensionMethodTypes =>
82 <InterfaceType>[rules.provider.listType, rules.provider.iterableType];
68 83
69 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or 84 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or
70 /// [ClassTypeAlias]. 85 /// [ClassTypeAlias].
71 final _pendingClasses = new HashMap<ClassElement, CompilationUnitMember>(); 86 final _pendingClasses = new HashMap<ClassElement, CompilationUnitMember>();
72 87
73 /// Memoized results of [_lazyClass]. 88 /// Memoized results of [_lazyClass].
74 final _lazyClassMemo = new HashMap<ClassElement, bool>(); 89 final _lazyClassMemo = new HashMap<ClassElement, bool>();
75 90
76 /// Memoized results of [_inLibraryCycle]. 91 /// Memoized results of [_inLibraryCycle].
77 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); 92 final _libraryCycleMemo = new HashMap<LibraryElement, bool>();
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 name, 151 name,
137 name, 152 name,
138 defaultValue 153 defaultValue
139 ]) 154 ])
140 ]); 155 ]);
141 } 156 }
142 157
143 JS.Statement _initPrivateSymbol(String name) => js.statement( 158 JS.Statement _initPrivateSymbol(String name) => js.statement(
144 'let # = $_SYMBOL(#);', [new JSTemporary(name), js.string(name, "'")]); 159 'let # = $_SYMBOL(#);', [new JSTemporary(name), js.string(name, "'")]);
145 160
161 JS.Statement _initExtensionMethodSymbol(String name) => js.statement(
162 'let # = $_SYMBOL(#);', [new JS.Identifier(name, allowRename: false), js.s tring(name, "'")]);
163
146 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, 164 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core,
147 // until we have better name tracking. 165 // until we have better name tracking.
148 String get _SYMBOL { 166 String get _SYMBOL {
149 var name = currentLibrary.name; 167 var name = currentLibrary.name;
150 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol'; 168 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol';
151 return 'Symbol'; 169 return 'Symbol';
152 } 170 }
153 171
154 @override 172 @override
155 JS.Statement visitCompilationUnit(CompilationUnit node) { 173 JS.Statement visitCompilationUnit(CompilationUnit node) {
156 var source = node.element.source; 174 var source = node.element.source;
157 175
158 _constEvaluator = new ConstantEvaluator(source, rules.provider); 176 _constEvaluator = new ConstantEvaluator(source, rules.provider);
159 _checkerReporter.enterSource(source); 177 _checkerReporter.enterSource(source);
160 178
161 // TODO(jmesserly): scriptTag, directives. 179 // TODO(jmesserly): scriptTag, directives.
162 var body = <JS.Statement>[]; 180 var body = <JS.Statement>[];
163 for (var child in node.declarations) { 181 for (var child in node.declarations) {
164 // Attempt to group adjacent fields/properties. 182 // Attempt to group adjacent fields/properties.
165 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); 183 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body);
166 if (child is! FunctionDeclaration) _flushLibraryProperties(body); 184 if (child is! FunctionDeclaration) _flushLibraryProperties(body);
167 185
168 var code = _visit(child); 186 var code = _visit(child);
169 187
170 if (code != null) { 188 if (code != null) {
171 if (_pendingPrivateNames.isNotEmpty) { 189 if (_pendingPrivateNames.isNotEmpty) {
172 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); 190 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol));
173 _pendingPrivateNames.clear(); 191 _pendingPrivateNames.clear();
174 } 192 }
193 if (_pendingExtensionMethodNames.isNotEmpty) {
194 body.addAll(_pendingExtensionMethodNames.map(_initExtensionMethodSymbo l));
195 _pendingExtensionMethodNames.clear();
196 }
175 body.add(code); 197 body.add(code);
176 } 198 }
177 } 199 }
178 200
179 // Flush any unwritten fields/properties. 201 // Flush any unwritten fields/properties.
180 _flushLazyFields(body); 202 _flushLazyFields(body);
181 _flushLibraryProperties(body); 203 _flushLibraryProperties(body);
182 204
183 _checkerReporter.leaveSource(); 205 _checkerReporter.leaveSource();
184 206
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 heritage = _emitTypeName(rules.provider.objectType); 519 heritage = _emitTypeName(rules.provider.objectType);
498 } 520 }
499 if (node.withClause != null) { 521 if (node.withClause != null) {
500 var mixins = _visitList(node.withClause.mixinTypes); 522 var mixins = _visitList(node.withClause.mixinTypes);
501 mixins.insert(0, heritage); 523 mixins.insert(0, heritage);
502 heritage = js.call('dart.mixin(#)', [mixins]); 524 heritage = js.call('dart.mixin(#)', [mixins]);
503 } 525 }
504 return heritage; 526 return heritage;
505 } 527 }
506 528
529 // TODO(jacobr): why doesn't the generic i1.isSubTypeOf(i2) work?
530 bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) {
531 if (i1 == i2) return true;
532
533 if (i1.element == i2.element) {
534 return true;
535 }
536
537 if (i2.isDartCoreFunction) {
538 if (i1.element.getMethod("call") != null) return true;
539 }
540
541 if (i1 == rules.provider.objectType) return false;
542
543 if (_isInterfaceSubTypeOf(i1.superclass, i2)) return true;
544
545 for (final parent in i1.interfaces) {
546 if (_isInterfaceSubTypeOf(parent, i2)) return true;
547 }
548
549 for (final parent in i1.mixins) {
550 if (_isInterfaceSubTypeOf(parent, i2)) return true;
551 }
552
553 return false;
554 }
555
507 /// Emit class members that can be generated as methods. 556 /// Emit class members that can be generated as methods.
508 /// Anything not handled here will be addressed in [_finishClassMembers]. 557 /// Anything not handled here will be addressed in [_finishClassMembers].
558 List<InterfaceType> getMatchingExtensionMethodTypes(InterfaceType type) {
559 var extensionTypes = <InterfaceType>[];
560 for (var extensionType in _JsExtensionMethodTypes) {
561 if (_isInterfaceSubTypeOf(type, extensionType)) {
562 extensionTypes.add(extensionType);
563 }
564 }
565 return extensionTypes;
566 }
567
568 LibraryElement lookupExtensionLibrary(Iterable<InterfaceType> extensionTypes, String name, {bool isGetter: false, bool isSetter: false}) {
569 var extensionLibrary;
570 assert (!isGetter || !isSetter);
571 for (var extensionType in extensionTypes) {
572 var match;
573 if (isGetter) {
574 match = extensionType.getGetter(name);
575 } else if (isSetter) {
576 match = extensionType.getSetter(name);
577 } else {
578 match = extensionType.getMethod(name);
579 }
580 // It is possible that the same method could need to be an extension
581 // method for classes defined in multiple libraries. Instead of handling
582 // that case we currently assert. The correct behavior is unclear so we
583 // might need to prevent this with a compile time error.
584 if (match != null) {
585 assert(extensionLibrary == null || extensionLibrary == extensionType.ele ment.library);
586 extensionLibrary = extensionType.element.library;
587 }
588 }
589 return extensionLibrary;
590 }
591
592 JS.Expression nameIfExtension(DartType targetType, String name, {bool isGetter : false, bool isSetter: false}) {
593 if (targetType is! InterfaceType) return null;
594 var extensionLibrary = lookupExtensionLibrary(getMatchingExtensionMethodType s(targetType), name, isGetter: isGetter, isSetter: isSetter);
595 if (extensionLibrary == null) return null;
596 return js.call('#.#', [_libraryName(extensionLibrary), _extensionMethodName( name)]);
597 }
598
509 List<JS.Method> _emitClassMethods(ClassDeclaration node, 599 List<JS.Method> _emitClassMethods(ClassDeclaration node,
510 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { 600 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
511 var element = node.element; 601 var element = node.element;
512 var isObject = element.type.isObject; 602 var isObject = element.type.isObject;
513 var name = node.name.name; 603 var name = node.name.name;
514 604
515 var jsMethods = <JS.Method>[]; 605 var jsMethods = <JS.Method>[];
516 // Iff no constructor is specified for a class C, it implicitly has a 606 // Iff no constructor is specified for a class C, it implicitly has a
517 // default constructor `C() : super() {}`, unless C is class Object. 607 // default constructor `C() : super() {}`, unless C is class Object.
518 if (ctors.isEmpty && !isObject) { 608 if (ctors.isEmpty && !isObject) {
519 jsMethods.add(_emitImplicitConstructor(node, name, fields)); 609 jsMethods.add(_emitImplicitConstructor(node, name, fields));
520 } 610 }
521 611 var extensionTypes = getMatchingExtensionMethodTypes(element.type);
522 for (var member in node.members) { 612 for (var member in node.members) {
523 if (member is ConstructorDeclaration) { 613 if (member is ConstructorDeclaration) {
524 jsMethods.add(_emitConstructor(member, name, fields, isObject)); 614 jsMethods.add(_emitConstructor(member, name, fields, isObject));
525 } else if (member is MethodDeclaration) { 615 } else if (member is MethodDeclaration) {
526 jsMethods.add(_visit(member)); 616 jsMethods.add(_visitMethodDeclaration(member, extensionTypes));
527 } 617 }
528 } 618 }
529 619
530 // Support for adapting dart:core Iterator/Iterable to ES6 versions. 620 // Support for adapting dart:core Iterator/Iterable to ES6 versions.
531 // This lets them use for-of loops transparently. 621 // This lets them use for-of loops transparently.
532 // https://github.com/lukehoban/es6features#iterators--forof 622 // https://github.com/lukehoban/es6features#iterators--forof
533 if (element.library.isDartCore && element.name == 'Iterable') { 623 if (element.library.isDartCore && element.name == 'Iterable') {
534 JS.Fun body = js.call('''function() { 624 JS.Fun body = js.call('''function() {
535 var iterator = this.iterator; 625 var iterator = this.iterator;
536 return { 626 return {
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 } 941 }
852 942
853 JS.Expression _defaultParamValue(FormalParameter param) { 943 JS.Expression _defaultParamValue(FormalParameter param) {
854 if (param is DefaultFormalParameter && param.defaultValue != null) { 944 if (param is DefaultFormalParameter && param.defaultValue != null) {
855 return _visit(param.defaultValue); 945 return _visit(param.defaultValue);
856 } else { 946 } else {
857 return new JS.LiteralNull(); 947 return new JS.LiteralNull();
858 } 948 }
859 } 949 }
860 950
861 @override 951 JS.Method _visitMethodDeclaration(MethodDeclaration node, List<InterfaceType> extensionTypes) {
862 JS.Method visitMethodDeclaration(MethodDeclaration node) {
863 if (node.isAbstract || _externalOrNative(node)) { 952 if (node.isAbstract || _externalOrNative(node)) {
864 return null; 953 return null;
865 } 954 }
866 955
867 var params = _visit(node.parameters); 956 var params = _visit(node.parameters);
868 if (params == null) params = []; 957 if (params == null) params = [];
869 958
870 return new JS.Method(_jsMemberName(node.name.name, isStatic: node.isStatic), 959 var extensionLibrary;
960 var memberName;
961 if (node.isStatic == false &&
962 (extensionLibrary = lookupExtensionLibrary(extensionTypes, node.name.name, i sGetter: node.isGetter, isSetter: node.isSetter)) != null) {
963 var extensionMethodName = _extensionMethodNameRaw(node.name.name);
964 if (extensionLibrary == libraryInfo.library.library) {
965 // TODO(jacobr): need to do a better job insuring that extension method
966 // name symbols do not conflict with other symbols before we can let
967 // user defined libraries define extension methods.
968 if (_extensionMethodNames.add(extensionMethodName)) {
969 _pendingExtensionMethodNames.add(extensionMethodName);
970 _exports.add(extensionMethodName);
971 }
972 }
973 memberName= js.call('#.#', [_libraryName(extensionLibrary), js.string(exte nsionMethodName, "'")]);
974 } else {
975 memberName = _jsMemberName(node.name.name, isStatic: node.isStatic);
976 }
977 return new JS.Method(memberName,
871 new JS.Fun(params, _visit(node.body)), 978 new JS.Fun(params, _visit(node.body)),
872 isGetter: node.isGetter, 979 isGetter: node.isGetter,
873 isSetter: node.isSetter, 980 isSetter: node.isSetter,
874 isStatic: node.isStatic); 981 isStatic: node.isStatic);
875 } 982 }
876 983
877 @override 984 @override
878 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { 985 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) {
879 assert(node.parent is CompilationUnit); 986 assert(node.parent is CompilationUnit);
880 987
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 } 1132 }
1026 1133
1027 bool _needQualifiedName(Element element) { 1134 bool _needQualifiedName(Element element) {
1028 var lib = element.library; 1135 var lib = element.library;
1029 1136
1030 return lib != null && 1137 return lib != null &&
1031 (lib != currentLibrary || 1138 (lib != currentLibrary ||
1032 element is ClassElement && _lazyClass(element)); 1139 element is ClassElement && _lazyClass(element));
1033 } 1140 }
1034 1141
1035 JS.Node _emitDPutIfDynamic( 1142 JS.Node _emitDSetIfDynamic(
1036 Expression target, SimpleIdentifier id, Expression rhs) { 1143 Expression target, SimpleIdentifier id, Expression rhs) {
1037 if (rules.isDynamicTarget(target)) { 1144 if (rules.isDynamicTarget(target)) {
1038 return js.call('dart.dput(#, #, #)', [ 1145 return js.call('dart.dput(#, #, #)', [
1039 _visit(target), 1146 _visit(target),
1040 js.string(id.name, "'"), 1147 js.string(id.name, "'"),
1041 _visit(rhs) 1148 _visit(rhs)
1042 ]); 1149 ]);
1043 } else { 1150 } else {
1044 return null; 1151 return null;
1045 } 1152 }
1046 } 1153 }
1047 1154
1048 @override 1155 @override
1049 JS.Node visitAssignmentExpression(AssignmentExpression node) { 1156 JS.Node visitAssignmentExpression(AssignmentExpression node) {
1050 var lhs = node.leftHandSide; 1157 var lhs = node.leftHandSide;
1051 var rhs = node.rightHandSide; 1158 var rhs = node.rightHandSide;
1052 return _emitAssignment(lhs, rhs, node.parent); 1159 return _emitSet(lhs, rhs, node.parent);
1053 } 1160 }
1054 1161
1055 JS.Node _emitAssignment(Expression lhs, Expression rhs, [AstNode parent]) { 1162 JS.Node _emitSet(Expression lhs, Expression rhs, [AstNode parent]) {
1056 if (lhs is IndexExpression) { 1163 if (lhs is IndexExpression) {
1057 String code; 1164 String code;
1058 var target = _getTarget(lhs); 1165 var target = _getTarget(lhs);
1059 if (rules.isDynamicTarget(target)) { 1166 if (rules.isDynamicTarget(target)) {
1060 code = 'dart.dsetindex(#, #, #)'; 1167 code = 'dart.dsetindex(#, #, #)';
1061 } else { 1168 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]);
1062 code = '#.set(#, #)';
1063 } 1169 }
1064 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]); 1170 var methodName = nameIfExtension(rules.getStaticType(target), "[]=");
1171 return js.call('#.#(#, #)', [_visit(target), methodName != null ? methodNa me: js.string('set'), _visit(lhs.index), _visit(rhs)]);
1065 } 1172 }
1066 1173
1067 if (lhs is PropertyAccess) { 1174 if (lhs is PropertyAccess) {
1068 var result = _emitDPutIfDynamic(_getTarget(lhs), lhs.propertyName, rhs); 1175 var result = _emitDSetIfDynamic(_getTarget(lhs), lhs.propertyName, rhs);
1069 if (result != null) return result; 1176 if (result != null) return result;
1070 } else if (lhs is PrefixedIdentifier) { 1177 } else if (lhs is PrefixedIdentifier) {
1071 // TODO(vsm): Is this the right code if the prefix is a library? 1178 // TODO(vsm): Is this the right code if the prefix is a library?
1072 var result = _emitDPutIfDynamic(lhs.prefix, lhs.identifier, rhs); 1179 var result = _emitDSetIfDynamic(lhs.prefix, lhs.identifier, rhs);
1073 if (result != null) return result; 1180 if (result != null) return result;
1074 } 1181 }
1075 1182
1076 if (parent is ExpressionStatement && 1183 if (parent is ExpressionStatement &&
1077 rhs is CascadeExpression && 1184 rhs is CascadeExpression &&
1078 _isStateless(lhs, rhs)) { 1185 _isStateless(lhs, rhs)) {
1079 // Special case: cascade assignment to a variable in a statement. 1186 // Special case: cascade assignment to a variable in a statement.
1080 // We can reuse the variable to desugar it: 1187 // We can reuse the variable to desugar it:
1081 // result = []..length = length; 1188 // result = []..length = length;
1082 // becomes: 1189 // becomes:
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1137 } else { 1244 } else {
1138 return js.call('dart.dinvokef(#, #)', [_visit(node.methodName), args]); 1245 return js.call('dart.dinvokef(#, #)', [_visit(node.methodName), args]);
1139 } 1246 }
1140 } 1247 }
1141 1248
1142 // TODO(jmesserly): if this resolves to a getter returning a function with 1249 // TODO(jmesserly): if this resolves to a getter returning a function with
1143 // a call method, we don't generate the `.call` correctly. 1250 // a call method, we don't generate the `.call` correctly.
1144 1251
1145 var targetJs; 1252 var targetJs;
1146 if (target != null) { 1253 if (target != null) {
1147 targetJs = js.call('#.#', [_visit(target), node.methodName.name]); 1254 var methodNameJs = nameIfExtension(rules.getStaticType(target), node.metho dName.name);
1255 targetJs = js.call('#.#', [_visit(target), methodNameJs != null ? methodNa meJs : node.methodName.name]);
1148 } else { 1256 } else {
1149 targetJs = _visit(node.methodName); 1257 targetJs = _visit(node.methodName);
1150 } 1258 }
1151 1259
1152 return js.call('#(#)', [targetJs, _visit(node.argumentList)]); 1260 return js.call('#(#)', [targetJs, _visit(node.argumentList)]);
1153 } 1261 }
1154 1262
1155 /// Emits code for the `JS(...)` builtin. 1263 /// Emits code for the `JS(...)` builtin.
1156 _emitForeignJS(MethodInvocation node) { 1264 _emitForeignJS(MethodInvocation node) {
1157 var e = node.methodName.staticElement; 1265 var e = node.methodName.staticElement;
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
1552 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { 1660 JS.Expression _emitPostfixIncrement(Expression expr, Token op) {
1553 var type = rules.getStaticType(expr); 1661 var type = rules.getStaticType(expr);
1554 assert(type != null); 1662 assert(type != null);
1555 var tmp = _createTemporary('x', type); 1663 var tmp = _createTemporary('x', type);
1556 1664
1557 // Increment and write 1665 // Increment and write
1558 var one = AstBuilder.integerLiteral(1); 1666 var one = AstBuilder.integerLiteral(1);
1559 one.staticType = rules.provider.intType; 1667 one.staticType = rules.provider.intType;
1560 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); 1668 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one);
1561 increment.staticType = type; 1669 increment.staticType = type;
1562 var write = _emitAssignment(expr, increment); 1670 var write = _emitSet(expr, increment);
1563 1671
1564 var bindThis = _maybeBindThis(expr); 1672 var bindThis = _maybeBindThis(expr);
1565 return js.call("((#) => (#, #))$bindThis(#)", [ 1673 return js.call("((#) => (#, #))$bindThis(#)", [
1566 _visit(tmp), 1674 _visit(tmp),
1567 write, 1675 write,
1568 _visit(tmp), 1676 _visit(tmp),
1569 _visit(expr) 1677 _visit(expr)
1570 ]); 1678 ]);
1571 } 1679 }
1572 1680
(...skipping 15 matching lines...) Expand all
1588 } 1696 }
1589 1697
1590 assert(op.lexeme == '++' || op.lexeme == '--'); 1698 assert(op.lexeme == '++' || op.lexeme == '--');
1591 return _emitPostfixIncrement(expr, op); 1699 return _emitPostfixIncrement(expr, op);
1592 } 1700 }
1593 1701
1594 JS.Expression _emitPrefixIncrement(Token op, Expression expr) { 1702 JS.Expression _emitPrefixIncrement(Token op, Expression expr) {
1595 var one = AstBuilder.integerLiteral(1); 1703 var one = AstBuilder.integerLiteral(1);
1596 one.staticType = rules.provider.intType; 1704 one.staticType = rules.provider.intType;
1597 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one); 1705 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one);
1598 return _emitAssignment(expr, increment); 1706 return _emitSet(expr, increment);
1599 } 1707 }
1600 1708
1601 @override 1709 @override
1602 JS.Expression visitPrefixExpression(PrefixExpression node) { 1710 JS.Expression visitPrefixExpression(PrefixExpression node) {
1603 return _emitPrefixExpression(node.operator, node.operand); 1711 return _emitPrefixExpression(node.operator, node.operand);
1604 } 1712 }
1605 1713
1606 JS.Expression _emitPrefixExpression(Token op, Expression expr) { 1714 JS.Expression _emitPrefixExpression(Token op, Expression expr) {
1607 var dispatchType = rules.getStaticType(expr); 1715 var dispatchType = rules.getStaticType(expr);
1608 if (unaryOperationIsPrimitive(dispatchType)) { 1716 if (unaryOperationIsPrimitive(dispatchType)) {
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1716 JS.This visitThisExpression(ThisExpression node) => new JS.This(); 1824 JS.This visitThisExpression(ThisExpression node) => new JS.This();
1717 1825
1718 @override 1826 @override
1719 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); 1827 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super();
1720 1828
1721 @override 1829 @override
1722 visitPrefixedIdentifier(PrefixedIdentifier node) { 1830 visitPrefixedIdentifier(PrefixedIdentifier node) {
1723 if (node.prefix.staticElement is PrefixElement) { 1831 if (node.prefix.staticElement is PrefixElement) {
1724 return _visit(node.identifier); 1832 return _visit(node.identifier);
1725 } else { 1833 } else {
1726 return _visitGet(node.prefix, node.identifier); 1834 return _emitGet(node.prefix, node.identifier);
1727 } 1835 }
1728 } 1836 }
1729 1837
1730 @override 1838 @override
1731 visitPropertyAccess(PropertyAccess node) => 1839 visitPropertyAccess(PropertyAccess node) =>
1732 _visitGet(_getTarget(node), node.propertyName); 1840 _emitGet(_getTarget(node), node.propertyName);
1733 1841
1734 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 1842 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
1735 _visitGet(Expression target, SimpleIdentifier name) { 1843 _emitGet(Expression target, SimpleIdentifier name) {
1736 if (rules.isDynamicTarget(target)) { 1844 if (rules.isDynamicTarget(target)) {
1737 return js.call( 1845 return js.call(
1738 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); 1846 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]);
1739 } else { 1847 } else {
1740 var e = name.staticElement; 1848 var e = name.staticElement;
1741 return js.call('#.#', [ 1849 bool isStatic = e is ExecutableElement && e.isStatic;
1850 var memberName;
1851 if (!isStatic) {
1852 memberName = nameIfExtension(rules.getStaticType(target), name.name, isG etter: true);
1853 }
1854
1855 var ret = js.call('#.#', [
1742 _visit(target), 1856 _visit(target),
1743 _jsMemberName(name.name, isStatic: e is ExecutableElement && e.isStatic) 1857 memberName != null ? memberName : _jsMemberName(name.name, isStatic: isS tatic)
1744 ]); 1858 ]);
1859 return ret;
1745 } 1860 }
1746 } 1861 }
1747 1862
1748 @override 1863 @override
1749 visitIndexExpression(IndexExpression node) { 1864 visitIndexExpression(IndexExpression node) {
1750 var target = _getTarget(node); 1865 var target = _getTarget(node);
1751 var code;
1752 if (rules.isDynamicTarget(target)) { 1866 if (rules.isDynamicTarget(target)) {
1753 code = 'dart.dindex(#, #)'; 1867 return js.call('dart.dindex(#, #)', [_visit(target), _visit(node.index)]);
1754 } else {
1755 code = '#.get(#)';
1756 } 1868 }
1757 return js.call(code, [_visit(target), _visit(node.index)]); 1869
1870 var targetJs = nameIfExtension(rules.getStaticType(target), '[]');
1871 return js.call('#.#(#)', [_visit(target), targetJs != null ? targetJs : js.s tring('get'), _visit(node.index)]);
1758 } 1872 }
1759 1873
1760 /// Gets the target of a [PropertyAccess] or [IndexExpression]. 1874 /// Gets the target of a [PropertyAccess] or [IndexExpression].
1761 /// Those two nodes are special because they're both allowed on left side of 1875 /// Those two nodes are special because they're both allowed on left side of
1762 /// an assignment expression and cascades. 1876 /// an assignment expression and cascades.
1763 Expression _getTarget(node) { 1877 Expression _getTarget(node) {
1764 assert(node is IndexExpression || node is PropertyAccess); 1878 assert(node is IndexExpression || node is PropertyAccess);
1765 return node.isCascaded ? _cascadeTarget : node.target; 1879 return node.isCascaded ? _cascadeTarget : node.target;
1766 } 1880 }
1767 1881
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
2139 /// 2253 ///
2140 /// Equality is a bit special, it is generated via the Dart `equals` runtime 2254 /// Equality is a bit special, it is generated via the Dart `equals` runtime
2141 /// helper, that checks for null. The user defined method is called '=='. 2255 /// helper, that checks for null. The user defined method is called '=='.
2142 /// 2256 ///
2143 JS.Expression _jsMemberName(String name, 2257 JS.Expression _jsMemberName(String name,
2144 {bool unary: false, bool isStatic: false}) { 2258 {bool unary: false, bool isStatic: false}) {
2145 if (name.startsWith('_')) { 2259 if (name.startsWith('_')) {
2146 if (_privateNames.add(name)) _pendingPrivateNames.add(name); 2260 if (_privateNames.add(name)) _pendingPrivateNames.add(name);
2147 return new JSTemporary(name); 2261 return new JSTemporary(name);
2148 } 2262 }
2149 if (name == '[]') { 2263 return _propertyName(_transformMemberNameHelper(name, unary: unary, isStatic : isStatic));
2150 name = 'get'; 2264 }
2151 } else if (name == '[]=') { 2265
2152 name = 'set'; 2266 String _transformMemberNameHelper(String name,
2153 } else if (unary && name == '-') { 2267 {bool unary: false, bool isStatic: false}) {
2154 name = 'unary-'; 2268 if (name == '[]') return 'get';
2155 } else if (isStatic && invalidJSStaticMethodName(name)) { 2269 if (name == '[]=') return 'set';
2270 if (unary && name == '-') return 'unary-';
2271 if (isStatic && invalidJSStaticMethodName(name)) {
2156 // Choose an string name. Use an invalid identifier so it won't conflict 2272 // Choose an string name. Use an invalid identifier so it won't conflict
2157 // with any valid member names. 2273 // with any valid member names.
2158 // TODO(jmesserly): this works around the problem, but I'm pretty sure we 2274 // TODO(jmesserly): this works around the problem, but I'm pretty sure we
2159 // don't need it, as static methods seemed to work. The only concrete 2275 // don't need it, as static methods seemed to work. The only concrete
2160 // issue we saw was in the defineNamedConstructor helper function. 2276 // issue we saw was in the defineNamedConstructor helper function.
2161 name = '$name*'; 2277 return '$name*';
2162 } 2278 }
2163 return _propertyName(name); 2279 return name;
2164 } 2280 }
2165 2281
2282
2283 // TODO(jacobr): we need to avoid possible collisions between extension
2284 // methods names and regular names.
2285 JS.LiteralString _extensionMethodName(String name) =>
2286 js.string(_extensionMethodNameRaw(name), "'");
2287
2288 String _extensionMethodNameRaw(String name) => '\$${_transformMemberNameHelper (name)}';
2289
2166 bool _externalOrNative(node) => 2290 bool _externalOrNative(node) =>
2167 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 2291 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
2168 2292
2169 FunctionBody _functionBody(node) => 2293 FunctionBody _functionBody(node) =>
2170 node is FunctionDeclaration ? node.functionExpression.body : node.body; 2294 node is FunctionDeclaration ? node.functionExpression.body : node.body;
2171 2295
2172 /// Choose a canonical name from the library element. 2296 /// Choose a canonical name from the library element.
2173 /// This never uses the library's name (the identifier in the `library` 2297 /// This never uses the library's name (the identifier in the `library`
2174 /// declaration) as it doesn't have any meaningful rules enforced. 2298 /// declaration) as it doesn't have any meaningful rules enforced.
2175 JS.Identifier _libraryName(LibraryElement library) { 2299 JS.Identifier _libraryName(LibraryElement library) {
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
2384 2508
2385 // TODO(jmesserly): in many cases marking the end will be unncessary. 2509 // TODO(jmesserly): in many cases marking the end will be unncessary.
2386 printer.mark(_location(node.end)); 2510 printer.mark(_location(node.end));
2387 } 2511 }
2388 2512
2389 String _getIdentifier(AstNode node) { 2513 String _getIdentifier(AstNode node) {
2390 if (node is SimpleIdentifier) return node.name; 2514 if (node is SimpleIdentifier) return node.name;
2391 return null; 2515 return null;
2392 } 2516 }
2393 } 2517 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698