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

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

Issue 1145833004: fixes #173, ability to use native JS indexers (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: merged Created 5 years, 6 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
« no previous file with comments | « no previous file | lib/src/utils.dart » ('j') | test/codegen/expect/sunflower/dom.js » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, 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 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 JS.Program emitLibrary(LibraryUnit library) { 102 JS.Program emitLibrary(LibraryUnit library) {
103 String jsDefaultValue = null; 103 String jsDefaultValue = null;
104 104
105 // Modify the AST to make coercions explicit. 105 // Modify the AST to make coercions explicit.
106 new CoercionReifier(library, compiler).reify(); 106 new CoercionReifier(library, compiler).reify();
107 107
108 var unit = library.library; 108 var unit = library.library;
109 if (unit.directives.isNotEmpty) { 109 if (unit.directives.isNotEmpty) {
110 var libraryDir = unit.directives.first; 110 var libraryDir = unit.directives.first;
111 if (libraryDir is LibraryDirective) { 111 if (libraryDir is LibraryDirective) {
112 var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation); 112 var jsName = findAnnotation(libraryDir.element, _isJsNameAnnotation);
113 jsDefaultValue = getConstantField(jsName, 'name', types.stringType); 113 jsDefaultValue = getConstantField(jsName, 'name', types.stringType);
114 } 114 }
115 } 115 }
116 if (jsDefaultValue == null) jsDefaultValue = '{}'; 116 if (jsDefaultValue == null) jsDefaultValue = '{}';
117 117
118 // TODO(jmesserly): visit scriptTag, directives? 118 // TODO(jmesserly): visit scriptTag, directives?
119 119
120 _loader.collectElements(currentLibrary, library.partsThenLibrary); 120 _loader.collectElements(currentLibrary, library.partsThenLibrary);
121 121
122 for (var unit in library.partsThenLibrary) { 122 for (var unit in library.partsThenLibrary) {
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 return js.statement('let # = #;', [dartClassName, jsTypeName]); 321 return js.statement('let # = #;', [dartClassName, jsTypeName]);
322 } 322 }
323 return null; 323 return null;
324 } 324 }
325 325
326 @override 326 @override
327 JS.Statement visitClassDeclaration(ClassDeclaration node) { 327 JS.Statement visitClassDeclaration(ClassDeclaration node) {
328 // If we've already emitted this class, skip it. 328 // If we've already emitted this class, skip it.
329 var classElem = node.element; 329 var classElem = node.element;
330 var type = classElem.type; 330 var type = classElem.type;
331 var jsName = getAnnotationValue(node, _isJsNameAnnotation); 331 var jsName = findAnnotation(classElem, _isJsNameAnnotation);
332 332
333 if (jsName != null) return _emitJsType(node.name.name, jsName); 333 if (jsName != null) return _emitJsType(node.name.name, jsName);
334 334
335 var ctors = <ConstructorDeclaration>[]; 335 var ctors = <ConstructorDeclaration>[];
336 var fields = <FieldDeclaration>[]; 336 var fields = <FieldDeclaration>[];
337 var methods = <MethodDeclaration>[]; 337 var methods = <MethodDeclaration>[];
338 for (var member in node.members) { 338 for (var member in node.members) {
339 if (member is ConstructorDeclaration) { 339 if (member is ConstructorDeclaration) {
340 ctors.add(member); 340 ctors.add(member);
341 } else if (member is FieldDeclaration && !member.isStatic) { 341 } else if (member is FieldDeclaration && !member.isStatic) {
342 fields.add(member); 342 fields.add(member);
343 } else if (member is MethodDeclaration) { 343 } else if (member is MethodDeclaration) {
344 methods.add(member); 344 methods.add(member);
345 } 345 }
346 } 346 }
347 347
348 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 348 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
349 _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); 349 _classHeritage(classElem), _emitClassMethods(node, ctors, fields));
350 350
351 String jsPeerName; 351 String jsPeerName;
352 var jsPeer = getAnnotationValue(node, _isJsPeerInterface); 352 var jsPeer = findAnnotation(classElem, _isJsPeerInterface);
353 if (jsPeer != null) { 353 if (jsPeer != null) {
354 jsPeerName = getConstantField(jsPeer, 'name', types.stringType); 354 jsPeerName = getConstantField(jsPeer, 'name', types.stringType);
355 } 355 }
356 356
357 var body = _finishClassMembers( 357 var body = _finishClassMembers(
358 classElem, classExpr, ctors, fields, methods, jsPeerName); 358 classElem, classExpr, ctors, fields, methods, jsPeerName);
359 359
360 var result = _finishClassDef(type, body); 360 var result = _finishClassDef(type, body);
361 361
362 if (jsPeerName != null) { 362 if (jsPeerName != null) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 var type = element.type; 467 var type = element.type;
468 var isObject = type.isObject; 468 var isObject = type.isObject;
469 469
470 // Iff no constructor is specified for a class C, it implicitly has a 470 // Iff no constructor is specified for a class C, it implicitly has a
471 // default constructor `C() : super() {}`, unless C is class Object. 471 // default constructor `C() : super() {}`, unless C is class Object.
472 var jsMethods = <JS.Method>[]; 472 var jsMethods = <JS.Method>[];
473 if (ctors.isEmpty && !isObject) { 473 if (ctors.isEmpty && !isObject) {
474 jsMethods.add(_emitImplicitConstructor(node, fields)); 474 jsMethods.add(_emitImplicitConstructor(node, fields));
475 } 475 }
476 476
477 bool hasJsPeer = getAnnotationValue(node, _isJsPeerInterface) != null; 477 bool hasJsPeer = findAnnotation(element, _isJsPeerInterface) != null;
478 478
479 bool hasIterator = false; 479 bool hasIterator = false;
480 for (var m in node.members) { 480 for (var m in node.members) {
481 if (m is ConstructorDeclaration) { 481 if (m is ConstructorDeclaration) {
482 jsMethods.add(_emitConstructor(m, type, fields, isObject)); 482 jsMethods.add(_emitConstructor(m, type, fields, isObject));
483 } else if (m is MethodDeclaration) { 483 } else if (m is MethodDeclaration) {
484 jsMethods.add(_emitMethodDeclaration(type, m)); 484 jsMethods.add(_emitMethodDeclaration(type, m));
485 485
486 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { 486 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') {
487 hasIterator = true; 487 hasIterator = true;
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after
1397 var vars = {}; 1397 var vars = {};
1398 var lhs = _bindLeftHandSide(vars, left, context: context); 1398 var lhs = _bindLeftHandSide(vars, left, context: context);
1399 var inc = AstBuilder.binaryExpression(lhs, op, right); 1399 var inc = AstBuilder.binaryExpression(lhs, op, right);
1400 inc.staticElement = element; 1400 inc.staticElement = element;
1401 inc.staticType = getStaticType(left); 1401 inc.staticType = getStaticType(left);
1402 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); 1402 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]);
1403 } 1403 }
1404 1404
1405 JS.Expression _emitSet(Expression lhs, Expression rhs) { 1405 JS.Expression _emitSet(Expression lhs, Expression rhs) {
1406 if (lhs is IndexExpression) { 1406 if (lhs is IndexExpression) {
1407 return _emitSend(_getTarget(lhs), '[]=', [lhs.index, rhs]); 1407 var target = _getTarget(lhs);
1408 if (_useNativeJsIndexer(target.staticType)) {
1409 return js.call(
1410 '#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]);
1411 }
1412 return _emitSend(target, '[]=', [lhs.index, rhs]);
1408 } 1413 }
1409 1414
1410 Expression target = null; 1415 Expression target = null;
1411 SimpleIdentifier id; 1416 SimpleIdentifier id;
1412 if (lhs is PropertyAccess) { 1417 if (lhs is PropertyAccess) {
1413 target = _getTarget(lhs); 1418 target = _getTarget(lhs);
1414 id = lhs.propertyName; 1419 id = lhs.propertyName;
1415 } else if (lhs is PrefixedIdentifier) { 1420 } else if (lhs is PrefixedIdentifier) {
1416 target = lhs.prefix; 1421 target = lhs.prefix;
1417 id = lhs.identifier; 1422 id = lhs.identifier;
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after
2188 _visitList(args) 2193 _visitList(args)
2189 ]); 2194 ]);
2190 } 2195 }
2191 2196
2192 // Generic dispatch to a statically known method. 2197 // Generic dispatch to a statically known method.
2193 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); 2198 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]);
2194 } 2199 }
2195 2200
2196 @override 2201 @override
2197 visitIndexExpression(IndexExpression node) { 2202 visitIndexExpression(IndexExpression node) {
2198 return _emitSend(_getTarget(node), '[]', [node.index]); 2203 var target = _getTarget(node);
2204 if (_useNativeJsIndexer(target.staticType)) {
2205 return new JS.PropertyAccess(_visit(target), _visit(node.index));
2206 }
2207 return _emitSend(target, '[]', [node.index]);
2199 } 2208 }
2200 2209
2210 // TODO(jmesserly): ideally we'd check the method and see if it is marked
2211 // `external`, but that doesn't work because it isn't in the element model.
2212 bool _useNativeJsIndexer(DartType type) =>
2213 findAnnotation(type.element, _isJsNameAnnotation) != null;
2214
2201 /// Gets the target of a [PropertyAccess] or [IndexExpression]. 2215 /// Gets the target of a [PropertyAccess] or [IndexExpression].
2202 /// Those two nodes are special because they're both allowed on left side of 2216 /// Those two nodes are special because they're both allowed on left side of
2203 /// an assignment expression and cascades. 2217 /// an assignment expression and cascades.
2204 Expression _getTarget(node) { 2218 Expression _getTarget(node) {
2205 assert(node is IndexExpression || node is PropertyAccess); 2219 assert(node is IndexExpression || node is PropertyAccess);
2206 return node.isCascaded ? _cascadeTarget : node.target; 2220 return node.isCascaded ? _cascadeTarget : node.target;
2207 } 2221 }
2208 2222
2209 @override 2223 @override
2210 visitConditionalExpression(ConditionalExpression node) { 2224 visitConditionalExpression(ConditionalExpression node) {
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after
2706 2720
2707 /// A special kind of element created by the compiler, signifying a temporary 2721 /// A special kind of element created by the compiler, signifying a temporary
2708 /// variable. These objects use instance equality, and should be shared 2722 /// variable. These objects use instance equality, and should be shared
2709 /// everywhere in the tree where they are treated as the same variable. 2723 /// everywhere in the tree where they are treated as the same variable.
2710 class TemporaryVariableElement extends LocalVariableElementImpl { 2724 class TemporaryVariableElement extends LocalVariableElementImpl {
2711 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 2725 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
2712 2726
2713 int get hashCode => identityHashCode(this); 2727 int get hashCode => identityHashCode(this);
2714 bool operator ==(Object other) => identical(this, other); 2728 bool operator ==(Object other) => identical(this, other);
2715 } 2729 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/utils.dart » ('j') | test/codegen/expect/sunflower/dom.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698