Chromium Code Reviews| 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 |