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

Unified 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, 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/compiler.dart ('k') | lib/src/directive_parser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/dart_parser.dart
diff --git a/lib/src/dart_parser.dart b/lib/src/dart_parser.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a6f2c9aad4cb8169156b097389b3515a37ed1af5
--- /dev/null
+++ b/lib/src/dart_parser.dart
@@ -0,0 +1,262 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Parser for Dart code based on the dart2js parser.
+ *
+ * Use [DartCodeParser.parse] to parse top-level code, and the returned
+ * instance to parse additonal structures such as classes.
+ */
+library dart_parser;
+
+import 'dart:uri';
+import 'dart:utf';
+import 'package:compiler_unsupported/implementation/dart2jslib.dart' as dart2js;
+import 'package:compiler_unsupported/implementation/elements/elements.dart';
+import 'package:compiler_unsupported/implementation/elements/modelx.dart';
+import 'package:compiler_unsupported/implementation/scanner/scannerlib.dart';
+import 'package:compiler_unsupported/implementation/source_file.dart';
+import 'package:compiler_unsupported/implementation/tree/tree.dart';
+import 'package:compiler_unsupported/implementation/util/util.dart';
+import 'package:compiler_unsupported/implementation/util/characters.dart';
+import 'package:compiler_unsupported/compiler.dart' as api;
+import 'package:html5lib/dom_parsing.dart' as dom_parsing;
+import 'messages.dart' show Messages;
+import 'file_system/path.dart' as fs;
+
+// TODO(jmesserly): reconcile this with DartCodeInfo
+class DartCodeParser {
+ final DiagnosticListener diagnostics;
+ final CompilationUnitElement unit;
+ final String code;
+ bool _success;
+
+ bool get success => _success;
+
+ Messages get messages => diagnostics.messages;
+
+ DartCodeParser._parse(this.diagnostics, this.unit, this.code) {
+ _success = _parseCompilationUnit();
+ }
+
+ /**
+ * Performs a partial parse of Dart code and returns the parser.
+ * From their you can determine if the parse was a [success] and get the
+ * compilation [unit].
+ *
+ * The partial parse only parses the top-level structure. Futher parsing can
+ * then be performed using the parser, such as [parseClass].
+ *
+ * You can provide a object to receive warning and error [messages] from the
+ * parser, otherwise [this.messages] will be a new messages instance that is
+ * silent (does not print).
+ */
+ factory DartCodeParser.parse(String path, String code, {Messages messages}) {
+ if (messages == null) messages = new Messages.silent();
+ var uri = new Uri.fromComponents(path: path);
+ var script = new dart2js.Script(uri, new SourceFile(uri.toString(), code));
+ var unit = new LibraryElementX(script, uri).entryCompilationUnit;
+ var fileSpanInfo = _createSourceFileInfo(code);
+ var diagnostics = new DiagnosticListener(fileSpanInfo, unit, messages);
+ return new DartCodeParser._parse(diagnostics, unit, code);
+ }
+
+ bool _parseCompilationUnit() {
+ int nextFreeClassId = 0;
+ var idGenerator = () => nextFreeClassId++;
+ var listener = new ElementListener(diagnostics, unit, idGenerator);
+
+ // Try parsing the code. Note that the parser can throw an exception to bail
+ // out of the call stack.
+ try {
+ var tokens = new StringScanner(code).tokenize();
+ new PartialParser(listener).parseUnit(tokens);
+ return true;
+ } on dart2js.CompilerCancelledException catch (e) {
+ return false;
+ }
+ }
+
+ ClassNode parseClass(PartialClassElement element) {
+ if (element.cachedNode != null) return element.cachedNode;
+ var listener = new MemberListener(diagnostics, element);
+ var parser = new ClassElementParser(listener);
+ var token = parser.parseTopLevelDeclaration(element.beginToken);
+ assert(identical(token, element.endToken.next));
+ var classNode = listener.popNode();
+ assert(listener.nodes.isEmpty);
+ return element.cachedNode = classNode;
+ }
+}
+
+
+/**
+ * DiagnosticListener for dart2js. Figures out warning/error spans, and adapts
+ * them to the [Messages] format used in web_ui.
+ *
+ * This class is madness. It has to deal with spans/messages/paths/uris from
+ * 3+ compilers colliding (for those keeping score: dart2js, frog remnants
+ * inside dart2js, html5lib, and web_ui ...). Also a lot of this code had to be
+ * copied from the dart2js Compiler class to make DiagnosticListener actually
+ * work.
+ *
+ * Avert your eyes!
+ */
+class DiagnosticListener implements dart2js.DiagnosticListener {
+ final dom_parsing.SourceFileInfo fileInfo;
+ final CompilationUnitElement currentElement;
+ final Messages messages;
+
+ DiagnosticListener(this.fileInfo, this.currentElement, this.messages);
+
+ void cancel(String reason, {node, token, instruction, element}) {
+ SourceSpan span = null;
+ if (node != null) {
+ span = spanFromNode(node);
+ } else if (token != null) {
+ span = spanFromTokens(token, token);
+ } else if (instruction != null) {
+ span = spanFromHInstruction(instruction);
+ } else if (element != null) {
+ span = spanFromElement(element);
+ } else {
+ throw 'No error location for error: $reason';
+ }
+ reportMessageString(span, reason, api.Diagnostic.ERROR);
+ throw new CompilerCancelledException(reason);
+ }
+
+ SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
+ if (begin == null || end == null) {
+ // TODO(ahe): We can almost always do better. Often it is only
+ // end that is null. Otherwise, we probably know the current
+ // URI.
+ throw 'Cannot find tokens to produce error message.';
+ }
+ if (uri == null && currentElement != null) {
+ uri = currentElement.getCompilationUnit().script.uri;
+ }
+ return SourceSpan.withCharacterOffsets(begin, end,
+ (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset));
+ }
+
+ SourceSpan spanFromNode(Node node, [Uri uri]) {
+ return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri);
+ }
+
+ SourceSpan spanFromElement(Element element) {
+ if (Elements.isErroneousElement(element)) {
+ element = element.enclosingElement;
+ }
+ if (element.position() == null && !element.isCompilationUnit()) {
+ // Sometimes, the backend fakes up elements that have no
+ // position. So we use the enclosing element instead. It is
+ // not a good error location, but cancel really is "internal
+ // error" or "not implemented yet", so the vicinity is good
+ // enough for now.
+ element = element.enclosingElement;
+ // TODO(ahe): I plan to overhaul this infrastructure anyways.
+ }
+ if (element == null) {
+ element = currentElement;
+ }
+ Token position = element.position();
+ Uri uri = element.getCompilationUnit().script.uri;
+ return (position == null)
+ ? new SourceSpan(uri, 0, 0)
+ : spanFromTokens(position, position, uri);
+ }
+
+ SourceSpan spanFromHInstruction(HInstruction instruction) {
+ Element element = instruction.sourceElement;
+ if (element == null) element = currentElement;
+ var position = instruction.sourcePosition;
+ if (position == null) return spanFromElement(element);
+ Token token = position.token;
+ if (token == null) return spanFromElement(element);
+ Uri uri = element.getCompilationUnit().script.uri;
+ return spanFromTokens(token, token, uri);
+ }
+
+ void log(message) {
+ print(message);
+ }
+
+ void internalError(String message,
+ {Node node, Token token, HInstruction instruction,
+ Element element}) {
+ cancel('Internal error: $message', node: node, token: token,
+ instruction: instruction, element: element);
+ }
+
+ void internalErrorOnElement(Element element, String message) {
+ internalError(message, element: element);
+ }
+
+ // What you say? One kind of "Diagnostic" isn't enough? Well, have two!
+ void reportMessage(SourceSpan span, Diagnostic message, api.Diagnostic kind) {
+ reportMessageString(span, "$message", kind);
+ }
+
+ // Note: renamed this, because otherwise you had "reportDiagnostic" reporting
+ // message strings and "reportMessage" reporting Diagnostics...
+ void reportMessageString(SourceSpan span, String message,
+ api.Diagnostic kind) {
+
+ // TODO(jmesserly): we should validate that the Uri is what we expected.
+ var msg = message.toString();
+ var ourSpan = convertToOurSpan(span);
+ var file = new fs.Path(span.uri.toString());
+
+ switch (kind) {
+ case api.Diagnostic.ERROR:
+ case api.Diagnostic.CRASH:
+ messages.error(msg, ourSpan, file: file);
+ return;
+ case api.Diagnostic.WARNING:
+ messages.error(msg, ourSpan, file: file);
+ return;
+ case api.Diagnostic.LINT:
+ case api.Diagnostic.INFO:
+ case api.Diagnostic.VERBOSE_INFO:
+ messages.info(msg, ourSpan, file: file);
+ return;
+ }
+ }
+
+ bool onDeprecatedFeature(Spannable span, String feature) {
+ // Not our job to warn about deprecated Dart features
+ return false;
+ }
+
+ dom_parsing.SourceSpan convertToOurSpan(SourceSpan span) {
+ // TODO(jmesserly): make html5lib spans less crazy.
+ return new dom_parsing.SourceSpan(fileInfo, span.begin, span.end);
+ }
+}
+
+
+// TODO(jmesserly): fix dom_parsing.SourceFileInfo. It should compute line
+// locations itself on demand and caching. At the very least this function
+// should move into that class.
+dom_parsing.SourceFileInfo _createSourceFileInfo(String text) {
+ var lineStarts = <int>[0];
+ var chars = stringToCodepoints(text);
+
+ for (int i = 0; i < chars.length; i++) {
+ var c = chars[i];
+
+ if (c == $CR) {
+ // Return not followed by newline is treated as a newline
+ int j = i + 1;
+ if (j >= chars.length || chars[j] != $LF) {
+ c = $LF;
+ }
+ }
+
+ if (c == $LF) lineStarts.add(i + 1);
+ }
+
+ return new dom_parsing.SourceFileInfo(lineStarts, chars);
+}
« 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