Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: lib/src/codegen/module_builder.dart

Issue 1633003002: Add --modules=node support (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: regen sdk and expectations Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.module_builder; 5 library dev_compiler.src.codegen.module_builder;
6 6
7 import '../js/js_ast.dart' as JS; 7 import '../js/js_ast.dart' as JS;
8 import '../js/js_ast.dart' show js; 8 import '../js/js_ast.dart' show js;
9 import '../options.dart' show ModuleFormat; 9 import '../options.dart' show ModuleFormat;
10 10
11 /// Helper that builds JS modules in a given [ModuleFormat]. 11 /// Helper that builds JS modules in a given [ModuleFormat].
12 abstract class ModuleBuilder { 12 abstract class ModuleBuilder {
13 final String _jsPath; 13 final _exports = <String, String>{};
14 final String _jsModuleValue; 14 final _imports = <_ModuleImport>[];
15 final JS.Identifier _exportsVar;
16 final List<String> _exports = <String>[];
17 final List<_ModuleImport> _imports = <_ModuleImport>[];
18 15
19 ModuleBuilder._(this._jsPath, this._jsModuleValue, this._exportsVar); 16 ModuleBuilder._();
20 17
21 /// Returns a [format]-specific [ModuleBuilder]. 18 /// Returns a [format]-specific [ModuleBuilder].
22 /// - [jsPath] is the path of the module being built. 19 /// - [jsPath] is the path of the module being built.
23 /// - [jsModuleValue] is the default value to use for the library, in case of 20 /// - [jsModuleValue] is the default value to use for the library, in case of
24 /// js interop (comes from the @js.JS(jsModuleValue) annotation on the 21 /// js interop (comes from the @js.JS(jsModuleValue) annotation on the
25 /// library directive). It is null in any other case. 22 /// library directive). It is null in any other case.
26 /// - [exportsVar] is the name of the object on which items are exported. Lazy 23 /// - [exportsVar] is the name of the object on which items are exported. Lazy
27 /// variables and constants are assumed to be declared on this instance. 24 /// variables and constants are assumed to be declared on this instance.
28 factory ModuleBuilder(String jsPath, String jsModuleValue, 25 factory ModuleBuilder(ModuleFormat format) {
29 JS.Identifier exportsVar, ModuleFormat format) {
30 switch (format) { 26 switch (format) {
31 case ModuleFormat.legacy: 27 case ModuleFormat.legacy:
32 return new LegacyModuleBuilder(jsPath, jsModuleValue, exportsVar); 28 return new LegacyModuleBuilder();
33 case ModuleFormat.es6: 29 case ModuleFormat.es6:
34 return new ES6ModuleBuilder(jsPath, jsModuleValue, exportsVar); 30 return new ES6ModuleBuilder();
31 case ModuleFormat.node:
32 return new NodeModuleBuilder();
35 } 33 }
36 } 34 }
37 35
38 /// Adds [name] to the list of names to be exported from the module. 36 /// Adds [name] to the list of names to be exported from the module.
39 void addExport(String name) { 37 void addExport(String name, String exportName) {
40 _exports.add(name); 38 _exports[name] = exportName;
41 } 39 }
42 40
43 /// Adds an import from a module named [name] and locally aliased as [libVar]. 41 /// Adds an import from a module named [name] and locally aliased as [libVar].
44 /// When [isLazy] is true, the import should be lazy (i.e. there is some 42 /// When [isLazy] is `true`, the import should be lazy (i.e. there is some
45 /// cyclic dependency of imports). 43 /// cyclic dependency of imports).
44 /// When [libVar] is `null`, the import is there just to force the import
45 /// order.
46 void addImport(String name, JS.Identifier libVar, {bool isLazy: false}) { 46 void addImport(String name, JS.Identifier libVar, {bool isLazy: false}) {
47 _imports.add(new _ModuleImport(name, libVar, isLazy)); 47 _imports.add(new _ModuleImport(name, libVar, isLazy));
48 } 48 }
49 49
50 /// Builds a program out of menu items. 50 /// Builds a program out of menu items.
51 JS.Program build(List<JS.ModuleItem> moduleItems); 51 JS.Program build(String jsPath, String jsModuleValue,
52 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems);
52 } 53 }
53 54
54 class _ModuleImport { 55 class _ModuleImport {
55 final String name; 56 final String name;
56 final JS.Identifier libVar; 57 final JS.Identifier libVar;
57 // TODO(jmesserly): Assess whether we can remove this (we shouldn't need it 58 // TODO(jmesserly): Assess whether we can remove this (we shouldn't need it
58 // even in our legacy module format, but it might still be useful for Closure 59 // even in our legacy module format, but it might still be useful for Closure
59 // with ES6 modules). 60 // with ES6 modules).
60 final bool isLazy; 61 final bool isLazy;
61 _ModuleImport(this.name, this.libVar, this.isLazy); 62 _ModuleImport(this.name, this.libVar, this.isLazy);
62 } 63 }
63 64
64 /// Generates modules for with DDC's `dart_library.js` loading mechanism. 65 /// Generates modules for with DDC's `dart_library.js` loading mechanism.
65 class LegacyModuleBuilder extends ModuleBuilder { 66 class LegacyModuleBuilder extends ModuleBuilder {
66 LegacyModuleBuilder(jsPath, _jsModuleValue, _exportsVar) 67 LegacyModuleBuilder() : super._();
67 : super._(jsPath, _jsModuleValue, _exportsVar);
68 68
69 JS.Program build(List<JS.ModuleItem> moduleItems) { 69 JS.Program build(String jsPath, String jsModuleValue,
70 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
70 // TODO(jmesserly): it would be great to run the renamer on the body, 71 // TODO(jmesserly): it would be great to run the renamer on the body,
71 // then figure out if we really need each of these parameters. 72 // then figure out if we really need each of these parameters.
72 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 73 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
73 var params = [_exportsVar]; 74 var params = [exportsVar];
74 var lazyParams = []; 75 var lazyParams = [];
75 76
76 var imports = <JS.Expression>[]; 77 var imports = <JS.Expression>[];
77 var lazyImports = <JS.Expression>[]; 78 var lazyImports = <JS.Expression>[];
78 var moduleStatements = <JS.Statement>[]; 79 var moduleStatements = <JS.Statement>[];
79 80
80 for (var i in _imports) { 81 for (var i in _imports) {
82 // No need to force the import order for the legacy library mechanism.
83 if (i.libVar == null) continue;
81 (i.isLazy ? lazyImports : imports).add(js.string(i.name, "'")); 84 (i.isLazy ? lazyImports : imports).add(js.string(i.name, "'"));
82 (i.isLazy ? lazyParams : params).add(i.libVar); 85 (i.isLazy ? lazyParams : params).add(i.libVar);
83 } 86 }
84 params.addAll(lazyParams); 87 params.addAll(lazyParams);
85 88
86 moduleStatements.addAll(_flattenBlocks(moduleItems)); 89 moduleStatements.addAll(_flattenBlocks(moduleItems));
87 90
88 if (_exports.isNotEmpty) { 91 if (_exports.isNotEmpty) {
89 moduleStatements.add(js.comment('Exports:')); 92 moduleStatements.add(js.comment('Exports:'));
90 // TODO(jmesserly): make these immutable in JS? 93 // TODO(jmesserly): make these immutable in JS?
91 for (var name in _exports) { 94 _exports.forEach((name, exportName) {
92 moduleStatements 95 moduleStatements
93 .add(js.statement('#.# = #;', [_exportsVar, name, name])); 96 .add(js.statement('#.# = #;', [exportsVar, exportName, name]));
94 } 97 });
95 } 98 }
96 99
97 var module = 100 var module =
98 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); 101 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
99 102
100 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ 103 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
101 js.string(_jsPath, "'"), 104 js.string(jsPath, "'"),
102 _jsModuleValue ?? new JS.LiteralNull(), 105 jsModuleValue ?? new JS.LiteralNull(),
103 js.commentExpression( 106 js.commentExpression(
104 "Imports", new JS.ArrayInitializer(imports, multiline: true)), 107 "Imports", new JS.ArrayInitializer(imports, multiline: true)),
105 js.commentExpression("Lazy imports", 108 js.commentExpression("Lazy imports",
106 new JS.ArrayInitializer(lazyImports, multiline: true)), 109 new JS.ArrayInitializer(lazyImports, multiline: true)),
107 module 110 module
108 ]); 111 ]);
109 return new JS.Program(<JS.ModuleItem>[moduleDef]); 112 return new JS.Program(<JS.ModuleItem>[moduleDef]);
110 } 113 }
111 } 114 }
112 115
113 /// Generates ES6 modules. 116 /// Generates ES6 modules.
114 // TODO(ochafik): Break strong dep cycles to accommodate the Closure Compiler. 117 // TODO(ochafik): Break strong dep cycles to accommodate the Closure Compiler.
115 class ES6ModuleBuilder extends ModuleBuilder { 118 class ES6ModuleBuilder extends ModuleBuilder {
116 ES6ModuleBuilder(jsPath, _jsModuleValue, _exportsVar) 119 ES6ModuleBuilder() : super._();
117 : super._(jsPath, _jsModuleValue, _exportsVar);
118 120
119 JS.Program build(List<JS.ModuleItem> moduleItems) { 121 JS.Program build(String jsPath, String jsModuleValue,
122 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
120 var moduleStatements = <JS.ModuleItem>[ 123 var moduleStatements = <JS.ModuleItem>[
121 // Lazy declarations may reference exports. 124 js.statement("const # = {};", [exportsVar])
122 js.statement("const # = {};", [_exportsVar])
123 ]; 125 ];
124 126
125 // TODO(jmesserly): it would be great to run the renamer on the body, 127 // TODO(jmesserly): it would be great to run the renamer on the body,
126 // then figure out if we really need each of these parameters. 128 // then figure out if we really need each of these parameters.
127 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 129 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
128 for (var i in _imports) { 130 for (var i in _imports) {
129 // TODO(ochafik): laziness, late binding, etc, to support Closure... 131 // TODO(ochafik): laziness, late binding, etc, to support Closure...
130 moduleStatements.add(new JS.ImportDeclaration( 132 if (i.libVar == null) {
131 defaultBinding: i.libVar, from: js.string(i.name))); 133 moduleStatements.add(new JS.ImportDeclaration(
134 namedImports: [], from: js.string(i.name)));
135 } else {
136 moduleStatements.add(new JS.ImportDeclaration(
137 defaultBinding: i.libVar, from: js.string(i.name)));
138 }
132 } 139 }
133 140
134 moduleStatements.addAll(_flattenBlocks(moduleItems)); 141 moduleStatements.addAll(_flattenBlocks(moduleItems));
135 142
136 if (_exports.isNotEmpty) { 143 if (_exports.isNotEmpty) {
137 moduleStatements.add(js.comment('Exports:')); 144 moduleStatements.add(js.comment('Exports:'));
138 // TODO(jmesserly): make these immutable in JS? 145 // TODO(jmesserly): make these immutable in JS?
139 for (var name in _exports) { 146 _exports.forEach((name, exportName) {
140 moduleStatements 147 moduleStatements
141 .add(js.statement('#.# = #;', [_exportsVar, name, name])); 148 .add(js.statement('#.# = #;', [exportsVar, exportName, name]));
142 } 149 });
143 moduleStatements 150 moduleStatements
144 .add(new JS.ExportDeclaration(_exportsVar, isDefault: true)); 151 .add(new JS.ExportDeclaration(exportsVar, isDefault: true));
145 } 152 }
146 // TODO(ochafik): What to do of _jsModuleValue? 153 // TODO(ochafik): What to do of jsModuleValue?
147 return new JS.Program(moduleStatements); 154 return new JS.Program(moduleStatements);
148 } 155 }
149 } 156 }
157
158 /// Generates node modules.
159 class NodeModuleBuilder extends ModuleBuilder {
160 NodeModuleBuilder() : super._();
161
162 JS.Program build(String jsPath, String jsModuleValue,
163 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
164 var moduleStatements = <JS.ModuleItem>[
165 js.statement("'use strict';"),
166 // js.statement("console.log('Loading ' + #);", [js.string(jsPath)])
vsm 2016/01/26 14:09:40 Remove?
ochafik 2016/01/26 16:27:37 Done.
167 ];
168
169 moduleItems = _flattenBlocks(moduleItems);
170
171 var prioritaryExportItems = <JS.ModuleItem>[];
vsm 2016/01/26 14:09:41 s/prioritary/priority/ here and below?
ochafik 2016/01/26 16:27:37 Acknowledged.
172 var normalItems = <JS.ModuleItem>[];
173
174 var exported = new Set<String>();
175 emitExport(String name, List<JS.ModuleItem> items) {
vsm 2016/01/26 14:09:41 return type void?
ochafik 2016/01/26 16:27:37 Acknowledged.
176 if (exported.add(name)) {
177 items.add(js.statement('#.# = #;', [exportsVar, _exports[name], name]));
178 }
179 }
180
181 getPrioritaryExportName(JS.ModuleItem item) {
vsm 2016/01/26 14:09:41 return type String?
ochafik 2016/01/26 16:27:37 Acknowledged.
182 if (jsPath == 'dart/core') {
183 if (item is JS.ClassDeclaration) {
184 var name = item.classExpr.name.name;
185 switch (name) {
186 case 'Object':
187 case 'Match':
188 return name;
vsm 2016/01/26 14:09:40 Can you add a comment on why these need special ca
ochafik 2016/01/26 16:27:37 Actually, no longer needed with the forced order,
189 }
190 }
191 }
192 return null;
193 }
194
195 for (var item in moduleItems) {
196 var prioritaryExportName = getPrioritaryExportName(item);
197 if (prioritaryExportName != null) {
198 prioritaryExportItems.add(item);
199 emitExport(prioritaryExportName, prioritaryExportItems);
200 } else {
201 normalItems.add(item);
202 }
203 }
204
205 moduleStatements.addAll(prioritaryExportItems);
206
207 for (var i in _imports) {
208 if (i.libVar == null) {
209 moduleStatements.add(js.statement('require(#);', [js.string(i.name)]));
210 } else {
211 moduleStatements.add(
212 js.statement('let # = require(#);', [i.libVar, js.string(i.name)]));
213 }
214 }
215
216 moduleStatements.addAll(normalItems);
217
218 if (_exports.isNotEmpty) {
219 moduleStatements.add(js.comment('Exports:'));
220 _exports.keys.forEach((name) => emitExport(name, moduleStatements));
221 }
222 // TODO(ochafik): What to do of jsModuleValue?
223 return new JS.Program(moduleStatements);
224 }
225 }
150 226
151 /// Flattens blocks in [stats] to a single list of module items. 227 /// Flattens blocks in [stats] to a single list of module items.
152 /// Note that in general, blocks should not be flattened, because it can 228 /// Note that in general, blocks should not be flattened, because it can
153 /// mess up with block-level scoping (let, const). 229 /// mess up with block-level scoping (let, const).
154 // TODO(ochafik): Remove this / find better pattern (adding statements as they 230 // TODO(ochafik): Remove this / find better pattern (adding statements as they
155 // are generated from [JSCodegenVisitor], instead of composing them with 231 // are generated from [JSCodegenVisitor], instead of composing them with
156 // [_statements]). 232 // [_statements]).
157 Iterable<JS.ModuleItem> _flattenBlocks(List<JS.ModuleItem> stats) => 233 Iterable<JS.ModuleItem> _flattenBlocks(List<JS.ModuleItem> stats) =>
158 stats.expand((item) => item is JS.Block ? item.statements : [item]); 234 stats.expand(
235 (item) => item is JS.Block ? _flattenBlocks(item.statements) : [item]);
OLDNEW
« no previous file with comments | « lib/src/codegen/js_names.dart ('k') | lib/src/compiler.dart » ('j') | lib/src/compiler.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698