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

Side by Side Diff: lib/src/dart_parser.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, 10 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
« no previous file with comments | « lib/src/compiler.dart ('k') | lib/src/directive_parser.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Parser for Dart code based on the dart2js parser.
7 *
8 * Use [DartCodeParser.parse] to parse top-level code, and the returned
9 * instance to parse additonal structures such as classes.
10 */
11 library dart_parser;
12
13 import 'dart:uri';
14 import 'dart:utf';
15 import 'package:compiler_unsupported/implementation/dart2jslib.dart' as dart2js;
16 import 'package:compiler_unsupported/implementation/elements/elements.dart';
17 import 'package:compiler_unsupported/implementation/elements/modelx.dart';
18 import 'package:compiler_unsupported/implementation/scanner/scannerlib.dart';
19 import 'package:compiler_unsupported/implementation/source_file.dart';
20 import 'package:compiler_unsupported/implementation/tree/tree.dart';
21 import 'package:compiler_unsupported/implementation/util/util.dart';
22 import 'package:compiler_unsupported/implementation/util/characters.dart';
23 import 'package:compiler_unsupported/compiler.dart' as api;
24 import 'package:html5lib/dom_parsing.dart' as dom_parsing;
25 import 'messages.dart' show Messages;
26 import 'file_system/path.dart' as fs;
27
28 // TODO(jmesserly): reconcile this with DartCodeInfo
29 class DartCodeParser {
30 final DiagnosticListener diagnostics;
31 final CompilationUnitElement unit;
32 final String code;
33 bool _success;
34
35 bool get success => _success;
36
37 Messages get messages => diagnostics.messages;
38
39 DartCodeParser._parse(this.diagnostics, this.unit, this.code) {
40 _success = _parseCompilationUnit();
41 }
42
43 /**
44 * Performs a partial parse of Dart code and returns the parser.
45 * From their you can determine if the parse was a [success] and get the
46 * compilation [unit].
47 *
48 * The partial parse only parses the top-level structure. Futher parsing can
49 * then be performed using the parser, such as [parseClass].
50 *
51 * You can provide a object to receive warning and error [messages] from the
52 * parser, otherwise [this.messages] will be a new messages instance that is
53 * silent (does not print).
54 */
55 factory DartCodeParser.parse(String path, String code, {Messages messages}) {
56 if (messages == null) messages = new Messages.silent();
57 var uri = new Uri.fromComponents(path: path);
58 var script = new dart2js.Script(uri, new SourceFile(uri.toString(), code));
59 var unit = new LibraryElementX(script, uri).entryCompilationUnit;
60 var fileSpanInfo = _createSourceFileInfo(code);
61 var diagnostics = new DiagnosticListener(fileSpanInfo, unit, messages);
62 return new DartCodeParser._parse(diagnostics, unit, code);
63 }
64
65 bool _parseCompilationUnit() {
66 int nextFreeClassId = 0;
67 var idGenerator = () => nextFreeClassId++;
68 var listener = new ElementListener(diagnostics, unit, idGenerator);
69
70 // Try parsing the code. Note that the parser can throw an exception to bail
71 // out of the call stack.
72 try {
73 var tokens = new StringScanner(code).tokenize();
74 new PartialParser(listener).parseUnit(tokens);
75 return true;
76 } on dart2js.CompilerCancelledException catch (e) {
77 return false;
78 }
79 }
80
81 ClassNode parseClass(PartialClassElement element) {
82 if (element.cachedNode != null) return element.cachedNode;
83 var listener = new MemberListener(diagnostics, element);
84 var parser = new ClassElementParser(listener);
85 var token = parser.parseTopLevelDeclaration(element.beginToken);
86 assert(identical(token, element.endToken.next));
87 var classNode = listener.popNode();
88 assert(listener.nodes.isEmpty);
89 return element.cachedNode = classNode;
90 }
91 }
92
93
94 /**
95 * DiagnosticListener for dart2js. Figures out warning/error spans, and adapts
96 * them to the [Messages] format used in web_ui.
97 *
98 * This class is madness. It has to deal with spans/messages/paths/uris from
99 * 3+ compilers colliding (for those keeping score: dart2js, frog remnants
100 * inside dart2js, html5lib, and web_ui ...). Also a lot of this code had to be
101 * copied from the dart2js Compiler class to make DiagnosticListener actually
102 * work.
103 *
104 * Avert your eyes!
105 */
106 class DiagnosticListener implements dart2js.DiagnosticListener {
107 final dom_parsing.SourceFileInfo fileInfo;
108 final CompilationUnitElement currentElement;
109 final Messages messages;
110
111 DiagnosticListener(this.fileInfo, this.currentElement, this.messages);
112
113 void cancel(String reason, {node, token, instruction, element}) {
114 SourceSpan span = null;
115 if (node != null) {
116 span = spanFromNode(node);
117 } else if (token != null) {
118 span = spanFromTokens(token, token);
119 } else if (instruction != null) {
120 span = spanFromHInstruction(instruction);
121 } else if (element != null) {
122 span = spanFromElement(element);
123 } else {
124 throw 'No error location for error: $reason';
125 }
126 reportMessageString(span, reason, api.Diagnostic.ERROR);
127 throw new CompilerCancelledException(reason);
128 }
129
130 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
131 if (begin == null || end == null) {
132 // TODO(ahe): We can almost always do better. Often it is only
133 // end that is null. Otherwise, we probably know the current
134 // URI.
135 throw 'Cannot find tokens to produce error message.';
136 }
137 if (uri == null && currentElement != null) {
138 uri = currentElement.getCompilationUnit().script.uri;
139 }
140 return SourceSpan.withCharacterOffsets(begin, end,
141 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset));
142 }
143
144 SourceSpan spanFromNode(Node node, [Uri uri]) {
145 return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri);
146 }
147
148 SourceSpan spanFromElement(Element element) {
149 if (Elements.isErroneousElement(element)) {
150 element = element.enclosingElement;
151 }
152 if (element.position() == null && !element.isCompilationUnit()) {
153 // Sometimes, the backend fakes up elements that have no
154 // position. So we use the enclosing element instead. It is
155 // not a good error location, but cancel really is "internal
156 // error" or "not implemented yet", so the vicinity is good
157 // enough for now.
158 element = element.enclosingElement;
159 // TODO(ahe): I plan to overhaul this infrastructure anyways.
160 }
161 if (element == null) {
162 element = currentElement;
163 }
164 Token position = element.position();
165 Uri uri = element.getCompilationUnit().script.uri;
166 return (position == null)
167 ? new SourceSpan(uri, 0, 0)
168 : spanFromTokens(position, position, uri);
169 }
170
171 SourceSpan spanFromHInstruction(HInstruction instruction) {
172 Element element = instruction.sourceElement;
173 if (element == null) element = currentElement;
174 var position = instruction.sourcePosition;
175 if (position == null) return spanFromElement(element);
176 Token token = position.token;
177 if (token == null) return spanFromElement(element);
178 Uri uri = element.getCompilationUnit().script.uri;
179 return spanFromTokens(token, token, uri);
180 }
181
182 void log(message) {
183 print(message);
184 }
185
186 void internalError(String message,
187 {Node node, Token token, HInstruction instruction,
188 Element element}) {
189 cancel('Internal error: $message', node: node, token: token,
190 instruction: instruction, element: element);
191 }
192
193 void internalErrorOnElement(Element element, String message) {
194 internalError(message, element: element);
195 }
196
197 // What you say? One kind of "Diagnostic" isn't enough? Well, have two!
198 void reportMessage(SourceSpan span, Diagnostic message, api.Diagnostic kind) {
199 reportMessageString(span, "$message", kind);
200 }
201
202 // Note: renamed this, because otherwise you had "reportDiagnostic" reporting
203 // message strings and "reportMessage" reporting Diagnostics...
204 void reportMessageString(SourceSpan span, String message,
205 api.Diagnostic kind) {
206
207 // TODO(jmesserly): we should validate that the Uri is what we expected.
208 var msg = message.toString();
209 var ourSpan = convertToOurSpan(span);
210 var file = new fs.Path(span.uri.toString());
211
212 switch (kind) {
213 case api.Diagnostic.ERROR:
214 case api.Diagnostic.CRASH:
215 messages.error(msg, ourSpan, file: file);
216 return;
217 case api.Diagnostic.WARNING:
218 messages.error(msg, ourSpan, file: file);
219 return;
220 case api.Diagnostic.LINT:
221 case api.Diagnostic.INFO:
222 case api.Diagnostic.VERBOSE_INFO:
223 messages.info(msg, ourSpan, file: file);
224 return;
225 }
226 }
227
228 bool onDeprecatedFeature(Spannable span, String feature) {
229 // Not our job to warn about deprecated Dart features
230 return false;
231 }
232
233 dom_parsing.SourceSpan convertToOurSpan(SourceSpan span) {
234 // TODO(jmesserly): make html5lib spans less crazy.
235 return new dom_parsing.SourceSpan(fileInfo, span.begin, span.end);
236 }
237 }
238
239
240 // TODO(jmesserly): fix dom_parsing.SourceFileInfo. It should compute line
241 // locations itself on demand and caching. At the very least this function
242 // should move into that class.
243 dom_parsing.SourceFileInfo _createSourceFileInfo(String text) {
244 var lineStarts = <int>[0];
245 var chars = stringToCodepoints(text);
246
247 for (int i = 0; i < chars.length; i++) {
248 var c = chars[i];
249
250 if (c == $CR) {
251 // Return not followed by newline is treated as a newline
252 int j = i + 1;
253 if (j >= chars.length || chars[j] != $LF) {
254 c = $LF;
255 }
256 }
257
258 if (c == $LF) lineStarts.add(i + 1);
259 }
260
261 return new dom_parsing.SourceFileInfo(lineStarts, chars);
262 }
OLDNEW
« no previous file with comments | « lib/src/compiler.dart ('k') | lib/src/directive_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698