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

Unified Diff: lib/compiler/implementation/scanner/scanner_task.dart

Issue 10990060: Added support for exports and re-exports. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Removed redundant check. Created 8 years, 3 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/compiler/implementation/scanner/scanner_task.dart
diff --git a/lib/compiler/implementation/scanner/scanner_task.dart b/lib/compiler/implementation/scanner/scanner_task.dart
index cd5e44f3e58c35ac1bc54d26ca0feebb0994f64b..f3342eec3f21e30c31289035b4fed4042e4b6e54 100644
--- a/lib/compiler/implementation/scanner/scanner_task.dart
+++ b/lib/compiler/implementation/scanner/scanner_task.dart
@@ -6,11 +6,16 @@ class ScannerTask extends CompilerTask {
ScannerTask(Compiler compiler) : super(compiler);
String get name => 'Scanner';
- void scanLibrary(LibraryElement library) {
+ /**
+ * Scans [library] and registers the declared top level entities to [handler]
+ * for the computation of the library export scope.
+ */
+ void scanLibrary(ImportExportHandler handler, LibraryElement library) {
var compilationUnit = library.entryCompilationUnit;
compiler.log("scanning library ${compilationUnit.script.name}");
scan(compilationUnit);
- processLibraryTags(library);
+ processLibraryTags(handler, library);
+ handler.registerLibraryExports(library);
}
void scan(CompilationUnitElement compilationUnit) {
@@ -19,7 +24,13 @@ class ScannerTask extends CompilerTask {
});
}
- void processLibraryTags(LibraryElement library) {
+ /**
+ * Processes the library tags in [library].
+ *
+ * The imported/exported libraries are loaded and processed recursively but
+ * the import/export scopes are not set up.
+ */
+ void processLibraryTags(ImportExportHandler handler, LibraryElement library) {
int tagState = TagState.NO_TAG_SEEN;
/**
@@ -35,7 +46,8 @@ class ScannerTask extends CompilerTask {
return TagState.NEXT[value];
}
- LinkBuilder<Import> imports = new LinkBuilder<Import>();
+ bool importsDartCore = false;
+ var importsExports = new LinkBuilder<ImportExport>();
Lasse Reichstein Nielsen 2012/09/28 07:45:36 ImportExport is very descriptive, but not very exp
Johnni Winther 2012/10/09 09:47:10 Done.
Uri base = library.entryCompilationUnit.script.uri;
for (LibraryTag tag in library.tags.reverse()) {
if (tag.isImport) {
@@ -44,7 +56,13 @@ class ScannerTask extends CompilerTask {
// another library could then observe the current library
// before it fully declares all the members that are sourced
// in.
- imports.addLast(tag);
+ if (tag.uri.dartString.slowToString() == 'dart:core') {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Using something called slowToString smells bad. Ho
Johnni Winther 2012/10/09 09:47:10 [uri] is a LiteralString, not a Uri.
+ importsDartCore = true;
+ }
+ importsExports.addLast(tag);
+ } else if (tag.isExport) {
+ tagState = checkTag(TagState.IMPORT, tag);
+ importsExports.addLast(tag);
} else if (tag.isLibraryName) {
tagState = checkTag(TagState.LIBRARY, tag);
if (library.libraryTag !== null) {
@@ -58,24 +76,27 @@ class ScannerTask extends CompilerTask {
tagState = checkTag(TagState.SOURCE, tag);
loadPart(tag, resolved, library);
} else {
- compiler.cancel("illegal script tag: ${tag.tag}", node: tag);
+ compiler.cancel("illegal script tag: ${tag}", node: tag);
}
}
// Apply patch, if any.
if (library.uri.scheme == 'dart') {
- compiler.patchDartLibrary(library, library.uri.path);
+ compiler.patchDartLibrary(handler, library, library.uri.path);
}
// Now that we have processed all the source tags, it is safe to
// start loading other libraries.
- if (library.uri.scheme != 'dart' || library.uri.path != 'core') {
- compiler.importCoreLibrary(library);
+ if (!importsDartCore ||
+ (library.uri.scheme != 'dart' || library.uri.path != 'core')) {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 I really can't read this. Please use if (!import
Johnni Winther 2012/10/09 09:47:10 Done.
+ handler.registerDependency(library, null,
+ compiler.importCoreLibrary(handler),
+ library.entryCompilationUnit);
}
- for (Import tag in imports.toLink()) {
- importLibraryFromTag(tag, library.entryCompilationUnit);
+ for (ImportExport tag in importsExports.toLink()) {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 We even have a class called ImportExport? Please c
Johnni Winther 2012/10/09 09:47:10 Done.
+ loadLibraryFromTag(handler, library, tag, library.entryCompilationUnit);
}
}
@@ -91,20 +112,26 @@ class ScannerTask extends CompilerTask {
}
/**
- * Handle an import script tag by importing the referenced library into the
- * current library.
- * Returns the resolved library [Uri].
+ * Handle an import/export tag by loading the referenced library and
+ * registering its dependency in [handler] for the computation of the import/
+ * export scope.
*/
- Uri importLibraryFromTag(Import tag,
- CompilationUnitElement compilationUnit) {
+ void loadLibraryFromTag(ImportExportHandler handler,
+ LibraryElement library,
+ ImportExport tag,
+ CompilationUnitElement compilationUnit) {
Uri base = compilationUnit.script.uri;
Uri resolved = base.resolve(tag.uri.dartString.slowToString());
- LibraryElement importedLibrary = loadLibrary(resolved, tag.uri, resolved);
- importLibrary(compilationUnit.getLibrary(),
- importedLibrary,
- tag,
- compilationUnit);
- return resolved;
+ LibraryElement loadedLibrary =
+ loadLibraryInternal(handler, resolved, tag.uri, resolved);
+ handler.registerDependency(library, tag, loadedLibrary, compilationUnit);
+
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Why are we passing both tag and compilationUnit? I
Johnni Winther 2012/10/09 09:47:10 CompilationUnit not needed anymore due to patch re
+ if (!loadedLibrary.hasLibraryName()) {
+ compiler.withCurrentElement(library, () {
+ compiler.reportError(tag === null ? null : tag.uri,
+ 'no #library tag found in ${loadedLibrary.uri}');
+ });
+ }
}
void scanElements(CompilationUnitElement compilationUnit) {
@@ -113,37 +140,214 @@ class ScannerTask extends CompilerTask {
compiler.dietParser.dietParse(compilationUnit, tokens);
}
+ /**
+ * Loads the library located at [uri] and returns its [LibraryElement].
+ *
+ * If the library is not already loaded, the method creates the
+ * [LibraryElement] for the library and computes the import/export scope,
+ * loading and computing the import/export scopes of all required libraries in
+ * the process. The method handles cyclic dependency between libraries.
+ *
+ * This is the main entry point for [ScannerTask].
+ */
LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri) {
+ var handler = new ImportExportHandler(compiler);
+ LibraryElement library =
+ loadLibraryInternal(handler, uri, node, canonicalUri);
+ handler.computeExports();
+ return library;
+ }
+
+ LibraryElement loadLibraryInternal(ImportExportHandler handler,
+ Uri uri, Node node, Uri canonicalUri) {
bool newLibrary = false;
LibraryElement library =
compiler.libraries.putIfAbsent(uri.toString(), () {
newLibrary = true;
Script script = compiler.readScript(uri, node);
LibraryElement element = new LibraryElement(script, canonicalUri);
+ handler.registerNewLibrary(element);
native.maybeEnableNative(compiler, element, uri);
return element;
});
if (newLibrary) {
compiler.withCurrentElement(library, () {
- scanLibrary(library);
+ scanLibrary(handler, library);
compiler.onLibraryLoaded(library, uri);
});
}
return library;
}
+}
- void importLibrary(LibraryElement library, LibraryElement imported,
- Import tag, [CompilationUnitElement compilationUnit]) {
- if (!imported.hasLibraryName()) {
- compiler.withCurrentElement(library, () {
- compiler.reportError(tag === null ? null : tag.uri,
- 'no #library tag found in ${imported.uri}');
+class DietParserTask extends CompilerTask {
+ DietParserTask(Compiler compiler) : super(compiler);
+ final String name = 'Diet Parser';
+
+ dietParse(CompilationUnitElement compilationUnit, Token tokens) {
+ measure(() {
+ Function idGenerator = compiler.getNextFreeClassId;
+ ElementListener listener =
+ new ElementListener(compiler, compilationUnit, idGenerator);
+ PartialParser parser = new PartialParser(listener);
+ parser.parseUnit(tokens);
+ });
+ }
+}
+
+/**
+ * The fields of this class models a state machine for checking script
+ * tags come in the correct order.
+ */
+class TagState {
+ static const int NO_TAG_SEEN = 0;
+ static const int LIBRARY = 1;
+ static const int IMPORT = 2;
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Includes export?
Johnni Winther 2012/10/09 09:47:10 Changed to IMPORT_OR_EXPORT.
+ static const int SOURCE = 3;
+ static const int RESOURCE = 4;
+
+ /** Next state. */
+ static const List<int> NEXT =
+ const <int>[NO_TAG_SEEN,
+ IMPORT, // Only one library tag is allowed.
+ IMPORT,
+ SOURCE,
+ RESOURCE];
+}
+
+/**
+ * Data class for handling import tags in [ImportExportHandler].
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Comment isn't helping me understand it. This is ju
+ */
+class ImportData {
+ final Import tag;
+ final LibraryElement library;
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Add documentation for fields. What is this library
+ final CompilationUnitElement compilationUnit;
Lasse Reichstein Nielsen 2012/09/28 07:45:36 What is it a compilationUnit of? What is it used f
Johnni Winther 2012/10/09 09:47:10 Not needed anymore due to patch refactoring.
+
+ ImportData(this.tag, this.library, this.compilationUnit);
+}
+
+/**
+ * Data class used for the computation of import/export scopes by
+ * [ImportExportHandler].
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Also bad explanation. I'm not any wiser, and I que
+ */
+class ImportExportData {
+ final LibraryElement library;
+ Link<ImportData> imports = const EmptyLink<ImportData>();
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Explain fields. Is this a work-list of import task
+ Map<Export, ImportExportData> dependencyMap =
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Just "dependencies". I can see it's a map, and if
+ new Map<Export, ImportExportData>();
Lasse Reichstein Nielsen 2012/09/28 07:45:36 This maps syntax to a data object. That seems odd.
+ Map<SourceString, Element> exportScope = new Map<SourceString, Element>();
Lasse Reichstein Nielsen 2012/09/28 07:45:36 This, I guess, is the export scope that is being b
+ Set<Element> pendingExportSet = new Set<Element>();
+
+ ImportExportData(LibraryElement this.library);
+}
+
+/**
+ * Helper class used for computing the possibly cyclic import/export scopes of
+ * a set of libraries.
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Are you sure this should not be a CompilerTask? It
+ *
+ * This class is used by [ScannerTask.loadLibrary] to collect all newly loaded
+ * libraries and to compute their import/export scopes through a fixed-point
+ * algorithm.
+ */
+class ImportExportHandler {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Again: "ImportExport" is a bad name. (I'll stop no
+ final Compiler compiler;
+
+ Map<LibraryElement,ImportExportData> dataMap =
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Plase give this a better name that describes how i
+ new Map<LibraryElement,ImportExportData>();
+
+ ImportExportHandler(Compiler this.compiler);
+
+ /**
+ * Performs a fixed-point computation on the export scopes of all registered
+ * libraries and creates the import/export of the libraries based on the
+ * fixed-point.
+ */
+ void computeExports() {
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ dataMap.forEach((LibraryElement library, ImportExportData data) {
+ var pendingExportSet = new Set<Element>.from(data.pendingExportSet);
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Why a Set? I'd think a list would have lower overh
Johnni Winther 2012/10/09 09:47:10 Done.
+ data.pendingExportSet.clear();
+ pendingExportSet.forEach((Element element) {
+ SourceString name = element.name;
+ Element existingElement =
+ data.exportScope.putIfAbsent(name, () => element);
+ if (existingElement !== null && existingElement !== element) {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 If you export the same library twice, should it be
+ element = data.exportScope[name] = new ErroneousElement(
+ MessageKind.DUPLICATE_EXPORT, [name], name, library);
+ }
+ data.dependencyMap.forEach((Export export,
+ ImportExportData exportData) {
+ // TODO(johnniwinther): Handle show and hide combinators.
+ if (exportData.exportScope[name] !== element) {
+ exportData.pendingExportSet.add(element);
+ changed = true;
+ }
+ });
+ });
});
}
+
+ // Setup export scopes.
+ dataMap.forEach((LibraryElement library, ImportExportData data) {
+ data.library.exportScope = data.exportScope;
+ });
+
+ // Setup import scopes.
+ dataMap.forEach((LibraryElement library, ImportExportData data) {
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Join loops?
Johnni Winther 2012/10/09 09:47:10 Can't do. We need the completion of exports before
+ for (ImportData importData in data.imports) {
+ importLibrary(library, importData);
+ }
+ });
+ }
+
+ /**
+ * Registers that [importingLibrary] depends on [importedLibrary] through
+ * [tag].
+ */
+ void registerDependency(LibraryElement importingLibrary,
+ ImportExport tag,
+ LibraryElement importedLibrary,
+ CompilationUnitElement compilationUnit) {
+ if (tag is Export) {
+ dataMap[importedLibrary].dependencyMap[tag] = dataMap[importingLibrary];
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Because dataMap says nothing about what it does, t
+ } else {
+ ImportExportData data = dataMap[importingLibrary];
+ var importData = new ImportData(tag, importedLibrary, compilationUnit);
+ data.imports = data.imports.prepend(importData);
+ }
+ }
+
+ /**
+ * Registers [library] for the processing of its import/export scope.
+ */
+ void registerNewLibrary(LibraryElement library) {
+ dataMap[library] = new ImportExportData(library);
Lasse Reichstein Nielsen 2012/09/28 07:45:36 So the ImportExportData is the data associated wit
+ }
+
+ /**
+ * Registers all top-level entities of [library] as starting point for the
+ * fixed-point computation of the import/export scopes.
+ */
+ void registerLibraryExports(LibraryElement library) {
+ dataMap[library].pendingExportSet.addAll(
+ library.localScope.getValues().filter((Element element) {
+ return !element.name.isPrivate();
+ }));
Lasse Reichstein Nielsen 2012/09/28 07:45:36 Ick. How about: ImportExportData libraryData = d
+ }
+
+ /**
+ * Imports the export scope of [import] to the import scope of [library].
+ */
+ void importLibrary(LibraryElement library, ImportData import) {
+ Import tag = import.tag;
+ LibraryElement imported = import.library;
if (tag !== null && tag.prefix !== null) {
SourceString prefix = tag.prefix.source;
Element e = library.find(prefix);
if (e === null) {
+ CompilationUnitElement compilationUnit = import.compilationUnit;
if (compilationUnit === null) {
compilationUnit = library.entryCompilationUnit;
}
@@ -159,6 +363,7 @@ class ScannerTask extends CompilerTask {
}
PrefixElement prefixElement = e;
imported.forEachExport((Element element) {
+ // TODO(johnniwinther): Handle show and hide combinators.
Element existing =
prefixElement.imported.putIfAbsent(element.name, () => element);
if (existing !== element) {
@@ -175,44 +380,10 @@ class ScannerTask extends CompilerTask {
} else {
imported.forEachExport((Element element) {
compiler.withCurrentElement(element, () {
+ // TODO(johnniwinther): Handle show and hide combinators.
library.addImport(element, compiler);
});
});
}
}
-}
-
-class DietParserTask extends CompilerTask {
- DietParserTask(Compiler compiler) : super(compiler);
- final String name = 'Diet Parser';
-
- dietParse(CompilationUnitElement compilationUnit, Token tokens) {
- measure(() {
- Function idGenerator = compiler.getNextFreeClassId;
- ElementListener listener =
- new ElementListener(compiler, compilationUnit, idGenerator);
- PartialParser parser = new PartialParser(listener);
- parser.parseUnit(tokens);
- });
- }
-}
-
-/**
- * The fields of this class models a state machine for checking script
- * tags come in the correct order.
- */
-class TagState {
- static const int NO_TAG_SEEN = 0;
- static const int LIBRARY = 1;
- static const int IMPORT = 2;
- static const int SOURCE = 3;
- static const int RESOURCE = 4;
-
- /** Next state. */
- static const List<int> NEXT =
- const <int>[NO_TAG_SEEN,
- IMPORT, // Only one library tag is allowed.
- IMPORT,
- SOURCE,
- RESOURCE];
-}
+}

Powered by Google App Engine
This is Rietveld 408576698