| 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; | 7 import 'dart:collection' show HashSet, HashMap; |
| 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 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 genericDef, | 331 genericDef, |
| 332 _EXPORTS, | 332 _EXPORTS, |
| 333 js.string(name, "'"), | 333 js.string(name, "'"), |
| 334 genericName | 334 genericName |
| 335 ]); | 335 ]); |
| 336 } | 336 } |
| 337 | 337 |
| 338 return js.statement( | 338 return js.statement( |
| 339 'dart.defineLazyClass(#, { get #() { #; return #; } });', [ | 339 'dart.defineLazyClass(#, { get #() { #; return #; } });', [ |
| 340 _EXPORTS, | 340 _EXPORTS, |
| 341 name, | 341 _propertyName(name), |
| 342 body, | 342 body, |
| 343 name | 343 name |
| 344 ]); | 344 ]); |
| 345 } | 345 } |
| 346 | 346 |
| 347 if (isPublic(name)) _exports.add(name); | 347 if (isPublic(name)) _exports.add(name); |
| 348 | 348 |
| 349 if (genericDef != null) { | 349 if (genericDef != null) { |
| 350 body = js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 350 body = js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); |
| 351 if (isPublic(name)) _exports.add(genericName); | 351 if (isPublic(name)) _exports.add(genericName); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 /// `C() : super() {}`. | 570 /// `C() : super() {}`. |
| 571 JS.Method _emitImplicitConstructor( | 571 JS.Method _emitImplicitConstructor( |
| 572 ClassDeclaration node, String name, List<FieldDeclaration> fields) { | 572 ClassDeclaration node, String name, List<FieldDeclaration> fields) { |
| 573 // If we don't have a method body, skip this. | 573 // If we don't have a method body, skip this. |
| 574 if (fields.isEmpty) return null; | 574 if (fields.isEmpty) return null; |
| 575 | 575 |
| 576 dynamic body = _initializeFields(fields); | 576 dynamic body = _initializeFields(fields); |
| 577 var superCall = _superConstructorCall(node); | 577 var superCall = _superConstructorCall(node); |
| 578 if (superCall != null) body = [[body, superCall]]; | 578 if (superCall != null) body = [[body, superCall]]; |
| 579 return new JS.Method( | 579 return new JS.Method( |
| 580 new JS.PropertyName(name), js.call('function() { #; }', body)); | 580 _propertyName(name), js.call('function() { #; }', body)); |
| 581 } | 581 } |
| 582 | 582 |
| 583 JS.Method _emitConstructor(ConstructorDeclaration node, String className, | 583 JS.Method _emitConstructor(ConstructorDeclaration node, String className, |
| 584 List<FieldDeclaration> fields, bool isObject) { | 584 List<FieldDeclaration> fields, bool isObject) { |
| 585 if (_externalOrNative(node)) return null; | 585 if (_externalOrNative(node)) return null; |
| 586 | 586 |
| 587 var name = _constructorName(className, node.name); | 587 var name = _constructorName(className, node.name); |
| 588 | 588 |
| 589 // Code generation for Object's constructor. | 589 // Code generation for Object's constructor. |
| 590 JS.Block body; | 590 JS.Block body; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 612 return result === void 0 ? this : result; | 612 return result === void 0 ? this : result; |
| 613 }'''); | 613 }'''); |
| 614 } else { | 614 } else { |
| 615 body = _emitConstructorBody(node, fields); | 615 body = _emitConstructorBody(node, fields); |
| 616 } | 616 } |
| 617 | 617 |
| 618 // We generate constructors as initializer methods in the class; | 618 // We generate constructors as initializer methods in the class; |
| 619 // this allows use of `super` for instance methods/properties. | 619 // this allows use of `super` for instance methods/properties. |
| 620 // It also avoids V8 restrictions on `super` in default constructors. | 620 // It also avoids V8 restrictions on `super` in default constructors. |
| 621 return new JS.Method( | 621 return new JS.Method( |
| 622 new JS.PropertyName(name), new JS.Fun(_visit(node.parameters), body)) | 622 _propertyName(name), new JS.Fun(_visit(node.parameters), body)) |
| 623 ..sourceInformation = node; | 623 ..sourceInformation = node; |
| 624 } | 624 } |
| 625 | 625 |
| 626 String _constructorName(String className, SimpleIdentifier name) { | 626 String _constructorName(String className, SimpleIdentifier name) { |
| 627 if (name == null) return className; | 627 if (name == null) return className; |
| 628 return '$className\$${name.name}'; | 628 return '$className\$${name.name}'; |
| 629 } | 629 } |
| 630 | 630 |
| 631 JS.Block _emitConstructorBody( | 631 JS.Block _emitConstructorBody( |
| 632 ConstructorDeclaration node, List<FieldDeclaration> fields) { | 632 ConstructorDeclaration node, List<FieldDeclaration> fields) { |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 | 862 |
| 863 body.add(new JS.FunctionDeclaration( | 863 body.add(new JS.FunctionDeclaration( |
| 864 new JS.VariableDeclaration(name), _visit(node.functionExpression))); | 864 new JS.VariableDeclaration(name), _visit(node.functionExpression))); |
| 865 | 865 |
| 866 if (isPublic(name)) _exports.add(name); | 866 if (isPublic(name)) _exports.add(name); |
| 867 return _statement(body); | 867 return _statement(body); |
| 868 } | 868 } |
| 869 | 869 |
| 870 JS.Method _emitTopLevelProperty(FunctionDeclaration node) { | 870 JS.Method _emitTopLevelProperty(FunctionDeclaration node) { |
| 871 var name = node.name.name; | 871 var name = node.name.name; |
| 872 return new JS.Method( | 872 return new JS.Method(_propertyName(name), _visit(node.functionExpression), |
| 873 new JS.PropertyName(name), _visit(node.functionExpression), | |
| 874 isGetter: node.isGetter, isSetter: node.isSetter); | 873 isGetter: node.isGetter, isSetter: node.isSetter); |
| 875 } | 874 } |
| 876 | 875 |
| 877 @override | 876 @override |
| 878 JS.Expression visitFunctionExpression(FunctionExpression node) { | 877 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 879 var params = _visit(node.parameters); | 878 var params = _visit(node.parameters); |
| 880 if (params == null) params = []; | 879 if (params == null) params = []; |
| 881 | 880 |
| 882 if (node.parent is FunctionDeclaration) { | 881 if (node.parent is FunctionDeclaration) { |
| 883 return new JS.Fun(params, _visit(node.body)); | 882 return new JS.Fun(params, _visit(node.body)); |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 if (named.isNotEmpty) { | 1147 if (named.isNotEmpty) { |
| 1149 args.add(new JS.ObjectInitializer(named)); | 1148 args.add(new JS.ObjectInitializer(named)); |
| 1150 } | 1149 } |
| 1151 return args; | 1150 return args; |
| 1152 } | 1151 } |
| 1153 | 1152 |
| 1154 @override | 1153 @override |
| 1155 JS.Property visitNamedExpression(NamedExpression node) { | 1154 JS.Property visitNamedExpression(NamedExpression node) { |
| 1156 assert(node.parent is ArgumentList); | 1155 assert(node.parent is ArgumentList); |
| 1157 return new JS.Property( | 1156 return new JS.Property( |
| 1158 new JS.PropertyName(node.name.label.name), _visit(node.expression)); | 1157 _propertyName(node.name.label.name), _visit(node.expression)); |
| 1159 } | 1158 } |
| 1160 | 1159 |
| 1161 @override | 1160 @override |
| 1162 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) { | 1161 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) { |
| 1163 var result = <JS.Parameter>[]; | 1162 var result = <JS.Parameter>[]; |
| 1164 for (FormalParameter param in node.parameters) { | 1163 for (FormalParameter param in node.parameters) { |
| 1165 if (param.kind == ParameterKind.NAMED) { | 1164 if (param.kind == ParameterKind.NAMED) { |
| 1166 result.add(new JS.Parameter(r'opt$')); | 1165 result.add(new JS.Parameter(r'opt$')); |
| 1167 break; | 1166 break; |
| 1168 } | 1167 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1274 _lazyFields.clear(); | 1273 _lazyFields.clear(); |
| 1275 } | 1274 } |
| 1276 | 1275 |
| 1277 JS.Statement _emitLazyFields( | 1276 JS.Statement _emitLazyFields( |
| 1278 String objExpr, List<VariableDeclaration> fields) { | 1277 String objExpr, List<VariableDeclaration> fields) { |
| 1279 if (fields.isEmpty) return null; | 1278 if (fields.isEmpty) return null; |
| 1280 | 1279 |
| 1281 var methods = []; | 1280 var methods = []; |
| 1282 for (var node in fields) { | 1281 for (var node in fields) { |
| 1283 var name = node.name.name; | 1282 var name = node.name.name; |
| 1284 methods.add(new JS.Method(new JS.PropertyName(name), | 1283 methods.add(new JS.Method(_propertyName(name), |
| 1285 js.call('function() { return #; }', _visit(node.initializer)), | 1284 js.call('function() { return #; }', _visit(node.initializer)), |
| 1286 isGetter: true)); | 1285 isGetter: true)); |
| 1287 | 1286 |
| 1288 // TODO(jmesserly): use a dummy setter to indicate writable. | 1287 // TODO(jmesserly): use a dummy setter to indicate writable. |
| 1289 if (!node.isFinal) { | 1288 if (!node.isFinal) { |
| 1290 methods.add(new JS.Method( | 1289 methods.add(new JS.Method( |
| 1291 new JS.PropertyName(name), js.call('function(_) {}'), | 1290 _propertyName(name), js.call('function(_) {}'), isSetter: true)); |
| 1292 isSetter: true)); | |
| 1293 } | 1291 } |
| 1294 } | 1292 } |
| 1295 | 1293 |
| 1296 return js.statement( | 1294 return js.statement( |
| 1297 'dart.defineLazyProperties(#, { # });', [objExpr, methods]); | 1295 'dart.defineLazyProperties(#, { # });', [objExpr, methods]); |
| 1298 } | 1296 } |
| 1299 | 1297 |
| 1300 void _flushLibraryProperties(List<JS.Statement> body) { | 1298 void _flushLibraryProperties(List<JS.Statement> body) { |
| 1301 if (_properties.isEmpty) return; | 1299 if (_properties.isEmpty) return; |
| 1302 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', | 1300 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', |
| (...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2078 if (_privateNames.add(name)) _pendingPrivateNames.add(name); | 2076 if (_privateNames.add(name)) _pendingPrivateNames.add(name); |
| 2079 return new JS.VariableUse(name); | 2077 return new JS.VariableUse(name); |
| 2080 } | 2078 } |
| 2081 if (name == '[]') { | 2079 if (name == '[]') { |
| 2082 name = 'get'; | 2080 name = 'get'; |
| 2083 } else if (name == '[]=') { | 2081 } else if (name == '[]=') { |
| 2084 name = 'set'; | 2082 name = 'set'; |
| 2085 } else if (unary && name == '-') { | 2083 } else if (unary && name == '-') { |
| 2086 name = 'unary-'; | 2084 name = 'unary-'; |
| 2087 } | 2085 } |
| 2088 return new JS.PropertyName(name); | 2086 return _propertyName(name); |
| 2089 } | 2087 } |
| 2090 | 2088 |
| 2091 bool _externalOrNative(node) => | 2089 bool _externalOrNative(node) => |
| 2092 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 2090 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 2093 | 2091 |
| 2094 FunctionBody _functionBody(node) => | 2092 FunctionBody _functionBody(node) => |
| 2095 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 2093 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 2096 | 2094 |
| 2097 /// Choose a canonical name from the library element. | 2095 /// Choose a canonical name from the library element. |
| 2098 /// This never uses the library's name (the identifier in the `library` | 2096 /// This never uses the library's name (the identifier in the `library` |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2232 var context = new JS.SimpleJavaScriptPrintingContext(); | 2230 var context = new JS.SimpleJavaScriptPrintingContext(); |
| 2233 _writeNode(context, node); | 2231 _writeNode(context, node); |
| 2234 return context.getText(); | 2232 return context.getText(); |
| 2235 } | 2233 } |
| 2236 | 2234 |
| 2237 /// Choose a canonical name from the library element. | 2235 /// Choose a canonical name from the library element. |
| 2238 /// This never uses the library's name (the identifier in the `library` | 2236 /// This never uses the library's name (the identifier in the `library` |
| 2239 /// declaration) as it doesn't have any meaningful rules enforced. | 2237 /// declaration) as it doesn't have any meaningful rules enforced. |
| 2240 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); | 2238 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); |
| 2241 | 2239 |
| 2240 /// Shorthand for identifier-like property names. |
| 2241 /// For now, we emit them as strings and the printer restores them to |
| 2242 /// identifiers if it can. |
| 2243 // TODO(jmesserly): avoid the round tripping through quoted form. |
| 2244 JS.LiteralString _propertyName(String name) => js.string(name, "'"); |
| 2245 |
| 2242 /// Path to file that will be generated for [info]. In case it's url is a | 2246 /// Path to file that will be generated for [info]. In case it's url is a |
| 2243 /// `file:` url, we use [root] to determine the relative path from the entry | 2247 /// `file:` url, we use [root] to determine the relative path from the entry |
| 2244 /// point file. | 2248 /// point file. |
| 2245 String jsOutputPath(LibraryInfo info, Uri root) { | 2249 String jsOutputPath(LibraryInfo info, Uri root) { |
| 2246 var uri = info.library.source.uri; | 2250 var uri = info.library.source.uri; |
| 2247 var filepath = '${path.withoutExtension(uri.path)}.js'; | 2251 var filepath = '${path.withoutExtension(uri.path)}.js'; |
| 2248 if (uri.scheme == 'dart') { | 2252 if (uri.scheme == 'dart') { |
| 2249 filepath = 'dart/$filepath'; | 2253 filepath = 'dart/$filepath'; |
| 2250 } else if (uri.scheme == 'file') { | 2254 } else if (uri.scheme == 'file') { |
| 2251 filepath = path.relative(filepath, from: path.dirname(root.path)); | 2255 filepath = path.relative(filepath, from: path.dirname(root.path)); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2308 | 2312 |
| 2309 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2313 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2310 printer.mark(_location(node.end)); | 2314 printer.mark(_location(node.end)); |
| 2311 } | 2315 } |
| 2312 | 2316 |
| 2313 String _getIdentifier(AstNode node) { | 2317 String _getIdentifier(AstNode node) { |
| 2314 if (node is SimpleIdentifier) return node.name; | 2318 if (node is SimpleIdentifier) return node.name; |
| 2315 return null; | 2319 return null; |
| 2316 } | 2320 } |
| 2317 } | 2321 } |
| OLD | NEW |