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 16 matching lines...) Expand all Loading... | |
| 27 import 'package:dev_compiler/src/checker/rules.dart'; | 27 import 'package:dev_compiler/src/checker/rules.dart'; |
| 28 import 'package:dev_compiler/src/info.dart'; | 28 import 'package:dev_compiler/src/info.dart'; |
| 29 import 'package:dev_compiler/src/options.dart'; | 29 import 'package:dev_compiler/src/options.dart'; |
| 30 import 'package:dev_compiler/src/report.dart'; | 30 import 'package:dev_compiler/src/report.dart'; |
| 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 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; | |
| 38 | |
| 39 bool _hasAnnotationType(AnnotatedNode node, String name) => | |
| 40 node.metadata.any((annotation) => _isAnnotationType(annotation, name)); | |
| 41 | |
| 37 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { | 42 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| 38 final LibraryInfo libraryInfo; | 43 final LibraryInfo libraryInfo; |
| 39 final TypeRules rules; | 44 final TypeRules rules; |
| 40 | 45 |
| 41 /// The variable for the target of the current `..` cascade expression. | 46 /// The variable for the target of the current `..` cascade expression. |
| 42 SimpleIdentifier _cascadeTarget; | 47 SimpleIdentifier _cascadeTarget; |
| 43 /// The variable for the current catch clause | 48 /// The variable for the current catch clause |
| 44 String _catchParameter; | 49 String _catchParameter; |
| 45 | 50 |
| 46 ClassDeclaration currentClass; | 51 ClassDeclaration currentClass; |
| 47 ConstantEvaluator _constEvaluator; | 52 ConstantEvaluator _constEvaluator; |
| 53 bool _containsJsGlobals = false; | |
|
Jennifer Messerly
2015/03/17 16:39:18
should this be explicit on the library tag? e.g. l
Jacob
2015/03/17 21:22:44
Discussed offline. Switched to @JsName here and fo
| |
| 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(LibraryInfo libraryInfo, TypeRules rules) |
| 56 : libraryInfo = libraryInfo, | 62 : libraryInfo = libraryInfo, |
| 57 rules = rules; | 63 rules = rules; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 73 } | 79 } |
| 74 | 80 |
| 75 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); | 81 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); |
| 76 | 82 |
| 77 // TODO(jmesserly): make these immutable in JS? | 83 // TODO(jmesserly): make these immutable in JS? |
| 78 for (var name in _exports) { | 84 for (var name in _exports) { |
| 79 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); | 85 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); |
| 80 } | 86 } |
| 81 | 87 |
| 82 var name = jsLibraryName(libraryInfo.library); | 88 var name = jsLibraryName(libraryInfo.library); |
| 89 var defaultValue = _containsJsGlobals ? 'window' : '{}'; | |
|
Jennifer Messerly
2015/03/17 16:39:18
normally we'd do this as an interpolated expressio
Jacob
2015/03/17 21:22:44
Done.
| |
| 83 return new JS.Program([ | 90 return new JS.Program([ |
| 84 js.statement('var #;', name), | 91 js.statement('var #;', name), |
| 85 js.statement("(function($_EXPORTS) { 'use strict'; #; })(# || (# = {}));", | 92 js.statement( |
| 93 "(function($_EXPORTS) { 'use strict'; #; })(# || (# = $defaultValue)); ", | |
|
Jennifer Messerly
2015/03/17 16:39:18
this should be:
"(function($_EXPORTS) { 'use stric
Jacob
2015/03/17 21:22:44
Done.
| |
| 86 [body, name, name]) | 94 [body, name, name]) |
|
Jennifer Messerly
2015/03/17 16:39:18
[body, name, name, defaultValue]
Jacob
2015/03/17 21:22:44
Done.
| |
| 87 ]); | 95 ]); |
| 88 } | 96 } |
| 89 | 97 |
| 90 JS.Statement _initPrivateSymbol(String name) => | 98 JS.Statement _initPrivateSymbol(String name) => |
| 91 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]); | 99 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]); |
| 92 | 100 |
| 93 @override | 101 @override |
| 94 JS.Statement visitCompilationUnit(CompilationUnit node) { | 102 JS.Statement visitCompilationUnit(CompilationUnit node) { |
| 95 // TODO(jmesserly): scriptTag, directives. | 103 // TODO(jmesserly): scriptTag, directives. |
| 96 var body = <JS.Statement>[]; | 104 var body = <JS.Statement>[]; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]); | 232 var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]); |
| 225 | 233 |
| 226 // TODO(jmesserly): is it worth exporting both names? Alternatively we could | 234 // TODO(jmesserly): is it worth exporting both names? Alternatively we could |
| 227 // put the generic type constructor on the <dynamic> instance. | 235 // put the generic type constructor on the <dynamic> instance. |
| 228 if (isPublic(name)) _exports.add('${name}\$'); | 236 if (isPublic(name)) _exports.add('${name}\$'); |
| 229 return new JS.Block([genericDef, dynInst]); | 237 return new JS.Block([genericDef, dynInst]); |
| 230 } | 238 } |
| 231 | 239 |
| 232 @override | 240 @override |
| 233 JS.Statement visitClassDeclaration(ClassDeclaration node) { | 241 JS.Statement visitClassDeclaration(ClassDeclaration node) { |
| 242 if (_hasAnnotationType(node, 'JsType')) return null; | |
| 243 | |
| 234 currentClass = node; | 244 currentClass = node; |
| 235 | 245 |
| 236 var body = <JS.Statement>[]; | 246 var body = <JS.Statement>[]; |
| 237 | 247 |
| 238 var name = node.name.name; | 248 var name = node.name.name; |
| 239 var ctors = <ConstructorDeclaration>[]; | 249 var ctors = <ConstructorDeclaration>[]; |
| 240 var fields = <FieldDeclaration>[]; | 250 var fields = <FieldDeclaration>[]; |
| 241 var staticFields = <FieldDeclaration>[]; | 251 var staticFields = <FieldDeclaration>[]; |
| 242 for (var member in node.members) { | 252 for (var member in node.members) { |
| 243 if (member is ConstructorDeclaration) { | 253 if (member is ConstructorDeclaration) { |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 JS.Statement visitAssertStatement(AssertStatement node) => | 917 JS.Statement visitAssertStatement(AssertStatement node) => |
| 908 // TODO(jmesserly): only emit in checked mode. | 918 // TODO(jmesserly): only emit in checked mode. |
| 909 js.statement('dart.assert(#);', _visit(node.condition)); | 919 js.statement('dart.assert(#);', _visit(node.condition)); |
| 910 | 920 |
| 911 @override | 921 @override |
| 912 JS.Return visitReturnStatement(ReturnStatement node) => | 922 JS.Return visitReturnStatement(ReturnStatement node) => |
| 913 new JS.Return(_visit(node.expression)); | 923 new JS.Return(_visit(node.expression)); |
| 914 | 924 |
| 915 @override | 925 @override |
| 916 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 926 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 927 if (_hasAnnotationType(node, 'JsGlobal')) { | |
| 928 _containsJsGlobals = true; | |
|
Jennifer Messerly
2015/03/17 16:39:18
per suggestion above, this won't be needed
| |
| 929 return null; | |
| 930 } | |
| 917 var body = <JS.Statement>[]; | 931 var body = <JS.Statement>[]; |
| 918 | 932 |
| 919 for (var field in node.variables.variables) { | 933 for (var field in node.variables.variables) { |
| 920 if (field.isConst) { | 934 if (field.isConst) { |
| 921 // constant fields don't change, so we can generate them as `let` | 935 // constant fields don't change, so we can generate them as `let` |
| 922 // but add them to the module's exports | 936 // but add them to the module's exports |
| 923 var name = field.name.name; | 937 var name = field.name.name; |
| 924 body.add(js.statement('let # = #;', [ | 938 body.add(js.statement('let # = #;', [ |
| 925 new JS.VariableDeclaration(name), | 939 new JS.VariableDeclaration(name), |
| 926 _visitInitializer(field) | 940 _visitInitializer(field) |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 953 // var result = []; | 967 // var result = []; |
| 954 // result.length = length; | 968 // result.length = length; |
| 955 var savedCascadeTemp = _cascadeTarget; | 969 var savedCascadeTemp = _cascadeTarget; |
| 956 _cascadeTarget = last.name; | 970 _cascadeTarget = last.name; |
| 957 | 971 |
| 958 variables = _visitList(node.variables.take(node.variables.length - 1)); | 972 variables = _visitList(node.variables.take(node.variables.length - 1)); |
| 959 variables.add(new JS.VariableInitialization( | 973 variables.add(new JS.VariableInitialization( |
| 960 new JS.VariableDeclaration(last.name.name), | 974 new JS.VariableDeclaration(last.name.name), |
| 961 _visit(lastInitializer.target))); | 975 _visit(lastInitializer.target))); |
| 962 | 976 |
| 963 var result = | 977 var result = <JS.Expression>[ |
|
Siggi Cherem (dart-lang)
2015/03/17 01:25:36
DBC - you might need to run pub-ugprade, seems lik
| |
| 964 <JS.Expression>[new JS.VariableDeclarationList('let', variables)]; | 978 new JS.VariableDeclarationList('let', variables) |
| 979 ]; | |
| 965 result.addAll(_visitList(lastInitializer.cascadeSections)); | 980 result.addAll(_visitList(lastInitializer.cascadeSections)); |
| 966 _cascadeTarget = savedCascadeTemp; | 981 _cascadeTarget = savedCascadeTemp; |
| 967 return _statement(result.map((e) => new JS.ExpressionStatement(e))); | 982 return _statement(result.map((e) => new JS.ExpressionStatement(e))); |
| 968 } else { | 983 } else { |
| 969 variables = _visitList(node.variables); | 984 variables = _visitList(node.variables); |
| 970 } | 985 } |
| 971 | 986 |
| 972 return new JS.VariableDeclarationList('let', variables); | 987 return new JS.VariableDeclarationList('let', variables); |
| 973 } | 988 } |
| 974 | 989 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1009 isSetter: true)); | 1024 isSetter: true)); |
| 1010 } | 1025 } |
| 1011 } | 1026 } |
| 1012 | 1027 |
| 1013 return js.statement( | 1028 return js.statement( |
| 1014 'dart.defineLazyProperties(#, { # })', [objExpr, methods]); | 1029 'dart.defineLazyProperties(#, { # })', [objExpr, methods]); |
| 1015 } | 1030 } |
| 1016 | 1031 |
| 1017 void _flushLibraryProperties(List<JS.Statement> body) { | 1032 void _flushLibraryProperties(List<JS.Statement> body) { |
| 1018 if (_properties.isEmpty) return; | 1033 if (_properties.isEmpty) return; |
| 1019 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', | 1034 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', [ |
| 1020 [_properties.map(_emitTopLevelProperty)])); | 1035 _properties.map(_emitTopLevelProperty) |
| 1036 ])); | |
| 1021 _properties.clear(); | 1037 _properties.clear(); |
| 1022 } | 1038 } |
| 1023 | 1039 |
| 1024 @override | 1040 @override |
| 1025 JS.Statement visitVariableDeclarationStatement( | 1041 JS.Statement visitVariableDeclarationStatement( |
| 1026 VariableDeclarationStatement node) => | 1042 VariableDeclarationStatement node) => |
| 1027 _expressionStatement(_visit(node.variables)); | 1043 _expressionStatement(_visit(node.variables)); |
| 1028 | 1044 |
| 1029 @override | 1045 @override |
| 1030 visitConstructorName(ConstructorName node) { | 1046 visitConstructorName(ConstructorName node) { |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1602 | 1618 |
| 1603 @override | 1619 @override |
| 1604 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value); | 1620 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value); |
| 1605 | 1621 |
| 1606 @override | 1622 @override |
| 1607 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 1623 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
| 1608 | 1624 |
| 1609 @override | 1625 @override |
| 1610 visitListLiteral(ListLiteral node) { | 1626 visitListLiteral(ListLiteral node) { |
| 1611 // TODO(jmesserly): make this faster. We're wasting an array. | 1627 // TODO(jmesserly): make this faster. We're wasting an array. |
| 1612 var list = js.call('new List.from(#)', | 1628 var list = js.call('new List.from(#)', [ |
| 1613 [new JS.ArrayInitializer(_visitList(node.elements))]); | 1629 new JS.ArrayInitializer(_visitList(node.elements)) |
| 1630 ]); | |
| 1614 if (node.constKeyword != null) { | 1631 if (node.constKeyword != null) { |
| 1615 list = js.commentExpression('Unimplemented const', list); | 1632 list = js.commentExpression('Unimplemented const', list); |
| 1616 } | 1633 } |
| 1617 return list; | 1634 return list; |
| 1618 } | 1635 } |
| 1619 | 1636 |
| 1620 @override | 1637 @override |
| 1621 visitMapLiteral(MapLiteral node) { | 1638 visitMapLiteral(MapLiteral node) { |
| 1622 var entries = node.entries; | 1639 var entries = node.entries; |
| 1623 var mapArguments = null; | 1640 var mapArguments = null; |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1929 CheckerReporter reporter) { | 1946 CheckerReporter reporter) { |
| 1930 JS.Program jsTree = | 1947 JS.Program jsTree = |
| 1931 new JSCodegenVisitor(info, rules).generateLibrary(units, reporter); | 1948 new JSCodegenVisitor(info, rules).generateLibrary(units, reporter); |
| 1932 | 1949 |
| 1933 var outputPath = path.join(outDir, jsOutputPath(info, root)); | 1950 var outputPath = path.join(outDir, jsOutputPath(info, root)); |
| 1934 new Directory(path.dirname(outputPath)).createSync(recursive: true); | 1951 new Directory(path.dirname(outputPath)).createSync(recursive: true); |
| 1935 | 1952 |
| 1936 if (options.emitSourceMaps) { | 1953 if (options.emitSourceMaps) { |
| 1937 var outFilename = path.basename(outputPath); | 1954 var outFilename = path.basename(outputPath); |
| 1938 var printer = new srcmaps.Printer(outFilename); | 1955 var printer = new srcmaps.Printer(outFilename); |
| 1939 _writeNode( | 1956 _writeNode(new SourceMapPrintingContext( |
| 1940 new SourceMapPrintingContext(printer, path.dirname(outputPath)), | 1957 printer, path.dirname(outputPath)), jsTree); |
| 1941 jsTree); | |
| 1942 printer.add('//# sourceMappingURL=$outFilename.map'); | 1958 printer.add('//# sourceMappingURL=$outFilename.map'); |
| 1943 // Write output file and source map | 1959 // Write output file and source map |
| 1944 var text = printer.text; | 1960 var text = printer.text; |
| 1945 new File(outputPath).writeAsStringSync(text); | 1961 new File(outputPath).writeAsStringSync(text); |
| 1946 new File('$outputPath.map').writeAsStringSync(printer.map); | 1962 new File('$outputPath.map').writeAsStringSync(printer.map); |
| 1947 return computeHash(text); | 1963 return computeHash(text); |
| 1948 } else { | 1964 } else { |
| 1949 var text = jsNodeToString(jsTree); | 1965 var text = jsNodeToString(jsTree); |
| 1950 new File(outputPath).writeAsStringSync(text); | 1966 new File(outputPath).writeAsStringSync(text); |
| 1951 return computeHash(text); | 1967 return computeHash(text); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2039 | 2055 |
| 2040 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2056 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2041 printer.mark(_location(node.end)); | 2057 printer.mark(_location(node.end)); |
| 2042 } | 2058 } |
| 2043 | 2059 |
| 2044 String _getIdentifier(AstNode node) { | 2060 String _getIdentifier(AstNode node) { |
| 2045 if (node is SimpleIdentifier) return node.name; | 2061 if (node is SimpleIdentifier) return node.name; |
| 2046 return null; | 2062 return null; |
| 2047 } | 2063 } |
| 2048 } | 2064 } |
| OLD | NEW |