OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
6 | 6 |
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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. |
398 // If we wanted to support laziness, we could defer the hookup until | 399 // If we wanted to support laziness, we could defer the hookup until |
399 // the end of the Dart library cycle load. | 400 // the end of the Dart library cycle load. |
400 assert(_loader.isLoaded(classElem)); | 401 assert(_loader.isLoaded(classElem)); |
401 | 402 |
402 // TODO(jmesserly): this copies the dynamic members. | 403 // TODO(jmesserly): this copies the dynamic members. |
403 // Probably fine for objects coming from JS, but not if we actually | 404 // Probably fine for objects coming from JS, but not if we actually |
404 // want to support construction of instances with generic types other | 405 // want to support construction of instances with generic types other |
405 // than dynamic. See issue #154 for Array and List<E> related bug. | 406 // than dynamic. See issue #154 for Array and List<E> related bug. |
406 var copyMembers = js.statement( | 407 var copyMembers = js.statement( |
407 'dart.registerExtension(dart.global.#, #);', [ | 408 'dart.registerExtension(dart.global.#, #);', [ |
408 _propertyName(jsPeerName), | 409 _propertyName(jsPeerName), |
409 classElem.name | 410 classElem.name |
410 ]); | 411 ]); |
411 return _statement([result, copyMembers]); | 412 return _statement(<JS.Statement>[result, copyMembers]); |
Leaf
2015/07/22 22:29:15
Is this necessary? I would have expected your cha
Jennifer Messerly
2015/07/22 22:35:52
Done. Reverted this.
| |
412 } | 413 } |
413 return result; | 414 return result; |
414 } | 415 } |
415 | 416 |
416 @override | 417 @override |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |