OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 compile; | 5 library compile; |
6 | 6 |
7 import 'dart:coreimpl'; | 7 import 'dart:coreimpl'; |
8 import 'package:html5lib/dom.dart'; | 8 import 'package:html5lib/dom.dart'; |
9 import 'package:html5lib/html5parser.dart'; | 9 import 'package:html5lib/parser.dart'; |
10 import 'package:html5lib/tokenizer.dart'; | |
11 | 10 |
12 import 'analyzer.dart'; | 11 import 'analyzer.dart'; |
13 import 'code_printer.dart'; | 12 import 'code_printer.dart'; |
14 import 'codegen.dart' as codegen; | 13 import 'codegen.dart' as codegen; |
15 import 'emitters.dart'; | 14 import 'emitters.dart'; |
16 import 'file_system.dart'; | 15 import 'file_system.dart'; |
17 import 'files.dart'; | 16 import 'files.dart'; |
18 import 'info.dart'; | 17 import 'info.dart'; |
19 import 'utils.dart'; | 18 import 'utils.dart'; |
20 import 'world.dart'; | 19 import 'world.dart'; |
21 | 20 |
22 // TODO(jmesserly): move these things into html5lib's public api | 21 // TODO(jmesserly): move these things into html5lib's public api |
23 // This is for voidElements: | 22 // This is for voidElements: |
24 import 'package:html5lib/src/constants.dart' as html5_constants; | 23 import 'package:html5lib/src/constants.dart' as html5_constants; |
25 // This is for htmlEscapeMinimal: | 24 // This is for htmlEscapeMinimal: |
26 import 'package:html5lib/src/utils.dart' as html5_utils; | 25 import 'package:html5lib/src/utils.dart' as html5_utils; |
27 | 26 |
28 | 27 |
29 Document parseHtml(String template, String sourcePath) { | 28 Document parseHtml(String template, String sourcePath) { |
30 var parser = new HTMLParser(); | 29 var parser = new HtmlParser(template, generateSpans: true); |
31 var document = parser.parse(new HTMLTokenizer(template)); | 30 var document = parser.parse(); |
32 | 31 |
33 // Note: errors aren't fatal in HTML (unless strict mode is on). | 32 // Note: errors aren't fatal in HTML (unless strict mode is on). |
34 // So just print them as warnings. | 33 // So just print them as warnings. |
35 for (var e in parser.errors) { | 34 for (var e in parser.errors) { |
36 world.warning('$sourcePath line ${e.line}:${e.column}: ${e.message}'); | 35 world.warning('$sourcePath line ${e.line}:${e.column}: ${e.message}'); |
37 } | 36 } |
38 return document; | 37 return document; |
39 } | 38 } |
40 | 39 |
41 /** | 40 /** |
42 * Walk the tree produced by the parser looking for templates, expressions, etc. | 41 * Walk the tree produced by the parser looking for templates, expressions, etc. |
43 * as a prelude to emitting the code for the template. | 42 * as a prelude to emitting the code for the template. |
44 */ | 43 */ |
45 class Compile { | 44 class Compile { |
46 final FileSystem filesystem; | 45 final FileSystem filesystem; |
47 final List<SourceFile> files; | 46 final List<SourceFile> files; |
48 final List<OutputFile> output; | 47 final List<OutputFile> output; |
49 | 48 |
50 /** Information about source [files] given their href. */ | 49 /** Information about source [files] given their href. */ |
51 final Map<String, FileInfo> info; | 50 final Map<String, FileInfo> info; |
52 | 51 |
53 /** Used by template tool to open a file. */ | 52 /** Used by template tool to open a file. */ |
54 Compile(this.filesystem) | 53 Compile(this.filesystem) |
55 : files = <SourceFile>[], | 54 : files = <SourceFile>[], |
56 output = <OutputFile>[], | 55 output = <OutputFile>[], |
57 info = new SplayTreeMap<String, FileInfo>(); | 56 info = new SplayTreeMap<String, FileInfo>(); |
58 | 57 |
59 /** Compile the application starting from the given [inputFile]. */ | 58 /** Compile the application starting from the given [mainFile]. */ |
60 void run(String inputFile, [String baseDir = ""]) { | 59 Future run(String mainFile, [String baseDir = ""]) { |
61 _parseAndDiscover(inputFile, baseDir); | 60 return _parseAndDiscover(mainFile, baseDir).transform((_) { |
62 _analyze(); | 61 _analyze(); |
63 _emit(); | 62 _emit(); |
| 63 return null; |
| 64 }); |
64 } | 65 } |
65 | 66 |
66 /** | 67 /** |
67 * Parse [inputFile] and recursively discover web components to load and | 68 * Asynchronously parse [inputFile] and recursively discover web components to |
68 * parse. | 69 * load and parse. Returns a future that completes when all files are |
| 70 * processed. |
69 */ | 71 */ |
70 void _parseAndDiscover(String inputFile, String baseDir) { | 72 Future _parseAndDiscover(String inputFile, String baseDir) { |
71 var pending = new Queue<String>(); // files to process | 73 var pending = new Queue<String>(); // files to process |
72 pending.addLast(inputFile); | |
73 while (!pending.isEmpty()) { | |
74 var filename = pending.removeFirst(); | |
75 | 74 |
76 // Parse the file. | 75 Completer done = new Completer(); |
77 if (info.containsKey(filename)) continue; | 76 // We are not done until the number of in progress requests goes back to 0. |
78 var file = _parseHtmlFile(filename, baseDir); | 77 int inProgress = 0; |
79 files.add(file); | |
80 | 78 |
81 // Find additional components being loaded. | 79 notifyIfDone() { |
82 var fileInfo = time('Analyzed definitions ${file.filename}', | 80 assert(inProgress >= 0); |
83 () => analyzeDefinitions(file, isEntryPoint: filename == inputFile)); | 81 if (inProgress == 0) { |
84 info[file.filename] = fileInfo; | 82 done.complete(null); |
85 | |
86 for (var href in fileInfo.componentLinks) { | |
87 pending.addLast(href); | |
88 } | |
89 | |
90 // Load .dart files being referenced in components. | |
91 for (var component in fileInfo.declaredComponents) { | |
92 var src = component.externalFile; | |
93 if (src != null) { | |
94 var dartFile = _parseDartFile(src, baseDir); | |
95 var fileInfo = new FileInfo(dartFile.filename); | |
96 info[dartFile.filename] = fileInfo; | |
97 fileInfo.userCode = dartFile.code; | |
98 files.add(dartFile); | |
99 } | |
100 } | 83 } |
101 } | 84 } |
| 85 |
| 86 pending.addLast(inputFile); |
| 87 |
| 88 parsePending() { |
| 89 while (!pending.isEmpty()) { |
| 90 var filename = pending.removeFirst(); |
| 91 |
| 92 // Parse the file. |
| 93 if (info.containsKey(filename)) continue; |
| 94 |
| 95 inProgress++; |
| 96 |
| 97 _parseHtmlFile(filename, baseDir).then((file) { |
| 98 files.add(file); |
| 99 |
| 100 // Find additional components being loaded. |
| 101 var fileInfo = time('Analyzed definitions ${file.filename}', |
| 102 () => analyzeDefinitions( |
| 103 file, isEntryPoint: filename == inputFile)); |
| 104 info[file.filename] = fileInfo; |
| 105 for (var href in fileInfo.componentLinks) { |
| 106 pending.addLast(href); |
| 107 } |
| 108 // Load .dart files being referenced in components. |
| 109 for (var component in fileInfo.declaredComponents) { |
| 110 var src = component.externalFile; |
| 111 if (src != null) { |
| 112 inProgress++; |
| 113 _parseDartFile(src, baseDir).then((dartFile) { |
| 114 var fileInfo = new FileInfo(dartFile.filename); |
| 115 info[dartFile.filename] = fileInfo; |
| 116 fileInfo.userCode = dartFile.code; |
| 117 files.add(dartFile); |
| 118 inProgress--; |
| 119 notifyIfDone(); |
| 120 }); |
| 121 } |
| 122 } |
| 123 inProgress--; |
| 124 parsePending(); |
| 125 }); |
| 126 } |
| 127 notifyIfDone(); |
| 128 } |
| 129 |
| 130 parsePending(); |
| 131 return done.future; |
102 } | 132 } |
103 | 133 |
104 /** Parse [filename]. */ | 134 /** Asynchronously parse [filename]. */ |
105 SourceFile _parseHtmlFile(String filename, String baseDir) { | 135 Future<SourceFile> _parseHtmlFile(String filename, String baseDir) { |
106 var file = new SourceFile(filename); | 136 return filesystem.readAll("$baseDir/$filename").transform( |
107 var source = filesystem.readAll("$baseDir/$filename"); | 137 (source) { |
108 file.document = time("Parsed $filename", () => parseHtml(source, filename)); | 138 var file = new SourceFile(filename); |
109 if (options.dumpTree) { | 139 file.document = time("Parsed $filename", |
110 print("\n\n Dump Tree $filename:\n\n"); | 140 () => parseHtml(source, filename)); |
111 print(file.document.outerHTML); | 141 if (options.dumpTree) { |
112 print("\n=========== End of AST ===========\n\n"); | 142 print("\n\n Dump Tree $filename:\n\n"); |
113 } | 143 print(file.document.outerHTML); |
114 return file; | 144 print("\n=========== End of AST ===========\n\n"); |
| 145 } |
| 146 return file; |
| 147 }); |
115 } | 148 } |
116 | 149 |
117 /** Parse [filename] and treat it as a .dart file. */ | 150 /** Parse [filename] and treat it as a .dart file. */ |
118 SourceFile _parseDartFile(String filename, String baseDir) { | 151 Future<SourceFile> _parseDartFile(String filename, String baseDir) { |
119 var file = new SourceFile(filename, isDart: true); | 152 return filesystem.readAll("$baseDir/$filename").transform((source) => |
120 file.code = time("Read $baseDir/$filename", | 153 new SourceFile(filename, isDart: true) |
121 () => filesystem.readAll("$baseDir/$filename")); | 154 ..code = source); |
122 return file; | |
123 } | 155 } |
124 | 156 |
125 /** Run the analyzer on every input html file. */ | 157 /** Run the analyzer on every input html file. */ |
126 void _analyze() { | 158 void _analyze() { |
127 for (var file in files) { | 159 for (var file in files) { |
128 if (file.isDart) continue; | 160 if (file.isDart) continue; |
129 time('Analyzed contents ${file.filename}', () => analyzeFile(file, info)); | 161 time('Analyzed contents ${file.filename}', () => analyzeFile(file, info)); |
130 } | 162 } |
131 } | 163 } |
132 | 164 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 if (doctype.tagName != 'html' || commentIndex != 1) { | 280 if (doctype.tagName != 'html' || commentIndex != 1) { |
249 world.warning('${file.filename}: file should start with <!DOCTYPE html> ' | 281 world.warning('${file.filename}: file should start with <!DOCTYPE html> ' |
250 'to avoid the possibility of it being parsed in quirks mode in IE. ' | 282 'to avoid the possibility of it being parsed in quirks mode in IE. ' |
251 'See http://www.w3.org/TR/html5-diff/#doctype'); | 283 'See http://www.w3.org/TR/html5-diff/#doctype'); |
252 } | 284 } |
253 } | 285 } |
254 document.nodes.insertAt(commentIndex, parseFragment( | 286 document.nodes.insertAt(commentIndex, parseFragment( |
255 '\n<!-- This file was auto-generated from template ' | 287 '\n<!-- This file was auto-generated from template ' |
256 '${file.filename}. -->\n')); | 288 '${file.filename}. -->\n')); |
257 } | 289 } |
OLD | NEW |