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

Unified Diff: lib/src/compiler.dart

Issue 12096106: work in progress: observable implementation using detailed change records (Closed) Base URL: https://github.com/dart-lang/web-ui.git@master
Patch Set: Created 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/codegen.dart ('k') | lib/src/dart_parser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/compiler.dart
diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart
index c12ffce6078049ec100e3d7c075624088d24817f..c526b27e6724a2e6621fb179b8027f9be5cf8133 100644
--- a/lib/src/compiler.dart
+++ b/lib/src/compiler.dart
@@ -6,6 +6,7 @@ library compiler;
import 'dart:async';
import 'dart:collection' show SplayTreeMap;
+import 'dart:uri';
import 'package:html5lib/dom.dart';
import 'package:html5lib/parser.dart';
@@ -20,6 +21,7 @@ import 'files.dart';
import 'html_cleaner.dart';
import 'info.dart';
import 'messages.dart';
+import 'observable_transform.dart' show transformObservables;
import 'options.dart';
import 'utils.dart';
@@ -53,6 +55,9 @@ class Compiler {
PathInfo _pathInfo;
Messages _messages;
+ FutureGroup _tasks;
+ Set _processed;
+
/** Information about source [files] given their href. */
final Map<Path, FileInfo> info = new SplayTreeMap<Path, FileInfo>();
@@ -99,6 +104,7 @@ class Compiler {
}
return _parseAndDiscover(_mainPath).then((_) {
_analyze();
+ _transformDart();
_emit();
});
}
@@ -109,49 +115,52 @@ class Compiler {
* processed.
*/
Future _parseAndDiscover(Path inputFile) {
- var tasks = new FutureGroup();
- bool isEntry = !options.componentsOnly;
-
- var processed = new Set();
- processHtmlFile(SourceFile file) {
- if (file == null) return;
- if (!_pathInfo.checkInputPath(file.path, _messages)) return;
-
- files.add(file);
-
- var fileInfo = _time('Analyzed definitions', file.path,
- () => analyzeDefinitions(file, _messages, isEntryPoint: isEntry));
- isEntry = false;
- info[file.path] = fileInfo;
-
- // Load component files referenced by [file].
- for (var href in fileInfo.componentLinks) {
- if (!processed.contains(href)) {
- processed.add(href);
- tasks.add(_parseHtmlFile(href).then(processHtmlFile));
- }
- }
+ _tasks = new FutureGroup();
+ _processed = new Set();
+ _processed.add(inputFile);
+ _tasks.add(_parseHtmlFile(inputFile).then(_processHtmlFile));
+ return _tasks.future;
+ }
- // Load .dart files being referenced in the page.
- var src = fileInfo.externalFile;
- if (src != null && !processed.contains(src)) {
- processed.add(src);
- tasks.add(_parseDartFile(src).then(_addDartFile));
- }
+ bool _shouldProcessFile(SourceFile file) =>
+ file != null && _pathInfo.checkInputPath(file.path, _messages);
- // Load .dart files being referenced in components.
- for (var component in fileInfo.declaredComponents) {
- var src = component.externalFile;
- if (src != null && !processed.contains(src)) {
- processed.add(src);
- tasks.add(_parseDartFile(src).then(_addDartFile));
- }
+ void _processHtmlFile(SourceFile file) {
+ if (!_shouldProcessFile(file)) return;
+
+ bool isEntryPoint = _processed.length == 1;
+
+ files.add(file);
+
+ var fileInfo = _time('Analyzed definitions', file.path,
+ () => analyzeDefinitions(file, _messages, isEntryPoint: isEntryPoint));
+ info[file.path] = fileInfo;
+
+ _processImports(fileInfo);
+
+ // Load component files referenced by [file].
+ for (var href in fileInfo.componentLinks) {
+ if (!_processed.contains(href)) {
+ _processed.add(href);
+ _tasks.add(_parseHtmlFile(href).then(_processHtmlFile));
}
}
- processed.add(inputFile);
- tasks.add(_parseHtmlFile(inputFile).then(processHtmlFile));
- return tasks.future;
+ // Load .dart files being referenced in the page.
+ var src = fileInfo.externalFile;
+ if (src != null && !_processed.contains(src)) {
+ _processed.add(src);
+ _tasks.add(_parseDartFile(src).then(_processDartFile));
+ }
+
+ // Load .dart files being referenced in components.
+ for (var component in fileInfo.declaredComponents) {
+ var src = component.externalFile;
+ if (src != null && !_processed.contains(src)) {
+ _processed.add(src);
+ _tasks.add(_parseDartFile(src).then(_processDartFile));
+ }
+ }
}
/** Asynchronously parse [path] as an .html file. */
@@ -179,20 +188,138 @@ class Compiler {
return null;
}
- void _addDartFile(SourceFile dartFile) {
- if (dartFile == null) return;
- if (!_pathInfo.checkInputPath(dartFile.path, _messages)) return;
+ void _processDartFile(SourceFile dartFile) {
+ if (!_shouldProcessFile(dartFile)) return;
files.add(dartFile);
var fileInfo = new FileInfo(dartFile.path);
info[dartFile.path] = fileInfo;
- fileInfo.inlinedCode = dartFile.code;
- fileInfo.userCode = parseDartCode(fileInfo.inlinedCode,
- fileInfo.path, messages:_messages);
- if (fileInfo.userCode.partOf != null) {
- _messages.error('expected a library, not a part.', null,
- file: dartFile.path);
+ fileInfo.userCode = parseDartCode(dartFile.code,
+ fileInfo.path, messages: _messages);
+
+ _processImports(fileInfo);
+ }
+
+ void _processImports(FileInfo fileInfo) {
+ if (fileInfo.userCode == null) return;
+
+ for (var directive in fileInfo.userCode.directives) {
+ var src = _getDirectivePath(fileInfo, directive.uri);
+ if (src == null) continue;
+ if (!_processed.contains(src)) {
+ _processed.add(src);
+ _tasks.add(_parseDartFile(src).then(_processDartFile));
+ }
+ }
+ }
+
+ Path _getDirectivePath(LibraryInfo libInfo, String uri) {
+ if (uri.startsWith('dart:')) return null;
+
+ if (uri.startsWith('package:')) {
+ // Don't process our own package -- we'll implement @observable manually.
+ if (uri.startsWith('package:web_ui/')) return null;
+
+ return _mainPath.directoryPath.join(new Path('packages'))
+ .join(new Path(uri.substring(8)));
+ } else {
+ return libInfo.inputPath.directoryPath.join(new Path(uri));
+ }
+ }
+
+ /**
+ * Transform Dart source code.
+ * Currently, the only transformation is [transformObservables].
+ * Calls _emitModifiedDartFiles to write the transformed files.
+ */
+ void _transformDart() {
+ var libraries = <LibraryInfo>[];
+ for (var sourceFile in files) {
+ var file = info[sourceFile.path];
+ libraries.add(file);
+ libraries.addAll(file.declaredComponents);
+ }
+ // Prefer to process the .dart file if it is external.
+ for (var i = 0; i < libraries.length; i++) {
+ var external = libraries[i].externalCode;
+ if (external != null) libraries[i] = external;
+ }
+ libraries = libraries.where((lib) => lib.userCode != null).toList();
+
+ var transformed = [];
+ for (var library in libraries) {
+ // TODO(jmesserly): does it make sense for us to warn about Dart parse
+ // errors? It seems useful, but the VM or dart2js would still issue these
+ // messages anyway later.
+ if (transformObservables(library, messages: _messages)) {
+ transformed.add(library);
+ }
+ }
+
+ _emitModifiedDartFiles(libraries, transformed);
+ }
+
+ /**
+ * This method rewrites imports transitively for any modified dart files,
+ * and queues the [outputs] to be written. This will not write files that
+ * are handled by [WebComponentEmitter] and [MainPageEmitter].
+ */
+ void _emitModifiedDartFiles(List<LibraryInfo> libraries,
+ List<FileInfo> transformed) {
+
+ if (transformed.length == 0) return;
+
+ // Compute files that reference each file, then use this information to
+ // flip the modified bit transitively. This is a lot simpler than trying
+ // to compute it the other way because of circular references.
+ for (var library in libraries) {
+ for (var directive in library.userCode.directives) {
+ var importPath = _getDirectivePath(library, directive.uri);
+ if (importPath == null) continue;
+
+ info[importPath].referencedBy.add(library);
+ }
+ }
+
+ // Propegate the modified bit to anything that references a modified file.
+ void setModified(LibraryInfo library) {
+ if (library.modified) return;
+ library.modified = true;
+ library.referencedBy.forEach(setModified);
+ }
+ transformed.forEach(setModified);
+
+ for (var library in libraries) {
+ // We don't need this anymore, so free it.
+ library.referencedBy = null;
+
+ if (!library.modified) continue;
+
+ var fileOutputPath = _pathInfo.outputLibraryPath(library);
+
+ // Fix imports of modified files to use the generated path.
+ for (var directive in library.userCode.directives) {
+ var importPath = _getDirectivePath(library, directive.uri);
+ if (importPath == null) continue;
+ var importInfo = info[importPath];
+
+ if (importInfo.modified && !directive.generated) {
+ // Use the generated URI for this file.
+ directive.generated = true;
+ directive.uri = _pathInfo.outputLibraryPath(importInfo)
+ .relativeTo(fileOutputPath.directoryPath).toString();
+ }
+ }
+
+ // Components will get emitted by WebComponentEmitter, and the
+ // entry point will get emitted by MainPageEmitter.
+ // So we only need to worry about other .dart files.
+ if (library is FileInfo && library.htmlFile == null) {
+ // Add an output file for the transformed .dart code:
+ output.add(new OutputFile(fileOutputPath,
+ emitDartFile(library, _pathInfo), source: library.inputPath));
+ }
}
}
@@ -318,5 +445,3 @@ class Compiler {
'\n<!-- This file was auto-generated from ${file.path}. -->\n'));
}
}
-
-
« no previous file with comments | « lib/src/codegen.dart ('k') | lib/src/dart_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698