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

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

Issue 1245013002: some fixes for --strong warnings (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 5 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, 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 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 String jsDefaultValue = null; 115 String jsDefaultValue = null;
116 116
117 // Modify the AST to make coercions explicit. 117 // Modify the AST to make coercions explicit.
118 new CoercionReifier(library, compiler).reify(); 118 new CoercionReifier(library, compiler).reify();
119 119
120 var unit = library.library; 120 var unit = library.library;
121 if (unit.directives.isNotEmpty) { 121 if (unit.directives.isNotEmpty) {
122 var libraryDir = unit.directives.first; 122 var libraryDir = unit.directives.first;
123 if (libraryDir is LibraryDirective) { 123 if (libraryDir is LibraryDirective) {
124 var jsName = findAnnotation(libraryDir.element, _isJsNameAnnotation); 124 var jsName = findAnnotation(libraryDir.element, _isJsNameAnnotation);
125 jsDefaultValue = getConstantField(jsName, 'name', types.stringType); 125 jsDefaultValue =
126 getConstantField(jsName, 'name', types.stringType) as String;
126 } 127 }
127 } 128 }
128 129
129 // TODO(jmesserly): visit scriptTag, directives? 130 // TODO(jmesserly): visit scriptTag, directives?
130 131
131 _loader.collectElements(currentLibrary, library.partsThenLibrary); 132 _loader.collectElements(currentLibrary, library.partsThenLibrary);
132 133
133 for (var unit in library.partsThenLibrary) { 134 for (var unit in library.partsThenLibrary) {
134 _constField = new ConstFieldVisitor(types, unit); 135 _constField = new ConstFieldVisitor(types, unit);
135 136
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 // TODO(jmesserly): it would be great to run the renamer on the body, 178 // TODO(jmesserly): it would be great to run the renamer on the body,
178 // then figure out if we really need each of these parameters. 179 // then figure out if we really need each of these parameters.
179 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 180 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
180 var params = [_exportsVar, _runtimeLibVar]; 181 var params = [_exportsVar, _runtimeLibVar];
181 var processImport = (LibraryElement library, JS.TemporaryId temp, 182 var processImport = (LibraryElement library, JS.TemporaryId temp,
182 List list) { 183 List list) {
183 params.add(temp); 184 params.add(temp);
184 list.add(js.string(compiler.getModuleName(library.source.uri), "'")); 185 list.add(js.string(compiler.getModuleName(library.source.uri), "'"));
185 }; 186 };
186 187
187 var imports = [js.string('dart_runtime/dart')]; 188 var imports = <JS.Expression>[js.string('dart_runtime/dart')];
188 _imports.forEach((library, temp) { 189 _imports.forEach((library, temp) {
189 if (_loader.libraryIsLoaded(library)) { 190 if (_loader.libraryIsLoaded(library)) {
190 processImport(library, temp, imports); 191 processImport(library, temp, imports);
191 } 192 }
192 }); 193 });
193 194
194 var lazyImports = []; 195 var lazyImports = <JS.Expression>[];
195 _imports.forEach((library, temp) { 196 _imports.forEach((library, temp) {
196 if (!_loader.libraryIsLoaded(library)) { 197 if (!_loader.libraryIsLoaded(library)) {
197 processImport(library, temp, lazyImports); 198 processImport(library, temp, lazyImports);
198 } 199 }
199 }); 200 });
200 201
201 var dartxImport = 202 var dartxImport =
202 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); 203 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
203 204
204 var module = js.call("function(#) { 'use strict'; #; #; }", [ 205 var module = js.call("function(#) { 'use strict'; #; #; }", [
205 params, 206 params,
206 dartxImport, 207 dartxImport,
207 _moduleItems 208 _moduleItems
208 ]); 209 ]);
209 210
210 var program = [ 211 var program = <JS.Statement>[
211 js.statement("dart_library.library(#, #, #, #, #)", [ 212 js.statement("dart_library.library(#, #, #, #, #)", [
212 js.string(jsPath, "'"), 213 js.string(jsPath, "'"),
213 jsDefaultValue != null ? jsDefaultValue : new JS.LiteralNull(), 214 jsDefaultValue != null ? jsDefaultValue : new JS.LiteralNull(),
214 js.commentExpression( 215 js.commentExpression(
215 "Imports", new JS.ArrayInitializer(imports, multiline: true)), 216 "Imports", new JS.ArrayInitializer(imports, multiline: true)),
216 js.commentExpression("Lazy imports", 217 js.commentExpression("Lazy imports",
217 new JS.ArrayInitializer(lazyImports, multiline: true)), 218 new JS.ArrayInitializer(lazyImports, multiline: true)),
218 module 219 module
219 ]) 220 ])
220 ]; 221 ];
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 } 319 }
319 320
320 @override 321 @override
321 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); 322 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type);
322 323
323 @override 324 @override
324 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { 325 JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
325 var element = node.element; 326 var element = node.element;
326 327
327 // Forward all generative constructors from the base class. 328 // Forward all generative constructors from the base class.
328 var body = []; 329 var body = <JS.Method>[];
329 330
330 var supertype = element.supertype; 331 var supertype = element.supertype;
331 if (!supertype.isObject) { 332 if (!supertype.isObject) {
332 for (var ctor in element.constructors) { 333 for (var ctor in element.constructors) {
333 var parentCtor = supertype.lookUpConstructor(ctor.name, ctor.library); 334 var parentCtor = supertype.lookUpConstructor(ctor.name, ctor.library);
334 var fun = js.call('function() { super.#(...arguments); }', 335 var fun = js.call('function() { super.#(...arguments); }',
335 [_constructorName(parentCtor)]); 336 [_constructorName(parentCtor)]) as JS.Fun;
336 body.add(new JS.Method(_constructorName(ctor), fun)); 337 body.add(new JS.Method(_constructorName(ctor), fun));
337 } 338 }
338 } 339 }
339 340
340 var classDecl = new JS.ClassDeclaration(new JS.ClassExpression( 341 var classDecl = new JS.ClassDeclaration(new JS.ClassExpression(
341 new JS.Identifier(element.name), _classHeritage(element), body)); 342 new JS.Identifier(element.name), _classHeritage(element), body));
342 343
343 return _finishClassDef(element.type, classDecl); 344 return _finishClassDef(element.type, classDecl);
344 } 345 }
345 346
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 methods.add(member); 378 methods.add(member);
378 } 379 }
379 } 380 }
380 381
381 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 382 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
382 _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); 383 _classHeritage(classElem), _emitClassMethods(node, ctors, fields));
383 384
384 String jsPeerName; 385 String jsPeerName;
385 var jsPeer = findAnnotation(classElem, _isJsPeerInterface); 386 var jsPeer = findAnnotation(classElem, _isJsPeerInterface);
386 if (jsPeer != null) { 387 if (jsPeer != null) {
387 jsPeerName = getConstantField(jsPeer, 'name', types.stringType); 388 jsPeerName = getConstantField(jsPeer, 'name', types.stringType) as String;
388 } 389 }
389 390
390 var body = _finishClassMembers(classElem, classExpr, ctors, fields, methods, 391 var body = _finishClassMembers(classElem, classExpr, ctors, fields, methods,
391 node.metadata, jsPeerName); 392 node.metadata, jsPeerName);
392 393
393 var result = _finishClassDef(type, body); 394 var result = _finishClassDef(type, body);
394 395
395 if (jsPeerName != null) { 396 if (jsPeerName != null) {
396 // This class isn't allowed to be lazy, because we need to set up 397 // This class isn't allowed to be lazy, because we need to set up
397 // the native JS type eagerly at this point. 398 // the native JS type eagerly at this point.
(...skipping 19 matching lines...) Expand all
417 JS.Statement visitEnumDeclaration(EnumDeclaration node) { 418 JS.Statement visitEnumDeclaration(EnumDeclaration node) {
418 var element = node.element; 419 var element = node.element;
419 var type = element.type; 420 var type = element.type;
420 var name = js.string(type.name); 421 var name = js.string(type.name);
421 var id = new JS.Identifier(type.name); 422 var id = new JS.Identifier(type.name);
422 423
423 // Generate a class per section 13 of the spec. 424 // Generate a class per section 13 of the spec.
424 // TODO(vsm): Generate any accompanying metadata 425 // TODO(vsm): Generate any accompanying metadata
425 426
426 // Create constructor and initialize index 427 // Create constructor and initialize index
427 var constructor = 428 var constructor = new JS.Method(
428 new JS.Method(name, js.call('function(index) { this.index = index; }')); 429 name, js.call('function(index) { this.index = index; }') as JS.Fun);
429 var fields = new List<ConstFieldElementImpl>.from( 430 var fields = new List<ConstFieldElementImpl>.from(
430 element.fields.where((f) => f.type == type)); 431 element.fields.where((f) => f.type == type));
431 432
432 // Create toString() method 433 // Create toString() method
433 var properties = new List<JS.Property>(); 434 var properties = new List<JS.Property>();
434 for (var i = 0; i < fields.length; ++i) { 435 for (var i = 0; i < fields.length; ++i) {
435 properties.add(new JS.Property( 436 properties.add(new JS.Property(
436 js.number(i), js.string('${type.name}.${fields[i].name}'))); 437 js.number(i), js.string('${type.name}.${fields[i].name}')));
437 } 438 }
438 var nameMap = new JS.ObjectInitializer(properties, multiline: true); 439 var nameMap = new JS.ObjectInitializer(properties, multiline: true);
439 var toStringF = new JS.Method(js.string('toString'), 440 var toStringF = new JS.Method(js.string('toString'),
440 js.call('function () { return #[this.index]; }', nameMap)); 441 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun);
441 442
442 // Create enum class 443 // Create enum class
443 var classExpr = new JS.ClassExpression( 444 var classExpr = new JS.ClassExpression(
444 id, _classHeritage(element), [constructor, toStringF]); 445 id, _classHeritage(element), [constructor, toStringF]);
445 var result = [js.statement('#', classExpr)]; 446 var result = <JS.Statement>[js.statement('#', classExpr)];
446 447
447 // Create static fields for each enum value 448 // Create static fields for each enum value
448 for (var i = 0; i < fields.length; ++i) { 449 for (var i = 0; i < fields.length; ++i) {
449 result.add(js.statement('#.# = dart.const(new #(#));', [ 450 result.add(js.statement('#.# = dart.const(new #(#));', [
450 id, 451 id,
451 fields[i].name, 452 fields[i].name,
452 id, 453 id,
453 js.number(i) 454 js.number(i)
454 ])); 455 ]));
455 } 456 }
456 457
457 // Create static values list 458 // Create static values list
458 var values = new JS.ArrayInitializer( 459 var values = new JS.ArrayInitializer(new List<JS.Expression>.from(
459 fields.map((f) => js.call('#.#', [id, f.name])).toList()); 460 fields.map((f) => js.call('#.#', [id, f.name]))));
460 result.add(js.statement('#.values = dart.const(dart.list(#, #));', [ 461 result.add(js.statement('#.values = dart.const(dart.list(#, #));', [
461 id, 462 id,
462 values, 463 values,
463 _emitTypeName(type) 464 _emitTypeName(type)
464 ])); 465 ]));
465 466
466 return _statement(result); 467 return _statement(result);
467 } 468 }
468 469
469 /// Given a class element and body, complete the class declaration. 470 /// Given a class element and body, complete the class declaration.
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // simple code size optimization. 605 // simple code size optimization.
605 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); 606 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library);
606 if (parent != null) return null; 607 if (parent != null) return null;
607 var parentType = findSupertype(t, _implementsIterable); 608 var parentType = findSupertype(t, _implementsIterable);
608 if (parentType != null) return null; 609 if (parentType != null) return null;
609 610
610 // Otherwise, emit the adapter method, which wraps the Dart iterator in 611 // Otherwise, emit the adapter method, which wraps the Dart iterator in
611 // an ES6 iterator. 612 // an ES6 iterator.
612 return new JS.Method(js.call('$_SYMBOL.iterator'), js.call( 613 return new JS.Method(js.call('$_SYMBOL.iterator'), js.call(
613 'function() { return new dart.JsIterator(this.#); }', 614 'function() { return new dart.JsIterator(this.#); }',
614 [_emitMemberName('iterator', type: t)])); 615 [_emitMemberName('iterator', type: t)]) as JS.Fun);
615 } 616 }
616 617
617 JS.Expression _instantiateAnnotation(Annotation node) { 618 JS.Expression _instantiateAnnotation(Annotation node) {
618 var element = node.element; 619 var element = node.element;
619 if (element is ConstructorElement) { 620 if (element is ConstructorElement) {
620 return _emitInstanceCreationExpression(element, element.returnType, 621 return _emitInstanceCreationExpression(element, element.returnType,
621 node.constructorName, node.arguments, true); 622 node.constructorName, node.arguments, true);
622 } else { 623 } else {
623 return _visit(node.name); 624 return _visit(node.name);
624 } 625 }
625 } 626 }
626 627
627 /// Emit class members that need to come after the class declaration, such 628 /// Emit class members that need to come after the class declaration, such
628 /// as static fields. See [_emitClassMethods] for things that are emitted 629 /// as static fields. See [_emitClassMethods] for things that are emitted
629 /// inside the ES6 `class { ... }` node. 630 /// inside the ES6 `class { ... }` node.
630 JS.Statement _finishClassMembers(ClassElement classElem, 631 JS.Statement _finishClassMembers(ClassElement classElem,
631 JS.ClassExpression cls, List<ConstructorDeclaration> ctors, 632 JS.ClassExpression cls, List<ConstructorDeclaration> ctors,
632 List<FieldDeclaration> fields, List<MethodDeclaration> methods, 633 List<FieldDeclaration> fields, List<MethodDeclaration> methods,
633 List<Annotation> metadata, String jsPeerName) { 634 List<Annotation> metadata, String jsPeerName) {
634 var name = classElem.name; 635 var name = classElem.name;
635 var body = <JS.Statement>[]; 636 var body = <JS.Statement>[];
636 637
637 if (_extensionTypes.contains(classElem)) { 638 if (_extensionTypes.contains(classElem)) {
638 var dartxNames = []; 639 var dartxNames = <JS.Expression>[];
639 for (var m in methods) { 640 for (var m in methods) {
640 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 641 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
641 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); 642 dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
642 } 643 }
643 } 644 }
644 if (dartxNames.isNotEmpty) { 645 if (dartxNames.isNotEmpty) {
645 body.add(js.statement('dart.defineExtensionNames(#)', 646 body.add(js.statement('dart.defineExtensionNames(#)',
646 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 647 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
647 } 648 }
648 } 649 }
649 650
650 body.add(new JS.ClassDeclaration(cls)); 651 body.add(new JS.ClassDeclaration(cls));
651 652
652 // TODO(jmesserly): we should really just extend native Array. 653 // TODO(jmesserly): we should really just extend native Array.
653 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { 654 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
654 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', [ 655 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', [
655 classElem.name, 656 classElem.name,
656 _propertyName(jsPeerName) 657 _propertyName(jsPeerName)
657 ])); 658 ]));
658 } 659 }
659 660
660 // Interfaces 661 // Interfaces
661 if (classElem.interfaces.isNotEmpty) { 662 if (classElem.interfaces.isNotEmpty) {
662 body.add(js.statement('#[dart.implements] = () => #;', [ 663 body.add(js.statement('#[dart.implements] = () => #;', [
663 name, 664 name,
664 new JS.ArrayInitializer( 665 new JS.ArrayInitializer(new List<JS.Expression>.from(
665 classElem.interfaces.map(_emitTypeName).toList()) 666 classElem.interfaces.map(_emitTypeName)))
666 ])); 667 ]));
667 } 668 }
668 669
669 // Named constructors 670 // Named constructors
670 for (ConstructorDeclaration member in ctors) { 671 for (ConstructorDeclaration member in ctors) {
671 if (member.name != null && member.factoryKeyword == null) { 672 if (member.name != null && member.factoryKeyword == null) {
672 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ 673 body.add(js.statement('dart.defineNamedConstructor(#, #);', [
673 name, 674 name,
674 _emitMemberName(member.name.name, isStatic: true) 675 _emitMemberName(member.name.name, isStatic: true)
675 ])); 676 ]));
676 } 677 }
677 } 678 }
678 679
679 // Instance fields, if they override getter/setter pairs 680 // Instance fields, if they override getter/setter pairs
680 for (FieldDeclaration member in fields) { 681 for (FieldDeclaration member in fields) {
681 for (VariableDeclaration fieldDecl in member.fields.variables) { 682 for (VariableDeclaration fieldDecl in member.fields.variables) {
682 var field = fieldDecl.element; 683 var field = fieldDecl.element as FieldElement;
683 if (_fieldsNeedingStorage.contains(field)) { 684 if (_fieldsNeedingStorage.contains(field)) {
684 body.add(_overrideField(field)); 685 body.add(_overrideField(field));
685 } 686 }
686 } 687 }
687 } 688 }
688 689
689 // Emit the signature on the class recording the runtime type information 690 // Emit the signature on the class recording the runtime type information
690 { 691 {
691 var tStatics = []; 692 var tStatics = <JS.Property>[];
692 var tMethods = []; 693 var tMethods = <JS.Property>[];
693 var sNames = []; 694 var sNames = <JS.Expression>[];
694 for (MethodDeclaration node in methods) { 695 for (MethodDeclaration node in methods) {
695 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 696 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
696 var name = node.name.name; 697 var name = node.name.name;
697 var element = node.element; 698 var element = node.element;
698 var inheritedElement = 699 var inheritedElement =
699 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); 700 classElem.lookUpInheritedConcreteMethod(name, currentLibrary);
700 if (inheritedElement != null && 701 if (inheritedElement != null &&
701 inheritedElement.type == element.type) continue; 702 inheritedElement.type == element.type) continue;
702 var memberName = _elementMemberName(element); 703 var memberName = _elementMemberName(element);
703 var parts = _emitFunctionTypeParts(element.type); 704 var parts = _emitFunctionTypeParts(element.type);
704 var property = 705 var property =
705 new JS.Property(memberName, new JS.ArrayInitializer(parts)); 706 new JS.Property(memberName, new JS.ArrayInitializer(parts));
706 if (node.isStatic) { 707 if (node.isStatic) {
707 tStatics.add(property); 708 tStatics.add(property);
708 sNames.add(memberName); 709 sNames.add(memberName);
709 } else { 710 } else {
710 tMethods.add(property); 711 tMethods.add(property);
711 } 712 }
712 } 713 }
713 } 714 }
714 715
715 var tCtors = []; 716 var tCtors = <JS.Property>[];
716 for (ConstructorDeclaration node in ctors) { 717 for (ConstructorDeclaration node in ctors) {
717 var memberName = _constructorName(node.element); 718 var memberName = _constructorName(node.element);
718 var element = node.element; 719 var element = node.element;
719 var parts = _emitFunctionTypeParts(element.type); 720 var parts = _emitFunctionTypeParts(element.type);
720 var property = 721 var property =
721 new JS.Property(memberName, new JS.ArrayInitializer(parts)); 722 new JS.Property(memberName, new JS.ArrayInitializer(parts));
722 tCtors.add(property); 723 tCtors.add(property);
723 } 724 }
724 725
725 build(name, elements) { 726 JS.Property build(String name, List<JS.Property> elements) {
726 var o = 727 var o =
727 new JS.ObjectInitializer(elements, multiline: elements.length > 1); 728 new JS.ObjectInitializer(elements, multiline: elements.length > 1);
728 var e = js.call('() => #', o); 729 var e = js.call('() => #', o);
729 var p = new JS.Property(_propertyName(name), e); 730 return new JS.Property(_propertyName(name), e);
730 return p;
731 } 731 }
732 var sigFields = []; 732 var sigFields = <JS.Property>[];
733 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors)); 733 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors));
734 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods)); 734 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods));
735 if (!tStatics.isEmpty) { 735 if (!tStatics.isEmpty) {
736 assert(!sNames.isEmpty); 736 assert(!sNames.isEmpty);
737 var aNames = new JS.Property( 737 var aNames = new JS.Property(
738 _propertyName('names'), new JS.ArrayInitializer(sNames)); 738 _propertyName('names'), new JS.ArrayInitializer(sNames));
739 sigFields.add(build('statics', tStatics)); 739 sigFields.add(build('statics', tStatics));
740 sigFields.add(aNames); 740 sigFields.add(aNames);
741 } 741 }
742 if (!sigFields.isEmpty) { 742 if (!sigFields.isEmpty) {
743 var sig = new JS.ObjectInitializer(sigFields); 743 var sig = new JS.ObjectInitializer(sigFields);
744 var classExpr = new JS.Identifier(name); 744 var classExpr = new JS.Identifier(name);
745 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig])); 745 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig]));
746 } 746 }
747 } 747 }
748 748
749 // If a concrete class implements one of our extensions, we might need to 749 // If a concrete class implements one of our extensions, we might need to
750 // add forwarders. 750 // add forwarders.
751 var extensions = _extensionsToImplement(classElem); 751 var extensions = _extensionsToImplement(classElem);
752 if (extensions.isNotEmpty) { 752 if (extensions.isNotEmpty) {
753 var methodNames = []; 753 var methodNames = <JS.Expression>[];
754 for (var e in extensions) { 754 for (var e in extensions) {
755 methodNames.add(_elementMemberName(e)); 755 methodNames.add(_elementMemberName(e));
756 } 756 }
757 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ 757 body.add(js.statement('dart.defineExtensionMembers(#, #);', [
758 name, 758 name,
759 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) 759 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
760 ])); 760 ]));
761 } 761 }
762 762
763 // Metadata 763 // Metadata
764 if (metadata.isNotEmpty) { 764 if (metadata.isNotEmpty) {
765 body.add(js.statement('#[dart.metadata] = () => #;', [ 765 body.add(js.statement('#[dart.metadata] = () => #;', [
766 name, 766 name,
767 new JS.ArrayInitializer(metadata.map(_instantiateAnnotation).toList()) 767 new JS.ArrayInitializer(
768 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation)))
768 ])); 769 ]));
769 } 770 }
770 771
771 return _statement(body); 772 return _statement(body);
772 } 773 }
773 774
774 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 775 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
775 var members = <ExecutableElement>[]; 776 var members = <ExecutableElement>[];
776 if (_extensionTypes.contains(element)) return members; 777 if (_extensionTypes.contains(element)) return members;
777 778
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 ClassDeclaration node, List<FieldDeclaration> fields) { 828 ClassDeclaration node, List<FieldDeclaration> fields) {
828 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); 829 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty);
829 830
830 // If we don't have a method body, skip this. 831 // If we don't have a method body, skip this.
831 var superCall = _superConstructorCall(node.element); 832 var superCall = _superConstructorCall(node.element);
832 if (fields.isEmpty && superCall == null) return null; 833 if (fields.isEmpty && superCall == null) return null;
833 834
834 dynamic body = _initializeFields(node, fields); 835 dynamic body = _initializeFields(node, fields);
835 if (superCall != null) body = [[body, superCall]]; 836 if (superCall != null) body = [[body, superCall]];
836 var name = _constructorName(node.element.unnamedConstructor); 837 var name = _constructorName(node.element.unnamedConstructor);
837 return new JS.Method(name, js.call('function() { #; }', body)); 838 return new JS.Method(name, js.call('function() { #; }', body) as JS.Fun);
838 } 839 }
839 840
840 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type, 841 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type,
841 List<FieldDeclaration> fields, bool isObject) { 842 List<FieldDeclaration> fields, bool isObject) {
842 if (_externalOrNative(node)) return null; 843 if (_externalOrNative(node)) return null;
843 844
844 var name = _constructorName(node.element); 845 var name = _constructorName(node.element);
845 846
846 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; 847 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz;
847 var redirect = node.redirectedConstructor; 848 var redirect = node.redirectedConstructor;
848 if (redirect != null) { 849 if (redirect != null) {
849 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; 850 var newKeyword = redirect.staticElement.isFactory ? '' : 'new';
850 // Pass along all arguments verbatim, and let the callee handle them. 851 // Pass along all arguments verbatim, and let the callee handle them.
851 // TODO(jmesserly): we'll need something different once we have 852 // TODO(jmesserly): we'll need something different once we have
852 // rest/spread support, but this should work for now. 853 // rest/spread support, but this should work for now.
853 var params = _visit(node.parameters); 854 var params = _visit(node.parameters);
854 var fun = js.call('function(#) { return $newKeyword #(#); }', [ 855 var fun = js.call('function(#) { return $newKeyword #(#); }', [
855 params, 856 params,
856 _visit(redirect), 857 _visit(redirect),
857 params, 858 params,
858 ]); 859 ]) as JS.Fun;
859 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node; 860 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node;
860 } 861 }
861 862
862 // Factory constructors are essentially static methods. 863 // Factory constructors are essentially static methods.
863 if (node.factoryKeyword != null) { 864 if (node.factoryKeyword != null) {
864 var body = <JS.Statement>[]; 865 var body = <JS.Statement>[];
865 var init = _emitArgumentInitializers(node, constructor: true); 866 var init = _emitArgumentInitializers(node, constructor: true);
866 if (init != null) body.add(init); 867 if (init != null) body.add(init);
867 body.add(_visit(node.body)); 868 body.add(_visit(node.body));
868 var fun = new JS.Fun(_visit(node.parameters), new JS.Block(body)); 869 var fun = new JS.Fun(
870 _visit(node.parameters) as List<JS.Parameter>, new JS.Block(body));
869 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node; 871 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node;
870 } 872 }
871 873
872 // Code generation for Object's constructor. 874 // Code generation for Object's constructor.
873 JS.Block body; 875 JS.Block body;
874 if (isObject && 876 if (isObject &&
875 node.body is EmptyFunctionBody && 877 node.body is EmptyFunctionBody &&
876 node.constKeyword != null && 878 node.constKeyword != null &&
877 node.name == null) { 879 node.name == null) {
878 // Implements Dart constructor behavior. Because of V8 `super` 880 // Implements Dart constructor behavior. Because of V8 `super`
879 // [constructor restrictions] 881 // [constructor restrictions]
880 // (https://code.google.com/p/v8/issues/detail?id=3330#c65) 882 // (https://code.google.com/p/v8/issues/detail?id=3330#c65)
881 // we cannot currently emit actual ES6 constructors with super calls. 883 // we cannot currently emit actual ES6 constructors with super calls.
882 // Instead we use the same trick as named constructors, and do them as 884 // Instead we use the same trick as named constructors, and do them as
883 // instance methods that perform initialization. 885 // instance methods that perform initialization.
884 // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8 886 // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8
885 // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>. 887 // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>.
886 // Performance of this pattern is likely to be bad. 888 // Performance of this pattern is likely to be bad.
887 name = _propertyName('constructor'); 889 name = _propertyName('constructor');
888 // Mark the parameter as no-rename. 890 // Mark the parameter as no-rename.
889 body = js.statement('''{ 891 body = js.statement('''{
890 // Get the class name for this instance. 892 // Get the class name for this instance.
891 let name = this.constructor.name; 893 let name = this.constructor.name;
892 // Call the default constructor. 894 // Call the default constructor.
893 let result = void 0; 895 let result = void 0;
894 if (name in this) result = this[name](...arguments); 896 if (name in this) result = this[name](...arguments);
895 return result === void 0 ? this : result; 897 return result === void 0 ? this : result;
896 }'''); 898 }''') as JS.Block;
897 } else { 899 } else {
898 body = _emitConstructorBody(node, fields); 900 body = _emitConstructorBody(node, fields);
899 } 901 }
900 902
901 // We generate constructors as initializer methods in the class; 903 // We generate constructors as initializer methods in the class;
902 // this allows use of `super` for instance methods/properties. 904 // this allows use of `super` for instance methods/properties.
903 // It also avoids V8 restrictions on `super` in default constructors. 905 // It also avoids V8 restrictions on `super` in default constructors.
904 return new JS.Method(name, new JS.Fun(_visit(node.parameters), body)) 906 return new JS.Method(
907 name, new JS.Fun(_visit(node.parameters) as List<JS.Parameter>, body))
905 ..sourceInformation = node; 908 ..sourceInformation = node;
906 } 909 }
907 910
908 JS.Expression _constructorName(ConstructorElement ctor) { 911 JS.Expression _constructorName(ConstructorElement ctor) {
909 var name = ctor.name; 912 var name = ctor.name;
910 if (name != '') { 913 if (name != '') {
911 return _emitMemberName(name, isStatic: true); 914 return _emitMemberName(name, isStatic: true);
912 } 915 }
913 916
914 // Factory default constructors use `new` as their name, for readability 917 // Factory default constructors use `new` as their name, for readability
(...skipping 26 matching lines...) Expand all
941 944
942 if (redirectCall != null) { 945 if (redirectCall != null) {
943 body.add(_visit(redirectCall)); 946 body.add(_visit(redirectCall));
944 return new JS.Block(body); 947 return new JS.Block(body);
945 } 948 }
946 949
947 // Generate field initializers. 950 // Generate field initializers.
948 // These are expanded into each non-redirecting constructor. 951 // These are expanded into each non-redirecting constructor.
949 // In the future we may want to create an initializer function if we have 952 // In the future we may want to create an initializer function if we have
950 // multiple constructors, but it needs to be balanced against readability. 953 // multiple constructors, but it needs to be balanced against readability.
951 body.add(_initializeFields(node.parent, fields, node)); 954 body.add(_initializeFields(cls, fields, node));
952 955
953 var superCall = node.initializers.firstWhere( 956 var superCall = node.initializers.firstWhere(
954 (i) => i is SuperConstructorInvocation, orElse: () => null); 957 (i) => i is SuperConstructorInvocation,
958 orElse: () => null) as SuperConstructorInvocation;
955 959
956 // If no superinitializer is provided, an implicit superinitializer of the 960 // If no superinitializer is provided, an implicit superinitializer of the
957 // form `super()` is added at the end of the initializer list, unless the 961 // form `super()` is added at the end of the initializer list, unless the
958 // enclosing class is class Object. 962 // enclosing class is class Object.
959 var jsSuper = _superConstructorCall(cls.element, superCall); 963 var jsSuper = _superConstructorCall(cls.element, superCall);
960 if (jsSuper != null) body.add(jsSuper); 964 if (jsSuper != null) body.add(jsSuper);
961 965
962 body.add(_visit(node.body)); 966 body.add(_visit(node.body));
963 return new JS.Block(body)..sourceInformation = node; 967 return new JS.Block(body)..sourceInformation = node;
964 } 968 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 1018
1015 /// Initialize fields. They follow the sequence: 1019 /// Initialize fields. They follow the sequence:
1016 /// 1020 ///
1017 /// 1. field declaration initializer if non-const, 1021 /// 1. field declaration initializer if non-const,
1018 /// 2. field initializing parameters, 1022 /// 2. field initializing parameters,
1019 /// 3. constructor field initializers, 1023 /// 3. constructor field initializers,
1020 /// 4. initialize fields not covered in 1-3 1024 /// 4. initialize fields not covered in 1-3
1021 JS.Statement _initializeFields( 1025 JS.Statement _initializeFields(
1022 ClassDeclaration cls, List<FieldDeclaration> fieldDecls, 1026 ClassDeclaration cls, List<FieldDeclaration> fieldDecls,
1023 [ConstructorDeclaration ctor]) { 1027 [ConstructorDeclaration ctor]) {
1024 var unit = cls.getAncestor((a) => a is CompilationUnit); 1028 var unit = cls.getAncestor((a) => a is CompilationUnit) as CompilationUnit;
1025 var constField = new ConstFieldVisitor(types, unit); 1029 var constField = new ConstFieldVisitor(types, unit);
1026 bool isConst = ctor != null && ctor.constKeyword != null; 1030 bool isConst = ctor != null && ctor.constKeyword != null;
1027 if (isConst) _loader.startTopLevel(cls.element); 1031 if (isConst) _loader.startTopLevel(cls.element);
1028 1032
1029 // Run field initializers if they can have side-effects. 1033 // Run field initializers if they can have side-effects.
1030 var fields = new Map<FieldElement, JS.Expression>(); 1034 var fields = new Map<FieldElement, JS.Expression>();
1031 var unsetFields = new Map<FieldElement, VariableDeclaration>(); 1035 var unsetFields = new Map<FieldElement, VariableDeclaration>();
1032 for (var declaration in fieldDecls) { 1036 for (var declaration in fieldDecls) {
1033 for (var fieldNode in declaration.fields.variables) { 1037 for (var fieldNode in declaration.fields.variables) {
1034 var element = fieldNode.element; 1038 var element = fieldNode.element;
1035 if (constField.isFieldInitConstant(fieldNode)) { 1039 if (constField.isFieldInitConstant(fieldNode)) {
1036 unsetFields[element] = fieldNode; 1040 unsetFields[element as FieldElement] = fieldNode;
1037 } else { 1041 } else {
1038 fields[element] = _visitInitializer(fieldNode); 1042 fields[element as FieldElement] = _visitInitializer(fieldNode);
1039 } 1043 }
1040 } 1044 }
1041 } 1045 }
1042 1046
1043 // Initialize fields from `this.fieldName` parameters. 1047 // Initialize fields from `this.fieldName` parameters.
1044 if (ctor != null) { 1048 if (ctor != null) {
1045 for (var p in ctor.parameters.parameters) { 1049 for (var p in ctor.parameters.parameters) {
1046 var element = p.element; 1050 var element = p.element;
1047 if (element is FieldFormalParameterElement) { 1051 if (element is FieldFormalParameterElement) {
1048 fields[element.field] = _visit(p); 1052 fields[element.field] = _visit(p);
1049 } 1053 }
1050 } 1054 }
1051 1055
1052 // Run constructor field initializers such as `: foo = bar.baz` 1056 // Run constructor field initializers such as `: foo = bar.baz`
1053 for (var init in ctor.initializers) { 1057 for (var init in ctor.initializers) {
1054 if (init is ConstructorFieldInitializer) { 1058 if (init is ConstructorFieldInitializer) {
1055 fields[init.fieldName.staticElement] = _visit(init.expression); 1059 fields[init.fieldName.staticElement as FieldElement] =
1060 _visit(init.expression);
1056 } 1061 }
1057 } 1062 }
1058 } 1063 }
1059 1064
1060 for (var f in fields.keys) unsetFields.remove(f); 1065 for (var f in fields.keys) unsetFields.remove(f);
1061 1066
1062 // Initialize all remaining fields 1067 // Initialize all remaining fields
1063 unsetFields.forEach((element, fieldNode) { 1068 unsetFields.forEach((element, fieldNode) {
1064 JS.Expression value; 1069 JS.Expression value;
1065 if (fieldNode.initializer != null) { 1070 if (fieldNode.initializer != null) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1097 /// Emits argument initializers, which handles optional/named args, as well 1102 /// Emits argument initializers, which handles optional/named args, as well
1098 /// as generic type checks needed due to our covariance. 1103 /// as generic type checks needed due to our covariance.
1099 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) { 1104 JS.Statement _emitArgumentInitializers(node, {bool constructor: false}) {
1100 // Constructor argument initializers are emitted earlier in the code, rather 1105 // Constructor argument initializers are emitted earlier in the code, rather
1101 // than always when we visit the function body, so we control it explicitly. 1106 // than always when we visit the function body, so we control it explicitly.
1102 if (node is ConstructorDeclaration != constructor) return null; 1107 if (node is ConstructorDeclaration != constructor) return null;
1103 1108
1104 var parameters = _parametersOf(node); 1109 var parameters = _parametersOf(node);
1105 if (parameters == null) return null; 1110 if (parameters == null) return null;
1106 1111
1107 var body = []; 1112 var body = <JS.Statement>[];
1108 for (var param in parameters.parameters) { 1113 for (var param in parameters.parameters) {
1109 var jsParam = _visit(param.identifier); 1114 var jsParam = _visit(param.identifier);
1110 1115
1111 if (param.kind == ParameterKind.NAMED) { 1116 if (param.kind == ParameterKind.NAMED) {
1112 // Parameters will be passed using their real names, not the (possibly 1117 // Parameters will be passed using their real names, not the (possibly
1113 // renamed) local variable. 1118 // renamed) local variable.
1114 var paramName = js.string(param.identifier.name, "'"); 1119 var paramName = js.string(param.identifier.name, "'");
1115 body.add(js.statement('let # = # && # in # ? #.# : #;', [ 1120 body.add(js.statement('let # = # && # in # ? #.# : #;', [
1116 jsParam, 1121 jsParam,
1117 _namedArgTemp, 1122 _namedArgTemp,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1149 } else { 1154 } else {
1150 return new JS.LiteralNull(); 1155 return new JS.LiteralNull();
1151 } 1156 }
1152 } 1157 }
1153 1158
1154 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { 1159 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
1155 if (node.isAbstract || _externalOrNative(node)) { 1160 if (node.isAbstract || _externalOrNative(node)) {
1156 return null; 1161 return null;
1157 } 1162 }
1158 1163
1159 var params = _visit(node.parameters); 1164 var params = _visit(node.parameters) as List<JS.Parameter>;
1160 if (params == null) params = []; 1165 if (params == null) params = <JS.Parameter>[];
1161 1166
1162 return new JS.Method( 1167 return new JS.Method(
1163 _elementMemberName(node.element), _emitJsFunction(params, node.body), 1168 _elementMemberName(node.element), _emitJsFunction(params, node.body),
1164 isGetter: node.isGetter, 1169 isGetter: node.isGetter,
1165 isSetter: node.isSetter, 1170 isSetter: node.isSetter,
1166 isStatic: node.isStatic); 1171 isStatic: node.isStatic);
1167 } 1172 }
1168 1173
1169 @override 1174 @override
1170 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { 1175 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1234 if (lazy) { 1239 if (lazy) {
1235 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); 1240 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]);
1236 } 1241 }
1237 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); 1242 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
1238 } 1243 }
1239 throw 'Function has non function type: $type'; 1244 throw 'Function has non function type: $type';
1240 } 1245 }
1241 1246
1242 @override 1247 @override
1243 JS.Expression visitFunctionExpression(FunctionExpression node) { 1248 JS.Expression visitFunctionExpression(FunctionExpression node) {
1244 var params = _visit(node.parameters); 1249 var params = _visit(node.parameters) as List<JS.Parameter>;
1245 if (params == null) params = []; 1250 if (params == null) params = <JS.Parameter>[];
1246 1251
1247 var parent = node.parent; 1252 var parent = node.parent;
1248 var inStmt = parent.parent is FunctionDeclarationStatement; 1253 var inStmt = parent.parent is FunctionDeclarationStatement;
1249 if (parent is FunctionDeclaration) { 1254 if (parent is FunctionDeclaration) {
1250 return _emitJsFunction(params, node.body); 1255 return _emitJsFunction(params, node.body);
1251 } else { 1256 } else {
1252 String code; 1257 String code;
1253 AstNode body; 1258 AstNode body;
1254 var nodeBody = node.body; 1259 var nodeBody = node.body;
1255 if (nodeBody is ExpressionFunctionBody) { 1260 if (nodeBody is ExpressionFunctionBody) {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1370 if (name[0] == '#') { 1375 if (name[0] == '#') {
1371 return new JS.InterpolatedExpression(name.substring(1)); 1376 return new JS.InterpolatedExpression(name.substring(1));
1372 } else { 1377 } else {
1373 return _getTemp(element, name); 1378 return _getTemp(element, name);
1374 } 1379 }
1375 } 1380 }
1376 1381
1377 return new JS.Identifier(name); 1382 return new JS.Identifier(name);
1378 } 1383 }
1379 1384
1380 JS.TemporaryId _getTemp(Object key, String name) => 1385 JS.TemporaryId _getTemp(Element key, String name) =>
1381 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); 1386 _temps.putIfAbsent(key, () => new JS.TemporaryId(name));
1382 1387
1383 JS.ArrayInitializer _emitTypeNames(List<DartType> types) { 1388 JS.ArrayInitializer _emitTypeNames(List<DartType> types) {
1384 var build = (t) => _emitTypeName(t); 1389 return new JS.ArrayInitializer(
1385 return new JS.ArrayInitializer(types.map(build).toList()); 1390 new List<JS.Expression>.from(types.map(_emitTypeName)));
1386 } 1391 }
1387 1392
1388 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { 1393 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) {
1389 var properties = <JS.Property>[]; 1394 var properties = <JS.Property>[];
1390 types.forEach((name, type) { 1395 types.forEach((name, type) {
1391 var key = _propertyName(name); 1396 var key = _propertyName(name);
1392 var value = _emitTypeName(type); 1397 var value = _emitTypeName(type);
1393 properties.add(new JS.Property(key, value)); 1398 properties.add(new JS.Property(key, value));
1394 }); 1399 });
1395 return new JS.ObjectInitializer(properties); 1400 return new JS.ObjectInitializer(properties);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1497 JS.Expression visitAssignmentExpression(AssignmentExpression node) { 1502 JS.Expression visitAssignmentExpression(AssignmentExpression node) {
1498 var left = node.leftHandSide; 1503 var left = node.leftHandSide;
1499 var right = node.rightHandSide; 1504 var right = node.rightHandSide;
1500 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); 1505 if (node.operator.type == TokenType.EQ) return _emitSet(left, right);
1501 return _emitOpAssign( 1506 return _emitOpAssign(
1502 left, right, node.operator.lexeme[0], node.staticElement, 1507 left, right, node.operator.lexeme[0], node.staticElement,
1503 context: node); 1508 context: node);
1504 } 1509 }
1505 1510
1506 JS.MetaLet _emitOpAssign( 1511 JS.MetaLet _emitOpAssign(
1507 Expression left, Expression right, String op, ExecutableElement element, 1512 Expression left, Expression right, String op, MethodElement element,
1508 {Expression context}) { 1513 {Expression context}) {
1509 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions 1514 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions
1510 // (for example, x is IndexExpression) we evaluate those once. 1515 // (for example, x is IndexExpression) we evaluate those once.
1511 var vars = {}; 1516 var vars = <String, JS.Expression>{};
1512 var lhs = _bindLeftHandSide(vars, left, context: context); 1517 var lhs = _bindLeftHandSide(vars, left, context: context);
1513 var inc = AstBuilder.binaryExpression(lhs, op, right); 1518 var inc = AstBuilder.binaryExpression(lhs, op, right);
1514 inc.staticElement = element; 1519 inc.staticElement = element;
1515 inc.staticType = getStaticType(left); 1520 inc.staticType = getStaticType(left);
1516 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); 1521 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]);
1517 } 1522 }
1518 1523
1519 JS.Expression _emitSet(Expression lhs, Expression rhs) { 1524 JS.Expression _emitSet(Expression lhs, Expression rhs) {
1520 if (lhs is IndexExpression) { 1525 if (lhs is IndexExpression) {
1521 var target = _getTarget(lhs); 1526 var target = _getTarget(lhs);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1559 1564
1560 @override 1565 @override
1561 JS.Block visitBlockFunctionBody(BlockFunctionBody node) { 1566 JS.Block visitBlockFunctionBody(BlockFunctionBody node) {
1562 var initArgs = _emitArgumentInitializers(node.parent); 1567 var initArgs = _emitArgumentInitializers(node.parent);
1563 var block = visitBlock(node.block); 1568 var block = visitBlock(node.block);
1564 if (initArgs != null) return new JS.Block([initArgs, block]); 1569 if (initArgs != null) return new JS.Block([initArgs, block]);
1565 return block; 1570 return block;
1566 } 1571 }
1567 1572
1568 @override 1573 @override
1569 JS.Block visitBlock(Block node) => new JS.Block(_visitList(node.statements)); 1574 JS.Block visitBlock(Block node) =>
1575 new JS.Block(_visitList(node.statements) as List<JS.Statement>);
1570 1576
1571 @override 1577 @override
1572 visitMethodInvocation(MethodInvocation node) { 1578 visitMethodInvocation(MethodInvocation node) {
1573 var target = node.isCascaded ? _cascadeTarget : node.target; 1579 var target = node.isCascaded ? _cascadeTarget : node.target;
1574 1580
1575 var result = _emitForeignJS(node); 1581 var result = _emitForeignJS(node);
1576 if (result != null) return result; 1582 if (result != null) return result;
1577 1583
1578 String code; 1584 String code;
1579 if (target == null || isLibraryPrefix(target)) { 1585 if (target == null || isLibraryPrefix(target)) {
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
1729 if (v.initializer != null) { 1735 if (v.initializer != null) {
1730 var name = new JS.Identifier(v.name.name); 1736 var name = new JS.Identifier(v.name.name);
1731 return _visit(v.initializer).toVariableDeclaration(name); 1737 return _visit(v.initializer).toVariableDeclaration(name);
1732 } 1738 }
1733 } 1739 }
1734 return _visit(node.variables).toStatement(); 1740 return _visit(node.variables).toStatement();
1735 } 1741 }
1736 1742
1737 @override 1743 @override
1738 visitVariableDeclarationList(VariableDeclarationList node) { 1744 visitVariableDeclarationList(VariableDeclarationList node) {
1739 return new JS.VariableDeclarationList('let', _visitList(node.variables)); 1745 return new JS.VariableDeclarationList(
1746 'let', _visitList(node.variables) as List<JS.VariableInitialization>);
1740 } 1747 }
1741 1748
1742 @override 1749 @override
1743 visitVariableDeclaration(VariableDeclaration node) { 1750 visitVariableDeclaration(VariableDeclaration node) {
1744 if (node.element is PropertyInducingElement) return _emitStaticField(node); 1751 if (node.element is PropertyInducingElement) return _emitStaticField(node);
1745 1752
1746 var name = new JS.Identifier(node.name.name); 1753 var name = new JS.Identifier(node.name.name);
1747 return new JS.VariableInitialization(name, _visitInitializer(node)); 1754 return new JS.VariableInitialization(name, _visitInitializer(node));
1748 } 1755 }
1749 1756
(...skipping 22 matching lines...) Expand all
1772 // anything they depend on first. 1779 // anything they depend on first.
1773 1780
1774 if (isPublic(fieldName)) _addExport(fieldName); 1781 if (isPublic(fieldName)) _addExport(fieldName);
1775 return js.statement('let # = #;', [new JS.Identifier(fieldName), jsInit]); 1782 return js.statement('let # = #;', [new JS.Identifier(fieldName), jsInit]);
1776 } 1783 }
1777 1784
1778 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { 1785 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) {
1779 return js.statement('# = #;', [_visit(field.name), jsInit]); 1786 return js.statement('# = #;', [_visit(field.name), jsInit]);
1780 } 1787 }
1781 1788
1782 var body = []; 1789 var body = <JS.Statement>[];
1783 if (_lazyFields.isNotEmpty) { 1790 if (_lazyFields.isNotEmpty) {
1784 var existingTarget = _lazyFields[0].element.enclosingElement; 1791 var existingTarget = _lazyFields[0].element.enclosingElement;
1785 if (existingTarget != element.enclosingElement) { 1792 if (existingTarget != element.enclosingElement) {
1786 _flushLazyFields(body); 1793 _flushLazyFields(body);
1787 } 1794 }
1788 } 1795 }
1789 1796
1790 _lazyFields.add(field); 1797 _lazyFields.add(field);
1791 1798
1792 return _statement(body); 1799 return _statement(body);
(...skipping 11 matching lines...) Expand all
1804 body.add(_emitLazyFields(_lazyFields)); 1811 body.add(_emitLazyFields(_lazyFields));
1805 _lazyFields.clear(); 1812 _lazyFields.clear();
1806 } 1813 }
1807 1814
1808 JS.Statement _emitLazyFields(List<VariableDeclaration> fields) { 1815 JS.Statement _emitLazyFields(List<VariableDeclaration> fields) {
1809 var methods = []; 1816 var methods = [];
1810 for (var node in fields) { 1817 for (var node in fields) {
1811 var name = node.name.name; 1818 var name = node.name.name;
1812 var element = node.element; 1819 var element = node.element;
1813 var access = _emitMemberName(name, type: element.type, isStatic: true); 1820 var access = _emitMemberName(name, type: element.type, isStatic: true);
1814 methods.add(new JS.Method( 1821 methods.add(new JS.Method(access, js.call(
1815 access, js.call('function() { return #; }', _visit(node.initializer)), 1822 'function() { return #; }', _visit(node.initializer)) as JS.Fun,
1816 isGetter: true)); 1823 isGetter: true));
1817 1824
1818 // TODO(jmesserly): use a dummy setter to indicate writable. 1825 // TODO(jmesserly): use a dummy setter to indicate writable.
1819 if (!node.isFinal) { 1826 if (!node.isFinal) {
1820 methods.add( 1827 methods.add(new JS.Method(access, js.call('function(_) {}') as JS.Fun,
1821 new JS.Method(access, js.call('function(_) {}'), isSetter: true)); 1828 isSetter: true));
1822 } 1829 }
1823 } 1830 }
1824 1831
1825 JS.Expression objExpr = _exportsVar; 1832 JS.Expression objExpr = _exportsVar;
1826 var target = _lazyFields[0].element.enclosingElement; 1833 var target = _lazyFields[0].element.enclosingElement;
1827 if (target is ClassElement) { 1834 if (target is ClassElement) {
1828 objExpr = new JS.Identifier(target.type.name); 1835 objExpr = new JS.Identifier(target.type.name);
1829 } 1836 }
1830 1837
1831 return js.statement( 1838 return js.statement(
(...skipping 20 matching lines...) Expand all
1852 } 1859 }
1853 1860
1854 @override 1861 @override
1855 visitConstructorName(ConstructorName node) { 1862 visitConstructorName(ConstructorName node) {
1856 return _emitConstructorName(node.staticElement, node.type.type, node.name); 1863 return _emitConstructorName(node.staticElement, node.type.type, node.name);
1857 } 1864 }
1858 1865
1859 JS.Expression _emitInstanceCreationExpression(ConstructorElement element, 1866 JS.Expression _emitInstanceCreationExpression(ConstructorElement element,
1860 DartType type, SimpleIdentifier name, ArgumentList argumentList, 1867 DartType type, SimpleIdentifier name, ArgumentList argumentList,
1861 bool isConst) { 1868 bool isConst) {
1862 emitNew() { 1869 JS.Expression emitNew() {
1863 JS.Expression ctor; 1870 JS.Expression ctor;
1864 bool isFactory = false; 1871 bool isFactory = false;
1865 // var element = node.staticElement; 1872 // var element = node.staticElement;
1866 if (element == null) { 1873 if (element == null) {
1867 // TODO(jmesserly): this only happens if we had a static error. 1874 // TODO(jmesserly): this only happens if we had a static error.
1868 // Should we generate a throw instead? 1875 // Should we generate a throw instead?
1869 ctor = _emitTypeName(type); 1876 ctor = _emitTypeName(type);
1870 if (name != null) { 1877 if (name != null) {
1871 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); 1878 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name));
1872 } 1879 }
1873 } else { 1880 } else {
1874 ctor = _emitConstructorName(element, type, name); 1881 ctor = _emitConstructorName(element, type, name);
1875 isFactory = element.isFactory; 1882 isFactory = element.isFactory;
1876 } 1883 }
1877 var args = _visit(argumentList); 1884 var args = _visit(argumentList) as List<JS.Expression>;
1878 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args); 1885 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args);
1879 } 1886 }
1880 if (isConst) return _emitConst(emitNew); 1887 if (isConst) return _emitConst(emitNew);
1881 return emitNew(); 1888 return emitNew();
1882 } 1889 }
1883 1890
1884 @override 1891 @override
1885 visitInstanceCreationExpression(InstanceCreationExpression node) { 1892 visitInstanceCreationExpression(InstanceCreationExpression node) {
1886 var element = node.staticElement; 1893 var element = node.staticElement;
1887 var constructor = node.constructorName; 1894 var constructor = node.constructorName;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
2091 index.leftBracket, 2098 index.leftBracket,
2092 _bindValue(scope, 'i', index.index, context: context), 2099 _bindValue(scope, 'i', index.index, context: context),
2093 index.rightBracket); 2100 index.rightBracket);
2094 } else if (expr is PropertyAccess) { 2101 } else if (expr is PropertyAccess) {
2095 PropertyAccess prop = expr; 2102 PropertyAccess prop = expr;
2096 result = new PropertyAccess( 2103 result = new PropertyAccess(
2097 _bindValue(scope, 'o', _getTarget(prop), context: context), 2104 _bindValue(scope, 'o', _getTarget(prop), context: context),
2098 prop.operator, prop.propertyName); 2105 prop.operator, prop.propertyName);
2099 } else if (expr is PrefixedIdentifier) { 2106 } else if (expr is PrefixedIdentifier) {
2100 PrefixedIdentifier ident = expr; 2107 PrefixedIdentifier ident = expr;
2101 result = new PrefixedIdentifier( 2108 result = new PrefixedIdentifier(_bindValue(scope, 'o', ident.prefix,
2102 _bindValue(scope, 'o', ident.prefix, context: context), ident.period, 2109 context: context) as SimpleIdentifier, ident.period,
2103 ident.identifier); 2110 ident.identifier);
2104 } else { 2111 } else {
2105 return expr as SimpleIdentifier; 2112 return expr as SimpleIdentifier;
2106 } 2113 }
2107 result.staticType = expr.staticType; 2114 result.staticType = expr.staticType;
2108 DynamicInvoke.set(result, DynamicInvoke.get(expr)); 2115 DynamicInvoke.set(result, DynamicInvoke.get(expr));
2109 return result; 2116 return result;
2110 } 2117 }
2111 2118
2112 /// Creates a temporary to contain the value of [expr]. The temporary can be 2119 /// Creates a temporary to contain the value of [expr]. The temporary can be
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2157 if (unaryOperationIsPrimitive(dispatchType)) { 2164 if (unaryOperationIsPrimitive(dispatchType)) {
2158 if (_isNonNullableExpression(expr)) { 2165 if (_isNonNullableExpression(expr)) {
2159 return js.call('#$op', _visit(expr)); 2166 return js.call('#$op', _visit(expr));
2160 } 2167 }
2161 } 2168 }
2162 2169
2163 assert(op.lexeme == '++' || op.lexeme == '--'); 2170 assert(op.lexeme == '++' || op.lexeme == '--');
2164 2171
2165 // Handle the left hand side, to ensure each of its subexpressions are 2172 // Handle the left hand side, to ensure each of its subexpressions are
2166 // evaluated only once. 2173 // evaluated only once.
2167 var vars = {}; 2174 var vars = <String, JS.Expression>{};
2168 var left = _bindLeftHandSide(vars, expr, context: expr); 2175 var left = _bindLeftHandSide(vars, expr, context: expr);
2169 2176
2170 // Desugar `x++` as `(x1 = x0 + 1, x0)` where `x0` is the original value 2177 // Desugar `x++` as `(x1 = x0 + 1, x0)` where `x0` is the original value
2171 // and `x1` is the new value for `x`. 2178 // and `x1` is the new value for `x`.
2172 var x = _bindValue(vars, 'x', left, context: expr); 2179 var x = _bindValue(vars, 'x', left, context: expr);
2173 2180
2174 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; 2181 var one = AstBuilder.integerLiteral(1)..staticType = types.intType;
2175 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) 2182 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one)
2176 ..staticElement = node.staticElement 2183 ..staticElement = node.staticElement
2177 ..staticType = getStaticType(expr); 2184 ..staticType = getStaticType(expr);
2178 2185
2179 var body = [_emitSet(left, increment), _visit(x)]; 2186 var body = <JS.Expression>[_emitSet(left, increment), _visit(x)];
2180 return new JS.MetaLet(vars, body, statelessResult: true); 2187 return new JS.MetaLet(vars, body, statelessResult: true);
2181 } 2188 }
2182 2189
2183 @override 2190 @override
2184 JS.Expression visitPrefixExpression(PrefixExpression node) { 2191 JS.Expression visitPrefixExpression(PrefixExpression node) {
2185 var op = node.operator; 2192 var op = node.operator;
2186 var expr = node.operand; 2193 var expr = node.operand;
2187 2194
2188 var dispatchType = getStaticType(expr); 2195 var dispatchType = getStaticType(expr);
2189 if (unaryOperationIsPrimitive(dispatchType)) { 2196 if (unaryOperationIsPrimitive(dispatchType)) {
2190 if (_isNonNullableExpression(expr)) { 2197 if (_isNonNullableExpression(expr)) {
2191 return js.call('$op#', _visit(expr)); 2198 return js.call('$op#', _visit(expr));
2192 } else if (op.lexeme == '++' || op.lexeme == '--') { 2199 } else if (op.lexeme == '++' || op.lexeme == '--') {
2193 // We need a null check, so the increment must be expanded out. 2200 // We need a null check, so the increment must be expanded out.
2194 var mathop = op.lexeme[0]; 2201 var mathop = op.lexeme[0];
2195 var vars = {}; 2202 var vars = <String, JS.Expression>{};
2196 var x = _bindLeftHandSide(vars, expr, context: expr); 2203 var x = _bindLeftHandSide(vars, expr, context: expr);
2197 var body = js.call('# = # $mathop 1', [_visit(x), notNull(x)]); 2204 var body = js.call('# = # $mathop 1', [_visit(x), notNull(x)]);
2198 return new JS.MetaLet(vars, [body]); 2205 return new JS.MetaLet(vars, [body]);
2199 } else { 2206 } else {
2200 return js.call('$op#', notNull(expr)); 2207 return js.call('$op#', notNull(expr));
2201 } 2208 }
2202 } 2209 }
2203 2210
2204 if (op.lexeme == '++' || op.lexeme == '--') { 2211 if (op.lexeme == '++' || op.lexeme == '--') {
2205 // Increment or decrement requires expansion. 2212 // Increment or decrement requires expansion.
2206 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions 2213 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions
2207 // (for example, x is IndexExpression) we evaluate those once. 2214 // (for example, x is IndexExpression) we evaluate those once.
2208 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; 2215 var one = AstBuilder.integerLiteral(1)..staticType = types.intType;
2209 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement, 2216 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement,
2210 context: expr); 2217 context: expr);
2211 } 2218 }
2212 2219
2213 return _emitSend(expr, op.lexeme[0], []); 2220 return _emitSend(expr, op.lexeme[0], []);
2214 } 2221 }
2215 2222
2216 // Cascades can contain [IndexExpression], [MethodInvocation] and 2223 // Cascades can contain [IndexExpression], [MethodInvocation] and
2217 // [PropertyAccess]. The code generation for those is handled in their 2224 // [PropertyAccess]. The code generation for those is handled in their
2218 // respective visit methods. 2225 // respective visit methods.
2219 @override 2226 @override
2220 JS.Node visitCascadeExpression(CascadeExpression node) { 2227 JS.Node visitCascadeExpression(CascadeExpression node) {
2221 var savedCascadeTemp = _cascadeTarget; 2228 var savedCascadeTemp = _cascadeTarget;
2222 2229
2223 var vars = {}; 2230 var vars = <String, JS.Expression>{};
2224 _cascadeTarget = _bindValue(vars, '_', node.target, context: node); 2231 _cascadeTarget =
2225 var sections = _visitList(node.cascadeSections); 2232 _bindValue(vars, '_', node.target, context: node) as SimpleIdentifier;
2233 var sections = _visitList(node.cascadeSections) as List<JS.Expression>;
2226 sections.add(_visit(_cascadeTarget)); 2234 sections.add(_visit(_cascadeTarget));
2227 var result = new JS.MetaLet(vars, sections, statelessResult: true); 2235 var result = new JS.MetaLet(vars, sections, statelessResult: true);
2228 _cascadeTarget = savedCascadeTemp; 2236 _cascadeTarget = savedCascadeTemp;
2229 return result; 2237 return result;
2230 } 2238 }
2231 2239
2232 @override 2240 @override
2233 visitParenthesizedExpression(ParenthesizedExpression node) => 2241 visitParenthesizedExpression(ParenthesizedExpression node) =>
2234 // The printer handles precedence so we don't need to. 2242 // The printer handles precedence so we don't need to.
2235 _visit(node.expression); 2243 _visit(node.expression);
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
2463 if (clause.exceptionType == null) return then; 2471 if (clause.exceptionType == null) return then;
2464 2472
2465 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which 2473 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which
2466 // has special case for typeof. 2474 // has special case for typeof.
2467 return new JS.If(js.call('dart.is(#, #)', [ 2475 return new JS.If(js.call('dart.is(#, #)', [
2468 _visit(_catchParameter), 2476 _visit(_catchParameter),
2469 _emitTypeName(clause.exceptionType.type), 2477 _emitTypeName(clause.exceptionType.type),
2470 ]), then, otherwise); 2478 ]), then, otherwise);
2471 } 2479 }
2472 2480
2473 JS.Statement _statement(Iterable stmts) { 2481 JS.Statement _statement(List<JS.Statement> statements) {
2474 List s = stmts is List ? stmts : new List<JS.Statement>.from(stmts);
2475 // TODO(jmesserly): empty block singleton? 2482 // TODO(jmesserly): empty block singleton?
2476 if (s.length == 0) return new JS.Block([]); 2483 if (statements.length == 0) return new JS.Block([]);
2477 if (s.length == 1) return s[0]; 2484 if (statements.length == 1) return statements[0];
2478 return new JS.Block(s); 2485 return new JS.Block(statements);
2479 } 2486 }
2480 2487
2481 /// Visits the catch clause body. This skips the exception type guard, if any. 2488 /// Visits the catch clause body. This skips the exception type guard, if any.
2482 /// That is handled in [_visitCatch]. 2489 /// That is handled in [_visitCatch].
2483 @override 2490 @override
2484 JS.Statement visitCatchClause(CatchClause node) { 2491 JS.Statement visitCatchClause(CatchClause node) {
2485 var body = []; 2492 var body = <JS.Statement>[];
2486 2493
2487 var savedCatch = _catchParameter; 2494 var savedCatch = _catchParameter;
2488 if (node.catchKeyword != null) { 2495 if (node.catchKeyword != null) {
2489 var name = node.exceptionParameter; 2496 var name = node.exceptionParameter;
2490 if (name != null && name != _catchParameter) { 2497 if (name != null && name != _catchParameter) {
2491 body.add(js.statement( 2498 body.add(js.statement(
2492 'let # = #;', [_visit(name), _visit(_catchParameter)])); 2499 'let # = #;', [_visit(name), _visit(_catchParameter)]));
2493 _catchParameter = name; 2500 _catchParameter = name;
2494 } 2501 }
2495 if (node.stackTraceParameter != null) { 2502 if (node.stackTraceParameter != null) {
2496 var stackVar = node.stackTraceParameter.name; 2503 var stackVar = node.stackTraceParameter.name;
2497 body.add(js.statement( 2504 body.add(js.statement(
2498 'let # = dart.stackTrace(#);', [stackVar, _visit(name)])); 2505 'let # = dart.stackTrace(#);', [stackVar, _visit(name)]));
2499 } 2506 }
2500 } 2507 }
2501 2508
2502 body.add(_visit(node.body)); 2509 body.add(_visit(node.body));
2503 _catchParameter = savedCatch; 2510 _catchParameter = savedCatch;
2504 return _statement(body); 2511 return _statement(body);
2505 } 2512 }
2506 2513
2507 @override 2514 @override
2508 JS.Case visitSwitchCase(SwitchCase node) { 2515 JS.Case visitSwitchCase(SwitchCase node) {
2509 var expr = _visit(node.expression); 2516 var expr = _visit(node.expression);
2510 var body = _visitList(node.statements); 2517 var body = _visitList(node.statements) as List<JS.Statement>;
2511 if (node.labels.isNotEmpty) { 2518 if (node.labels.isNotEmpty) {
2512 body.insert(0, js.comment('Unimplemented case labels: ${node.labels}')); 2519 body.insert(0, js.comment('Unimplemented case labels: ${node.labels}'));
2513 } 2520 }
2514 // TODO(jmesserly): make sure we are statically checking fall through 2521 // TODO(jmesserly): make sure we are statically checking fall through
2515 return new JS.Case(expr, new JS.Block(body)); 2522 return new JS.Case(expr, new JS.Block(body));
2516 } 2523 }
2517 2524
2518 @override 2525 @override
2519 JS.Default visitSwitchDefault(SwitchDefault node) { 2526 JS.Default visitSwitchDefault(SwitchDefault node) {
2520 var body = _visitList(node.statements); 2527 var body = _visitList(node.statements) as List<JS.Statement>;
2521 if (node.labels.isNotEmpty) { 2528 if (node.labels.isNotEmpty) {
2522 body.insert(0, js.comment('Unimplemented case labels: ${node.labels}')); 2529 body.insert(0, js.comment('Unimplemented case labels: ${node.labels}'));
2523 } 2530 }
2524 // TODO(jmesserly): make sure we are statically checking fall through 2531 // TODO(jmesserly): make sure we are statically checking fall through
2525 return new JS.Default(new JS.Block(body)); 2532 return new JS.Default(new JS.Block(body));
2526 } 2533 }
2527 2534
2528 @override 2535 @override
2529 JS.Switch visitSwitchStatement(SwitchStatement node) => 2536 JS.Switch visitSwitchStatement(SwitchStatement node) => new JS.Switch(
2530 new JS.Switch(_visit(node.expression), _visitList(node.members)); 2537 _visit(node.expression),
2538 _visitList(node.members) as List<JS.SwitchClause>);
2531 2539
2532 @override 2540 @override
2533 JS.Statement visitLabeledStatement(LabeledStatement node) { 2541 JS.Statement visitLabeledStatement(LabeledStatement node) {
2534 var result = _visit(node.statement); 2542 var result = _visit(node.statement);
2535 for (var label in node.labels.reversed) { 2543 for (var label in node.labels.reversed) {
2536 result = new JS.LabeledStatement(label.label.name, result); 2544 result = new JS.LabeledStatement(label.label.name, result);
2537 } 2545 }
2538 return result; 2546 return result;
2539 } 2547 }
2540 2548
2541 @override 2549 @override
2542 visitIntegerLiteral(IntegerLiteral node) => js.number(node.value); 2550 visitIntegerLiteral(IntegerLiteral node) => js.number(node.value);
2543 2551
2544 @override 2552 @override
2545 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value); 2553 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value);
2546 2554
2547 @override 2555 @override
2548 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); 2556 visitNullLiteral(NullLiteral node) => new JS.LiteralNull();
2549 2557
2550 @override 2558 @override
2551 visitSymbolLiteral(SymbolLiteral node) { 2559 visitSymbolLiteral(SymbolLiteral node) {
2552 emitSymbol() { 2560 JS.New emitSymbol() {
2553 // TODO(vsm): When we canonicalize, we need to treat private symbols 2561 // TODO(vsm): When we canonicalize, we need to treat private symbols
2554 // correctly. 2562 // correctly.
2555 var name = js.string(node.components.join('.'), "'"); 2563 var name = js.string(node.components.join('.'), "'");
2556 return new JS.New(_emitTypeName(types.symbolType), [name]); 2564 return new JS.New(_emitTypeName(types.symbolType), [name]);
2557 } 2565 }
2558 return _emitConst(emitSymbol); 2566 return _emitConst(emitSymbol);
2559 } 2567 }
2560 2568
2561 @override 2569 @override
2562 visitListLiteral(ListLiteral node) { 2570 visitListLiteral(ListLiteral node) {
2563 emitList() { 2571 JS.Expression emitList() {
2564 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); 2572 JS.Expression list = new JS.ArrayInitializer(
2573 _visitList(node.elements) as List<JS.Expression>);
2565 ParameterizedType type = node.staticType; 2574 ParameterizedType type = node.staticType;
2566 var elementType = type.typeArguments.single; 2575 var elementType = type.typeArguments.single;
2567 if (elementType != types.dynamicType) { 2576 if (elementType != types.dynamicType) {
2568 // dart.list helper internally depends on _interceptors.JSArray. 2577 // dart.list helper internally depends on _interceptors.JSArray.
2569 _loader.declareBeforeUse(_jsArray); 2578 _loader.declareBeforeUse(_jsArray);
2570 list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]); 2579 list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]);
2571 } 2580 }
2572 return list; 2581 return list;
2573 } 2582 }
2574 if (node.constKeyword != null) return _emitConst(emitList); 2583 if (node.constKeyword != null) return _emitConst(emitList);
2575 return emitList(); 2584 return emitList();
2576 } 2585 }
2577 2586
2578 @override 2587 @override
2579 visitMapLiteral(MapLiteral node) { 2588 visitMapLiteral(MapLiteral node) {
2580 // TODO(jmesserly): we can likely make these faster. 2589 // TODO(jmesserly): we can likely make these faster.
2581 emitMap() { 2590 JS.Expression emitMap() {
2582 var entries = node.entries; 2591 var entries = node.entries;
2583 var mapArguments = null; 2592 var mapArguments = null;
2584 if (entries.isEmpty) { 2593 if (entries.isEmpty) {
2585 mapArguments = []; 2594 mapArguments = [];
2586 } else if (entries.every((e) => e.key is StringLiteral)) { 2595 } else if (entries.every((e) => e.key is StringLiteral)) {
2587 // Use JS object literal notation if possible, otherwise use an array. 2596 // Use JS object literal notation if possible, otherwise use an array.
2588 // We could do this any time all keys are non-nullable String type. 2597 // We could do this any time all keys are non-nullable String type.
2589 // For now, support StringLiteral as the common non-nullable String case . 2598 // For now, support StringLiteral as the common non-nullable String case .
2590 var props = []; 2599 var props = <JS.Property>[];
2591 for (var e in entries) { 2600 for (var e in entries) {
2592 props.add(new JS.Property(_visit(e.key), _visit(e.value))); 2601 props.add(new JS.Property(_visit(e.key), _visit(e.value)));
2593 } 2602 }
2594 mapArguments = new JS.ObjectInitializer(props); 2603 mapArguments = new JS.ObjectInitializer(props);
2595 } else { 2604 } else {
2596 var values = []; 2605 var values = <JS.Expression>[];
2597 for (var e in entries) { 2606 for (var e in entries) {
2598 values.add(_visit(e.key)); 2607 values.add(_visit(e.key));
2599 values.add(_visit(e.value)); 2608 values.add(_visit(e.value));
2600 } 2609 }
2601 mapArguments = new JS.ArrayInitializer(values); 2610 mapArguments = new JS.ArrayInitializer(values);
2602 } 2611 }
2603 // TODO(jmesserly): add generic types args. 2612 // TODO(jmesserly): add generic types args.
2604 return js.call('dart.map(#)', [mapArguments]); 2613 return js.call('dart.map(#)', [mapArguments]);
2605 } 2614 }
2606 if (node.constKeyword != null) return _emitConst(emitMap); 2615 if (node.constKeyword != null) return _emitConst(emitMap);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2651 throw 'Unimplemented ${node.runtimeType}: $node'; 2660 throw 'Unimplemented ${node.runtimeType}: $node';
2652 } 2661 }
2653 2662
2654 _visit(AstNode node) { 2663 _visit(AstNode node) {
2655 if (node == null) return null; 2664 if (node == null) return null;
2656 var result = node.accept(this); 2665 var result = node.accept(this);
2657 if (result is JS.Node) result.sourceInformation = node; 2666 if (result is JS.Node) result.sourceInformation = node;
2658 return result; 2667 return result;
2659 } 2668 }
2660 2669
2661 List _visitList(Iterable<AstNode> nodes) { 2670 // TODO(jmesserly): this will need to be a generic method, if we ever want to
2671 // self-host strong mode.
2672 List /*<T>*/ _visitList /*<T>*/ (Iterable<AstNode> nodes) {
2662 if (nodes == null) return null; 2673 if (nodes == null) return null;
2663 var result = []; 2674 var result = /*<T>*/ [];
2664 for (var node in nodes) result.add(_visit(node)); 2675 for (var node in nodes) result.add(_visit(node));
2665 return result; 2676 return result;
2666 } 2677 }
2667 2678
2668 /// Visits a list of expressions, creating a comma expression if needed in JS. 2679 /// Visits a list of expressions, creating a comma expression if needed in JS.
2669 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 2680 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
2670 if (nodes == null || nodes.isEmpty) return null; 2681 if (nodes == null || nodes.isEmpty) return null;
2671 return new JS.Expression.binary(_visitList(nodes), operator); 2682 return new JS.Expression.binary(
2683 _visitList(nodes) as List<JS.Expression>, operator);
2672 } 2684 }
2673 2685
2674 /// Like [_emitMemberName], but for declaration sites. 2686 /// Like [_emitMemberName], but for declaration sites.
2675 /// 2687 ///
2676 /// Unlike call sites, we always have an element available, so we can use it 2688 /// Unlike call sites, we always have an element available, so we can use it
2677 /// directly rather than computing the relevant options for [_emitMemberName]. 2689 /// directly rather than computing the relevant options for [_emitMemberName].
2678 JS.Expression _elementMemberName(ExecutableElement e, 2690 JS.Expression _elementMemberName(ExecutableElement e,
2679 {bool allowExtensions: true}) { 2691 {bool allowExtensions: true}) {
2680 String name; 2692 String name;
2681 if (e is PropertyAccessorElement) { 2693 if (e is PropertyAccessorElement) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
2732 /// helper, that checks for null. The user defined method is called '=='. 2744 /// helper, that checks for null. The user defined method is called '=='.
2733 /// 2745 ///
2734 JS.Expression _emitMemberName(String name, {DartType type, bool unary: false, 2746 JS.Expression _emitMemberName(String name, {DartType type, bool unary: false,
2735 bool isStatic: false, bool allowExtensions: true}) { 2747 bool isStatic: false, bool allowExtensions: true}) {
2736 2748
2737 // Static members skip the rename steps. 2749 // Static members skip the rename steps.
2738 if (isStatic) return _propertyName(name); 2750 if (isStatic) return _propertyName(name);
2739 2751
2740 if (name.startsWith('_')) { 2752 if (name.startsWith('_')) {
2741 return _privateNames.putIfAbsent( 2753 return _privateNames.putIfAbsent(
2742 name, () => _initSymbol(new JS.TemporaryId(name))); 2754 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId);
2743 } 2755 }
2744 2756
2745 if (name == '[]') { 2757 if (name == '[]') {
2746 name = 'get'; 2758 name = 'get';
2747 } else if (name == '[]=') { 2759 } else if (name == '[]=') {
2748 name = 'set'; 2760 name = 'set';
2749 } else if (name == '-' && unary) { 2761 } else if (name == '-' && unary) {
2750 name = 'unary-'; 2762 name = 'unary-';
2751 } 2763 }
2752 2764
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2788 var context = compiler.context; 2800 var context = compiler.context;
2789 var src = context.sourceFactory.forUri('dart:_interceptors'); 2801 var src = context.sourceFactory.forUri('dart:_interceptors');
2790 var interceptors = context.computeLibraryElement(src); 2802 var interceptors = context.computeLibraryElement(src);
2791 for (var t in ['JSArray', 'JSString', 'JSInt', 'JSDouble', 'JSBool']) { 2803 for (var t in ['JSArray', 'JSString', 'JSInt', 'JSDouble', 'JSBool']) {
2792 _addExtensionType(interceptors.getType(t).type); 2804 _addExtensionType(interceptors.getType(t).type);
2793 } 2805 }
2794 } 2806 }
2795 2807
2796 void _addExtensionType(InterfaceType t) { 2808 void _addExtensionType(InterfaceType t) {
2797 if (t.isObject || !_extensionTypes.add(t.element)) return; 2809 if (t.isObject || !_extensionTypes.add(t.element)) return;
2798 t = fillDynamicTypeArgs(t, rules.provider); 2810 t = fillDynamicTypeArgs(t, rules.provider) as InterfaceType;
2799 t.interfaces.forEach(_addExtensionType); 2811 t.interfaces.forEach(_addExtensionType);
2800 t.mixins.forEach(_addExtensionType); 2812 t.mixins.forEach(_addExtensionType);
2801 _addExtensionType(t.superclass); 2813 _addExtensionType(t.superclass);
2802 } 2814 }
2803 2815
2804 String generateLibrary(LibraryUnit unit) { 2816 String generateLibrary(LibraryUnit unit) {
2805 var library = unit.library.element.library; 2817 var library = unit.library.element.library;
2806 var fields = findFieldsNeedingStorage(unit); 2818 var fields = findFieldsNeedingStorage(unit);
2807 var codegen = 2819 var codegen =
2808 new JSCodegenVisitor(compiler, library, _extensionTypes, fields); 2820 new JSCodegenVisitor(compiler, library, _extensionTypes, fields);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2846 2858
2847 class _JsThisFinder extends JS.BaseVisitor { 2859 class _JsThisFinder extends JS.BaseVisitor {
2848 bool found = false; 2860 bool found = false;
2849 visitThis(JS.This node) { 2861 visitThis(JS.This node) {
2850 found = true; 2862 found = true;
2851 } 2863 }
2852 visitNode(JS.Node node) { 2864 visitNode(JS.Node node) {
2853 if (!found) super.visitNode(node); 2865 if (!found) super.visitNode(node);
2854 } 2866 }
2855 } 2867 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698