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

Unified Diff: utils/yaml/parser.dart

Issue 10153004: Add a basic YAML processor. Much of the language is still unimplemented. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove tests/lib from TEST_SUITE_DIRECTORIES. Created 8 years, 8 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
Index: utils/yaml/parser.dart
diff --git a/utils/yaml/parser.dart b/utils/yaml/parser.dart
new file mode 100644
index 0000000000000000000000000000000000000000..97726d21985148b9f142d022fb4f72b976bbcdbb
--- /dev/null
+++ b/utils/yaml/parser.dart
@@ -0,0 +1,959 @@
+// 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.
+
+/**
+ * Translates a string of characters into a YAML serialization tree.
+ *
+ * This parser is designed to closely follow the spec. All productions in the
+ * spec are numbered, and the corresponding methods in the parser have the same
+ * numbers. This is certainly not the most efficient way of parsing YAML, but it
+ * is the easiest to write and read in the context of the spec.
+ *
+ * Methods corresponding to productions are also named as in the spec,
+ * translating the name of the method (although not the annotation characters)
+ * into camel-case for dart style.. For example, the spec has a production named
+ * `nb-ns-plain-in-line`, and the method implementing it is named
+ * `_nb_ns_plainInLine`. The exception to that rule is methods that just
+ * recognize character classes; these are named `_is*`.
+ */
+class _Parser {
+ static final TAB = 0x9;
+ static final LF = 0xA;
+ static final CR = 0xD;
+ static final SP = 0x20;
+ static final TILDE = 0x7E;
+ static final NEL = 0x85;
+ static final HYPHEN = 0x2D;
+ static final QUESTION_MARK = 0x3F;
+ static final COLON = 0x3A;
+ static final COMMA = 0x2C;
+ static final LEFT_BRACKET = 0x5B;
+ static final RIGHT_BRACKET = 0x5D;
+ static final LEFT_BRACE = 0x7B;
+ static final RIGHT_BRACE = 0x7D;
+ static final HASH = 0x23;
+ static final AMPERSAND = 0x26;
+ static final ASTERISK = 0x2A;
+ static final EXCLAMATION = 0x21;
+ static final VERTICAL_BAR = 0x7C;
+ static final GREATER_THAN = 0x3E;
+ static final SINGLE_QUOTE = 0x27;
+ static final DOUBLE_QUOTE = 0x22;
+ static final PERCENT = 0x25;
+ static final AT = 0x40;
+ static final GRAVE_ACCENT = 0x60;
+
+ static final NULL = 0x0;
+ static final BELL = 0x7;
+ static final BACKSPACE = 0x8;
+ static final VERTICAL_TAB = 0xB;
+ static final FORM_FEED = 0xC;
+ static final ESCAPE = 0x1B;
+ static final BACKSLASH = 0x5C;
+ static final NBSP = 0xA0;
+ static final LINE_SEPARATOR = 0x2028;
+ static final PARAGRAPH_SEPARATOR = 0x2029;
+
+ static final _C_SEQUENCE_ENTRY = 4;
+ static final _C_MAPPING_KEY = 5;
+ static final _C_MAPPING_VALUE = 6;
+ static final _C_COLLECT_ENTRY = 7;
+ static final _C_SEQUENCE_START = 8;
+ static final _C_SEQUENCE_END = 9;
+ static final _C_MAPPING_START = 10;
+ static final _C_MAPPING_END = 11;
+ static final _C_COMMENT = 12;
+ static final _C_ANCHOR = 13;
+ static final _C_ALIAS = 14;
+ static final _C_TAG = 15;
+ static final _C_LITERAL = 16;
+ static final _C_FOLDED = 17;
+ static final _C_SINGLE_QUOTE = 18;
+ static final _C_DOUBLE_QUOTE = 19;
+ static final _C_DIRECTIVE = 20;
+ static final _C_RESERVED = 21;
+
+ static final BLOCK_OUT = 0;
+ static final BLOCK_IN = 1;
+ static final FLOW_OUT = 2;
+ static final FLOW_IN = 3;
+ static final BLOCK_KEY = 4;
+ static final FLOW_KEY = 5;
+
+ /** The source string being parsed. */
+ final String _s;
+
+ /** The current position in the source string. */
+ int _pos = 0;
+
+ /** The length of the string being parsed. */
+ final int _len;
+
+ /** The current (0-based) line in the source string. */
+ int _line = 0;
+
+ /** The curent (0-based) column in the source string. */
+ int _column = 0;
+
+ /**
+ * Whether we're parsing a bare document (that is, one that doesn't begin with
+ * `---`). Bare documents don't allow `%` immediately following newlines.
+ */
+ bool _inBareDocument = false;
+
+ /**
+ * The line number of the farthest position that has been parsed successfully
+ * before backtracking. Used for error reporting.
+ */
+ int _farthestLine = 0;
+
+ /**
+ * The column number of the farthest position that has been parsed
+ * successfully before backtracking. Used for error reporting.
+ */
+ int _farthestColumn = 0;
+
+ /**
+ * The name of the context of the farthest position that has been parsed
+ * successfully before backtracking. Used for error reporting.
+ */
+ String _farthestContext = "document";
+
+ /** A stack of the names of parse contexts. Used for error reporting. */
+ List<String> _contextStack;
+
+ _Parser(String s) : _s = s, _len = s.length,
+ _contextStack = <String>["document"];
+
+ /**
+ * Return the character at the current position, then move that position
+ * forward one character. Also updates the current line and column numbers.
+ */
+ int _next() {
+ if (_pos == _len) return -1;
+ var char = _s.charCodeAt(_pos++);
+ if (_isBreak(char)) {
+ _line++;
+ _column = 0;
+ } else {
+ _column++;
+ }
+
+ if (_farthestLine < _line) {
+ _farthestLine = _line;
+ _farthestColumn = _column;
+ _farthestContext = _contextStack.last();
+ } else if (_farthestLine == _line && _farthestColumn < _column) {
+ _farthestColumn = _column;
+ _farthestContext = _contextStack.last();
+ }
+
+ return char;
+ }
+
+ /**
+ * Returns the character at the current position, or the character [i]
+ * characters after the current position.
+ *
+ * Returns -1 if this would return a character after the end or before the
+ * beginning of the input string.
+ */
+ int _peek([int i = 0]) {
+ var pos = _pos + i;
+ return (pos >= _len || pos < 0) ? -1 : _s.charCodeAt(pos);
+ }
+
+ /**
+ * The truthiness operator. Returns false if [obj] is null or false, true
+ * otherwise.
+ */
+ bool _(obj) => obj != null && obj != false;
Bob Nystrom 2012/04/20 20:28:55 This is kind of perverse, especially the name. For
+
+ /**
+ * Consumes the current character if it matches [matcher]. Returns the result
+ * of [matcher].
+ */
+ bool _consume(bool matcher(int)) {
+ if (matcher(_peek())) {
+ _next();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Calls [consumer] until it returns a falsey value. Returns a list of all
+ * truthy return values of [consumer], or null if it didn't consume anything.
+ *
+ * Conceptually, repeats a production one or more times.
+ */
+ List _oneOrMore(consumer()) {
+ var first = consumer();
+ if (!_(first)) return null;
+ var out = [first];
+ while (true) {
+ var el = consumer();
+ if (!_(el)) return out;
+ out.add(el);
+ }
+ }
+
+ /**
+ * Calls [consumer] until it returns a falsey value. Returns a list of all
+ * truthy return values of [consumer], or the empty list if it didn't consume
+ * anything.
+ *
+ * Conceptually, repeats a production any number of times.
+ */
+ List _zeroOrMore(consumer()) {
+ var out = [];
+ var pos = _pos;
+ while (true) {
+ var el = consumer();
+ if (!_(el) || pos == _pos) return out;
+ pos = _pos;
+ out.add(el);
+ }
+ }
+
+ /**
+ * Just calls [consumer] and returns its result. Used to make it explicit that a
+ * production is intended to be optional.
+ */
+ _zeroOrOne(consumer()) => consumer();
+
+ /**
+ * Calls each function in [consumers] until one returns a truthy value, then
+ * returns that.
+ */
+ _or(List<Function> consumers) {
+ for (var c in consumers) {
+ var res = c();
+ if (_(res)) return res;
+ }
+ return null;
+ }
+
+ /**
+ * Calls [consumer] and returns its result, but rolls back the parser state if
+ * [consumer] returns a falsey value.
+ */
+ _group(consumer()) {
+ int pos = _pos, line = _line, column = _column;
+ var res = consumer();
+ if (_(res)) return res;
+
+ _pos = pos;
+ _line = line;
+ _column = column;
+ return res;
+ }
+
+ /**
+ * Consumes [n] characters matching [matcher], or none if there isn't a
+ * complete match. The first argument to [matcher] is the character code, the
+ * second is the index (from 0 to [n] - 1).
+ *
+ * Returns whether or not the characters were consumed.
+ */
+ bool _nAtOnce(int n, bool matcher(int, int)) => _group(() {
+ for (int i = 0; i < n; i++) {
+ if (!_consume((c) => matcher(c, i))) return false;
+ }
+ return true;
+ });
+
+ /**
+ * Consumes the exact characters in [str], or nothing.
+ *
+ * Returns whether or not the string was consumed.
+ */
+ bool _rawString(String str) =>
+ _nAtOnce(str.length, (c, i) => str.charCodeAt(i) == c);
+
+ /**
+ * Consumes and returns a string of characters matching [matcher], or null if
+ * there are no such characters.
+ */
+ String _stringOf(bool matcher(int)) =>
+ _captureString(_oneOrMore(() => _consume(matcher)));
+
+ /**
+ * Calls [consumer] and returns the string that was consumed while doing so,
+ * or null if [consumer] returned a falsey value. Automatically wraps
+ * [consumer] in `_group`.
+ */
+ String _captureString(consumer()) {
+ int start = _pos;
+ var res = _group(consumer);
+ if (!_(res)) return null;
+ return _s.substring(start, _pos);
+ }
+
+ /**
+ * Adds a tag and an anchor to [node], if they're defined. [props] should be a
+ * two-element list where the first element is a Tag or null and the second is
+ * a String or null.
+ */
+ _Node _addProps(_Node node, List props) {
+ if (_(props[0])) node.tag = props[0];
+ if (_(props[1])) node.anchor = props[1];
+ return node;
+ }
+
+ /** Creates a MappingNode from [pairs]. */
+ _MappingNode _map(List<List<_Node>> pairs) {
+ var content = new Map<_Node, _Node>();
+ pairs.forEach((pair) { content[pair[0]] = pair[1]; });
+ return new _MappingNode("?", content);
+ }
+
+ /** Runs [fn] in a context named [name]. Used for error reporting. */
+ _context(String name, fn()) {
+ try {
+ _contextStack.add(name);
+ return fn();
+ } finally {
+ var popped = _contextStack.removeLast();
+ assert(popped == name);
+ }
+ }
+
+ /** Throws an error with additional context information. */
+ _error(String message) {
+ // Line and column should be one-based
+ throw new SyntaxError(_line + 1, _column + 1,
+ "$message (in $_farthestContext)");
+ }
+
+ /**
+ * If [result] is falsey, throws an error saying that [expected] was
+ * expected.
+ */
+ _expect(result, String expected) {
+ if (_(result)) return result;
+ _error("expected $expected");
+ }
+
+ /**
+ * Throws an error saying that the parse failed. Uses `_farthestLine`,
+ * `_farthestColumn`, and `_farthestContext` to provide additional
+ * information.
+ */
+ _parseFailed() {
+ throw new SyntaxError(_farthestLine + 1, _farthestColumn + 1,
+ "invalid YAML in $_farthestContext");
+ }
+
+ /** Returns the number of spaces after the current position. */
+ int _detectIndentation() {
+ var i = 0;
+ while (_peek(i) == SP) i++;
+ return i;
+ }
+
+ /** Returns whether the current position is at the beginning of a line. */
+ bool get _atStartOfLine() {
+ var char = _peek(-1);
+ return char == -1 || _isBreak(char);
+ }
+
+ /** Returns whether the current position is at the end of the input. */
+ bool get _atEndOfFile() => _pos == _len;
+
+ /**
+ * Given an indicator character, returns the type of that indicator (or null
+ * if the indicator isn't found.
+ */
+ int _indicatorType(int char) {
+ switch (char) {
+ case HYPHEN: return _C_SEQUENCE_ENTRY;
+ case QUESTION_MARK: return _C_MAPPING_KEY;
+ case COLON: return _C_MAPPING_VALUE;
+ case COMMA: return _C_COLLECT_ENTRY;
+ case LEFT_BRACKET: return _C_SEQUENCE_START;
+ case RIGHT_BRACKET: return _C_SEQUENCE_END;
+ case LEFT_BRACE: return _C_MAPPING_START;
+ case RIGHT_BRACE: return _C_MAPPING_END;
+ case HASH: return _C_COMMENT;
+ case AMPERSAND: return _C_ANCHOR;
+ case ASTERISK: return _C_ALIAS;
+ case EXCLAMATION: return _C_TAG;
+ case VERTICAL_BAR: return _C_LITERAL;
+ case GREATER_THAN: return _C_FOLDED;
+ case SINGLE_QUOTE: return _C_SINGLE_QUOTE;
+ case DOUBLE_QUOTE: return _C_DOUBLE_QUOTE;
+ case PERCENT: return _C_DIRECTIVE;
+ case AT:
+ case GRAVE_ACCENT:
+ return _C_RESERVED;
+ default: return null;
+ }
+ }
+
+ // 1
+ bool _isPrintable(int char) {
+ return char == TAB || char == LF || char == CR ||
+ (char >= SP && char <= TILDE) || char == NEL ||
+ (char >= 0xA0 && char <= 0xD7FF) || (char >= 0xE000 && char <= 0xFFFD) ||
+ (char >= 0x10000 && char <= 0x10FFFF);
+ }
+
+ // 22
+ bool _c_indicator(int type) => _consume((c) => _indicatorType(c) == type);
+
+ // 23
+ bool _isFlowIndicator(int char) {
+ var indicator = _indicatorType(char);
+ return indicator == _C_COLLECT_ENTRY || indicator == _C_SEQUENCE_START ||
+ indicator == _C_SEQUENCE_END || indicator == _C_MAPPING_START ||
+ indicator == _C_MAPPING_END;
+ }
+
+ // 26
+ bool _isBreak(int char) => char == LF || char == CR;
+
+ // 27
+ bool _isNonBreak(int char) => _isPrintable(char) && !_isBreak(char);
+
+ // 30
+ bool _b_non_content() => _consume(_isBreak);
+
+ // 33
+ bool _isSpace(int char) => char == SP || char == TAB;
+
+ // 34
+ bool _isNonSpace(int char) => _isNonBreak(char) && !_isSpace(char);
+
+ // 63
+ bool _s_indent(int n) => _nAtOnce(n, (c, i) => c == SP);
+
+ // 66
+ bool _s_separateInLine() => _group(() =>
+ _(_oneOrMore(() => _consume(_isSpace))) || _atStartOfLine);
+
+ // 69
+ bool _s_flowLinePrefix(int n) {
+ if (!_s_indent(n)) return false;
+ _zeroOrOne(_s_separateInLine);
+ return true;
+ }
+
+ // 74
+ bool _s_flowFolded(int n) => false; // TODO(nweiz): implement
+
+ // 75
+ bool _c_nb_commentText() {
+ if (!_c_indicator(_C_COMMENT)) return false;
+ _zeroOrMore(() => _consume(_isNonBreak));
+ return true;
+ }
+
+ // 76
+ bool _b_comment() => _atEndOfFile || _b_non_content();
+
+ // 77
+ bool _s_b_comment() {
+ if (_s_separateInLine()) {
+ _zeroOrOne(_c_nb_commentText);
+ }
+ return _b_comment();
+ }
+
+ // 78
+ bool _l_comment() => _group(() {
+ if (!_s_separateInLine()) return false;
+ _zeroOrOne(_c_nb_commentText);
+ return _b_comment();
+ });
+
+ // 79
+ bool _s_l_comments() {
+ if (!_s_b_comment() && !_atStartOfLine) return false;
+ _zeroOrMore(_l_comment);
+ return true;
+ }
+
+ // 80
+ bool _s_separate(int n, int c) {
+ switch (c) {
+ case BLOCK_OUT:
+ case BLOCK_IN:
+ case FLOW_OUT:
+ case FLOW_IN:
+ return _s_separateLines(n);
+ case BLOCK_KEY:
+ case FLOW_KEY:
+ return _s_separateInLine();
+ }
+ }
+
+ // 81
+ bool _s_separateLines(int n) {
+ return _group(() => _s_l_comments() && _s_flowLinePrefix(n)) ||
+ _s_separateInLine();
+ }
+
+ // 82
+ bool _l_directive() => false; // TODO(nweiz): implement
+
+ // 96
+ List _c_ns_properties(int n, int c) {
+ var tag, anchor;
+ tag = _c_ns_tagProperty();
+ if (_(tag)) {
+ anchor = _group(() {
+ if (!_s_separate(n, c)) return null;
+ return _c_ns_anchorProperty();
+ });
+ return [tag, anchor];
+ }
+
+ anchor = _c_ns_anchorProperty();
+ if (_(anchor)) {
+ tag = _group(() {
+ if (!_s_separate(n, c)) return null;
+ return _c_ns_tagProperty();
+ });
+ return [tag, anchor];
+ }
+
+ return null;
+ }
+
+ // 97
+ _Tag _c_ns_tagProperty() => null; // TODO(nweiz): implement
+
+ // 101
+ String _c_ns_anchorProperty() => null; // TODO(nweiz): implement
+
+ // 102
+ bool _isAnchorChar(int char) => _isNonSpace(char) && !_isFlowIndicator(char);
+
+ // 103
+ String _ns_anchorName() => _captureString(_isAnchorChar);
+
+ // 104
+ _Node _c_ns_aliasNode() {
+ if (!_c_indicator(_C_ALIAS)) return null;
+ var name = _expect(_ns_anchorName(), 'anchor name');
+ return new _AliasNode(name);
+ }
+
+ // 105
+ _ScalarNode _e_scalar() => new _ScalarNode("?", content: "");
+
+ // 106
+ _ScalarNode _e_node() => _e_scalar();
+
+ // 126
+ bool _ns_plainFirst(int c) {
+ var char = _peek();
+ var indicator = _indicatorType(char);
+ if (indicator == _C_RESERVED) {
+ _error("reserved indicators can't start a plain scalar");
+ }
+ var match = (_isNonSpace(char) && indicator == null) ||
+ ((indicator == _C_MAPPING_KEY ||
+ indicator == _C_MAPPING_VALUE ||
+ indicator == _C_SEQUENCE_ENTRY) &&
+ _isPlainSafe(c, _peek(1)));
+
+ if (match) _next();
+ return match;
+ }
+
+ // 127
+ bool _isPlainSafe(int c, int char) {
+ switch (c) {
+ case FLOW_OUT:
+ case BLOCK_KEY:
+ // 128
+ return _isNonSpace(char);
+ case FLOW_IN:
+ case FLOW_KEY:
+ // 129
+ return _isNonSpace(char) && !_isFlowIndicator(char);
+ }
+ }
+
+ // 130
+ bool _ns_plainChar(int c) {
+ var char = _peek();
+ var indicator = _indicatorType(char);
+ var match = (_isPlainSafe(c, char) && indicator != _C_MAPPING_VALUE &&
+ indicator != _C_COMMENT) ||
+ (_isNonSpace(_peek(-1)) && indicator == _C_COMMENT) ||
+ (indicator == _C_MAPPING_VALUE && _isPlainSafe(c, _peek(1)));
+
+ if (match) _next();
+ return match;
+ }
+
+ // 131
+ String _ns_plain(int n, int c) => _context('plain scalar', () {
+ switch (c) {
+ case FLOW_OUT:
+ case FLOW_IN:
+ return _ns_plainMultiLine(n, c);
+ case BLOCK_KEY:
+ case FLOW_KEY:
+ return _ns_plainOneLine(c);
+ }
+ });
+
+ // 132
+ void _nb_ns_plainInLine(int c) {
+ _zeroOrMore(() => _group(() {
+ _zeroOrMore(() => _consume(_isSpace));
+ return _ns_plainChar(c);
+ }));
+ }
+
+ // 133
+ String _ns_plainOneLine(int c) => _captureString(() {
+ if (_c_forbidden()) return false;
+ if (!_ns_plainFirst(c)) return false;
+ _nb_ns_plainInLine(c);
+ return true;
+ });
+
+ // 134
+ bool _s_ns_plainNextLine(int n, int c) => _group(() {
+ if (_c_forbidden()) return false;
+ if (!_s_flowFolded(n)) return false;
+ if (!_ns_plainChar(c)) return false;
+ _nb_ns_plainInLine(c);
+ return true;
+ });
+
+ // 135
+ String _ns_plainMultiLine(int n, int c) => _captureString(() {
+ if (!_(_ns_plainOneLine(c))) return false;
+ _zeroOrMore(() => _s_ns_plainNextLine(n, c));
+ return true;
+ });
+
+ // 154
+ _Node _c_s_implicitYamlKey(int c) => _group(() {
+ /* Indentation parameter is unused in this path */
+ var node = _ns_flowYamlNode(-10, c);
+ if (!_(node)) return null;
+ _zeroOrOne(_s_separateInLine);
+ return node;
+ });
+
+ // 155
+ _Node _c_s_implicitJsonKey(int c) => null; // TODO(nweiz): implement
+
+ // 156
+ _Node _ns_flowYamlContent(int n, int c) {
+ var str = _ns_plain(n, c);
+ if (!_(str)) return null;
+ return new _ScalarNode("?", content: str);
+ }
+
+ // 157
+ _Node _ns_flowJsonContent(int n, int c) => null; // TODO(nweiz): implement
+
+ // 158
+ _Node _ns_flowContent(int n, int c) => _or([
+ () => _ns_flowYamlContent(n, c),
+ () => _ns_flowJsonContent(n, c)
+ ]);
+
+ // 159
+ _Node _ns_flowYamlNode(int n, int c) => _or([
+ _c_ns_aliasNode,
+ () => _ns_flowYamlContent(n, c),
+ () {
+ var props = _c_ns_properties(n, c);
+ if (!_(props)) return null;
+ var node = _or([
+ () => _group(() {
+ if (!_s_separate(n, c)) return null;
+ return _ns_flowYamlContent(n, c);
+ }),
+ _e_scalar
+ ]);
+ return _addProps(node, props);
+ }
+ ]);
+
+ // 161
+ _Node _ns_flowNode(int n, int c) => _or([
+ _c_ns_aliasNode,
+ () => _ns_flowContent(n, c),
+ () => _group(() {
+ var props = _c_ns_properties(n, c);
+ if (!_(props)) return null;
+ var node = _or([
+ () => _group(() => _s_separate(n, c) ? _ns_flowContent(n, c) : null),
+ _e_scalar]);
+ return _addProps(node, props);
+ })
+ ]);
+
+ // 170
+ _Node _c_l_literal(int n) => null; // TODO(nweiz); implement
+
+ // 174
+ _Node _c_l_folded(int n) => null; // TODO(nweiz); implement
+
+ // 183
+ _SequenceNode _l_blockSequence(int n) => _context('sequence', () {
+ var m = _detectIndentation() - n;
+ if (m <= 0) return null;
+
+ var content = _oneOrMore(() => _group(() {
+ if (!_s_indent(n + m)) return null;
+ return _c_l_blockSeqEntry(n + m);
+ }));
+ if (!_(content)) return null;
+
+ return new _SequenceNode("?", content);
+ });
+
+ // 184
+ _Node _c_l_blockSeqEntry(int n) => _group(() {
+ if (!_c_indicator(_C_SEQUENCE_ENTRY)) return null;
+ if (_isNonSpace(_peek())) return null;
+
+ return _s_l_blockIndented(n, BLOCK_IN);
+ });
+
+ // 185
+ _Node _s_l_blockIndented(int n, int c) {
+ var m = _detectIndentation();
+ return _or([() => _group(() {
+ if (!_s_indent(m)) return null;
+ return _or([
+ () => _ns_l_compactSequence(n+1+m),
+ () => _ns_l_compactMapping(n+1+m)]);
+ }),
+ () => _s_l_blockNode(n, c),
+ () => _s_l_comments() ? _e_node() : null]);
+ }
+
+ // 186
+ _Node _ns_l_compactSequence(int n) => _context('sequence', () {
+ var first = _c_l_blockSeqEntry(n);
+ if (!_(first)) return null;
+
+ var content = _zeroOrMore(() => _group(() {
+ if (!_s_indent(n)) return null;
+ return _c_l_blockSeqEntry(n);
+ }));
+ content.insertRange(0, 1, first);
+
+ return new _SequenceNode("?", content);
+ });
+
+ // 187
+ _Node _l_blockMapping(int n) => _context('mapping', () {
+ var m = _detectIndentation() - n;
+ if (m <= 0) return null;
+
+ var pairs = _oneOrMore(() => _group(() {
+ if (!_s_indent(n + m)) return null;
+ return _ns_l_blockMapEntry(n + m);
+ }));
+ if (!_(pairs)) return null;
+
+ return _map(pairs);
+ });
+
+ // 188
+ List<_Node> _ns_l_blockMapEntry(int n) => _or([
+ () => _c_l_blockMapExplicitEntry(n),
+ () => _ns_l_blockMapImplicitEntry(n)
+ ]);
+
+ // 189
+ List<_Node> _c_l_blockMapExplicitEntry(int n) => null; // TODO(nweiz): implement
+
+ // 192
+ List<_Node> _ns_l_blockMapImplicitEntry(int n) => _group(() {
+ var key = _or([_ns_s_blockMapImplicitKey, _e_node]);
+ var value = _c_l_blockMapImplicitValue(n);
+ return _(value) ? [key, value] : null;
+ });
+
+ // 193
+ _Node _ns_s_blockMapImplicitKey() => _context('mapping key', () => _or([
+ () => _c_s_implicitJsonKey(BLOCK_KEY),
+ () => _c_s_implicitYamlKey(BLOCK_KEY)
+ ]));
+
+ // 194
+ _Node _c_l_blockMapImplicitValue(int n) => _context('mapping value', () =>
+ _group(() {
+ if (!_c_indicator(_C_MAPPING_VALUE)) return null;
+ return _or([
+ () => _s_l_blockNode(n, BLOCK_OUT),
+ () => _s_l_comments() ? _e_node() : null
+ ]);
+ }));
+
+ // 195
+ _Node _ns_l_compactMapping(int n) => _context('mapping', () {
+ var first = _ns_l_blockMapEntry(n);
+ if (!_(first)) return null;
+
+ var pairs = _zeroOrMore(() => _group(() {
+ if (!_s_indent(n)) return null;
+ return _ns_l_blockMapEntry(n);
+ }));
+ pairs.insertRange(0, 1, first);
+
+ return _map(pairs);
+ });
+
+ // 196
+ _Node _s_l_blockNode(int n, int c) =>
+ _or([() => _s_l_blockInBlock(n, c), () => _s_l_flowInBlock(n)]);
+
+ // 197
+ _Node _s_l_flowInBlock(int n) => _group(() {
+ if (!_s_separate(n+1, FLOW_OUT)) return null;
+ var node = _ns_flowNode(n+1, FLOW_OUT);
+ if (!_(node)) return null;
+ if (!_s_l_comments()) return null;
+ return node;
+ });
+
+ // 198
+ _Node _s_l_blockInBlock(int n, int c) =>
+ _or([() => _s_l_blockScalar(n, c), () => _s_l_blockCollection(n, c)]);
+
+ // 199
+ _Node _s_l_blockScalar(int n, int c) => _group(() {
+ if (!_s_separate(n+1, c)) return null;
+ var props = _group(() {
+ var props = _c_ns_properties(n+1, c);
+ if (!_(props)) return null;
+ if (!_s_separate(n+1, c)) return null;
+ return props;
+ });
+ if (!_(props)) props = [null, null];
+
+ var node = _or([() => _c_l_literal(n), () => _c_l_folded(n)]);
+ if (!_(node)) return null;
+ return _addProps(node, props);
+ });
+
+ // 200
+ _Node _s_l_blockCollection(int n, int c) => _group(() {
+ var props = _group(() {
+ if (!_s_separate(n+1, c)) return null;
+ return _c_ns_properties(n+1, c);
+ });
+ if (!_(props)) props = [null, null];
+
+ if (!_s_l_comments()) return null;
+ return _or([
+ () => _l_blockSequence(_seqSpaces(n, c)),
+ () => _l_blockMapping(n)]);
+ });
+
+ // 201
+ int _seqSpaces(int n, int c) => c == BLOCK_OUT ? n - 1 : n;
+
+ // 202
+ void _l_documentPrefix() {
+ _zeroOrMore(_l_comment);
+ }
+
+ // 203
+ bool _c_directivesEnd() => _rawString("---");
+
+ // 204
+ bool _c_documentEnd() => _rawString("...");
+
+ // 205
+ bool _l_documentSuffix() => _group(() {
+ if (!_c_documentEnd()) return false;
+ return _s_l_comments();
+ });
+
+ // 206
+ bool _c_forbidden() {
+ if (!_inBareDocument || !_atStartOfLine) return false;
+ var forbidden = false;
+ _group(() {
+ if (!_or([_c_directivesEnd, _c_documentEnd])) return;
+ var char = _peek();
+ forbidden = _isBreak(char) || _isWhite(char) || _atEndOfFile;
+ return;
+ });
+ return forbidden;
+ }
+
+ // 207
+ _Node _l_bareDocument() {
+ try {
+ _inBareDocument = true;
+ return _s_l_blockNode(-1, BLOCK_IN);
+ } finally {
+ _inBareDocument = false;
+ }
+ }
+
+ // 208
+ _Node _l_explicitDocument() {
+ if (!_c_directivesEnd()) return null;
+ var doc = _l_bareDocument();
+ if (_(doc)) return doc;
+
+ doc = _e_node();
+ _s_l_comments();
+ return doc;
+ }
+
+ // 209
+ _Node _l_directiveDocument() {
+ if (!_(_oneOrMore(_l_directive))) return null;
+ var doc = _l_explicitDocument();
+ if (doc != null) return doc;
+ _parseFailed();
+ }
+
+ // 210
+ _Node _l_anyDocument() =>
+ _or([_l_directiveDocument, _l_explicitDocument, _l_bareDocument]);
+
+ // 211
+ List<_Node> _l_yamlStream() {
+ var docs = [];
+ _zeroOrMore(_l_documentPrefix);
+ var first = _zeroOrOne(_l_anyDocument);
+ if (!_(first)) first = _e_node();
+ docs.add(first);
+
+ _zeroOrMore(() {
+ var doc;
+ if (_(_oneOrMore(_l_documentSuffix))) {
+ _zeroOrMore(_l_documentPrefix);
+ doc = _zeroOrOne(_l_anyDocument);
+ } else {
+ _zeroOrMore(_l_documentPrefix);
+ doc = _zeroOrOne(_l_explicitDocument);
+ }
+ if (_(doc)) docs.add(doc);
+ return doc;
+ });
+
+ if (!_atEndOfFile) _parseFailed();
+ return docs;
+ }
+}
+
+class SyntaxError extends Error {
+ final int _line;
+ final int _column;
+
+ SyntaxError(int this._line, int this._column, String _msg) : super(_msg);
+
+ String toString() => "Syntax error on line $_line, column $_column: $_msg";
+}
« utils/yaml/composer.dart ('K') | « utils/yaml/model.dart ('k') | utils/yaml/visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698