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

Unified Diff: lib/src/codegen/js_codegen.dart

Issue 1263583005: implement exports, fixes #141 (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: rebase Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 8a769573489637c8247f625e89d4fc13b699bf65..1207e484d88d6e003e85c478586638b43c04e840 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -13,6 +13,7 @@ import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/generated/scanner.dart'
show StringToken, Token, TokenType;
+import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder;
import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder;
import 'package:dev_compiler/src/codegen/reify_coercions.dart'
@@ -95,6 +96,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
/// _interceptors.JSArray<E>, used for List literals.
ClassElement _jsArray;
+ /// The default value of the module object. See [visitLibraryDirective].
+ String _jsModuleValue;
+
Map<String, DartType> _objectMembers;
JSCodegenVisitor(AbstractCompiler compiler, this.currentLibrary,
@@ -115,23 +119,24 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
TypeProvider get types => rules.provider;
JS.Program emitLibrary(LibraryUnit library) {
- String jsDefaultValue = null;
-
// Modify the AST to make coercions explicit.
new CoercionReifier(library, compiler).reify();
- var unit = library.library;
- if (unit.directives.isNotEmpty) {
- var libraryDir = unit.directives.first;
- if (libraryDir is LibraryDirective) {
- var jsName = findAnnotation(libraryDir.element, _isJsNameAnnotation);
- jsDefaultValue =
- getConstantField(jsName, 'name', types.stringType) as String;
- }
+ // Build the public namespace for this library. This allows us to do
+ // constant time lookups (contrast with `Element.getChild(name)`).
+ if (currentLibrary.publicNamespace == null) {
+ (currentLibrary as LibraryElementImpl).publicNamespace =
+ new PublicNamespaceBuilder().build(currentLibrary);
}
- // TODO(jmesserly): visit scriptTag, directives?
Jennifer Messerly 2015/08/03 21:11:50 went ahead and fixed scriptTag too
+ library.library.directives.forEach(_visit);
+ // Rather than directly visit declarations, we instead use [_loader] to
+ // visit them. It has the ability to sort elements on demand, so
+ // dependencies between top level items are handled with a minimal
+ // reordering of the user's input code. The loader will call back into
+ // this visitor via [_emitModuleItem] when it's ready to visit the item
+ // for real.
_loader.collectElements(currentLibrary, library.partsThenLibrary);
for (var unit in library.partsThenLibrary) {
@@ -139,7 +144,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
for (var decl in unit.declarations) {
if (decl is TopLevelVariableDeclaration) {
- _visit(decl);
+ visitTopLevelVariableDeclaration(decl);
} else {
_loader.loadDeclaration(decl, decl.element);
}
@@ -147,10 +152,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
// Static fields can be emitted into the top-level code, so they need
// to potentially be ordered independently of the class.
for (var member in decl.members) {
- if (member is FieldDeclaration && member.isStatic) {
- for (var f in member.fields.variables) {
- _loader.loadDeclaration(f, f.element);
- }
+ if (member is FieldDeclaration) {
+ visitFieldDeclaration(member);
}
}
}
@@ -208,19 +211,21 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
var module = js.call("function(#) { 'use strict'; #; #; }",
[params, dartxImport, _moduleItems]);
- var program = <JS.Statement>[
- js.statement("dart_library.library(#, #, #, #, #)", [
- js.string(jsPath, "'"),
- jsDefaultValue ?? new JS.LiteralNull(),
- js.commentExpression(
- "Imports", new JS.ArrayInitializer(imports, multiline: true)),
- js.commentExpression("Lazy imports",
- new JS.ArrayInitializer(lazyImports, multiline: true)),
- module
- ])
- ];
+ var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
+ js.string(jsPath, "'"),
+ _jsModuleValue ?? new JS.LiteralNull(),
+ js.commentExpression(
+ "Imports", new JS.ArrayInitializer(imports, multiline: true)),
+ js.commentExpression("Lazy imports",
+ new JS.ArrayInitializer(lazyImports, multiline: true)),
+ module
+ ]);
+
+ var jsBin = compiler.options.runnerOptions.v8Binary;
- return new JS.Program(program);
+ String scriptTag = null;
+ if (library.library.scriptTag != null) scriptTag = '/usr/bin/env $jsBin';
+ return new JS.Program(<JS.Statement>[moduleDef], scriptTag: scriptTag);
}
void _emitModuleItem(AstNode node) {
@@ -232,6 +237,54 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
if (code != null) _moduleItems.add(code);
}
+ @override
+ void visitLibraryDirective(LibraryDirective node) {
+ assert(_jsModuleValue == null);
+
+ var jsName = findAnnotation(node.element, _isJsNameAnnotation);
+ _jsModuleValue =
+ getConstantField(jsName, 'name', types.stringType) as String;
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ // Nothing to do yet, but we'll want to convert this to an ES6 import once
+ // we have support for modules.
+ }
+
+ @override void visitPartDirective(PartDirective node) {}
+ @override void visitPartOfDirective(PartOfDirective node) {}
+
+ @override
+ void visitExportDirective(ExportDirective node) {
+ var exportName = _libraryName(node.uriElement);
+
+ var currentLibNames = currentLibrary.publicNamespace.definedNames;
+
+ var args = [_exportsVar, exportName];
+ if (node.combinators.isNotEmpty) {
+ var shownNames = <JS.Expression>[];
+ var hiddenNames = <JS.Expression>[];
+
+ var show = node.combinators.firstWhere((c) => c is ShowCombinator,
+ orElse: () => null) as ShowCombinator;
+ var hide = node.combinators.firstWhere((c) => c is HideCombinator,
+ orElse: () => null) as HideCombinator;
+ if (show != null) {
+ shownNames.addAll(show.shownNames
+ .map((i) => i.name)
+ .where((s) => !currentLibNames.containsKey(s))
+ .map((s) => js.string(s, "'")));
+ }
+ if (hide != null) {
+ hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'")));
+ }
+ args.add(new JS.ArrayInitializer(shownNames));
+ args.add(new JS.ArrayInitializer(hiddenNames));
+ }
+ _moduleItems.add(js.statement('dart.export(#);', [args]));
+ }
+
JS.Identifier _initSymbol(JS.Identifier id) {
var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]);
_moduleItems.add(s);
@@ -1776,6 +1829,21 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
}
}
+ /// Emits static fields.
+ ///
+ /// Instance fields are emitted in [_initializeFields].
+ ///
+ /// These are generally treated the same as top-level fields, see
+ /// [visitTopLevelVariableDeclaration].
+ @override
+ visitFieldDeclaration(FieldDeclaration node) {
+ if (!node.isStatic) return;
+
+ for (var f in node.fields.variables) {
+ _loader.loadDeclaration(f, f.element);
+ }
+ }
+
_addExport(String name) {
if (!_exports.add(name)) throw 'Duplicate top level name found: $name';
}

Powered by Google App Engine
This is Rietveld 408576698