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

Side by Side Diff: yaml/lib/src/parser.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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 | « yaml/lib/src/null_span.dart ('k') | yaml/lib/src/scanner.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) 2014, 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 library yaml.parser;
6
7 import 'package:source_span/source_span.dart';
8 import 'package:string_scanner/string_scanner.dart';
9
10 import 'event.dart';
11 import 'scanner.dart';
12 import 'style.dart';
13 import 'token.dart';
14 import 'utils.dart';
15 import 'yaml_document.dart';
16 import 'yaml_exception.dart';
17
18 /// A parser that reads [Token]s emitted by a [Scanner] and emits [Event]s.
19 ///
20 /// This is based on the libyaml parser, available at
21 /// https://github.com/yaml/libyaml/blob/master/src/parser.c. The license for
22 /// that is available in ../../libyaml-license.txt.
23 class Parser {
24 /// The underlying [Scanner] that generates [Token]s.
25 final Scanner _scanner;
26
27 /// The stack of parse states for nested contexts.
28 final _states = new List<_State>();
29
30 /// The current parse state.
31 var _state = _State.STREAM_START;
32
33 /// The custom tag directives, by tag handle.
34 final _tagDirectives = new Map<String, TagDirective>();
35
36 /// Whether the parser has finished parsing.
37 bool get isDone => _state == _State.END;
38
39 /// Creates a parser that parses [source].
40 ///
41 /// [sourceUrl] can be a String or a [Uri].
42 Parser(String source, {sourceUrl})
43 : _scanner = new Scanner(source, sourceUrl: sourceUrl);
44
45 /// Consumes and returns the next event.
46 Event parse() {
47 try {
48 if (isDone) throw new StateError("No more events.");
49 var event = _stateMachine();
50 return event;
51 } on StringScannerException catch (error) {
52 throw new YamlException(error.message, error.span);
53 }
54 }
55
56 /// Dispatches parsing based on the current state.
57 Event _stateMachine() {
58 switch (_state) {
59 case _State.STREAM_START:
60 return _parseStreamStart();
61 case _State.DOCUMENT_START:
62 return _parseDocumentStart();
63 case _State.DOCUMENT_CONTENT:
64 return _parseDocumentContent();
65 case _State.DOCUMENT_END:
66 return _parseDocumentEnd();
67 case _State.BLOCK_NODE:
68 return _parseNode(block: true);
69 case _State.BLOCK_NODE_OR_INDENTLESS_SEQUENCE:
70 return _parseNode(block: true, indentlessSequence: true);
71 case _State.FLOW_NODE:
72 return _parseNode();
73 case _State.BLOCK_SEQUENCE_FIRST_ENTRY:
74 // Scan past the `BLOCK-SEQUENCE-FIRST-ENTRY` token to the
75 // `BLOCK-SEQUENCE-ENTRY` token.
76 _scanner.scan();
77 return _parseBlockSequenceEntry();
78 case _State.BLOCK_SEQUENCE_ENTRY:
79 return _parseBlockSequenceEntry();
80 case _State.INDENTLESS_SEQUENCE_ENTRY:
81 return _parseIndentlessSequenceEntry();
82 case _State.BLOCK_MAPPING_FIRST_KEY:
83 // Scan past the `BLOCK-MAPPING-FIRST-KEY` token to the
84 // `BLOCK-MAPPING-KEY` token.
85 _scanner.scan();
86 return _parseBlockMappingKey();
87 case _State.BLOCK_MAPPING_KEY:
88 return _parseBlockMappingKey();
89 case _State.BLOCK_MAPPING_VALUE:
90 return _parseBlockMappingValue();
91 case _State.FLOW_SEQUENCE_FIRST_ENTRY:
92 return _parseFlowSequenceEntry(first: true);
93 case _State.FLOW_SEQUENCE_ENTRY:
94 return _parseFlowSequenceEntry();
95 case _State.FLOW_SEQUENCE_ENTRY_MAPPING_KEY:
96 return _parseFlowSequenceEntryMappingKey();
97 case _State.FLOW_SEQUENCE_ENTRY_MAPPING_VALUE:
98 return _parseFlowSequenceEntryMappingValue();
99 case _State.FLOW_SEQUENCE_ENTRY_MAPPING_END:
100 return _parseFlowSequenceEntryMappingEnd();
101 case _State.FLOW_MAPPING_FIRST_KEY:
102 return _parseFlowMappingKey(first: true);
103 case _State.FLOW_MAPPING_KEY:
104 return _parseFlowMappingKey();
105 case _State.FLOW_MAPPING_VALUE:
106 return _parseFlowMappingValue();
107 case _State.FLOW_MAPPING_EMPTY_VALUE:
108 return _parseFlowMappingValue(empty: true);
109 default:
110 throw "Unreachable";
111 }
112 }
113
114 /// Parses the production:
115 ///
116 /// stream ::=
117 /// STREAM-START implicit_document? explicit_document* STREAM-END
118 /// ************
119 Event _parseStreamStart() {
120 var token = _scanner.scan();
121 assert(token.type == TokenType.STREAM_START);
122
123 _state = _State.DOCUMENT_START;
124 return new Event(EventType.STREAM_START, token.span);
125 }
126
127 /// Parses the productions:
128 ///
129 /// implicit_document ::= block_node DOCUMENT-END*
130 /// *
131 /// explicit_document ::=
132 /// DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
133 /// *************************
134 Event _parseDocumentStart() {
135 var token = _scanner.peek();
136
137 // libyaml requires any document beyond the first in the stream to have an
138 // explicit document start indicator, but the spec allows it to be omitted
139 // as long as there was an end indicator.
140
141 // Parse extra document end indicators.
142 while (token.type == TokenType.DOCUMENT_END) {
143 token = _scanner.advance();
144 }
145
146 if (token.type != TokenType.VERSION_DIRECTIVE &&
147 token.type != TokenType.TAG_DIRECTIVE &&
148 token.type != TokenType.DOCUMENT_START &&
149 token.type != TokenType.STREAM_END) {
150 // Parse an implicit document.
151 _processDirectives();
152 _states.add(_State.DOCUMENT_END);
153 _state = _State.BLOCK_NODE;
154 return new DocumentStartEvent(token.span.start.pointSpan());
155 }
156
157 if (token.type == TokenType.STREAM_END) {
158 _state = _State.END;
159 _scanner.scan();
160 return new Event(EventType.STREAM_END, token.span);
161 }
162
163 // Parse an explicit document.
164 var start = token.span;
165 var pair = _processDirectives();
166 var versionDirective = pair.first;
167 var tagDirectives = pair.last;
168 token = _scanner.peek();
169 if (token.type != TokenType.DOCUMENT_START) {
170 throw new YamlException("Expected document start.", token.span);
171 }
172
173 _states.add(_State.DOCUMENT_END);
174 _state = _State.DOCUMENT_CONTENT;
175 _scanner.scan();
176 return new DocumentStartEvent(start.expand(token.span),
177 versionDirective: versionDirective,
178 tagDirectives: tagDirectives,
179 isImplicit: false);
180 }
181
182 /// Parses the productions:
183 ///
184 /// explicit_document ::=
185 /// DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
186 /// ***********
187 Event _parseDocumentContent() {
188 var token = _scanner.peek();
189
190 switch (token.type) {
191 case TokenType.VERSION_DIRECTIVE:
192 case TokenType.TAG_DIRECTIVE:
193 case TokenType.DOCUMENT_START:
194 case TokenType.DOCUMENT_END:
195 case TokenType.STREAM_END:
196 _state = _states.removeLast();
197 return _processEmptyScalar(token.span.start);
198 default:
199 return _parseNode(block: true);
200 }
201 }
202
203 /// Parses the productions:
204 ///
205 /// implicit_document ::= block_node DOCUMENT-END*
206 /// *************
207 /// explicit_document ::=
208 /// DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
209 /// *************
210 Event _parseDocumentEnd() {
211 _tagDirectives.clear();
212 _state = _State.DOCUMENT_START;
213
214 var token = _scanner.peek();
215 if (token.type == TokenType.DOCUMENT_END) {
216 _scanner.scan();
217 return new DocumentEndEvent(token.span, isImplicit: false);
218 } else {
219 return new DocumentEndEvent(
220 token.span.start.pointSpan(), isImplicit: true);
221 }
222 }
223
224 /// Parses the productions:
225 ///
226 /// block_node_or_indentless_sequence ::=
227 /// ALIAS
228 /// *****
229 /// | properties (block_content | indentless_block_sequence)?
230 /// ********** *
231 /// | block_content | indentless_block_sequence
232 /// *
233 /// block_node ::= ALIAS
234 /// *****
235 /// | properties block_content?
236 /// ********** *
237 /// | block_content
238 /// *
239 /// flow_node ::= ALIAS
240 /// *****
241 /// | properties flow_content?
242 /// ********** *
243 /// | flow_content
244 /// *
245 /// properties ::= TAG ANCHOR? | ANCHOR TAG?
246 /// *************************
247 /// block_content ::= block_collection | flow_collection | SCALAR
248 /// ******
249 /// flow_content ::= flow_collection | SCALAR
250 /// ******
251 Event _parseNode({bool block: false, bool indentlessSequence: false}) {
252 var token = _scanner.peek();
253
254 if (token is AliasToken) {
255 _scanner.scan();
256 _state = _states.removeLast();
257 return new AliasEvent(token.span, token.name);
258 }
259
260 var anchor;
261 var tagToken;
262 var span = token.span.start.pointSpan();
263 parseAnchor() {
264 anchor = token.name;
265 span = span.expand(token.span);
266 token = _scanner.advance();
267 }
268
269 parseTag() {
270 tagToken = token;
271 span = span.expand(token.span);
272 token = _scanner.advance();
273 }
274
275 if (token is AnchorToken) {
276 parseAnchor();
277 if (token is TagToken) parseTag();
278 } else if (token is TagToken) {
279 parseTag();
280 if (token is AnchorToken) parseAnchor();
281 }
282
283 var tag;
284 if (tagToken != null) {
285 if (tagToken.handle == null) {
286 tag = tagToken.suffix;
287 } else {
288 var tagDirective = _tagDirectives[tagToken.handle];
289 if (tagDirective == null) {
290 throw new YamlException("Undefined tag handle.", tagToken.span);
291 }
292
293 tag = tagDirective.prefix + tagToken.suffix;
294 }
295 }
296
297 if (indentlessSequence && token.type == TokenType.BLOCK_ENTRY) {
298 _state = _State.INDENTLESS_SEQUENCE_ENTRY;
299 return new SequenceStartEvent(
300 span.expand(token.span), CollectionStyle.BLOCK,
301 anchor: anchor, tag: tag);
302 }
303
304 if (token is ScalarToken) {
305 // All non-plain scalars have the "!" tag by default.
306 if (tag == null && token.style != ScalarStyle.PLAIN) tag = "!";
307
308 _state = _states.removeLast();
309 _scanner.scan();
310 return new ScalarEvent(
311 span.expand(token.span), token.value, token.style,
312 anchor: anchor, tag: tag);
313 }
314
315 if (token.type == TokenType.FLOW_SEQUENCE_START) {
316 _state = _State.FLOW_SEQUENCE_FIRST_ENTRY;
317 return new SequenceStartEvent(
318 span.expand(token.span), CollectionStyle.FLOW,
319 anchor: anchor, tag: tag);
320 }
321
322 if (token.type == TokenType.FLOW_MAPPING_START) {
323 _state = _State.FLOW_MAPPING_FIRST_KEY;
324 return new MappingStartEvent(
325 span.expand(token.span), CollectionStyle.FLOW,
326 anchor: anchor, tag: tag);
327 }
328
329 if (block && token.type == TokenType.BLOCK_SEQUENCE_START) {
330 _state = _State.BLOCK_SEQUENCE_FIRST_ENTRY;
331 return new SequenceStartEvent(
332 span.expand(token.span), CollectionStyle.BLOCK,
333 anchor: anchor, tag: tag);
334 }
335
336
337 if (block && token.type == TokenType.BLOCK_MAPPING_START) {
338 _state = _State.BLOCK_MAPPING_FIRST_KEY;
339 return new MappingStartEvent(
340 span.expand(token.span), CollectionStyle.BLOCK,
341 anchor: anchor, tag: tag);
342 }
343
344 if (anchor != null || tag != null) {
345 _state = _states.removeLast();
346 return new ScalarEvent(
347 span, '', ScalarStyle.PLAIN,
348 anchor: anchor, tag: tag);
349 }
350
351 throw new YamlException("Expected node content.", span);
352 }
353
354 /// Parses the productions:
355 ///
356 /// block_sequence ::=
357 /// BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
358 /// ******************** *********** * *********
359 Event _parseBlockSequenceEntry() {
360 var token = _scanner.peek();
361
362 if (token.type == TokenType.BLOCK_ENTRY) {
363 token = _scanner.advance();
364
365 if (token.type == TokenType.BLOCK_ENTRY ||
366 token.type == TokenType.BLOCK_END) {
367 _state = _State.BLOCK_SEQUENCE_ENTRY;
368 return _processEmptyScalar(token.span.end);
369 } else {
370 _states.add(_State.BLOCK_SEQUENCE_ENTRY);
371 return _parseNode(block: true);
372 }
373 }
374
375 if (token.type == TokenType.BLOCK_END) {
376 _scanner.scan();
377 _state = _states.removeLast();
378 return new Event(EventType.SEQUENCE_END, token.span);
379 }
380
381 throw new YamlException("While parsing a block collection, expected '-'.",
382 token.span.start.pointSpan());
383 }
384
385 /// Parses the productions:
386 ///
387 /// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
388 /// *********** *
389 Event _parseIndentlessSequenceEntry() {
390 var token = _scanner.peek();
391
392 if (token.type != TokenType.BLOCK_ENTRY) {
393 _state = _states.removeLast();
394 return new Event(EventType.SEQUENCE_END, token.span.start.pointSpan());
395 }
396
397 var start = token.span.start;
398 token = _scanner.advance();
399
400 if (token.type == TokenType.BLOCK_ENTRY ||
401 token.type == TokenType.KEY ||
402 token.type == TokenType.VALUE ||
403 token.type == TokenType.BLOCK_END) {
404 _state = _State.INDENTLESS_SEQUENCE_ENTRY;
405 return _processEmptyScalar(start);
406 } else {
407 _states.add(_State.INDENTLESS_SEQUENCE_ENTRY);
408 return _parseNode(block: true);
409 }
410 }
411
412 /// Parses the productions:
413 ///
414 /// block_mapping ::= BLOCK-MAPPING_START
415 /// *******************
416 /// ((KEY block_node_or_indentless_sequence?)?
417 /// *** *
418 /// (VALUE block_node_or_indentless_sequence?)?)*
419 ///
420 /// BLOCK-END
421 /// *********
422 Event _parseBlockMappingKey() {
423 var token = _scanner.peek();
424 if (token.type == TokenType.KEY) {
425 var start = token.span.start;
426 token = _scanner.advance();
427
428 if (token.type == TokenType.KEY ||
429 token.type == TokenType.VALUE ||
430 token.type == TokenType.BLOCK_END) {
431 _state = _State.BLOCK_MAPPING_VALUE;
432 return _processEmptyScalar(start);
433 } else {
434 _states.add(_State.BLOCK_MAPPING_VALUE);
435 return _parseNode(block: true, indentlessSequence: true);
436 }
437 }
438
439 // libyaml doesn't allow empty keys without an explicit key indicator, but
440 // the spec does. See example 8.18:
441 // http://yaml.org/spec/1.2/spec.html#id2798896.
442 if (token.type == TokenType.VALUE) {
443 _state = _State.BLOCK_MAPPING_VALUE;
444 return _processEmptyScalar(token.span.start);
445 }
446
447 if (token.type == TokenType.BLOCK_END) {
448 _scanner.scan();
449 _state = _states.removeLast();
450 return new Event(EventType.MAPPING_END, token.span);
451 }
452
453 throw new YamlException("Expected a key while parsing a block mapping.",
454 token.span.start.pointSpan());
455 }
456
457 /// Parses the productions:
458 ///
459 /// block_mapping ::= BLOCK-MAPPING_START
460 ///
461 /// ((KEY block_node_or_indentless_sequence?)?
462 ///
463 /// (VALUE block_node_or_indentless_sequence?)?)*
464 /// ***** *
465 /// BLOCK-END
466 ///
467 Event _parseBlockMappingValue() {
468 var token = _scanner.peek();
469
470 if (token.type != TokenType.VALUE) {
471 _state = _State.BLOCK_MAPPING_KEY;
472 return _processEmptyScalar(token.span.start);
473 }
474
475 var start = token.span.start;
476 token = _scanner.advance();
477 if (token.type == TokenType.KEY ||
478 token.type == TokenType.VALUE ||
479 token.type == TokenType.BLOCK_END) {
480 _state = _State.BLOCK_MAPPING_KEY;
481 return _processEmptyScalar(start);
482 } else {
483 _states.add(_State.BLOCK_MAPPING_KEY);
484 return _parseNode(block: true, indentlessSequence: true);
485 }
486 }
487
488 /// Parses the productions:
489 ///
490 /// flow_sequence ::= FLOW-SEQUENCE-START
491 /// *******************
492 /// (flow_sequence_entry FLOW-ENTRY)*
493 /// * **********
494 /// flow_sequence_entry?
495 /// *
496 /// FLOW-SEQUENCE-END
497 /// *****************
498 /// flow_sequence_entry ::=
499 /// flow_node | KEY flow_node? (VALUE flow_node?)?
500 /// *
501 Event _parseFlowSequenceEntry({bool first: false}) {
502 if (first) _scanner.scan();
503 var token = _scanner.peek();
504
505 if (token.type != TokenType.FLOW_SEQUENCE_END) {
506 if (!first) {
507 if (token.type != TokenType.FLOW_ENTRY) {
508 throw new YamlException(
509 "While parsing a flow sequence, expected ',' or ']'.",
510 token.span.start.pointSpan());
511 }
512
513 token = _scanner.advance();
514 }
515
516 if (token.type == TokenType.KEY) {
517 _state = _State.FLOW_SEQUENCE_ENTRY_MAPPING_KEY;
518 _scanner.scan();
519 return new MappingStartEvent(
520 token.span, CollectionStyle.FLOW);
521 } else if (token.type != TokenType.FLOW_SEQUENCE_END) {
522 _states.add(_State.FLOW_SEQUENCE_ENTRY);
523 return _parseNode();
524 }
525 }
526
527 _scanner.scan();
528 _state = _states.removeLast();
529 return new Event(EventType.SEQUENCE_END, token.span);
530 }
531
532 /// Parses the productions:
533 ///
534 /// flow_sequence_entry ::=
535 /// flow_node | KEY flow_node? (VALUE flow_node?)?
536 /// *** *
537 Event _parseFlowSequenceEntryMappingKey() {
538 var token = _scanner.peek();
539
540 if (token.type == TokenType.VALUE ||
541 token.type == TokenType.FLOW_ENTRY ||
542 token.type == TokenType.FLOW_SEQUENCE_END) {
543 // libyaml consumes the token here, but that seems like a bug, since it
544 // always causes [_parseFlowSequenceEntryMappingValue] to emit an empty
545 // scalar.
546
547 var start = token.span.start;
548 _state = _State.FLOW_SEQUENCE_ENTRY_MAPPING_VALUE;
549 return _processEmptyScalar(start);
550 } else {
551 _states.add(_State.FLOW_SEQUENCE_ENTRY_MAPPING_VALUE);
552 return _parseNode();
553 }
554 }
555
556 /// Parses the productions:
557 ///
558 /// flow_sequence_entry ::=
559 /// flow_node | KEY flow_node? (VALUE flow_node?)?
560 /// ***** *
561 Event _parseFlowSequenceEntryMappingValue() {
562 var token = _scanner.peek();
563
564 if (token.type == TokenType.VALUE) {
565 token = _scanner.advance();
566 if (token.type != TokenType.FLOW_ENTRY &&
567 token.type != TokenType.FLOW_SEQUENCE_END) {
568 _states.add(_State.FLOW_SEQUENCE_ENTRY_MAPPING_END);
569 return _parseNode();
570 }
571 }
572
573 _state = _State.FLOW_SEQUENCE_ENTRY_MAPPING_END;
574 return _processEmptyScalar(token.span.start);
575 }
576
577 /// Parses the productions:
578 ///
579 /// flow_sequence_entry ::=
580 /// flow_node | KEY flow_node? (VALUE flow_node?)?
581 /// *
582 Event _parseFlowSequenceEntryMappingEnd() {
583 _state = _State.FLOW_SEQUENCE_ENTRY;
584 return new Event(EventType.MAPPING_END,
585 _scanner.peek().span.start.pointSpan());
586 }
587
588 /// Parses the productions:
589 ///
590 /// flow_mapping ::= FLOW-MAPPING-START
591 /// ******************
592 /// (flow_mapping_entry FLOW-ENTRY)*
593 /// * **********
594 /// flow_mapping_entry?
595 /// ******************
596 /// FLOW-MAPPING-END
597 /// ****************
598 /// flow_mapping_entry ::=
599 /// flow_node | KEY flow_node? (VALUE flow_node?)?
600 /// * *** *
601 Event _parseFlowMappingKey({bool first: false}) {
602 if (first) _scanner.scan();
603 var token = _scanner.peek();
604
605 if (token.type != TokenType.FLOW_MAPPING_END) {
606 if (!first) {
607 if (token.type != TokenType.FLOW_ENTRY) {
608 throw new YamlException(
609 "While parsing a flow mapping, expected ',' or '}'.",
610 token.span.start.pointSpan());
611 }
612
613 token = _scanner.advance();
614 }
615
616 if (token.type == TokenType.KEY) {
617 token = _scanner.advance();
618 if (token.type != TokenType.VALUE &&
619 token.type != TokenType.FLOW_ENTRY &&
620 token.type != TokenType.FLOW_MAPPING_END) {
621 _states.add(_State.FLOW_MAPPING_VALUE);
622 return _parseNode();
623 } else {
624 _state = _State.FLOW_MAPPING_VALUE;
625 return _processEmptyScalar(token.span.start);
626 }
627 } else if (token.type != TokenType.FLOW_MAPPING_END) {
628 _states.add(_State.FLOW_MAPPING_EMPTY_VALUE);
629 return _parseNode();
630 }
631 }
632
633 _scanner.scan();
634 _state = _states.removeLast();
635 return new Event(EventType.MAPPING_END, token.span);
636 }
637
638 /// Parses the productions:
639 ///
640 /// flow_mapping_entry ::=
641 /// flow_node | KEY flow_node? (VALUE flow_node?)?
642 /// * ***** *
643 Event _parseFlowMappingValue({bool empty: false}) {
644 var token = _scanner.peek();
645
646 if (empty) {
647 _state = _State.FLOW_MAPPING_KEY;
648 return _processEmptyScalar(token.span.start);
649 }
650
651 if (token.type == TokenType.VALUE) {
652 token = _scanner.advance();
653 if (token.type != TokenType.FLOW_ENTRY &&
654 token.type != TokenType.FLOW_MAPPING_END) {
655 _states.add(_State.FLOW_MAPPING_KEY);
656 return _parseNode();
657 }
658 }
659
660 _state = _State.FLOW_MAPPING_KEY;
661 return _processEmptyScalar(token.span.start);
662 }
663
664 /// Generate an empty scalar event.
665 Event _processEmptyScalar(SourceLocation location) =>
666 new ScalarEvent(location.pointSpan(), '', ScalarStyle.PLAIN);
667
668 /// Parses directives.
669 Pair<VersionDirective, List<TagDirective>> _processDirectives() {
670 var token = _scanner.peek();
671
672 var versionDirective;
673 var tagDirectives = [];
674 while (token.type == TokenType.VERSION_DIRECTIVE ||
675 token.type == TokenType.TAG_DIRECTIVE) {
676 if (token is VersionDirectiveToken) {
677 if (versionDirective != null) {
678 throw new YamlException("Duplicate %YAML directive.", token.span);
679 }
680
681 if (token.major != 1 || token.minor == 0) {
682 throw new YamlException(
683 "Incompatible YAML document. This parser only supports YAML 1.1 "
684 "and 1.2.",
685 token.span);
686 } else if (token.minor > 2) {
687 // TODO(nweiz): Print to stderr when issue 6943 is fixed and dart:io
688 // is available.
689 warn("Warning: this parser only supports YAML 1.1 and 1.2.",
690 token.span);
691 }
692
693 versionDirective = new VersionDirective(token.major, token.minor);
694 } else if (token is TagDirectiveToken) {
695 var tagDirective = new TagDirective(token.handle, token.prefix);
696 _appendTagDirective(tagDirective, token.span);
697 tagDirectives.add(tagDirective);
698 }
699
700 token = _scanner.advance();
701 }
702
703 _appendTagDirective(
704 new TagDirective("!", "!"),
705 token.span.start.pointSpan(),
706 allowDuplicates: true);
707 _appendTagDirective(
708 new TagDirective("!!", "tag:yaml.org,2002:"),
709 token.span.start.pointSpan(),
710 allowDuplicates: true);
711
712 return new Pair(versionDirective, tagDirectives);
713 }
714
715 /// Adds a tag directive to the directives stack.
716 void _appendTagDirective(TagDirective newDirective, FileSpan span,
717 {bool allowDuplicates: false}) {
718 if (_tagDirectives.containsKey(newDirective.handle)) {
719 if (allowDuplicates) return;
720 throw new YamlException("Duplicate %TAG directive.", span);
721 }
722
723 _tagDirectives[newDirective.handle] = newDirective;
724 }
725 }
726
727 /// The possible states for the parser.
728 class _State {
729 /// Expect [TokenType.STREAM_START].
730 static const STREAM_START = const _State("STREAM_START");
731
732 /// Expect the beginning of an implicit document.
733 static const IMPLICIT_DOCUMENT_START =
734 const _State("IMPLICIT_DOCUMENT_START");
735
736 /// Expect [TokenType.DOCUMENT_START].
737 static const DOCUMENT_START = const _State("DOCUMENT_START");
738
739 /// Expect the content of a document.
740 static const DOCUMENT_CONTENT = const _State("DOCUMENT_CONTENT");
741
742 /// Expect [TokenType.DOCUMENT_END].
743 static const DOCUMENT_END = const _State("DOCUMENT_END");
744
745 /// Expect a block node.
746 static const BLOCK_NODE = const _State("BLOCK_NODE");
747
748 /// Expect a block node or indentless sequence.
749 static const BLOCK_NODE_OR_INDENTLESS_SEQUENCE =
750 const _State("BLOCK_NODE_OR_INDENTLESS_SEQUENCE");
751
752 /// Expect a flow node.
753 static const FLOW_NODE = const _State("FLOW_NODE");
754
755 /// Expect the first entry of a block sequence.
756 static const BLOCK_SEQUENCE_FIRST_ENTRY =
757 const _State("BLOCK_SEQUENCE_FIRST_ENTRY");
758
759 /// Expect an entry of a block sequence.
760 static const BLOCK_SEQUENCE_ENTRY = const _State("BLOCK_SEQUENCE_ENTRY");
761
762 /// Expect an entry of an indentless sequence.
763 static const INDENTLESS_SEQUENCE_ENTRY =
764 const _State("INDENTLESS_SEQUENCE_ENTRY");
765
766 /// Expect the first key of a block mapping.
767 static const BLOCK_MAPPING_FIRST_KEY =
768 const _State("BLOCK_MAPPING_FIRST_KEY");
769
770 /// Expect a block mapping key.
771 static const BLOCK_MAPPING_KEY = const _State("BLOCK_MAPPING_KEY");
772
773 /// Expect a block mapping value.
774 static const BLOCK_MAPPING_VALUE = const _State("BLOCK_MAPPING_VALUE");
775
776 /// Expect the first entry of a flow sequence.
777 static const FLOW_SEQUENCE_FIRST_ENTRY =
778 const _State("FLOW_SEQUENCE_FIRST_ENTRY");
779
780 /// Expect an entry of a flow sequence.
781 static const FLOW_SEQUENCE_ENTRY = const _State("FLOW_SEQUENCE_ENTRY");
782
783 /// Expect a key of an ordered mapping.
784 static const FLOW_SEQUENCE_ENTRY_MAPPING_KEY =
785 const _State("FLOW_SEQUENCE_ENTRY_MAPPING_KEY");
786
787 /// Expect a value of an ordered mapping.
788 static const FLOW_SEQUENCE_ENTRY_MAPPING_VALUE =
789 const _State("FLOW_SEQUENCE_ENTRY_MAPPING_VALUE");
790
791 /// Expect the and of an ordered mapping entry.
792 static const FLOW_SEQUENCE_ENTRY_MAPPING_END =
793 const _State("FLOW_SEQUENCE_ENTRY_MAPPING_END");
794
795 /// Expect the first key of a flow mapping.
796 static const FLOW_MAPPING_FIRST_KEY = const _State("FLOW_MAPPING_FIRST_KEY");
797
798 /// Expect a key of a flow mapping.
799 static const FLOW_MAPPING_KEY = const _State("FLOW_MAPPING_KEY");
800
801 /// Expect a value of a flow mapping.
802 static const FLOW_MAPPING_VALUE = const _State("FLOW_MAPPING_VALUE");
803
804 /// Expect an empty value of a flow mapping.
805 static const FLOW_MAPPING_EMPTY_VALUE =
806 const _State("FLOW_MAPPING_EMPTY_VALUE");
807
808 /// Expect nothing.
809 static const END = const _State("END");
810
811 final String name;
812
813 const _State(this.name);
814
815 String toString() => name;
816 }
OLDNEW
« no previous file with comments | « yaml/lib/src/null_span.dart ('k') | yaml/lib/src/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698