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; | 7 import 'dart:collection' show HashSet; |
| 8 import 'dart:io' show Directory, File; | 8 import 'dart:io' show Directory, File; |
| 9 | 9 |
| 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 import 'package:dev_compiler/src/utils.dart'; | 31 import 'package:dev_compiler/src/utils.dart'; |
| 32 import 'code_generator.dart'; | 32 import 'code_generator.dart'; |
| 33 | 33 |
| 34 // This must match the optional parameter name used in runtime.js | 34 // This must match the optional parameter name used in runtime.js |
| 35 const String _jsNamedParameterName = r'opt$'; | 35 const String _jsNamedParameterName = r'opt$'; |
| 36 | 36 |
| 37 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { | 37 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| 38 final LibraryInfo libraryInfo; | 38 final LibraryInfo libraryInfo; |
| 39 final TypeRules rules; | 39 final TypeRules rules; |
| 40 | 40 |
| 41 // TODO(jmesserly): this is needed because RestrictedTypeRules can send | |
| 42 // messages to CheckerReporter, for things like missing types. | |
| 43 // We should probably refactor so this can't happen, as codegen would be too | |
| 44 // late to be issuing these messages. | |
| 45 final CheckerReporter _checkerReporter; | |
| 46 | |
| 41 /// The variable for the target of the current `..` cascade expression. | 47 /// The variable for the target of the current `..` cascade expression. |
| 42 SimpleIdentifier _cascadeTarget; | 48 SimpleIdentifier _cascadeTarget; |
| 43 /// The variable for the current catch clause | 49 /// The variable for the current catch clause |
| 44 String _catchParameter; | 50 String _catchParameter; |
| 45 | 51 |
| 46 ClassDeclaration currentClass; | 52 ClassDeclaration currentClass; |
| 47 ConstantEvaluator _constEvaluator; | 53 ConstantEvaluator _constEvaluator; |
| 48 | 54 |
| 49 final _exports = <String>[]; | 55 final _exports = <String>[]; |
| 50 final _lazyFields = <VariableDeclaration>[]; | 56 final _lazyFields = <VariableDeclaration>[]; |
| 51 final _properties = <FunctionDeclaration>[]; | 57 final _properties = <FunctionDeclaration>[]; |
| 52 final _privateNames = new HashSet<String>(); | 58 final _privateNames = new HashSet<String>(); |
| 53 final _pendingPrivateNames = <String>[]; | 59 final _pendingPrivateNames = <String>[]; |
| 54 | 60 |
| 55 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules) | 61 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter); |
| 56 : libraryInfo = libraryInfo, | |
| 57 rules = rules; | |
| 58 | 62 |
| 59 Element get currentLibrary => libraryInfo.library; | 63 Element get currentLibrary => libraryInfo.library; |
| 60 | 64 |
| 61 JS.Program generateLibrary( | 65 JS.Program generateLibrary(Iterable<CompilationUnit> units) { |
| 62 Iterable<CompilationUnit> units, CheckerReporter reporter) { | |
| 63 var body = <JS.Statement>[]; | 66 var body = <JS.Statement>[]; |
| 64 for (var unit in units) { | 67 |
| 65 // TODO(jmesserly): this is needed because RestrictedTypeRules can send | 68 // Visit parts first, since the "part" declarations come before code |
| 66 // messages to CheckerReporter, for things like missing types. | 69 // in the main library's compilation unit. |
|
vsm
2015/03/17 18:27:32
Is there a way to assert that the first is a libra
Jennifer Messerly
2015/03/17 18:58:45
Done. Introduced "LibraryUnit" type to assert the
| |
| 67 // We should probably refactor so this can't happen. | 70 for (var unit in units.skip(1)) { |
| 68 var source = unit.element.source; | |
| 69 _constEvaluator = new ConstantEvaluator(source, rules.provider); | |
| 70 reporter.enterSource(source); | |
| 71 body.add(_visit(unit)); | 71 body.add(_visit(unit)); |
| 72 reporter.leaveSource(); | |
| 73 } | 72 } |
| 74 | 73 |
| 74 // Visit main library | |
| 75 body.add(_visit(units.first)); | |
| 76 | |
| 75 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); | 77 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); |
| 76 | 78 |
| 77 // TODO(jmesserly): make these immutable in JS? | 79 // TODO(jmesserly): make these immutable in JS? |
| 78 for (var name in _exports) { | 80 for (var name in _exports) { |
| 79 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); | 81 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); |
| 80 } | 82 } |
| 81 | 83 |
| 82 var name = jsLibraryName(libraryInfo.library); | 84 var name = jsLibraryName(libraryInfo.library); |
| 83 return new JS.Program([ | 85 return new JS.Program([ |
| 84 js.statement('var #;', name), | 86 js.statement('var #;', name), |
| 85 js.statement("(function($_EXPORTS) { 'use strict'; #; })(# || (# = {}));", | 87 js.statement("(function($_EXPORTS) { 'use strict'; #; })(# || (# = {}));", |
| 86 [body, name, name]) | 88 [body, name, name]) |
| 87 ]); | 89 ]); |
| 88 } | 90 } |
| 89 | 91 |
| 90 JS.Statement _initPrivateSymbol(String name) => | 92 JS.Statement _initPrivateSymbol(String name) => |
| 91 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]); | 93 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]); |
| 92 | 94 |
| 93 @override | 95 @override |
| 94 JS.Statement visitCompilationUnit(CompilationUnit node) { | 96 JS.Statement visitCompilationUnit(CompilationUnit node) { |
| 97 var source = node.element.source; | |
| 98 | |
| 99 _constEvaluator = new ConstantEvaluator(source, rules.provider); | |
| 100 _checkerReporter.enterSource(source); | |
| 101 | |
| 95 // TODO(jmesserly): scriptTag, directives. | 102 // TODO(jmesserly): scriptTag, directives. |
| 96 var body = <JS.Statement>[]; | 103 var body = <JS.Statement>[]; |
| 97 for (var child in node.declarations) { | 104 for (var child in node.declarations) { |
| 98 // Attempt to group adjacent fields/properties. | 105 // Attempt to group adjacent fields/properties. |
| 99 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); | 106 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); |
| 100 if (child is! FunctionDeclaration) _flushLibraryProperties(body); | 107 if (child is! FunctionDeclaration) _flushLibraryProperties(body); |
| 101 | 108 |
| 102 var code = _visit(child); | 109 var code = _visit(child); |
| 103 | 110 |
| 104 if (code != null) { | 111 if (code != null) { |
| 105 if (_pendingPrivateNames.isNotEmpty) { | 112 if (_pendingPrivateNames.isNotEmpty) { |
| 106 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); | 113 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); |
| 107 _pendingPrivateNames.clear(); | 114 _pendingPrivateNames.clear(); |
| 108 } | 115 } |
| 109 body.add(code); | 116 body.add(code); |
| 110 } | 117 } |
| 111 } | 118 } |
| 112 | 119 |
| 113 // Flush any unwritten fields/properties. | 120 // Flush any unwritten fields/properties. |
| 114 _flushLazyFields(body); | 121 _flushLazyFields(body); |
| 115 _flushLibraryProperties(body); | 122 _flushLibraryProperties(body); |
| 116 | 123 |
| 124 _checkerReporter.leaveSource(); | |
| 125 | |
| 117 assert(_pendingPrivateNames.isEmpty); | 126 assert(_pendingPrivateNames.isEmpty); |
| 118 return _statement(body); | 127 return _statement(body); |
| 119 } | 128 } |
| 120 | 129 |
| 121 bool isPublic(String name) => !name.startsWith('_'); | 130 bool isPublic(String name) => !name.startsWith('_'); |
| 122 | 131 |
| 123 /// Conversions that we don't handle end up here. | 132 /// Conversions that we don't handle end up here. |
| 124 @override | 133 @override |
| 125 visitConversion(Conversion node) { | 134 visitConversion(Conversion node) { |
| 126 var from = node.baseType; | 135 var from = node.baseType; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 'let # = dart.generic(function(#) { #; return #; });', [ | 221 'let # = dart.generic(function(#) { #; return #; });', [ |
| 213 genericName, | 222 genericName, |
| 214 _visitList(node.typeParameters), | 223 _visitList(node.typeParameters), |
| 215 clazz, | 224 clazz, |
| 216 name | 225 name |
| 217 ]); | 226 ]); |
| 218 | 227 |
| 219 // TODO(jmesserly): we may not want this to be `dynamic` if the generic | 228 // TODO(jmesserly): we may not want this to be `dynamic` if the generic |
| 220 // has a lower bound, e.g. `<T extends SomeType>`. | 229 // has a lower bound, e.g. `<T extends SomeType>`. |
| 221 // https://github.com/dart-lang/dart-dev-compiler/issues/38 | 230 // https://github.com/dart-lang/dart-dev-compiler/issues/38 |
| 222 var typeArgs = new List.filled(node.typeParameters.length, 'dynamic'); | 231 var typeArgs = |
| 232 new List.filled(node.typeParameters.length, js.call('dart.dynamic')); | |
| 223 | 233 |
| 224 var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]); | 234 var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]); |
| 225 | 235 |
| 226 // TODO(jmesserly): is it worth exporting both names? Alternatively we could | 236 // TODO(jmesserly): is it worth exporting both names? Alternatively we could |
| 227 // put the generic type constructor on the <dynamic> instance. | 237 // put the generic type constructor on the <dynamic> instance. |
| 228 if (isPublic(name)) _exports.add('${name}\$'); | 238 if (isPublic(name)) _exports.add('${name}\$'); |
| 229 return new JS.Block([genericDef, dynInst]); | 239 return new JS.Block([genericDef, dynInst]); |
| 230 } | 240 } |
| 231 | 241 |
| 232 @override | 242 @override |
| 233 JS.Statement visitClassDeclaration(ClassDeclaration node) { | 243 JS.Statement visitClassDeclaration(ClassDeclaration node) { |
| 234 currentClass = node; | 244 currentClass = node; |
| 235 | 245 |
| 246 // dart:core Object is a bit special. | |
| 247 var isObject = node.element.type.isObject; | |
| 248 | |
| 236 var body = <JS.Statement>[]; | 249 var body = <JS.Statement>[]; |
| 237 | 250 |
| 238 var name = node.name.name; | 251 var name = node.name.name; |
| 239 var ctors = <ConstructorDeclaration>[]; | 252 var ctors = <ConstructorDeclaration>[]; |
| 240 var fields = <FieldDeclaration>[]; | 253 var fields = <FieldDeclaration>[]; |
| 241 var staticFields = <FieldDeclaration>[]; | 254 var staticFields = <FieldDeclaration>[]; |
| 242 for (var member in node.members) { | 255 for (var member in node.members) { |
| 243 if (member is ConstructorDeclaration) { | 256 if (member is ConstructorDeclaration) { |
| 244 ctors.add(member); | 257 ctors.add(member); |
| 245 } else if (member is FieldDeclaration) { | 258 } else if (member is FieldDeclaration) { |
| 246 (member.isStatic ? staticFields : fields).add(member); | 259 (member.isStatic ? staticFields : fields).add(member); |
| 247 } | 260 } |
| 248 } | 261 } |
| 249 | 262 |
| 250 var jsMethods = <JS.Method>[]; | 263 var jsMethods = <JS.Method>[]; |
| 251 // Iff no constructor is specified for a class C, it implicitly has a | 264 // Iff no constructor is specified for a class C, it implicitly has a |
| 252 // default constructor `C() : super() {}`, unless C is class Object. | 265 // default constructor `C() : super() {}`, unless C is class Object. |
| 253 if (ctors.isEmpty && !node.element.type.isObject) { | 266 if (ctors.isEmpty && !isObject) { |
| 254 jsMethods.add(_emitImplicitConstructor(node, name, fields)); | 267 jsMethods.add(_emitImplicitConstructor(node, name, fields)); |
| 255 } | 268 } |
| 256 | 269 |
| 257 for (var member in node.members) { | 270 for (var member in node.members) { |
| 258 if (member is ConstructorDeclaration) { | 271 if (member is ConstructorDeclaration) { |
| 259 jsMethods.add(_emitConstructor(member, name, fields)); | 272 jsMethods.add(_emitConstructor(member, name, fields, isObject)); |
| 260 } else if (member is MethodDeclaration) { | 273 } else if (member is MethodDeclaration) { |
| 261 jsMethods.add(_visit(member)); | 274 jsMethods.add(_visit(member)); |
| 262 } | 275 } |
| 263 } | 276 } |
| 264 | 277 |
| 265 // Support for adapting dart:core Iterator/Iterable to ES6 versions. | 278 // Support for adapting dart:core Iterator/Iterable to ES6 versions. |
| 266 // This lets them use for-of loops transparently. | 279 // This lets them use for-of loops transparently. |
| 267 // https://github.com/lukehoban/es6features#iterators--forof | 280 // https://github.com/lukehoban/es6features#iterators--forof |
| 268 if (node.element.library.isDartCore && node.element.name == 'Iterable') { | 281 if (node.element.library.isDartCore && node.element.name == 'Iterable') { |
| 269 JS.Fun body = js.call('''function() { | 282 JS.Fun body = js.call('''function() { |
| 270 var iterator = this.iterator; | 283 var iterator = this.iterator; |
| 271 return { | 284 return { |
| 272 next() { | 285 next() { |
| 273 var done = iterator.moveNext(); | 286 var done = iterator.moveNext(); |
| 274 return { done: done, current: done ? void 0 : iterator.current }; | 287 return { done: done, current: done ? void 0 : iterator.current }; |
| 275 } | 288 } |
| 276 }; | 289 }; |
| 277 }'''); | 290 }'''); |
| 278 jsMethods.add(new JS.Method(js.call('Symbol.iterator'), body)); | 291 jsMethods.add(new JS.Method(js.call('Symbol.iterator'), body)); |
| 279 } | 292 } |
| 280 | 293 |
| 281 JS.Expression heritage; | 294 JS.Expression heritage = null; |
| 282 if (node.extendsClause != null) { | 295 if (node.extendsClause != null) { |
| 283 heritage = _visit(node.extendsClause.superclass); | 296 heritage = _visit(node.extendsClause.superclass); |
| 284 } else { | 297 } else if (!isObject) { |
| 285 heritage = js.call('dart.Object'); | 298 heritage = _emitTypeName(rules.provider.objectType); |
| 286 } | 299 } |
| 287 if (node.withClause != null) { | 300 if (node.withClause != null) { |
| 288 var mixins = _visitList(node.withClause.mixinTypes); | 301 var mixins = _visitList(node.withClause.mixinTypes); |
| 289 mixins.insert(0, heritage); | 302 mixins.insert(0, heritage); |
| 290 heritage = js.call('dart.mixin(#)', [mixins]); | 303 heritage = js.call('dart.mixin(#)', [mixins]); |
| 291 } | 304 } |
| 292 body.add(new JS.ClassDeclaration(new JS.ClassExpression( | 305 body.add(new JS.ClassDeclaration(new JS.ClassExpression( |
| 293 new JS.VariableDeclaration(name), heritage, | 306 new JS.VariableDeclaration(name), heritage, |
| 294 jsMethods.where((m) => m != null).toList(growable: false)))); | 307 jsMethods.where((m) => m != null).toList(growable: false)))); |
| 295 | 308 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 if (fields.isEmpty) return null; | 347 if (fields.isEmpty) return null; |
| 335 | 348 |
| 336 dynamic body = _initializeFields(fields); | 349 dynamic body = _initializeFields(fields); |
| 337 var superCall = _superConstructorCall(node); | 350 var superCall = _superConstructorCall(node); |
| 338 if (superCall != null) body = [[body, superCall]]; | 351 if (superCall != null) body = [[body, superCall]]; |
| 339 return new JS.Method( | 352 return new JS.Method( |
| 340 new JS.PropertyName(name), js.call('function() { #; }', body)); | 353 new JS.PropertyName(name), js.call('function() { #; }', body)); |
| 341 } | 354 } |
| 342 | 355 |
| 343 JS.Method _emitConstructor(ConstructorDeclaration node, String className, | 356 JS.Method _emitConstructor(ConstructorDeclaration node, String className, |
| 344 List<FieldDeclaration> fields) { | 357 List<FieldDeclaration> fields, bool isObject) { |
| 345 if (_externalOrNative(node)) return null; | 358 if (_externalOrNative(node)) return null; |
| 346 | 359 |
| 347 var name = _constructorName(className, node.name); | 360 var name = _constructorName(className, node.name); |
| 348 | 361 |
| 362 // Code generation for Object's constructor. | |
| 363 JS.Block body; | |
| 364 if (isObject && | |
| 365 node.body is EmptyFunctionBody && | |
| 366 node.constKeyword != null && | |
| 367 node.name == null) { | |
| 368 // Implements Dart constructor behavior. Because of V8 `super` | |
| 369 // [constructor restrictions] | |
| 370 // (https://code.google.com/p/v8/issues/detail?id=3330#c65) | |
| 371 // we cannot currently emit actual ES6 constructors with super calls. | |
| 372 // Instead we use the same trick as named constructors, and do them as | |
| 373 // instance methods that perform initialization. | |
| 374 // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8 | |
| 375 // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>. | |
| 376 // Performance of this pattern is likely to be bad. | |
| 377 body = js.statement('''{ | |
| 378 // Get the class name for this instance. | |
| 379 var name = this.constructor.name; | |
| 380 // Call the default constructor. | |
| 381 var init = this[name]; | |
| 382 var result = void 0; | |
| 383 if (init) result = init.apply(this, arguments); | |
| 384 return result === void 0 ? this : result; | |
| 385 }'''); | |
| 386 } else { | |
| 387 body = _emitConstructorBody(node, fields); | |
| 388 } | |
| 389 | |
| 349 // We generate constructors as initializer methods in the class; | 390 // We generate constructors as initializer methods in the class; |
| 350 // this allows use of `super` for instance methods/properties. | 391 // this allows use of `super` for instance methods/properties. |
| 351 // It also avoids V8 restrictions on `super` in default constructors. | 392 // It also avoids V8 restrictions on `super` in default constructors. |
| 352 return new JS.Method(new JS.PropertyName(name), | 393 return new JS.Method( |
| 353 new JS.Fun(_visit(node.parameters), _emitConstructorBody(node, fields))) | 394 new JS.PropertyName(name), new JS.Fun(_visit(node.parameters), body)) |
| 354 ..sourceInformation = node; | 395 ..sourceInformation = node; |
| 355 } | 396 } |
| 356 | 397 |
| 357 String _constructorName(String className, SimpleIdentifier name) { | 398 String _constructorName(String className, SimpleIdentifier name) { |
| 358 if (name == null) return className; | 399 if (name == null) return className; |
| 359 return '$className\$${name.name}'; | 400 return '$className\$${name.name}'; |
| 360 } | 401 } |
| 361 | 402 |
| 362 JS.Block _emitConstructorBody( | 403 JS.Block _emitConstructorBody( |
| 363 ConstructorDeclaration node, List<FieldDeclaration> fields) { | 404 ConstructorDeclaration node, List<FieldDeclaration> fields) { |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 647 | 688 |
| 648 /// Writes a simple identifier. This can handle implicit `this` as well as | 689 /// Writes a simple identifier. This can handle implicit `this` as well as |
| 649 /// going through the qualified library name if necessary. | 690 /// going through the qualified library name if necessary. |
| 650 @override | 691 @override |
| 651 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { | 692 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
| 652 var e = node.staticElement; | 693 var e = node.staticElement; |
| 653 if (e == null) { | 694 if (e == null) { |
| 654 return js.commentExpression( | 695 return js.commentExpression( |
| 655 'Unimplemented unknown name', new JS.VariableUse(node.name)); | 696 'Unimplemented unknown name', new JS.VariableUse(node.name)); |
| 656 } | 697 } |
| 698 | |
| 657 var name = node.name; | 699 var name = node.name; |
| 700 var variable = e is PropertyAccessorElement ? e.variable : e; | |
| 701 | |
| 658 if (e.enclosingElement is CompilationUnitElement && | 702 if (e.enclosingElement is CompilationUnitElement && |
| 659 (e.library != libraryInfo.library || _needsModuleGetter(e))) { | 703 (e.library != libraryInfo.library || |
| 704 variable is TopLevelVariableElement && !variable.isConst)) { | |
| 660 return js.call('#.#', [_libraryName(e.library), name]); | 705 return js.call('#.#', [_libraryName(e.library), name]); |
| 661 } else if (currentClass != null && _needsImplicitThis(e)) { | 706 } else if (currentClass != null && _needsImplicitThis(e)) { |
| 662 return js.call('this.#', _jsMemberName(name)); | 707 return js.call('this.#', _jsMemberName(name)); |
| 708 } else if (variable is ConstFieldElementImpl) { | |
| 709 var className = (variable.enclosingElement as ClassElement).name; | |
| 710 return js.call('#.#', [className, name]); | |
| 663 } else if (e is ParameterElement && e.isInitializingFormal) { | 711 } else if (e is ParameterElement && e.isInitializingFormal) { |
| 664 name = _fieldParameterName(name); | 712 name = _fieldParameterName(name); |
| 665 } | 713 } |
| 666 return new JS.VariableUse(name); | 714 return new JS.VariableUse(name); |
| 667 } | 715 } |
| 668 | 716 |
| 669 JS.Expression _emitTypeName(DartType type) { | 717 JS.Expression _emitTypeName(DartType type) { |
| 670 var name = type.name; | 718 var name = type.name; |
| 671 var lib = type.element.library; | 719 var lib = type.element.library; |
| 672 if (name == '') { | 720 if (name == '') { |
| (...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1711 // ConstantEvaluator will not compute constants for non-const fields | 1759 // ConstantEvaluator will not compute constants for non-const fields |
| 1712 // at least for cases like `int x = 0;`, so run ConstantVisitor for those. | 1760 // at least for cases like `int x = 0;`, so run ConstantVisitor for those. |
| 1713 // TODO(jmesserly): ideally we'd only do this if we're sure it was skipped | 1761 // TODO(jmesserly): ideally we'd only do this if we're sure it was skipped |
| 1714 // by ConstantEvaluator. | 1762 // by ConstantEvaluator. |
| 1715 var initializer = field.initializer; | 1763 var initializer = field.initializer; |
| 1716 if (initializer == null) return null; | 1764 if (initializer == null) return null; |
| 1717 | 1765 |
| 1718 return _constEvaluator.evaluate(initializer); | 1766 return _constEvaluator.evaluate(initializer); |
| 1719 } | 1767 } |
| 1720 | 1768 |
| 1721 /// Returns true if [element] is a getter in JS, therefore needs | |
| 1722 /// `lib.topLevel` syntax instead of just `topLevel`. | |
| 1723 bool _needsModuleGetter(Element element) { | |
| 1724 if (element is PropertyAccessorElement) { | |
| 1725 element = (element as PropertyAccessorElement).variable; | |
| 1726 } | |
| 1727 return element is TopLevelVariableElement && !element.isConst; | |
| 1728 } | |
| 1729 | |
| 1730 _visit(AstNode node) { | 1769 _visit(AstNode node) { |
| 1731 if (node == null) return null; | 1770 if (node == null) return null; |
| 1732 var result = node.accept(this); | 1771 var result = node.accept(this); |
| 1733 if (result is JS.Node) result.sourceInformation = node; | 1772 if (result is JS.Node) result.sourceInformation = node; |
| 1734 return result; | 1773 return result; |
| 1735 } | 1774 } |
| 1736 | 1775 |
| 1737 JS.Statement _visitOrEmpty(Statement node) { | 1776 JS.Statement _visitOrEmpty(Statement node) { |
| 1738 if (node == null) return new JS.EmptyStatement(); | 1777 if (node == null) return new JS.EmptyStatement(); |
| 1739 return _visit(node); | 1778 return _visit(node); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1921 | 1960 |
| 1922 class JSGenerator extends CodeGenerator { | 1961 class JSGenerator extends CodeGenerator { |
| 1923 final JSCodeOptions options; | 1962 final JSCodeOptions options; |
| 1924 | 1963 |
| 1925 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) | 1964 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) |
| 1926 : super(outDir, root, rules); | 1965 : super(outDir, root, rules); |
| 1927 | 1966 |
| 1928 String generateLibrary(Iterable<CompilationUnit> units, LibraryInfo info, | 1967 String generateLibrary(Iterable<CompilationUnit> units, LibraryInfo info, |
| 1929 CheckerReporter reporter) { | 1968 CheckerReporter reporter) { |
| 1930 JS.Program jsTree = | 1969 JS.Program jsTree = |
| 1931 new JSCodegenVisitor(info, rules).generateLibrary(units, reporter); | 1970 new JSCodegenVisitor(info, rules, reporter).generateLibrary(units); |
| 1932 | 1971 |
| 1933 var outputPath = path.join(outDir, jsOutputPath(info, root)); | 1972 var outputPath = path.join(outDir, jsOutputPath(info, root)); |
| 1934 new Directory(path.dirname(outputPath)).createSync(recursive: true); | 1973 new Directory(path.dirname(outputPath)).createSync(recursive: true); |
| 1935 | 1974 |
| 1936 if (options.emitSourceMaps) { | 1975 if (options.emitSourceMaps) { |
| 1937 var outFilename = path.basename(outputPath); | 1976 var outFilename = path.basename(outputPath); |
| 1938 var printer = new srcmaps.Printer(outFilename); | 1977 var printer = new srcmaps.Printer(outFilename); |
| 1939 _writeNode( | 1978 _writeNode( |
| 1940 new SourceMapPrintingContext(printer, path.dirname(outputPath)), | 1979 new SourceMapPrintingContext(printer, path.dirname(outputPath)), |
| 1941 jsTree); | 1980 jsTree); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2039 | 2078 |
| 2040 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2079 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2041 printer.mark(_location(node.end)); | 2080 printer.mark(_location(node.end)); |
| 2042 } | 2081 } |
| 2043 | 2082 |
| 2044 String _getIdentifier(AstNode node) { | 2083 String _getIdentifier(AstNode node) { |
| 2045 if (node is SimpleIdentifier) return node.name; | 2084 if (node is SimpleIdentifier) return node.name; |
| 2046 return null; | 2085 return null; |
| 2047 } | 2086 } |
| 2048 } | 2087 } |
| OLD | NEW |