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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
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 * Translates a string of characters into a YAML serialization tree.
7 *
8 * This parser is designed to closely follow the spec. All productions in the
9 * spec are numbered, and the corresponding methods in the parser have the same
10 * numbers. This is certainly not the most efficient way of parsing YAML, but it
11 * is the easiest to write and read in the context of the spec.
12 *
13 * Methods corresponding to productions are also named as in the spec,
14 * translating the name of the method (although not the annotation characters)
15 * into camel-case for dart style.. For example, the spec has a production named
16 * `nb-ns-plain-in-line`, and the method implementing it is named
17 * `_nb_ns_plainInLine`. The exception to that rule is methods that just
18 * recognize character classes; these are named `_is*`.
19 */
20 class _Parser {
21 static final TAB = 0x9;
22 static final LF = 0xA;
23 static final CR = 0xD;
24 static final SP = 0x20;
25 static final TILDE = 0x7E;
26 static final NEL = 0x85;
27 static final HYPHEN = 0x2D;
28 static final QUESTION_MARK = 0x3F;
29 static final COLON = 0x3A;
30 static final COMMA = 0x2C;
31 static final LEFT_BRACKET = 0x5B;
32 static final RIGHT_BRACKET = 0x5D;
33 static final LEFT_BRACE = 0x7B;
34 static final RIGHT_BRACE = 0x7D;
35 static final HASH = 0x23;
36 static final AMPERSAND = 0x26;
37 static final ASTERISK = 0x2A;
38 static final EXCLAMATION = 0x21;
39 static final VERTICAL_BAR = 0x7C;
40 static final GREATER_THAN = 0x3E;
41 static final SINGLE_QUOTE = 0x27;
42 static final DOUBLE_QUOTE = 0x22;
43 static final PERCENT = 0x25;
44 static final AT = 0x40;
45 static final GRAVE_ACCENT = 0x60;
46
47 static final NULL = 0x0;
48 static final BELL = 0x7;
49 static final BACKSPACE = 0x8;
50 static final VERTICAL_TAB = 0xB;
51 static final FORM_FEED = 0xC;
52 static final ESCAPE = 0x1B;
53 static final BACKSLASH = 0x5C;
54 static final NBSP = 0xA0;
55 static final LINE_SEPARATOR = 0x2028;
56 static final PARAGRAPH_SEPARATOR = 0x2029;
57
58 static final _C_SEQUENCE_ENTRY = 4;
59 static final _C_MAPPING_KEY = 5;
60 static final _C_MAPPING_VALUE = 6;
61 static final _C_COLLECT_ENTRY = 7;
62 static final _C_SEQUENCE_START = 8;
63 static final _C_SEQUENCE_END = 9;
64 static final _C_MAPPING_START = 10;
65 static final _C_MAPPING_END = 11;
66 static final _C_COMMENT = 12;
67 static final _C_ANCHOR = 13;
68 static final _C_ALIAS = 14;
69 static final _C_TAG = 15;
70 static final _C_LITERAL = 16;
71 static final _C_FOLDED = 17;
72 static final _C_SINGLE_QUOTE = 18;
73 static final _C_DOUBLE_QUOTE = 19;
74 static final _C_DIRECTIVE = 20;
75 static final _C_RESERVED = 21;
76
77 static final BLOCK_OUT = 0;
78 static final BLOCK_IN = 1;
79 static final FLOW_OUT = 2;
80 static final FLOW_IN = 3;
81 static final BLOCK_KEY = 4;
82 static final FLOW_KEY = 5;
83
84 /** The source string being parsed. */
85 final String _s;
86
87 /** The current position in the source string. */
88 int _pos = 0;
89
90 /** The length of the string being parsed. */
91 final int _len;
92
93 /** The current (0-based) line in the source string. */
94 int _line = 0;
95
96 /** The curent (0-based) column in the source string. */
97 int _column = 0;
98
99 /**
100 * Whether we're parsing a bare document (that is, one that doesn't begin with
101 * `---`). Bare documents don't allow `%` immediately following newlines.
102 */
103 bool _inBareDocument = false;
104
105 /**
106 * The line number of the farthest position that has been parsed successfully
107 * before backtracking. Used for error reporting.
108 */
109 int _farthestLine = 0;
110
111 /**
112 * The column number of the farthest position that has been parsed
113 * successfully before backtracking. Used for error reporting.
114 */
115 int _farthestColumn = 0;
116
117 /**
118 * The name of the context of the farthest position that has been parsed
119 * successfully before backtracking. Used for error reporting.
120 */
121 String _farthestContext = "document";
122
123 /** A stack of the names of parse contexts. Used for error reporting. */
124 List<String> _contextStack;
125
126 _Parser(String s) : _s = s, _len = s.length,
127 _contextStack = <String>["document"];
128
129 /**
130 * Return the character at the current position, then move that position
131 * forward one character. Also updates the current line and column numbers.
132 */
133 int _next() {
134 if (_pos == _len) return -1;
135 var char = _s.charCodeAt(_pos++);
136 if (_isBreak(char)) {
137 _line++;
138 _column = 0;
139 } else {
140 _column++;
141 }
142
143 if (_farthestLine < _line) {
144 _farthestLine = _line;
145 _farthestColumn = _column;
146 _farthestContext = _contextStack.last();
147 } else if (_farthestLine == _line && _farthestColumn < _column) {
148 _farthestColumn = _column;
149 _farthestContext = _contextStack.last();
150 }
151
152 return char;
153 }
154
155 /**
156 * Returns the character at the current position, or the character [i]
157 * characters after the current position.
158 *
159 * Returns -1 if this would return a character after the end or before the
160 * beginning of the input string.
161 */
162 int _peek([int i = 0]) {
163 var pos = _pos + i;
164 return (pos >= _len || pos < 0) ? -1 : _s.charCodeAt(pos);
165 }
166
167 /**
168 * The truthiness operator. Returns false if [obj] is null or false, true
169 * otherwise.
170 */
171 bool _(obj) => obj != null && obj != false;
Bob Nystrom 2012/04/20 20:28:55 This is kind of perverse, especially the name. For
172
173 /**
174 * Consumes the current character if it matches [matcher]. Returns the result
175 * of [matcher].
176 */
177 bool _consume(bool matcher(int)) {
178 if (matcher(_peek())) {
179 _next();
180 return true;
181 }
182 return false;
183 }
184
185 /**
186 * Calls [consumer] until it returns a falsey value. Returns a list of all
187 * truthy return values of [consumer], or null if it didn't consume anything.
188 *
189 * Conceptually, repeats a production one or more times.
190 */
191 List _oneOrMore(consumer()) {
192 var first = consumer();
193 if (!_(first)) return null;
194 var out = [first];
195 while (true) {
196 var el = consumer();
197 if (!_(el)) return out;
198 out.add(el);
199 }
200 }
201
202 /**
203 * Calls [consumer] until it returns a falsey value. Returns a list of all
204 * truthy return values of [consumer], or the empty list if it didn't consume
205 * anything.
206 *
207 * Conceptually, repeats a production any number of times.
208 */
209 List _zeroOrMore(consumer()) {
210 var out = [];
211 var pos = _pos;
212 while (true) {
213 var el = consumer();
214 if (!_(el) || pos == _pos) return out;
215 pos = _pos;
216 out.add(el);
217 }
218 }
219
220 /**
221 * Just calls [consumer] and returns its result. Used to make it explicit that a
222 * production is intended to be optional.
223 */
224 _zeroOrOne(consumer()) => consumer();
225
226 /**
227 * Calls each function in [consumers] until one returns a truthy value, then
228 * returns that.
229 */
230 _or(List<Function> consumers) {
231 for (var c in consumers) {
232 var res = c();
233 if (_(res)) return res;
234 }
235 return null;
236 }
237
238 /**
239 * Calls [consumer] and returns its result, but rolls back the parser state if
240 * [consumer] returns a falsey value.
241 */
242 _group(consumer()) {
243 int pos = _pos, line = _line, column = _column;
244 var res = consumer();
245 if (_(res)) return res;
246
247 _pos = pos;
248 _line = line;
249 _column = column;
250 return res;
251 }
252
253 /**
254 * Consumes [n] characters matching [matcher], or none if there isn't a
255 * complete match. The first argument to [matcher] is the character code, the
256 * second is the index (from 0 to [n] - 1).
257 *
258 * Returns whether or not the characters were consumed.
259 */
260 bool _nAtOnce(int n, bool matcher(int, int)) => _group(() {
261 for (int i = 0; i < n; i++) {
262 if (!_consume((c) => matcher(c, i))) return false;
263 }
264 return true;
265 });
266
267 /**
268 * Consumes the exact characters in [str], or nothing.
269 *
270 * Returns whether or not the string was consumed.
271 */
272 bool _rawString(String str) =>
273 _nAtOnce(str.length, (c, i) => str.charCodeAt(i) == c);
274
275 /**
276 * Consumes and returns a string of characters matching [matcher], or null if
277 * there are no such characters.
278 */
279 String _stringOf(bool matcher(int)) =>
280 _captureString(_oneOrMore(() => _consume(matcher)));
281
282 /**
283 * Calls [consumer] and returns the string that was consumed while doing so,
284 * or null if [consumer] returned a falsey value. Automatically wraps
285 * [consumer] in `_group`.
286 */
287 String _captureString(consumer()) {
288 int start = _pos;
289 var res = _group(consumer);
290 if (!_(res)) return null;
291 return _s.substring(start, _pos);
292 }
293
294 /**
295 * Adds a tag and an anchor to [node], if they're defined. [props] should be a
296 * two-element list where the first element is a Tag or null and the second is
297 * a String or null.
298 */
299 _Node _addProps(_Node node, List props) {
300 if (_(props[0])) node.tag = props[0];
301 if (_(props[1])) node.anchor = props[1];
302 return node;
303 }
304
305 /** Creates a MappingNode from [pairs]. */
306 _MappingNode _map(List<List<_Node>> pairs) {
307 var content = new Map<_Node, _Node>();
308 pairs.forEach((pair) { content[pair[0]] = pair[1]; });
309 return new _MappingNode("?", content);
310 }
311
312 /** Runs [fn] in a context named [name]. Used for error reporting. */
313 _context(String name, fn()) {
314 try {
315 _contextStack.add(name);
316 return fn();
317 } finally {
318 var popped = _contextStack.removeLast();
319 assert(popped == name);
320 }
321 }
322
323 /** Throws an error with additional context information. */
324 _error(String message) {
325 // Line and column should be one-based
326 throw new SyntaxError(_line + 1, _column + 1,
327 "$message (in $_farthestContext)");
328 }
329
330 /**
331 * If [result] is falsey, throws an error saying that [expected] was
332 * expected.
333 */
334 _expect(result, String expected) {
335 if (_(result)) return result;
336 _error("expected $expected");
337 }
338
339 /**
340 * Throws an error saying that the parse failed. Uses `_farthestLine`,
341 * `_farthestColumn`, and `_farthestContext` to provide additional
342 * information.
343 */
344 _parseFailed() {
345 throw new SyntaxError(_farthestLine + 1, _farthestColumn + 1,
346 "invalid YAML in $_farthestContext");
347 }
348
349 /** Returns the number of spaces after the current position. */
350 int _detectIndentation() {
351 var i = 0;
352 while (_peek(i) == SP) i++;
353 return i;
354 }
355
356 /** Returns whether the current position is at the beginning of a line. */
357 bool get _atStartOfLine() {
358 var char = _peek(-1);
359 return char == -1 || _isBreak(char);
360 }
361
362 /** Returns whether the current position is at the end of the input. */
363 bool get _atEndOfFile() => _pos == _len;
364
365 /**
366 * Given an indicator character, returns the type of that indicator (or null
367 * if the indicator isn't found.
368 */
369 int _indicatorType(int char) {
370 switch (char) {
371 case HYPHEN: return _C_SEQUENCE_ENTRY;
372 case QUESTION_MARK: return _C_MAPPING_KEY;
373 case COLON: return _C_MAPPING_VALUE;
374 case COMMA: return _C_COLLECT_ENTRY;
375 case LEFT_BRACKET: return _C_SEQUENCE_START;
376 case RIGHT_BRACKET: return _C_SEQUENCE_END;
377 case LEFT_BRACE: return _C_MAPPING_START;
378 case RIGHT_BRACE: return _C_MAPPING_END;
379 case HASH: return _C_COMMENT;
380 case AMPERSAND: return _C_ANCHOR;
381 case ASTERISK: return _C_ALIAS;
382 case EXCLAMATION: return _C_TAG;
383 case VERTICAL_BAR: return _C_LITERAL;
384 case GREATER_THAN: return _C_FOLDED;
385 case SINGLE_QUOTE: return _C_SINGLE_QUOTE;
386 case DOUBLE_QUOTE: return _C_DOUBLE_QUOTE;
387 case PERCENT: return _C_DIRECTIVE;
388 case AT:
389 case GRAVE_ACCENT:
390 return _C_RESERVED;
391 default: return null;
392 }
393 }
394
395 // 1
396 bool _isPrintable(int char) {
397 return char == TAB || char == LF || char == CR ||
398 (char >= SP && char <= TILDE) || char == NEL ||
399 (char >= 0xA0 && char <= 0xD7FF) || (char >= 0xE000 && char <= 0xFFFD) ||
400 (char >= 0x10000 && char <= 0x10FFFF);
401 }
402
403 // 22
404 bool _c_indicator(int type) => _consume((c) => _indicatorType(c) == type);
405
406 // 23
407 bool _isFlowIndicator(int char) {
408 var indicator = _indicatorType(char);
409 return indicator == _C_COLLECT_ENTRY || indicator == _C_SEQUENCE_START ||
410 indicator == _C_SEQUENCE_END || indicator == _C_MAPPING_START ||
411 indicator == _C_MAPPING_END;
412 }
413
414 // 26
415 bool _isBreak(int char) => char == LF || char == CR;
416
417 // 27
418 bool _isNonBreak(int char) => _isPrintable(char) && !_isBreak(char);
419
420 // 30
421 bool _b_non_content() => _consume(_isBreak);
422
423 // 33
424 bool _isSpace(int char) => char == SP || char == TAB;
425
426 // 34
427 bool _isNonSpace(int char) => _isNonBreak(char) && !_isSpace(char);
428
429 // 63
430 bool _s_indent(int n) => _nAtOnce(n, (c, i) => c == SP);
431
432 // 66
433 bool _s_separateInLine() => _group(() =>
434 _(_oneOrMore(() => _consume(_isSpace))) || _atStartOfLine);
435
436 // 69
437 bool _s_flowLinePrefix(int n) {
438 if (!_s_indent(n)) return false;
439 _zeroOrOne(_s_separateInLine);
440 return true;
441 }
442
443 // 74
444 bool _s_flowFolded(int n) => false; // TODO(nweiz): implement
445
446 // 75
447 bool _c_nb_commentText() {
448 if (!_c_indicator(_C_COMMENT)) return false;
449 _zeroOrMore(() => _consume(_isNonBreak));
450 return true;
451 }
452
453 // 76
454 bool _b_comment() => _atEndOfFile || _b_non_content();
455
456 // 77
457 bool _s_b_comment() {
458 if (_s_separateInLine()) {
459 _zeroOrOne(_c_nb_commentText);
460 }
461 return _b_comment();
462 }
463
464 // 78
465 bool _l_comment() => _group(() {
466 if (!_s_separateInLine()) return false;
467 _zeroOrOne(_c_nb_commentText);
468 return _b_comment();
469 });
470
471 // 79
472 bool _s_l_comments() {
473 if (!_s_b_comment() && !_atStartOfLine) return false;
474 _zeroOrMore(_l_comment);
475 return true;
476 }
477
478 // 80
479 bool _s_separate(int n, int c) {
480 switch (c) {
481 case BLOCK_OUT:
482 case BLOCK_IN:
483 case FLOW_OUT:
484 case FLOW_IN:
485 return _s_separateLines(n);
486 case BLOCK_KEY:
487 case FLOW_KEY:
488 return _s_separateInLine();
489 }
490 }
491
492 // 81
493 bool _s_separateLines(int n) {
494 return _group(() => _s_l_comments() && _s_flowLinePrefix(n)) ||
495 _s_separateInLine();
496 }
497
498 // 82
499 bool _l_directive() => false; // TODO(nweiz): implement
500
501 // 96
502 List _c_ns_properties(int n, int c) {
503 var tag, anchor;
504 tag = _c_ns_tagProperty();
505 if (_(tag)) {
506 anchor = _group(() {
507 if (!_s_separate(n, c)) return null;
508 return _c_ns_anchorProperty();
509 });
510 return [tag, anchor];
511 }
512
513 anchor = _c_ns_anchorProperty();
514 if (_(anchor)) {
515 tag = _group(() {
516 if (!_s_separate(n, c)) return null;
517 return _c_ns_tagProperty();
518 });
519 return [tag, anchor];
520 }
521
522 return null;
523 }
524
525 // 97
526 _Tag _c_ns_tagProperty() => null; // TODO(nweiz): implement
527
528 // 101
529 String _c_ns_anchorProperty() => null; // TODO(nweiz): implement
530
531 // 102
532 bool _isAnchorChar(int char) => _isNonSpace(char) && !_isFlowIndicator(char);
533
534 // 103
535 String _ns_anchorName() => _captureString(_isAnchorChar);
536
537 // 104
538 _Node _c_ns_aliasNode() {
539 if (!_c_indicator(_C_ALIAS)) return null;
540 var name = _expect(_ns_anchorName(), 'anchor name');
541 return new _AliasNode(name);
542 }
543
544 // 105
545 _ScalarNode _e_scalar() => new _ScalarNode("?", content: "");
546
547 // 106
548 _ScalarNode _e_node() => _e_scalar();
549
550 // 126
551 bool _ns_plainFirst(int c) {
552 var char = _peek();
553 var indicator = _indicatorType(char);
554 if (indicator == _C_RESERVED) {
555 _error("reserved indicators can't start a plain scalar");
556 }
557 var match = (_isNonSpace(char) && indicator == null) ||
558 ((indicator == _C_MAPPING_KEY ||
559 indicator == _C_MAPPING_VALUE ||
560 indicator == _C_SEQUENCE_ENTRY) &&
561 _isPlainSafe(c, _peek(1)));
562
563 if (match) _next();
564 return match;
565 }
566
567 // 127
568 bool _isPlainSafe(int c, int char) {
569 switch (c) {
570 case FLOW_OUT:
571 case BLOCK_KEY:
572 // 128
573 return _isNonSpace(char);
574 case FLOW_IN:
575 case FLOW_KEY:
576 // 129
577 return _isNonSpace(char) && !_isFlowIndicator(char);
578 }
579 }
580
581 // 130
582 bool _ns_plainChar(int c) {
583 var char = _peek();
584 var indicator = _indicatorType(char);
585 var match = (_isPlainSafe(c, char) && indicator != _C_MAPPING_VALUE &&
586 indicator != _C_COMMENT) ||
587 (_isNonSpace(_peek(-1)) && indicator == _C_COMMENT) ||
588 (indicator == _C_MAPPING_VALUE && _isPlainSafe(c, _peek(1)));
589
590 if (match) _next();
591 return match;
592 }
593
594 // 131
595 String _ns_plain(int n, int c) => _context('plain scalar', () {
596 switch (c) {
597 case FLOW_OUT:
598 case FLOW_IN:
599 return _ns_plainMultiLine(n, c);
600 case BLOCK_KEY:
601 case FLOW_KEY:
602 return _ns_plainOneLine(c);
603 }
604 });
605
606 // 132
607 void _nb_ns_plainInLine(int c) {
608 _zeroOrMore(() => _group(() {
609 _zeroOrMore(() => _consume(_isSpace));
610 return _ns_plainChar(c);
611 }));
612 }
613
614 // 133
615 String _ns_plainOneLine(int c) => _captureString(() {
616 if (_c_forbidden()) return false;
617 if (!_ns_plainFirst(c)) return false;
618 _nb_ns_plainInLine(c);
619 return true;
620 });
621
622 // 134
623 bool _s_ns_plainNextLine(int n, int c) => _group(() {
624 if (_c_forbidden()) return false;
625 if (!_s_flowFolded(n)) return false;
626 if (!_ns_plainChar(c)) return false;
627 _nb_ns_plainInLine(c);
628 return true;
629 });
630
631 // 135
632 String _ns_plainMultiLine(int n, int c) => _captureString(() {
633 if (!_(_ns_plainOneLine(c))) return false;
634 _zeroOrMore(() => _s_ns_plainNextLine(n, c));
635 return true;
636 });
637
638 // 154
639 _Node _c_s_implicitYamlKey(int c) => _group(() {
640 /* Indentation parameter is unused in this path */
641 var node = _ns_flowYamlNode(-10, c);
642 if (!_(node)) return null;
643 _zeroOrOne(_s_separateInLine);
644 return node;
645 });
646
647 // 155
648 _Node _c_s_implicitJsonKey(int c) => null; // TODO(nweiz): implement
649
650 // 156
651 _Node _ns_flowYamlContent(int n, int c) {
652 var str = _ns_plain(n, c);
653 if (!_(str)) return null;
654 return new _ScalarNode("?", content: str);
655 }
656
657 // 157
658 _Node _ns_flowJsonContent(int n, int c) => null; // TODO(nweiz): implement
659
660 // 158
661 _Node _ns_flowContent(int n, int c) => _or([
662 () => _ns_flowYamlContent(n, c),
663 () => _ns_flowJsonContent(n, c)
664 ]);
665
666 // 159
667 _Node _ns_flowYamlNode(int n, int c) => _or([
668 _c_ns_aliasNode,
669 () => _ns_flowYamlContent(n, c),
670 () {
671 var props = _c_ns_properties(n, c);
672 if (!_(props)) return null;
673 var node = _or([
674 () => _group(() {
675 if (!_s_separate(n, c)) return null;
676 return _ns_flowYamlContent(n, c);
677 }),
678 _e_scalar
679 ]);
680 return _addProps(node, props);
681 }
682 ]);
683
684 // 161
685 _Node _ns_flowNode(int n, int c) => _or([
686 _c_ns_aliasNode,
687 () => _ns_flowContent(n, c),
688 () => _group(() {
689 var props = _c_ns_properties(n, c);
690 if (!_(props)) return null;
691 var node = _or([
692 () => _group(() => _s_separate(n, c) ? _ns_flowContent(n, c) : null),
693 _e_scalar]);
694 return _addProps(node, props);
695 })
696 ]);
697
698 // 170
699 _Node _c_l_literal(int n) => null; // TODO(nweiz); implement
700
701 // 174
702 _Node _c_l_folded(int n) => null; // TODO(nweiz); implement
703
704 // 183
705 _SequenceNode _l_blockSequence(int n) => _context('sequence', () {
706 var m = _detectIndentation() - n;
707 if (m <= 0) return null;
708
709 var content = _oneOrMore(() => _group(() {
710 if (!_s_indent(n + m)) return null;
711 return _c_l_blockSeqEntry(n + m);
712 }));
713 if (!_(content)) return null;
714
715 return new _SequenceNode("?", content);
716 });
717
718 // 184
719 _Node _c_l_blockSeqEntry(int n) => _group(() {
720 if (!_c_indicator(_C_SEQUENCE_ENTRY)) return null;
721 if (_isNonSpace(_peek())) return null;
722
723 return _s_l_blockIndented(n, BLOCK_IN);
724 });
725
726 // 185
727 _Node _s_l_blockIndented(int n, int c) {
728 var m = _detectIndentation();
729 return _or([() => _group(() {
730 if (!_s_indent(m)) return null;
731 return _or([
732 () => _ns_l_compactSequence(n+1+m),
733 () => _ns_l_compactMapping(n+1+m)]);
734 }),
735 () => _s_l_blockNode(n, c),
736 () => _s_l_comments() ? _e_node() : null]);
737 }
738
739 // 186
740 _Node _ns_l_compactSequence(int n) => _context('sequence', () {
741 var first = _c_l_blockSeqEntry(n);
742 if (!_(first)) return null;
743
744 var content = _zeroOrMore(() => _group(() {
745 if (!_s_indent(n)) return null;
746 return _c_l_blockSeqEntry(n);
747 }));
748 content.insertRange(0, 1, first);
749
750 return new _SequenceNode("?", content);
751 });
752
753 // 187
754 _Node _l_blockMapping(int n) => _context('mapping', () {
755 var m = _detectIndentation() - n;
756 if (m <= 0) return null;
757
758 var pairs = _oneOrMore(() => _group(() {
759 if (!_s_indent(n + m)) return null;
760 return _ns_l_blockMapEntry(n + m);
761 }));
762 if (!_(pairs)) return null;
763
764 return _map(pairs);
765 });
766
767 // 188
768 List<_Node> _ns_l_blockMapEntry(int n) => _or([
769 () => _c_l_blockMapExplicitEntry(n),
770 () => _ns_l_blockMapImplicitEntry(n)
771 ]);
772
773 // 189
774 List<_Node> _c_l_blockMapExplicitEntry(int n) => null; // TODO(nweiz): impleme nt
775
776 // 192
777 List<_Node> _ns_l_blockMapImplicitEntry(int n) => _group(() {
778 var key = _or([_ns_s_blockMapImplicitKey, _e_node]);
779 var value = _c_l_blockMapImplicitValue(n);
780 return _(value) ? [key, value] : null;
781 });
782
783 // 193
784 _Node _ns_s_blockMapImplicitKey() => _context('mapping key', () => _or([
785 () => _c_s_implicitJsonKey(BLOCK_KEY),
786 () => _c_s_implicitYamlKey(BLOCK_KEY)
787 ]));
788
789 // 194
790 _Node _c_l_blockMapImplicitValue(int n) => _context('mapping value', () =>
791 _group(() {
792 if (!_c_indicator(_C_MAPPING_VALUE)) return null;
793 return _or([
794 () => _s_l_blockNode(n, BLOCK_OUT),
795 () => _s_l_comments() ? _e_node() : null
796 ]);
797 }));
798
799 // 195
800 _Node _ns_l_compactMapping(int n) => _context('mapping', () {
801 var first = _ns_l_blockMapEntry(n);
802 if (!_(first)) return null;
803
804 var pairs = _zeroOrMore(() => _group(() {
805 if (!_s_indent(n)) return null;
806 return _ns_l_blockMapEntry(n);
807 }));
808 pairs.insertRange(0, 1, first);
809
810 return _map(pairs);
811 });
812
813 // 196
814 _Node _s_l_blockNode(int n, int c) =>
815 _or([() => _s_l_blockInBlock(n, c), () => _s_l_flowInBlock(n)]);
816
817 // 197
818 _Node _s_l_flowInBlock(int n) => _group(() {
819 if (!_s_separate(n+1, FLOW_OUT)) return null;
820 var node = _ns_flowNode(n+1, FLOW_OUT);
821 if (!_(node)) return null;
822 if (!_s_l_comments()) return null;
823 return node;
824 });
825
826 // 198
827 _Node _s_l_blockInBlock(int n, int c) =>
828 _or([() => _s_l_blockScalar(n, c), () => _s_l_blockCollection(n, c)]);
829
830 // 199
831 _Node _s_l_blockScalar(int n, int c) => _group(() {
832 if (!_s_separate(n+1, c)) return null;
833 var props = _group(() {
834 var props = _c_ns_properties(n+1, c);
835 if (!_(props)) return null;
836 if (!_s_separate(n+1, c)) return null;
837 return props;
838 });
839 if (!_(props)) props = [null, null];
840
841 var node = _or([() => _c_l_literal(n), () => _c_l_folded(n)]);
842 if (!_(node)) return null;
843 return _addProps(node, props);
844 });
845
846 // 200
847 _Node _s_l_blockCollection(int n, int c) => _group(() {
848 var props = _group(() {
849 if (!_s_separate(n+1, c)) return null;
850 return _c_ns_properties(n+1, c);
851 });
852 if (!_(props)) props = [null, null];
853
854 if (!_s_l_comments()) return null;
855 return _or([
856 () => _l_blockSequence(_seqSpaces(n, c)),
857 () => _l_blockMapping(n)]);
858 });
859
860 // 201
861 int _seqSpaces(int n, int c) => c == BLOCK_OUT ? n - 1 : n;
862
863 // 202
864 void _l_documentPrefix() {
865 _zeroOrMore(_l_comment);
866 }
867
868 // 203
869 bool _c_directivesEnd() => _rawString("---");
870
871 // 204
872 bool _c_documentEnd() => _rawString("...");
873
874 // 205
875 bool _l_documentSuffix() => _group(() {
876 if (!_c_documentEnd()) return false;
877 return _s_l_comments();
878 });
879
880 // 206
881 bool _c_forbidden() {
882 if (!_inBareDocument || !_atStartOfLine) return false;
883 var forbidden = false;
884 _group(() {
885 if (!_or([_c_directivesEnd, _c_documentEnd])) return;
886 var char = _peek();
887 forbidden = _isBreak(char) || _isWhite(char) || _atEndOfFile;
888 return;
889 });
890 return forbidden;
891 }
892
893 // 207
894 _Node _l_bareDocument() {
895 try {
896 _inBareDocument = true;
897 return _s_l_blockNode(-1, BLOCK_IN);
898 } finally {
899 _inBareDocument = false;
900 }
901 }
902
903 // 208
904 _Node _l_explicitDocument() {
905 if (!_c_directivesEnd()) return null;
906 var doc = _l_bareDocument();
907 if (_(doc)) return doc;
908
909 doc = _e_node();
910 _s_l_comments();
911 return doc;
912 }
913
914 // 209
915 _Node _l_directiveDocument() {
916 if (!_(_oneOrMore(_l_directive))) return null;
917 var doc = _l_explicitDocument();
918 if (doc != null) return doc;
919 _parseFailed();
920 }
921
922 // 210
923 _Node _l_anyDocument() =>
924 _or([_l_directiveDocument, _l_explicitDocument, _l_bareDocument]);
925
926 // 211
927 List<_Node> _l_yamlStream() {
928 var docs = [];
929 _zeroOrMore(_l_documentPrefix);
930 var first = _zeroOrOne(_l_anyDocument);
931 if (!_(first)) first = _e_node();
932 docs.add(first);
933
934 _zeroOrMore(() {
935 var doc;
936 if (_(_oneOrMore(_l_documentSuffix))) {
937 _zeroOrMore(_l_documentPrefix);
938 doc = _zeroOrOne(_l_anyDocument);
939 } else {
940 _zeroOrMore(_l_documentPrefix);
941 doc = _zeroOrOne(_l_explicitDocument);
942 }
943 if (_(doc)) docs.add(doc);
944 return doc;
945 });
946
947 if (!_atEndOfFile) _parseFailed();
948 return docs;
949 }
950 }
951
952 class SyntaxError extends Error {
953 final int _line;
954 final int _column;
955
956 SyntaxError(int this._line, int this._column, String _msg) : super(_msg);
957
958 String toString() => "Syntax error on line $_line, column $_column: $_msg";
959 }
OLDNEW
« 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