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

Unified Diff: utils/pub/yaml/parser.dart

Issue 10886055: Add a friendly error message for using a tab as indentation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 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 | « no previous file | utils/tests/pub/yaml_test.dart » ('j') | utils/tests/pub/yaml_test.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/pub/yaml/parser.dart
diff --git a/utils/pub/yaml/parser.dart b/utils/pub/yaml/parser.dart
index 7f4875ebfcdcbe4e291b030aee2ed6451bea71f1..bc721c3e0a6ef8b6bee7cda2e1a76f7b426dfceb 100644
--- a/utils/pub/yaml/parser.dart
+++ b/utils/pub/yaml/parser.dart
@@ -144,6 +144,12 @@ class _Parser {
int farthestColumn = 0;
/**
+ * The farthest position in the source string that has been parsed
+ * successfully before backtracking. Used for error reporting.
+ */
+ int farthestPos = 0;
+
+ /**
* The name of the context of the farthest position that has been parsed
* successfully before backtracking. Used for error reporting.
*/
@@ -153,6 +159,12 @@ class _Parser {
List<String> contextStack;
/**
+ * Annotations attached to ranges of the source string that add extra
+ * information to any errors that occur in the annotated range.
+ */
+ _RangeMap<String> errorAnnotations;
+
+ /**
* The buffer containing the string currently being captured.
*/
StringBuffer capturedString;
@@ -170,7 +182,8 @@ class _Parser {
_Parser(String s)
: this.s = s,
len = s.length,
- contextStack = <String>["document"];
+ contextStack = <String>["document"],
+ errorAnnotations = new _RangeMap();
/**
* Return the character at the current position, then move that position
@@ -194,6 +207,7 @@ class _Parser {
farthestColumn = column;
farthestContext = contextStack.last();
}
+ farthestPos = pos;
return char;
}
@@ -416,6 +430,22 @@ class _Parser {
}
}
+ /**
+ * Adds [message] as extra information to any errors that occur between the
+ * current position and the position of the cursor after running [fn]. The
+ * cursor is reset after [fn] is run.
+ */
+ annotateError(String message, fn()) {
+ var start = pos;
+ var end;
+ transaction(() {
+ fn();
+ end = pos;
+ return false;
+ });
+ errorAnnotations[new _Range(start, end)] = message;
+ }
+
/** Throws an error with additional context information. */
error(String message) {
// Line and column should be one-based.
@@ -437,8 +467,10 @@ class _Parser {
* [farthestColumn], and [farthestContext] to provide additional information.
*/
parseFailed() {
- throw new SyntaxError(farthestLine + 1, farthestColumn + 1,
- "invalid YAML in $farthestContext");
+ var message = "invalid YAML in $farthestContext";
+ var extraError = errorAnnotations[farthestPos];
+ if (extraError != null) message = "$message ($extraError)";
+ throw new SyntaxError(farthestLine + 1, farthestColumn + 1, message);
}
/** Returns the number of spaces after the current position. */
@@ -674,12 +706,28 @@ class _Parser {
}));
// 63
- bool s_indent(int indent) => nAtOnce(indent, (c, i) => c == SP);
+ bool s_indent(int indent) {
+ var result = nAtOnce(indent, (c, i) => c == SP);
+ if (peek() == TAB) {
+ annotateError("\\t is not allowed as indentation in YAML",
Bob Nystrom 2012/08/30 16:43:51 I would use "tab characters" instead of the escape
nweiz 2012/08/30 19:19:02 Done.
+ () => zeroOrMore(() => consume(isSpace)));
+ }
+ return result;
+ }
// 64
bool s_indentLessThan(int indent) {
for (int i = 0; i < indent - 1; i++) {
- if (!consumeChar(SP)) break;
+ if (!consumeChar(SP)) {
+ if (peek() == TAB) {
+ annotateError("\\t is not allowed as indentation in YAML", () {
Bob Nystrom 2012/08/30 16:43:51 Ditto.
nweiz 2012/08/30 19:19:02 Done.
+ for (; i < indent - 1; i++) {
+ if (!consume(isSpace)) break;
+ }
+ });
+ }
+ break;
+ }
}
return true;
}
@@ -1901,3 +1949,50 @@ class _BlockHeader {
bool get autoDetectIndent => additionalIndent == null;
}
+
+/**
+ * A range of characters in the YAML document, from [start] to [end] (inclusive).
+ */
+class _Range {
+ /** The first character in the range. */
+ final int start;
+
+ /** The last character in the range. */
+ final int end;
+
+ _Range(this.start, this.end);
+
+ /** Returns whether or not [pos] lies within this range. */
+ bool contains(int pos) => pos >= start && pos <= end;
+}
+
+/**
+ * A map that associates [E] values with [_Range]s. It's efficient to create new
+ * associations, but finding the value associated with a position is more
+ * expensive.
+ */
+class _RangeMap<E> {
+ /** The ranges and their associated elements. */
+ final List<_Pair<_Range, E>> contents;
+
+ _RangeMap() : this.contents = <_Pair<_Range, E>>[];
+
+ /**
+ * Returns the value associated with the range in which [pos] lies, or null if
+ * there is no such range. If there's more than one such range, the most
+ * recently set one is used.
+ */
+ E operator[](int pos) {
+ // Iterate backwards through contents so the more recent range takes
+ // precedence. TODO(nweiz): clean this up when issue 2804 is fixed.
+ for (var i = contents.length - 1; i >= 0; i--) {
+ var pair = contents[i];
+ if (pair.first.contains(pos)) return pair.last;
+ }
+ return null;
+ }
+
+ /** Associates [value] with [range]. */
+ operator[]=(_Range range, E value) =>
+ contents.add(new _Pair<_Range, E>(range, value));
+}
« no previous file with comments | « no previous file | utils/tests/pub/yaml_test.dart » ('j') | utils/tests/pub/yaml_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698