| 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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 for (var name in _exports) { | 175 for (var name in _exports) { |
| 176 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); | 176 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); |
| 177 } | 177 } |
| 178 | 178 |
| 179 var jsPath = compiler.getModuleName(currentLibrary.source.uri); | 179 var jsPath = compiler.getModuleName(currentLibrary.source.uri); |
| 180 | 180 |
| 181 // TODO(jmesserly): it would be great to run the renamer on the body, | 181 // TODO(jmesserly): it would be great to run the renamer on the body, |
| 182 // then figure out if we really need each of these parameters. | 182 // then figure out if we really need each of these parameters. |
| 183 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 | 183 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 |
| 184 var params = [_exportsVar, _runtimeLibVar]; | 184 var params = [_exportsVar, _runtimeLibVar]; |
| 185 var processImport = (LibraryElement library, JS.TemporaryId temp, | 185 var processImport = |
| 186 List list) { | 186 (LibraryElement library, JS.TemporaryId temp, List list) { |
| 187 params.add(temp); | 187 params.add(temp); |
| 188 list.add(js.string(compiler.getModuleName(library.source.uri), "'")); | 188 list.add(js.string(compiler.getModuleName(library.source.uri), "'")); |
| 189 }; | 189 }; |
| 190 | 190 |
| 191 var imports = <JS.Expression>[js.string('dart_runtime/dart')]; | 191 var imports = <JS.Expression>[js.string('dart_runtime/dart')]; |
| 192 _imports.forEach((library, temp) { | 192 _imports.forEach((library, temp) { |
| 193 if (_loader.libraryIsLoaded(library)) { | 193 if (_loader.libraryIsLoaded(library)) { |
| 194 processImport(library, temp, imports); | 194 processImport(library, temp, imports); |
| 195 } | 195 } |
| 196 }); | 196 }); |
| 197 | 197 |
| 198 var lazyImports = <JS.Expression>[]; | 198 var lazyImports = <JS.Expression>[]; |
| 199 _imports.forEach((library, temp) { | 199 _imports.forEach((library, temp) { |
| 200 if (!_loader.libraryIsLoaded(library)) { | 200 if (!_loader.libraryIsLoaded(library)) { |
| 201 processImport(library, temp, lazyImports); | 201 processImport(library, temp, lazyImports); |
| 202 } | 202 } |
| 203 }); | 203 }); |
| 204 | 204 |
| 205 var dartxImport = | 205 var dartxImport = |
| 206 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); | 206 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); |
| 207 | 207 |
| 208 var module = js.call("function(#) { 'use strict'; #; #; }", [ | 208 var module = js.call("function(#) { 'use strict'; #; #; }", |
| 209 params, | 209 [params, dartxImport, _moduleItems]); |
| 210 dartxImport, | |
| 211 _moduleItems | |
| 212 ]); | |
| 213 | 210 |
| 214 var program = <JS.Statement>[ | 211 var program = <JS.Statement>[ |
| 215 js.statement("dart_library.library(#, #, #, #, #)", [ | 212 js.statement("dart_library.library(#, #, #, #, #)", [ |
| 216 js.string(jsPath, "'"), | 213 js.string(jsPath, "'"), |
| 217 jsDefaultValue != null ? jsDefaultValue : new JS.LiteralNull(), | 214 jsDefaultValue != null ? jsDefaultValue : new JS.LiteralNull(), |
| 218 js.commentExpression( | 215 js.commentExpression( |
| 219 "Imports", new JS.ArrayInitializer(imports, multiline: true)), | 216 "Imports", new JS.ArrayInitializer(imports, multiline: true)), |
| 220 js.commentExpression("Lazy imports", | 217 js.commentExpression("Lazy imports", |
| 221 new JS.ArrayInitializer(lazyImports, multiline: true)), | 218 new JS.ArrayInitializer(lazyImports, multiline: true)), |
| 222 module | 219 module |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 return js.call('dart.notNull(#)', _visit(node.expression)); | 266 return js.call('dart.notNull(#)', _visit(node.expression)); |
| 270 } else { | 267 } else { |
| 271 // A no-op in JavaScript. | 268 // A no-op in JavaScript. |
| 272 return _visit(node.expression); | 269 return _visit(node.expression); |
| 273 } | 270 } |
| 274 } | 271 } |
| 275 | 272 |
| 276 return _emitCast(node.expression, to); | 273 return _emitCast(node.expression, to); |
| 277 } | 274 } |
| 278 | 275 |
| 279 _emitCast(Expression node, DartType type) => | 276 _emitCast(Expression node, DartType type) => js.call('dart.as(#)', [ |
| 280 js.call('dart.as(#)', [[_visit(node), _emitTypeName(type)]]); | 277 [_visit(node), _emitTypeName(type)] |
| 278 ]); |
| 281 | 279 |
| 282 @override | 280 @override |
| 283 visitIsExpression(IsExpression node) { | 281 visitIsExpression(IsExpression node) { |
| 284 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 282 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
| 285 JS.Expression result; | 283 JS.Expression result; |
| 286 var type = node.type.type; | 284 var type = node.type.type; |
| 287 var lhs = _visit(node.expression); | 285 var lhs = _visit(node.expression); |
| 288 var typeofName = _jsTypeofName(type); | 286 var typeofName = _jsTypeofName(type); |
| 289 if (typeofName != null) { | 287 if (typeofName != null) { |
| 290 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); | 288 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 305 if (rules.isBoolType(t)) return 'boolean'; | 303 if (rules.isBoolType(t)) return 'boolean'; |
| 306 return null; | 304 return null; |
| 307 } | 305 } |
| 308 | 306 |
| 309 @override | 307 @override |
| 310 visitFunctionTypeAlias(FunctionTypeAlias node) { | 308 visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 311 var element = node.element; | 309 var element = node.element; |
| 312 var type = element.type; | 310 var type = element.type; |
| 313 var name = element.name; | 311 var name = element.name; |
| 314 | 312 |
| 315 var fnType = js.statement('let # = dart.typedef(#, () => #);', [ | 313 var fnType = js.statement('let # = dart.typedef(#, () => #);', |
| 316 name, | 314 [name, js.string(name, "'"), _emitTypeName(type, lowerTypedef: true)]); |
| 317 js.string(name, "'"), | |
| 318 _emitTypeName(type, lowerTypedef: true) | |
| 319 ]); | |
| 320 | 315 |
| 321 return _finishClassDef(type, fnType); | 316 return _finishClassDef(type, fnType); |
| 322 } | 317 } |
| 323 | 318 |
| 324 @override | 319 @override |
| 325 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); | 320 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); |
| 326 | 321 |
| 327 @override | 322 @override |
| 328 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { | 323 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { |
| 329 var element = node.element; | 324 var element = node.element; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 // the native JS type eagerly at this point. | 396 // the native JS type eagerly at this point. |
| 402 // If we wanted to support laziness, we could defer the hookup until | 397 // If we wanted to support laziness, we could defer the hookup until |
| 403 // the end of the Dart library cycle load. | 398 // the end of the Dart library cycle load. |
| 404 assert(_loader.isLoaded(classElem)); | 399 assert(_loader.isLoaded(classElem)); |
| 405 | 400 |
| 406 // TODO(jmesserly): this copies the dynamic members. | 401 // TODO(jmesserly): this copies the dynamic members. |
| 407 // Probably fine for objects coming from JS, but not if we actually | 402 // Probably fine for objects coming from JS, but not if we actually |
| 408 // want to support construction of instances with generic types other | 403 // want to support construction of instances with generic types other |
| 409 // than dynamic. See issue #154 for Array and List<E> related bug. | 404 // than dynamic. See issue #154 for Array and List<E> related bug. |
| 410 var copyMembers = js.statement( | 405 var copyMembers = js.statement( |
| 411 'dart.registerExtension(dart.global.#, #);', [ | 406 'dart.registerExtension(dart.global.#, #);', |
| 412 _propertyName(jsPeerName), | 407 [_propertyName(jsPeerName), classElem.name]); |
| 413 classElem.name | |
| 414 ]); | |
| 415 return _statement([result, copyMembers]); | 408 return _statement([result, copyMembers]); |
| 416 } | 409 } |
| 417 return result; | 410 return result; |
| 418 } | 411 } |
| 419 | 412 |
| 420 @override | 413 @override |
| 421 JS.Statement visitEnumDeclaration(EnumDeclaration node) { | 414 JS.Statement visitEnumDeclaration(EnumDeclaration node) { |
| 422 var element = node.element; | 415 var element = node.element; |
| 423 var type = element.type; | 416 var type = element.type; |
| 424 var name = js.string(type.name); | 417 var name = js.string(type.name); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 443 var toStringF = new JS.Method(js.string('toString'), | 436 var toStringF = new JS.Method(js.string('toString'), |
| 444 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); | 437 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); |
| 445 | 438 |
| 446 // Create enum class | 439 // Create enum class |
| 447 var classExpr = new JS.ClassExpression( | 440 var classExpr = new JS.ClassExpression( |
| 448 id, _classHeritage(element), [constructor, toStringF]); | 441 id, _classHeritage(element), [constructor, toStringF]); |
| 449 var result = <JS.Statement>[js.statement('#', classExpr)]; | 442 var result = <JS.Statement>[js.statement('#', classExpr)]; |
| 450 | 443 |
| 451 // Create static fields for each enum value | 444 // Create static fields for each enum value |
| 452 for (var i = 0; i < fields.length; ++i) { | 445 for (var i = 0; i < fields.length; ++i) { |
| 453 result.add(js.statement('#.# = dart.const(new #(#));', [ | 446 result.add(js.statement('#.# = dart.const(new #(#));', |
| 454 id, | 447 [id, fields[i].name, id, js.number(i)])); |
| 455 fields[i].name, | |
| 456 id, | |
| 457 js.number(i) | |
| 458 ])); | |
| 459 } | 448 } |
| 460 | 449 |
| 461 // Create static values list | 450 // Create static values list |
| 462 var values = new JS.ArrayInitializer(new List<JS.Expression>.from( | 451 var values = new JS.ArrayInitializer(new List<JS.Expression>.from( |
| 463 fields.map((f) => js.call('#.#', [id, f.name])))); | 452 fields.map((f) => js.call('#.#', [id, f.name])))); |
| 464 result.add(js.statement('#.values = dart.const(dart.list(#, #));', [ | 453 result.add(js.statement('#.values = dart.const(dart.list(#, #));', |
| 465 id, | 454 [id, values, _emitTypeName(type)])); |
| 466 values, | |
| 467 _emitTypeName(type) | |
| 468 ])); | |
| 469 | 455 |
| 470 return _statement(result); | 456 return _statement(result); |
| 471 } | 457 } |
| 472 | 458 |
| 473 /// Given a class element and body, complete the class declaration. | 459 /// Given a class element and body, complete the class declaration. |
| 474 /// This handles generic type parameters, laziness (in library-cycle cases), | 460 /// This handles generic type parameters, laziness (in library-cycle cases), |
| 475 /// and ensuring dependencies are loaded first. | 461 /// and ensuring dependencies are loaded first. |
| 476 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) { | 462 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) { |
| 477 var name = type.name; | 463 var name = type.name; |
| 478 var genericName = '$name\$'; | 464 var genericName = '$name\$'; |
| 479 | 465 |
| 480 JS.Statement genericDef = null; | 466 JS.Statement genericDef = null; |
| 481 if (type.typeParameters.isNotEmpty) { | 467 if (type.typeParameters.isNotEmpty) { |
| 482 genericDef = _emitGenericClassDef(type, body); | 468 genericDef = _emitGenericClassDef(type, body); |
| 483 } | 469 } |
| 484 | 470 |
| 485 // The base class and all mixins must be declared before this class. | 471 // The base class and all mixins must be declared before this class. |
| 486 if (!_loader.isLoaded(type.element)) { | 472 if (!_loader.isLoaded(type.element)) { |
| 487 // TODO(jmesserly): the lazy class def is a simple solution for now. | 473 // TODO(jmesserly): the lazy class def is a simple solution for now. |
| 488 // We may want to consider other options in the future. | 474 // We may want to consider other options in the future. |
| 489 | 475 |
| 490 if (genericDef != null) { | 476 if (genericDef != null) { |
| 491 return js.statement( | 477 return js.statement( |
| 492 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', [ | 478 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', |
| 493 genericDef, | 479 [genericDef, _exportsVar, _propertyName(name), genericName]); |
| 494 _exportsVar, | |
| 495 _propertyName(name), | |
| 496 genericName | |
| 497 ]); | |
| 498 } | 480 } |
| 499 | 481 |
| 500 return js.statement( | 482 return js.statement( |
| 501 'dart.defineLazyClass(#, { get #() { #; return #; } });', [ | 483 'dart.defineLazyClass(#, { get #() { #; return #; } });', |
| 502 _exportsVar, | 484 [_exportsVar, _propertyName(name), body, name]); |
| 503 _propertyName(name), | |
| 504 body, | |
| 505 name | |
| 506 ]); | |
| 507 } | 485 } |
| 508 | 486 |
| 509 if (isPublic(name)) _addExport(name); | 487 if (isPublic(name)) _addExport(name); |
| 510 | 488 |
| 511 if (genericDef != null) { | 489 if (genericDef != null) { |
| 512 var dynType = fillDynamicTypeArgs(type, types); | 490 var dynType = fillDynamicTypeArgs(type, types); |
| 513 var genericInst = _emitTypeName(dynType, lowerGeneric: true); | 491 var genericInst = _emitTypeName(dynType, lowerGeneric: true); |
| 514 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 492 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); |
| 515 } | 493 } |
| 516 return body; | 494 return body; |
| 517 } | 495 } |
| 518 | 496 |
| 519 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { | 497 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { |
| 520 var name = type.name; | 498 var name = type.name; |
| 521 var genericName = '$name\$'; | 499 var genericName = '$name\$'; |
| 522 var typeParams = type.typeParameters.map((p) => p.name); | 500 var typeParams = type.typeParameters.map((p) => p.name); |
| 523 if (isPublic(name)) _exports.add(genericName); | 501 if (isPublic(name)) _exports.add(genericName); |
| 524 return js.statement('let # = dart.generic(function(#) { #; return #; });', [ | 502 return js.statement('let # = dart.generic(function(#) { #; return #; });', |
| 525 genericName, | 503 [genericName, typeParams, body, name]); |
| 526 typeParams, | |
| 527 body, | |
| 528 name | |
| 529 ]); | |
| 530 } | 504 } |
| 531 | 505 |
| 532 JS.Expression _classHeritage(ClassElement element) { | 506 JS.Expression _classHeritage(ClassElement element) { |
| 533 var type = element.type; | 507 var type = element.type; |
| 534 if (type.isObject) return null; | 508 if (type.isObject) return null; |
| 535 | 509 |
| 536 // Assume we can load eagerly, until proven otherwise. | 510 // Assume we can load eagerly, until proven otherwise. |
| 537 _loader.startTopLevel(element); | 511 _loader.startTopLevel(element); |
| 538 | 512 |
| 539 JS.Expression heritage = _emitTypeName(type.superclass); | 513 JS.Expression heritage = _emitTypeName(type.superclass); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 // If a parent had an `iterator` (concrete or abstract) or implements | 580 // If a parent had an `iterator` (concrete or abstract) or implements |
| 607 // Iterable, we know the adapter is already there, so we can skip it as a | 581 // Iterable, we know the adapter is already there, so we can skip it as a |
| 608 // simple code size optimization. | 582 // simple code size optimization. |
| 609 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); | 583 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); |
| 610 if (parent != null) return null; | 584 if (parent != null) return null; |
| 611 var parentType = findSupertype(t, _implementsIterable); | 585 var parentType = findSupertype(t, _implementsIterable); |
| 612 if (parentType != null) return null; | 586 if (parentType != null) return null; |
| 613 | 587 |
| 614 // Otherwise, emit the adapter method, which wraps the Dart iterator in | 588 // Otherwise, emit the adapter method, which wraps the Dart iterator in |
| 615 // an ES6 iterator. | 589 // an ES6 iterator. |
| 616 return new JS.Method(js.call('$_SYMBOL.iterator'), js.call( | 590 return new JS.Method( |
| 617 'function() { return new dart.JsIterator(this.#); }', | 591 js.call('$_SYMBOL.iterator'), |
| 618 [_emitMemberName('iterator', type: t)]) as JS.Fun); | 592 js.call('function() { return new dart.JsIterator(this.#); }', |
| 593 [_emitMemberName('iterator', type: t)]) as JS.Fun); |
| 619 } | 594 } |
| 620 | 595 |
| 621 JS.Expression _instantiateAnnotation(Annotation node) { | 596 JS.Expression _instantiateAnnotation(Annotation node) { |
| 622 var element = node.element; | 597 var element = node.element; |
| 623 if (element is ConstructorElement) { | 598 if (element is ConstructorElement) { |
| 624 return _emitInstanceCreationExpression(element, element.returnType, | 599 return _emitInstanceCreationExpression(element, element.returnType, |
| 625 node.constructorName, node.arguments, true); | 600 node.constructorName, node.arguments, true); |
| 626 } else { | 601 } else { |
| 627 return _visit(node.name); | 602 return _visit(node.name); |
| 628 } | 603 } |
| 629 } | 604 } |
| 630 | 605 |
| 631 /// Emit class members that need to come after the class declaration, such | 606 /// Emit class members that need to come after the class declaration, such |
| 632 /// as static fields. See [_emitClassMethods] for things that are emitted | 607 /// as static fields. See [_emitClassMethods] for things that are emitted |
| 633 /// inside the ES6 `class { ... }` node. | 608 /// inside the ES6 `class { ... }` node. |
| 634 JS.Statement _finishClassMembers(ClassElement classElem, | 609 JS.Statement _finishClassMembers( |
| 635 JS.ClassExpression cls, List<ConstructorDeclaration> ctors, | 610 ClassElement classElem, |
| 636 List<FieldDeclaration> fields, List<MethodDeclaration> methods, | 611 JS.ClassExpression cls, |
| 637 List<Annotation> metadata, String jsPeerName) { | 612 List<ConstructorDeclaration> ctors, |
| 613 List<FieldDeclaration> fields, |
| 614 List<MethodDeclaration> methods, |
| 615 List<Annotation> metadata, |
| 616 String jsPeerName) { |
| 638 var name = classElem.name; | 617 var name = classElem.name; |
| 639 var body = <JS.Statement>[]; | 618 var body = <JS.Statement>[]; |
| 640 | 619 |
| 641 if (_extensionTypes.contains(classElem)) { | 620 if (_extensionTypes.contains(classElem)) { |
| 642 var dartxNames = <JS.Expression>[]; | 621 var dartxNames = <JS.Expression>[]; |
| 643 for (var m in methods) { | 622 for (var m in methods) { |
| 644 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 623 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
| 645 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); | 624 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); |
| 646 } | 625 } |
| 647 } | 626 } |
| 648 if (dartxNames.isNotEmpty) { | 627 if (dartxNames.isNotEmpty) { |
| 649 body.add(js.statement('dart.defineExtensionNames(#)', | 628 body.add(js.statement('dart.defineExtensionNames(#)', |
| 650 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 629 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
| 651 } | 630 } |
| 652 } | 631 } |
| 653 | 632 |
| 654 body.add(new JS.ClassDeclaration(cls)); | 633 body.add(new JS.ClassDeclaration(cls)); |
| 655 | 634 |
| 656 // TODO(jmesserly): we should really just extend native Array. | 635 // TODO(jmesserly): we should really just extend native Array. |
| 657 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { | 636 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { |
| 658 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', [ | 637 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', |
| 659 classElem.name, | 638 [classElem.name, _propertyName(jsPeerName)])); |
| 660 _propertyName(jsPeerName) | |
| 661 ])); | |
| 662 } | 639 } |
| 663 | 640 |
| 664 // Interfaces | 641 // Interfaces |
| 665 if (classElem.interfaces.isNotEmpty) { | 642 if (classElem.interfaces.isNotEmpty) { |
| 666 body.add(js.statement('#[dart.implements] = () => #;', [ | 643 body.add(js.statement('#[dart.implements] = () => #;', [ |
| 667 name, | 644 name, |
| 668 new JS.ArrayInitializer(new List<JS.Expression>.from( | 645 new JS.ArrayInitializer(new List<JS.Expression>.from( |
| 669 classElem.interfaces.map(_emitTypeName))) | 646 classElem.interfaces.map(_emitTypeName))) |
| 670 ])); | 647 ])); |
| 671 } | 648 } |
| 672 | 649 |
| 673 // Named constructors | 650 // Named constructors |
| 674 for (ConstructorDeclaration member in ctors) { | 651 for (ConstructorDeclaration member in ctors) { |
| 675 if (member.name != null && member.factoryKeyword == null) { | 652 if (member.name != null && member.factoryKeyword == null) { |
| 676 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ | 653 body.add(js.statement('dart.defineNamedConstructor(#, #);', |
| 677 name, | 654 [name, _emitMemberName(member.name.name, isStatic: true)])); |
| 678 _emitMemberName(member.name.name, isStatic: true) | |
| 679 ])); | |
| 680 } | 655 } |
| 681 } | 656 } |
| 682 | 657 |
| 683 // Instance fields, if they override getter/setter pairs | 658 // Instance fields, if they override getter/setter pairs |
| 684 for (FieldDeclaration member in fields) { | 659 for (FieldDeclaration member in fields) { |
| 685 for (VariableDeclaration fieldDecl in member.fields.variables) { | 660 for (VariableDeclaration fieldDecl in member.fields.variables) { |
| 686 var field = fieldDecl.element as FieldElement; | 661 var field = fieldDecl.element as FieldElement; |
| 687 if (_fieldsNeedingStorage.contains(field)) { | 662 if (_fieldsNeedingStorage.contains(field)) { |
| 688 body.add(_overrideField(field)); | 663 body.add(_overrideField(field)); |
| 689 } | 664 } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 812 _collectExtensions(m, types); | 787 _collectExtensions(m, types); |
| 813 } | 788 } |
| 814 for (var i in type.interfaces) { | 789 for (var i in type.interfaces) { |
| 815 _collectExtensions(i, types); | 790 _collectExtensions(i, types); |
| 816 } | 791 } |
| 817 _collectExtensions(type.superclass, types); | 792 _collectExtensions(type.superclass, types); |
| 818 } | 793 } |
| 819 | 794 |
| 820 JS.Statement _overrideField(FieldElement e) { | 795 JS.Statement _overrideField(FieldElement e) { |
| 821 var cls = e.enclosingElement; | 796 var cls = e.enclosingElement; |
| 822 return js.statement('dart.virtualField(#, #)', [ | 797 return js.statement('dart.virtualField(#, #)', |
| 823 cls.name, | 798 [cls.name, _emitMemberName(e.name, type: cls.type)]); |
| 824 _emitMemberName(e.name, type: cls.type) | |
| 825 ]); | |
| 826 } | 799 } |
| 827 | 800 |
| 828 /// Generates the implicit default constructor for class C of the form | 801 /// Generates the implicit default constructor for class C of the form |
| 829 /// `C() : super() {}`. | 802 /// `C() : super() {}`. |
| 830 JS.Method _emitImplicitConstructor( | 803 JS.Method _emitImplicitConstructor( |
| 831 ClassDeclaration node, List<FieldDeclaration> fields) { | 804 ClassDeclaration node, List<FieldDeclaration> fields) { |
| 832 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); | 805 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); |
| 833 | 806 |
| 834 // If we don't have a method body, skip this. | 807 // If we don't have a method body, skip this. |
| 835 var superCall = _superConstructorCall(node.element); | 808 var superCall = _superConstructorCall(node.element); |
| 836 if (fields.isEmpty && superCall == null) return null; | 809 if (fields.isEmpty && superCall == null) return null; |
| 837 | 810 |
| 838 dynamic body = _initializeFields(node, fields); | 811 dynamic body = _initializeFields(node, fields); |
| 839 if (superCall != null) body = [[body, superCall]]; | 812 if (superCall != null) body = [ |
| 813 [body, superCall] |
| 814 ]; |
| 840 var name = _constructorName(node.element.unnamedConstructor); | 815 var name = _constructorName(node.element.unnamedConstructor); |
| 841 return new JS.Method(name, js.call('function() { #; }', body) as JS.Fun); | 816 return new JS.Method(name, js.call('function() { #; }', body) as JS.Fun); |
| 842 } | 817 } |
| 843 | 818 |
| 844 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type, | 819 JS.Method _emitConstructor(ConstructorDeclaration node, InterfaceType type, |
| 845 List<FieldDeclaration> fields, bool isObject) { | 820 List<FieldDeclaration> fields, bool isObject) { |
| 846 if (_externalOrNative(node)) return null; | 821 if (_externalOrNative(node)) return null; |
| 847 | 822 |
| 848 var name = _constructorName(node.element); | 823 var name = _constructorName(node.element); |
| 849 | 824 |
| 850 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; | 825 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; |
| 851 var redirect = node.redirectedConstructor; | 826 var redirect = node.redirectedConstructor; |
| 852 if (redirect != null) { | 827 if (redirect != null) { |
| 853 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; | 828 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; |
| 854 // Pass along all arguments verbatim, and let the callee handle them. | 829 // Pass along all arguments verbatim, and let the callee handle them. |
| 855 // TODO(jmesserly): we'll need something different once we have | 830 // TODO(jmesserly): we'll need something different once we have |
| 856 // rest/spread support, but this should work for now. | 831 // rest/spread support, but this should work for now. |
| 857 var params = _visit(node.parameters); | 832 var params = _visit(node.parameters); |
| 858 var fun = js.call('function(#) { return $newKeyword #(#); }', [ | 833 var fun = js.call('function(#) { return $newKeyword #(#); }', |
| 859 params, | 834 [params, _visit(redirect), params,]) as JS.Fun; |
| 860 _visit(redirect), | |
| 861 params, | |
| 862 ]) as JS.Fun; | |
| 863 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node; | 835 return new JS.Method(name, fun, isStatic: true)..sourceInformation = node; |
| 864 } | 836 } |
| 865 | 837 |
| 866 // Factory constructors are essentially static methods. | 838 // Factory constructors are essentially static methods. |
| 867 if (node.factoryKeyword != null) { | 839 if (node.factoryKeyword != null) { |
| 868 var body = <JS.Statement>[]; | 840 var body = <JS.Statement>[]; |
| 869 var init = _emitArgumentInitializers(node, constructor: true); | 841 var init = _emitArgumentInitializers(node, constructor: true); |
| 870 if (init != null) body.add(init); | 842 if (init != null) body.add(init); |
| 871 body.add(_visit(node.body)); | 843 body.add(_visit(node.body)); |
| 872 var fun = new JS.Fun( | 844 var fun = new JS.Fun( |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 // available for use by top-level constant initializers. | 908 // available for use by top-level constant initializers. |
| 937 ClassDeclaration cls = node.parent; | 909 ClassDeclaration cls = node.parent; |
| 938 if (node.constKeyword != null) _loader.startTopLevel(cls.element); | 910 if (node.constKeyword != null) _loader.startTopLevel(cls.element); |
| 939 var init = _emitArgumentInitializers(node, constructor: true); | 911 var init = _emitArgumentInitializers(node, constructor: true); |
| 940 if (node.constKeyword != null) _loader.finishTopLevel(cls.element); | 912 if (node.constKeyword != null) _loader.finishTopLevel(cls.element); |
| 941 if (init != null) body.add(init); | 913 if (init != null) body.add(init); |
| 942 | 914 |
| 943 // Redirecting constructors: these are not allowed to have initializers, | 915 // Redirecting constructors: these are not allowed to have initializers, |
| 944 // and the redirecting ctor invocation runs before field initializers. | 916 // and the redirecting ctor invocation runs before field initializers. |
| 945 var redirectCall = node.initializers.firstWhere( | 917 var redirectCall = node.initializers.firstWhere( |
| 946 (i) => i is RedirectingConstructorInvocation, orElse: () => null); | 918 (i) => i is RedirectingConstructorInvocation, |
| 919 orElse: () => null); |
| 947 | 920 |
| 948 if (redirectCall != null) { | 921 if (redirectCall != null) { |
| 949 body.add(_visit(redirectCall)); | 922 body.add(_visit(redirectCall)); |
| 950 return new JS.Block(body); | 923 return new JS.Block(body); |
| 951 } | 924 } |
| 952 | 925 |
| 953 // Generate field initializers. | 926 // Generate field initializers. |
| 954 // These are expanded into each non-redirecting constructor. | 927 // These are expanded into each non-redirecting constructor. |
| 955 // In the future we may want to create an initializer function if we have | 928 // In the future we may want to create an initializer function if we have |
| 956 // multiple constructors, but it needs to be balanced against readability. | 929 // multiple constructors, but it needs to be balanced against readability. |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 body.add(js.statement('let # = # && # in # ? #.# : #;', [ | 1096 body.add(js.statement('let # = # && # in # ? #.# : #;', [ |
| 1124 jsParam, | 1097 jsParam, |
| 1125 _namedArgTemp, | 1098 _namedArgTemp, |
| 1126 paramName, | 1099 paramName, |
| 1127 _namedArgTemp, | 1100 _namedArgTemp, |
| 1128 _namedArgTemp, | 1101 _namedArgTemp, |
| 1129 paramName, | 1102 paramName, |
| 1130 _defaultParamValue(param), | 1103 _defaultParamValue(param), |
| 1131 ])); | 1104 ])); |
| 1132 } else if (param.kind == ParameterKind.POSITIONAL) { | 1105 } else if (param.kind == ParameterKind.POSITIONAL) { |
| 1133 body.add(js.statement('if (# === void 0) # = #;', [ | 1106 body.add(js.statement('if (# === void 0) # = #;', |
| 1134 jsParam, | 1107 [jsParam, jsParam, _defaultParamValue(param)])); |
| 1135 jsParam, | |
| 1136 _defaultParamValue(param) | |
| 1137 ])); | |
| 1138 } | 1108 } |
| 1139 | 1109 |
| 1140 // TODO(jmesserly): various problems here, see: | 1110 // TODO(jmesserly): various problems here, see: |
| 1141 // https://github.com/dart-lang/dev_compiler/issues/161 | 1111 // https://github.com/dart-lang/dev_compiler/issues/161 |
| 1142 var paramType = param.element.type; | 1112 var paramType = param.element.type; |
| 1143 if (!constructor && _hasTypeParameter(paramType)) { | 1113 if (!constructor && _hasTypeParameter(paramType)) { |
| 1144 body.add(js.statement( | 1114 body.add(js.statement( |
| 1145 'dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); | 1115 'dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); |
| 1146 } | 1116 } |
| 1147 } | 1117 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1276 return _emitFunctionTagged(clos, type, | 1246 return _emitFunctionTagged(clos, type, |
| 1277 topLevel: _executesAtTopLevel(node)); | 1247 topLevel: _executesAtTopLevel(node)); |
| 1278 } | 1248 } |
| 1279 return clos; | 1249 return clos; |
| 1280 } | 1250 } |
| 1281 } | 1251 } |
| 1282 | 1252 |
| 1283 JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body) { | 1253 JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body) { |
| 1284 // sync*, async, async* | 1254 // sync*, async, async* |
| 1285 if (body.isAsynchronous || body.isGenerator) { | 1255 if (body.isAsynchronous || body.isGenerator) { |
| 1286 return new JS.Fun(params, js.statement( | 1256 return new JS.Fun( |
| 1287 '{ return #; }', [_emitGeneratorFunctionBody(params, body)])); | 1257 params, |
| 1258 js.statement( |
| 1259 '{ return #; }', [_emitGeneratorFunctionBody(params, body)])); |
| 1288 } | 1260 } |
| 1289 // normal function (sync) | 1261 // normal function (sync) |
| 1290 return new JS.Fun(params, _visit(body)); | 1262 return new JS.Fun(params, _visit(body)); |
| 1291 } | 1263 } |
| 1292 | 1264 |
| 1293 JS.Expression _emitGeneratorFunctionBody( | 1265 JS.Expression _emitGeneratorFunctionBody( |
| 1294 List<JS.Parameter> params, FunctionBody body) { | 1266 List<JS.Parameter> params, FunctionBody body) { |
| 1295 var kind = body.isSynchronous ? 'sync' : 'async'; | 1267 var kind = body.isSynchronous ? 'sync' : 'async'; |
| 1296 if (body.isGenerator) kind += 'Star'; | 1268 if (body.isGenerator) kind += 'Star'; |
| 1297 | 1269 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1335 _asyncStarController = null; | 1307 _asyncStarController = null; |
| 1336 jsParams = params; | 1308 jsParams = params; |
| 1337 } | 1309 } |
| 1338 JS.Expression gen = new JS.Fun(jsParams, _visit(body), isGenerator: true); | 1310 JS.Expression gen = new JS.Fun(jsParams, _visit(body), isGenerator: true); |
| 1339 if (JS.This.foundIn(gen)) { | 1311 if (JS.This.foundIn(gen)) { |
| 1340 gen = js.call('#.bind(this)', gen); | 1312 gen = js.call('#.bind(this)', gen); |
| 1341 } | 1313 } |
| 1342 _asyncStarController = savedController; | 1314 _asyncStarController = savedController; |
| 1343 | 1315 |
| 1344 var T = _emitTypeName(rules.getExpectedReturnType(body)); | 1316 var T = _emitTypeName(rules.getExpectedReturnType(body)); |
| 1345 return js.call('dart.#(#)', [kind, [gen, T]..addAll(params)]); | 1317 return js.call('dart.#(#)', [ |
| 1318 kind, |
| 1319 [gen, T]..addAll(params) |
| 1320 ]); |
| 1346 } | 1321 } |
| 1347 | 1322 |
| 1348 @override | 1323 @override |
| 1349 JS.Statement visitFunctionDeclarationStatement( | 1324 JS.Statement visitFunctionDeclarationStatement( |
| 1350 FunctionDeclarationStatement node) { | 1325 FunctionDeclarationStatement node) { |
| 1351 var func = node.functionDeclaration; | 1326 var func = node.functionDeclaration; |
| 1352 if (func.isGetter || func.isSetter) { | 1327 if (func.isGetter || func.isSetter) { |
| 1353 return js.comment('Unimplemented function get/set statement: $node'); | 1328 return js.comment('Unimplemented function get/set statement: $node'); |
| 1354 } | 1329 } |
| 1355 | 1330 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 } | 1466 } |
| 1492 | 1467 |
| 1493 /// Emits a Dart [type] into code. | 1468 /// Emits a Dart [type] into code. |
| 1494 /// | 1469 /// |
| 1495 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a | 1470 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a |
| 1496 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form | 1471 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form |
| 1497 /// will be used instead of `List`. These flags are used when generating | 1472 /// will be used instead of `List`. These flags are used when generating |
| 1498 /// the definitions for typedefs and generic types, respectively. | 1473 /// the definitions for typedefs and generic types, respectively. |
| 1499 JS.Expression _emitTypeName(DartType type, | 1474 JS.Expression _emitTypeName(DartType type, |
| 1500 {bool lowerTypedef: false, bool lowerGeneric: false}) { | 1475 {bool lowerTypedef: false, bool lowerGeneric: false}) { |
| 1501 | |
| 1502 // The void and dynamic types are not defined in core. | 1476 // The void and dynamic types are not defined in core. |
| 1503 if (type.isVoid) { | 1477 if (type.isVoid) { |
| 1504 return js.call('dart.void'); | 1478 return js.call('dart.void'); |
| 1505 } else if (type.isDynamic) { | 1479 } else if (type.isDynamic) { |
| 1506 return js.call('dart.dynamic'); | 1480 return js.call('dart.dynamic'); |
| 1507 } else if (type.isBottom) { | 1481 } else if (type.isBottom) { |
| 1508 return js.call('dart.bottom'); | 1482 return js.call('dart.bottom'); |
| 1509 } | 1483 } |
| 1510 | 1484 |
| 1511 _loader.declareBeforeUse(type.element); | 1485 _loader.declareBeforeUse(type.element); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1664 if (DynamicInvoke.get(target)) { | 1638 if (DynamicInvoke.get(target)) { |
| 1665 code = 'dart.$DSEND(#, #, #)'; | 1639 code = 'dart.$DSEND(#, #, #)'; |
| 1666 } else if (DynamicInvoke.get(node.methodName)) { | 1640 } else if (DynamicInvoke.get(node.methodName)) { |
| 1667 // This is a dynamic call to a statically know target. For example: | 1641 // This is a dynamic call to a statically know target. For example: |
| 1668 // class Foo { Function bar; } | 1642 // class Foo { Function bar; } |
| 1669 // new Foo().bar(); // dynamic call | 1643 // new Foo().bar(); // dynamic call |
| 1670 code = 'dart.$DCALL(#.#, #)'; | 1644 code = 'dart.$DCALL(#.#, #)'; |
| 1671 } else if (_requiresStaticDispatch(target, name)) { | 1645 } else if (_requiresStaticDispatch(target, name)) { |
| 1672 assert(rules.objectMembers[name] is FunctionType); | 1646 assert(rules.objectMembers[name] is FunctionType); |
| 1673 // Object methods require a helper for null checks. | 1647 // Object methods require a helper for null checks. |
| 1674 return js.call('dart.#(#, #)', [ | 1648 return js.call('dart.#(#, #)', |
| 1675 memberName, | 1649 [memberName, _visit(target), _visit(node.argumentList)]); |
| 1676 _visit(target), | |
| 1677 _visit(node.argumentList) | |
| 1678 ]); | |
| 1679 } else { | 1650 } else { |
| 1680 code = '#.#(#)'; | 1651 code = '#.#(#)'; |
| 1681 } | 1652 } |
| 1682 | 1653 |
| 1683 return js.call( | 1654 return js.call( |
| 1684 code, [_visit(target), memberName, _visit(node.argumentList)]); | 1655 code, [_visit(target), memberName, _visit(node.argumentList)]); |
| 1685 } | 1656 } |
| 1686 | 1657 |
| 1687 /// Emits code for the `JS(...)` builtin. | 1658 /// Emits code for the `JS(...)` builtin. |
| 1688 _emitForeignJS(MethodInvocation node) { | 1659 _emitForeignJS(MethodInvocation node) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1779 // becomes: | 1750 // becomes: |
| 1780 // | 1751 // |
| 1781 // if (stream.add(e)) return; | 1752 // if (stream.add(e)) return; |
| 1782 // yield; | 1753 // yield; |
| 1783 // | 1754 // |
| 1784 // `yield* e` becomes: | 1755 // `yield* e` becomes: |
| 1785 // | 1756 // |
| 1786 // if (stream.addStream(e)) return; | 1757 // if (stream.addStream(e)) return; |
| 1787 // yield; | 1758 // yield; |
| 1788 var helperName = star ? 'addStream' : 'add'; | 1759 var helperName = star ? 'addStream' : 'add'; |
| 1789 return js.statement('{ if(#.#(#)) return; #; }', [ | 1760 return js.statement('{ if(#.#(#)) return; #; }', |
| 1790 _asyncStarController, | 1761 [_asyncStarController, helperName, jsExpr, new JS.Yield(null)]); |
| 1791 helperName, | |
| 1792 jsExpr, | |
| 1793 new JS.Yield(null) | |
| 1794 ]); | |
| 1795 } | 1762 } |
| 1796 // A normal yield in a sync* | 1763 // A normal yield in a sync* |
| 1797 return jsExpr.toYieldStatement(star: star); | 1764 return jsExpr.toYieldStatement(star: star); |
| 1798 } | 1765 } |
| 1799 | 1766 |
| 1800 @override | 1767 @override |
| 1801 JS.Expression visitAwaitExpression(AwaitExpression node) { | 1768 JS.Expression visitAwaitExpression(AwaitExpression node) { |
| 1802 return new JS.Yield(_visit(node.expression)); | 1769 return new JS.Yield(_visit(node.expression)); |
| 1803 } | 1770 } |
| 1804 | 1771 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1900 body.add(_emitLazyFields(_lazyFields)); | 1867 body.add(_emitLazyFields(_lazyFields)); |
| 1901 _lazyFields.clear(); | 1868 _lazyFields.clear(); |
| 1902 } | 1869 } |
| 1903 | 1870 |
| 1904 JS.Statement _emitLazyFields(List<VariableDeclaration> fields) { | 1871 JS.Statement _emitLazyFields(List<VariableDeclaration> fields) { |
| 1905 var methods = []; | 1872 var methods = []; |
| 1906 for (var node in fields) { | 1873 for (var node in fields) { |
| 1907 var name = node.name.name; | 1874 var name = node.name.name; |
| 1908 var element = node.element; | 1875 var element = node.element; |
| 1909 var access = _emitMemberName(name, type: element.type, isStatic: true); | 1876 var access = _emitMemberName(name, type: element.type, isStatic: true); |
| 1910 methods.add(new JS.Method(access, js.call( | 1877 methods.add(new JS.Method( |
| 1911 'function() { return #; }', _visit(node.initializer)) as JS.Fun, | 1878 access, |
| 1879 js.call('function() { return #; }', _visit(node.initializer)) |
| 1880 as JS.Fun, |
| 1912 isGetter: true)); | 1881 isGetter: true)); |
| 1913 | 1882 |
| 1914 // TODO(jmesserly): use a dummy setter to indicate writable. | 1883 // TODO(jmesserly): use a dummy setter to indicate writable. |
| 1915 if (!node.isFinal) { | 1884 if (!node.isFinal) { |
| 1916 methods.add(new JS.Method(access, js.call('function(_) {}') as JS.Fun, | 1885 methods.add(new JS.Method(access, js.call('function(_) {}') as JS.Fun, |
| 1917 isSetter: true)); | 1886 isSetter: true)); |
| 1918 } | 1887 } |
| 1919 } | 1888 } |
| 1920 | 1889 |
| 1921 JS.Expression objExpr = _exportsVar; | 1890 JS.Expression objExpr = _exportsVar; |
| 1922 var target = _lazyFields[0].element.enclosingElement; | 1891 var target = _lazyFields[0].element.enclosingElement; |
| 1923 if (target is ClassElement) { | 1892 if (target is ClassElement) { |
| 1924 objExpr = new JS.Identifier(target.type.name); | 1893 objExpr = new JS.Identifier(target.type.name); |
| 1925 } | 1894 } |
| 1926 | 1895 |
| 1927 return js.statement( | 1896 return js.statement( |
| 1928 'dart.defineLazyProperties(#, { # });', [objExpr, methods]); | 1897 'dart.defineLazyProperties(#, { # });', [objExpr, methods]); |
| 1929 } | 1898 } |
| 1930 | 1899 |
| 1931 void _flushLibraryProperties(List<JS.Statement> body) { | 1900 void _flushLibraryProperties(List<JS.Statement> body) { |
| 1932 if (_properties.isEmpty) return; | 1901 if (_properties.isEmpty) return; |
| 1933 body.add(js.statement('dart.copyProperties(#, { # });', [ | 1902 body.add(js.statement('dart.copyProperties(#, { # });', |
| 1934 _exportsVar, | 1903 [_exportsVar, _properties.map(_emitTopLevelProperty)])); |
| 1935 _properties.map(_emitTopLevelProperty) | |
| 1936 ])); | |
| 1937 _properties.clear(); | 1904 _properties.clear(); |
| 1938 } | 1905 } |
| 1939 | 1906 |
| 1940 JS.Expression _emitConstructorName( | 1907 JS.Expression _emitConstructorName( |
| 1941 ConstructorElement element, DartType type, SimpleIdentifier name) { | 1908 ConstructorElement element, DartType type, SimpleIdentifier name) { |
| 1942 var typeName = _emitTypeName(type); | 1909 var typeName = _emitTypeName(type); |
| 1943 if (name != null || element.isFactory) { | 1910 if (name != null || element.isFactory) { |
| 1944 var namedCtor = _constructorName(element); | 1911 var namedCtor = _constructorName(element); |
| 1945 return new JS.PropertyAccess(typeName, namedCtor); | 1912 return new JS.PropertyAccess(typeName, namedCtor); |
| 1946 } | 1913 } |
| 1947 return typeName; | 1914 return typeName; |
| 1948 } | 1915 } |
| 1949 | 1916 |
| 1950 @override | 1917 @override |
| 1951 visitConstructorName(ConstructorName node) { | 1918 visitConstructorName(ConstructorName node) { |
| 1952 return _emitConstructorName(node.staticElement, node.type.type, node.name); | 1919 return _emitConstructorName(node.staticElement, node.type.type, node.name); |
| 1953 } | 1920 } |
| 1954 | 1921 |
| 1955 JS.Expression _emitInstanceCreationExpression(ConstructorElement element, | 1922 JS.Expression _emitInstanceCreationExpression( |
| 1956 DartType type, SimpleIdentifier name, ArgumentList argumentList, | 1923 ConstructorElement element, |
| 1924 DartType type, |
| 1925 SimpleIdentifier name, |
| 1926 ArgumentList argumentList, |
| 1957 bool isConst) { | 1927 bool isConst) { |
| 1958 JS.Expression emitNew() { | 1928 JS.Expression emitNew() { |
| 1959 JS.Expression ctor; | 1929 JS.Expression ctor; |
| 1960 bool isFactory = false; | 1930 bool isFactory = false; |
| 1961 // var element = node.staticElement; | 1931 // var element = node.staticElement; |
| 1962 if (element == null) { | 1932 if (element == null) { |
| 1963 // TODO(jmesserly): this only happens if we had a static error. | 1933 // TODO(jmesserly): this only happens if we had a static error. |
| 1964 // Should we generate a throw instead? | 1934 // Should we generate a throw instead? |
| 1965 ctor = _emitTypeName(type); | 1935 ctor = _emitTypeName(type); |
| 1966 if (name != null) { | 1936 if (name != null) { |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2096 return _emitSend(left, op.lexeme, [right]); | 2066 return _emitSend(left, op.lexeme, [right]); |
| 2097 } else { | 2067 } else { |
| 2098 var bang = op.type == TokenType.BANG_EQ ? '!' : ''; | 2068 var bang = op.type == TokenType.BANG_EQ ? '!' : ''; |
| 2099 code = '${bang}dart.equals(#, #)'; | 2069 code = '${bang}dart.equals(#, #)'; |
| 2100 } | 2070 } |
| 2101 return js.call(code, [_visit(left), _visit(right)]); | 2071 return js.call(code, [_visit(left), _visit(right)]); |
| 2102 } | 2072 } |
| 2103 | 2073 |
| 2104 if (binaryOperationIsPrimitive(leftType, rightType) || | 2074 if (binaryOperationIsPrimitive(leftType, rightType) || |
| 2105 rules.isStringType(leftType) && op.type == TokenType.PLUS) { | 2075 rules.isStringType(leftType) && op.type == TokenType.PLUS) { |
| 2106 | |
| 2107 // special cases where we inline the operation | 2076 // special cases where we inline the operation |
| 2108 // these values are assumed to be non-null (determined by the checker) | 2077 // these values are assumed to be non-null (determined by the checker) |
| 2109 // TODO(jmesserly): it would be nice to just inline the method from core, | 2078 // TODO(jmesserly): it would be nice to just inline the method from core, |
| 2110 // instead of special cases here. | 2079 // instead of special cases here. |
| 2111 if (op.type == TokenType.TILDE_SLASH) { | 2080 if (op.type == TokenType.TILDE_SLASH) { |
| 2112 // `a ~/ b` is equivalent to `(a / b).truncate()` | 2081 // `a ~/ b` is equivalent to `(a / b).truncate()` |
| 2113 var div = AstBuilder.binaryExpression(left, '/', right) | 2082 var div = AstBuilder.binaryExpression(left, '/', right) |
| 2114 ..staticType = node.staticType; | 2083 ..staticType = node.staticType; |
| 2115 return _emitSend(div, 'truncate', []); | 2084 return _emitSend(div, 'truncate', []); |
| 2116 } else { | 2085 } else { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2173 /// | 2142 /// |
| 2174 /// If the expression does not end up using `x1` or `x2` more than once, or | 2143 /// If the expression does not end up using `x1` or `x2` more than once, or |
| 2175 /// if those expressions can be treated as stateless (e.g. they are | 2144 /// if those expressions can be treated as stateless (e.g. they are |
| 2176 /// non-mutated variables), then the resulting code will be simplified | 2145 /// non-mutated variables), then the resulting code will be simplified |
| 2177 /// automatically. | 2146 /// automatically. |
| 2178 /// | 2147 /// |
| 2179 /// [scope] can be mutated to contain any new temporaries that were created, | 2148 /// [scope] can be mutated to contain any new temporaries that were created, |
| 2180 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not | 2149 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not |
| 2181 /// needed. | 2150 /// needed. |
| 2182 Expression _bindLeftHandSide( | 2151 Expression _bindLeftHandSide( |
| 2183 Map<String, JS.Expression> scope, Expression expr, {Expression context}) { | 2152 Map<String, JS.Expression> scope, Expression expr, |
| 2153 {Expression context}) { |
| 2184 Expression result; | 2154 Expression result; |
| 2185 if (expr is IndexExpression) { | 2155 if (expr is IndexExpression) { |
| 2186 IndexExpression index = expr; | 2156 IndexExpression index = expr; |
| 2187 result = new IndexExpression.forTarget( | 2157 result = new IndexExpression.forTarget( |
| 2188 _bindValue(scope, 'o', index.target, context: context), | 2158 _bindValue(scope, 'o', index.target, context: context), |
| 2189 index.leftBracket, | 2159 index.leftBracket, |
| 2190 _bindValue(scope, 'i', index.index, context: context), | 2160 _bindValue(scope, 'i', index.index, context: context), |
| 2191 index.rightBracket); | 2161 index.rightBracket); |
| 2192 } else if (expr is PropertyAccess) { | 2162 } else if (expr is PropertyAccess) { |
| 2193 PropertyAccess prop = expr; | 2163 PropertyAccess prop = expr; |
| 2194 result = new PropertyAccess( | 2164 result = new PropertyAccess( |
| 2195 _bindValue(scope, 'o', _getTarget(prop), context: context), | 2165 _bindValue(scope, 'o', _getTarget(prop), context: context), |
| 2196 prop.operator, prop.propertyName); | 2166 prop.operator, |
| 2167 prop.propertyName); |
| 2197 } else if (expr is PrefixedIdentifier) { | 2168 } else if (expr is PrefixedIdentifier) { |
| 2198 PrefixedIdentifier ident = expr; | 2169 PrefixedIdentifier ident = expr; |
| 2199 result = new PrefixedIdentifier(_bindValue(scope, 'o', ident.prefix, | 2170 result = new PrefixedIdentifier( |
| 2200 context: context) as SimpleIdentifier, ident.period, | 2171 _bindValue(scope, 'o', ident.prefix, context: context) |
| 2172 as SimpleIdentifier, |
| 2173 ident.period, |
| 2201 ident.identifier); | 2174 ident.identifier); |
| 2202 } else { | 2175 } else { |
| 2203 return expr as SimpleIdentifier; | 2176 return expr as SimpleIdentifier; |
| 2204 } | 2177 } |
| 2205 result.staticType = expr.staticType; | 2178 result.staticType = expr.staticType; |
| 2206 DynamicInvoke.set(result, DynamicInvoke.get(expr)); | 2179 DynamicInvoke.set(result, DynamicInvoke.get(expr)); |
| 2207 return result; | 2180 return result; |
| 2208 } | 2181 } |
| 2209 | 2182 |
| 2210 /// Creates a temporary to contain the value of [expr]. The temporary can be | 2183 /// Creates a temporary to contain the value of [expr]. The temporary can be |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2411 Expression target, String name, List<Expression> args) { | 2384 Expression target, String name, List<Expression> args) { |
| 2412 var type = getStaticType(target); | 2385 var type = getStaticType(target); |
| 2413 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); | 2386 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); |
| 2414 if (DynamicInvoke.get(target)) { | 2387 if (DynamicInvoke.get(target)) { |
| 2415 // dynamic dispatch | 2388 // dynamic dispatch |
| 2416 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name]; | 2389 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name]; |
| 2417 if (dynamicHelper != null) { | 2390 if (dynamicHelper != null) { |
| 2418 return js.call( | 2391 return js.call( |
| 2419 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); | 2392 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); |
| 2420 } | 2393 } |
| 2421 return js.call('dart.$DSEND(#, #, #)', [ | 2394 return js.call('dart.$DSEND(#, #, #)', |
| 2422 _visit(target), | 2395 [_visit(target), memberName, _visitList(args)]); |
| 2423 memberName, | |
| 2424 _visitList(args) | |
| 2425 ]); | |
| 2426 } | 2396 } |
| 2427 | 2397 |
| 2428 // Generic dispatch to a statically known method. | 2398 // Generic dispatch to a statically known method. |
| 2429 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); | 2399 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); |
| 2430 } | 2400 } |
| 2431 | 2401 |
| 2432 @override | 2402 @override |
| 2433 visitIndexExpression(IndexExpression node) { | 2403 visitIndexExpression(IndexExpression node) { |
| 2434 var target = _getTarget(node); | 2404 var target = _getTarget(node); |
| 2435 if (_useNativeJsIndexer(target.staticType)) { | 2405 if (_useNativeJsIndexer(target.staticType)) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2536 // TODO(jmesserly): we may want a helper if these become common. For now the | 2506 // TODO(jmesserly): we may want a helper if these become common. For now the |
| 2537 // full desugaring seems okay. | 2507 // full desugaring seems okay. |
| 2538 var context = compiler.context; | 2508 var context = compiler.context; |
| 2539 var dart_async = context | 2509 var dart_async = context |
| 2540 .computeLibraryElement(context.sourceFactory.forUri('dart:async')); | 2510 .computeLibraryElement(context.sourceFactory.forUri('dart:async')); |
| 2541 var T = node.loopVariable.element.type; | 2511 var T = node.loopVariable.element.type; |
| 2542 var StreamIterator_T = | 2512 var StreamIterator_T = |
| 2543 dart_async.getType('StreamIterator').type.substitute4([T]); | 2513 dart_async.getType('StreamIterator').type.substitute4([T]); |
| 2544 | 2514 |
| 2545 var createStreamIter = _emitInstanceCreationExpression( | 2515 var createStreamIter = _emitInstanceCreationExpression( |
| 2546 StreamIterator_T.element.unnamedConstructor, StreamIterator_T, null, | 2516 StreamIterator_T.element.unnamedConstructor, |
| 2547 AstBuilder.argumentList([node.iterable]), false); | 2517 StreamIterator_T, |
| 2518 null, |
| 2519 AstBuilder.argumentList([node.iterable]), |
| 2520 false); |
| 2548 var iter = _visit(_createTemporary('it', StreamIterator_T)); | 2521 var iter = _visit(_createTemporary('it', StreamIterator_T)); |
| 2549 | 2522 |
| 2550 var init = _visit(node.identifier); | 2523 var init = _visit(node.identifier); |
| 2551 if (init == null) { | 2524 if (init == null) { |
| 2552 init = js.call( | 2525 init = js.call( |
| 2553 'let # = #.current', [node.loopVariable.identifier.name, iter]); | 2526 'let # = #.current', [node.loopVariable.identifier.name, iter]); |
| 2554 } else { | 2527 } else { |
| 2555 init = js.call('# = #.current', [init, iter]); | 2528 init = js.call('# = #.current', [init, iter]); |
| 2556 } | 2529 } |
| 2557 return js.statement('{' | 2530 return js.statement( |
| 2531 '{' |
| 2558 ' let # = #;' | 2532 ' let # = #;' |
| 2559 ' try {' | 2533 ' try {' |
| 2560 ' while (#) { #; #; }' | 2534 ' while (#) { #; #; }' |
| 2561 ' } finally { #; }' | 2535 ' } finally { #; }' |
| 2562 '}', [ | 2536 '}', |
| 2537 [ |
| 2563 iter, | 2538 iter, |
| 2564 createStreamIter, | 2539 createStreamIter, |
| 2565 new JS.Yield(js.call('#.moveNext()', iter)), | 2540 new JS.Yield(js.call('#.moveNext()', iter)), |
| 2566 init, | 2541 init, |
| 2567 _visit(node.body), | 2542 _visit(node.body), |
| 2568 new JS.Yield(js.call('#.cancel()', iter)) | 2543 new JS.Yield(js.call('#.cancel()', iter)) |
| 2569 ]); | 2544 ]); |
| 2570 } | 2545 } |
| 2571 | 2546 |
| 2572 @override | 2547 @override |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2612 } | 2587 } |
| 2613 | 2588 |
| 2614 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { | 2589 JS.Statement _catchClauseGuard(CatchClause clause, JS.Statement otherwise) { |
| 2615 var then = visitCatchClause(clause); | 2590 var then = visitCatchClause(clause); |
| 2616 | 2591 |
| 2617 // Discard following clauses, if any, as they are unreachable. | 2592 // Discard following clauses, if any, as they are unreachable. |
| 2618 if (clause.exceptionType == null) return then; | 2593 if (clause.exceptionType == null) return then; |
| 2619 | 2594 |
| 2620 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which | 2595 // TODO(jmesserly): this is inconsistent with [visitIsExpression], which |
| 2621 // has special case for typeof. | 2596 // has special case for typeof. |
| 2622 return new JS.If(js.call('dart.is(#, #)', [ | 2597 return new JS.If( |
| 2623 _visit(_catchParameter), | 2598 js.call('dart.is(#, #)', [ |
| 2624 _emitTypeName(clause.exceptionType.type), | 2599 _visit(_catchParameter), |
| 2625 ]), then, otherwise); | 2600 _emitTypeName(clause.exceptionType.type), |
| 2601 ]), |
| 2602 then, |
| 2603 otherwise); |
| 2626 } | 2604 } |
| 2627 | 2605 |
| 2628 JS.Statement _statement(List<JS.Statement> statements) { | 2606 JS.Statement _statement(List<JS.Statement> statements) { |
| 2629 // TODO(jmesserly): empty block singleton? | 2607 // TODO(jmesserly): empty block singleton? |
| 2630 if (statements.length == 0) return new JS.Block([]); | 2608 if (statements.length == 0) return new JS.Block([]); |
| 2631 if (statements.length == 1) return statements[0]; | 2609 if (statements.length == 1) return statements[0]; |
| 2632 return new JS.Block(statements); | 2610 return new JS.Block(statements); |
| 2633 } | 2611 } |
| 2634 | 2612 |
| 2635 /// Visits the catch clause body. This skips the exception type guard, if any. | 2613 /// Visits the catch clause body. This skips the exception type guard, if any. |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2883 /// | 2861 /// |
| 2884 /// This follows the same pattern as EcmaScript 6 Map: | 2862 /// This follows the same pattern as EcmaScript 6 Map: |
| 2885 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> | 2863 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> |
| 2886 /// | 2864 /// |
| 2887 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed | 2865 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed |
| 2888 /// for this transformation to happen, otherwise binary minus is assumed. | 2866 /// for this transformation to happen, otherwise binary minus is assumed. |
| 2889 /// | 2867 /// |
| 2890 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 2868 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
| 2891 /// helper, that checks for null. The user defined method is called '=='. | 2869 /// helper, that checks for null. The user defined method is called '=='. |
| 2892 /// | 2870 /// |
| 2893 JS.Expression _emitMemberName(String name, {DartType type, bool unary: false, | 2871 JS.Expression _emitMemberName(String name, |
| 2894 bool isStatic: false, bool allowExtensions: true}) { | 2872 {DartType type, |
| 2895 | 2873 bool unary: false, |
| 2874 bool isStatic: false, |
| 2875 bool allowExtensions: true}) { |
| 2896 // Static members skip the rename steps. | 2876 // Static members skip the rename steps. |
| 2897 if (isStatic) return _propertyName(name); | 2877 if (isStatic) return _propertyName(name); |
| 2898 | 2878 |
| 2899 if (name.startsWith('_')) { | 2879 if (name.startsWith('_')) { |
| 2900 return _privateNames.putIfAbsent( | 2880 return _privateNames.putIfAbsent( |
| 2901 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); | 2881 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId); |
| 2902 } | 2882 } |
| 2903 | 2883 |
| 2904 if (name == '[]') { | 2884 if (name == '[]') { |
| 2905 name = 'get'; | 2885 name = 'get'; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2999 | 2979 |
| 3000 /// A special kind of element created by the compiler, signifying a temporary | 2980 /// A special kind of element created by the compiler, signifying a temporary |
| 3001 /// variable. These objects use instance equality, and should be shared | 2981 /// variable. These objects use instance equality, and should be shared |
| 3002 /// everywhere in the tree where they are treated as the same variable. | 2982 /// everywhere in the tree where they are treated as the same variable. |
| 3003 class TemporaryVariableElement extends LocalVariableElementImpl { | 2983 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3004 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 2984 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3005 | 2985 |
| 3006 int get hashCode => identityHashCode(this); | 2986 int get hashCode => identityHashCode(this); |
| 3007 bool operator ==(Object other) => identical(this, other); | 2987 bool operator ==(Object other) => identical(this, other); |
| 3008 } | 2988 } |
| OLD | NEW |