##### Coverage Report - org.yaml.snakeyaml.parser.ParserImpl

Classes in this File | Line Coverage | Branch Coverage | Complexity
ParserImpl |
99% | 141/142
96% | 77/80
| 4.34375;4.344
ParserImpl$1 |
N/A | N/A
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseBlockMappingFirstKey |
100% | 4/4
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseBlockMappingKey |
100% | 16/16
100% | 6/6
| 4.34375;4.344
ParserImpl$ParseBlockMappingValue |
100% | 11/11
100% | 4/4
| 4.34375;4.344
ParserImpl$ParseBlockNode |
100% | 2/2
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseBlockSequenceEntry |
100% | 16/16
100% | 6/6
| 4.34375;4.344
ParserImpl$ParseBlockSequenceFirstEntry |
100% | 4/4
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseDocumentContent |
100% | 7/7
100% | 2/2
| 4.34375;4.344
ParserImpl$ParseDocumentEnd |
100% | 12/12
100% | 2/2
| 4.34375;4.344
ParserImpl$ParseDocumentStart |
93% | 27/29
83% | 10/12
| 4.34375;4.344
ParserImpl$ParseFlowMappingEmptyValue |
100% | 3/3
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseFlowMappingFirstKey |
100% | 4/4
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseFlowMappingKey |
100% | 25/25
100% | 12/12
| 4.34375;4.344
ParserImpl$ParseFlowMappingValue |
100% | 11/11
100% | 4/4
| 4.34375;4.344
ParserImpl$ParseFlowSequenceEntry |
100% | 23/23
100% | 10/10
| 4.34375;4.344
ParserImpl$ParseFlowSequenceEntryMappingEnd |
100% | 4/4
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseFlowSequenceEntryMappingKey |
71% | 5/7
50% | 1/2
| 4.34375;4.344
ParserImpl$ParseFlowSequenceEntryMappingValue |
100% | 11/11
100% | 4/4
| 4.34375;4.344
ParserImpl$ParseFlowSequenceFirstEntry |
100% | 4/4
N/A | N/A
| 4.34375;4.344
ParserImpl$ParseImplicitDocumentStart |
100% | 12/12
100% | 2/2
| 4.34375;4.344
ParserImpl$ParseIndentlessSequenceEntry |
83% | 10/12
75% | 3/4
| 4.34375;4.344
ParserImpl$ParseStreamStart |
100% | 5/5
N/A | N/A
| 4.34375;4.344

1 |  |
     /**
2 |  |
      * Copyright (c) 2008-2011, http://www.snakeyaml.org
3 |  |
      *
4 |  |
      * Licensed under the Apache License, Version 2.0 (the "License");
5 |  |
      * you may not use this file except in compliance with the License.
6 |  |
      * You may obtain a copy of the License at
7 |  |
      *
8 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
9 |  |
      *
10 |  |
      * Unless required by applicable law or agreed to in writing, software
11 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
12 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  |
      * See the License for the specific language governing permissions and
14 |  |
      * limitations under the License.
15 |  |
      */
16 |  |
17 |  |
     package org.yaml.snakeyaml.parser;
18 |  |
19 |  |
     import java.util.ArrayList;
20 |  |
     import java.util.HashMap;
21 |  |
     import java.util.List;
22 |  |
     import java.util.Map;
23 |  |
24 |  |
     import org.yaml.snakeyaml.error.Mark;
25 |  |
     import org.yaml.snakeyaml.error.YAMLException;
26 |  |
     import org.yaml.snakeyaml.events.AliasEvent;
27 |  |
     import org.yaml.snakeyaml.events.DocumentEndEvent;
28 |  |
     import org.yaml.snakeyaml.events.DocumentStartEvent;
29 |  |
     import org.yaml.snakeyaml.events.Event;
30 |  |
     import org.yaml.snakeyaml.events.ImplicitTuple;
31 |  |
     import org.yaml.snakeyaml.events.MappingEndEvent;
32 |  |
     import org.yaml.snakeyaml.events.MappingStartEvent;
33 |  |
     import org.yaml.snakeyaml.events.ScalarEvent;
34 |  |
     import org.yaml.snakeyaml.events.SequenceEndEvent;
35 |  |
     import org.yaml.snakeyaml.events.SequenceStartEvent;
36 |  |
     import org.yaml.snakeyaml.events.StreamEndEvent;
37 |  |
     import org.yaml.snakeyaml.events.StreamStartEvent;
38 |  |
     import org.yaml.snakeyaml.nodes.Tag;
39 |  |
     import org.yaml.snakeyaml.reader.StreamReader;
40 |  |
     import org.yaml.snakeyaml.scanner.Scanner;
41 |  |
     import org.yaml.snakeyaml.scanner.ScannerImpl;
42 |  |
     import org.yaml.snakeyaml.tokens.AliasToken;
43 |  |
     import org.yaml.snakeyaml.tokens.AnchorToken;
44 |  |
     import org.yaml.snakeyaml.tokens.BlockEntryToken;
45 |  |
     import org.yaml.snakeyaml.tokens.DirectiveToken;
46 |  |
     import org.yaml.snakeyaml.tokens.ScalarToken;
47 |  |
     import org.yaml.snakeyaml.tokens.StreamEndToken;
48 |  |
     import org.yaml.snakeyaml.tokens.StreamStartToken;
49 |  |
     import org.yaml.snakeyaml.tokens.TagToken;
50 |  |
     import org.yaml.snakeyaml.tokens.TagTuple;
51 |  |
     import org.yaml.snakeyaml.tokens.Token;
52 |  |
     import org.yaml.snakeyaml.util.ArrayStack;
53 |  |
54 |  |
     /**
55 |  |
      * <pre>
56 |  |
      * # The following YAML grammar is LL(1) and is parsed by a recursive descent
57 |  |
      * parser.
58 |  |
      * stream            ::= STREAM-START implicit_document? explicit_document* STREAM-END
59 |  |
      * implicit_document ::= block_node DOCUMENT-END*
60 |  |
      * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
61 |  |
      * block_node_or_indentless_sequence ::=
62 |  |
      *                       ALIAS
63 |  |
      *                       | properties (block_content | indentless_block_sequence)?
64 |  |
      *                       | block_content
65 |  |
      *                       | indentless_block_sequence
66 |  |
      * block_node        ::= ALIAS
67 |  |
      *                       | properties block_content?
68 |  |
      *                       | block_content
69 |  |
      * flow_node         ::= ALIAS
70 |  |
      *                       | properties flow_content?
71 |  |
      *                       | flow_content
72 |  |
      * properties        ::= TAG ANCHOR? | ANCHOR TAG?
73 |  |
      * block_content     ::= block_collection | flow_collection | SCALAR
74 |  |
      * flow_content      ::= flow_collection | SCALAR
75 |  |
      * block_collection  ::= block_sequence | block_mapping
76 |  |
      * flow_collection   ::= flow_sequence | flow_mapping
77 |  |
      * block_sequence    ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
78 |  |
      * indentless_sequence   ::= (BLOCK-ENTRY block_node?)+
79 |  |
      * block_mapping     ::= BLOCK-MAPPING_START
80 |  |
      *                       ((KEY block_node_or_indentless_sequence?)?
81 |  |
      *                       (VALUE block_node_or_indentless_sequence?)?)*
82 |  |
      *                       BLOCK-END
83 |  |
      * flow_sequence     ::= FLOW-SEQUENCE-START
84 |  |
      *                       (flow_sequence_entry FLOW-ENTRY)*
85 |  |
      *                       flow_sequence_entry?
86 |  |
      *                       FLOW-SEQUENCE-END
87 |  |
      * flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
88 |  |
      * flow_mapping      ::= FLOW-MAPPING-START
89 |  |
      *                       (flow_mapping_entry FLOW-ENTRY)*
90 |  |
      *                       flow_mapping_entry?
91 |  |
      *                       FLOW-MAPPING-END
92 |  |
      * flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?
93 |  |
      * FIRST sets:
94 |  |
      * stream: { STREAM-START }
95 |  |
      * explicit_document: { DIRECTIVE DOCUMENT-START }
96 |  |
      * implicit_document: FIRST(block_node)
97 |  |
      * block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
98 |  |
      * flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
99 |  |
      * block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
100 |  |
      * flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
101 |  |
      * block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
102 |  |
      * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
103 |  |
      * block_sequence: { BLOCK-SEQUENCE-START }
104 |  |
      * block_mapping: { BLOCK-MAPPING-START }
105 |  |
      * block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
106 |  |
      * indentless_sequence: { ENTRY }
107 |  |
      * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
108 |  |
      * flow_sequence: { FLOW-SEQUENCE-START }
109 |  |
      * flow_mapping: { FLOW-MAPPING-START }
110 |  |
      * flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
111 |  |
      * flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
112 |  |
      * </pre>
113 |  |
      *
114 |  |
      * Since writing a recursive-descendant parser is a straightforward task, we do
115 |  |
      * not give many comments here.
116 |  |
      */
117 | 2323524 |
     public final class ParserImpl implements Parser {
118 | 1 |
         private static final Map<String, String> DEFAULT_TAGS = new HashMap<String, String>();
119 |  |
         static {
120 | 1 |
             DEFAULT_TAGS.put("!", "!");
121 | 1 |
             DEFAULT_TAGS.put("!!", Tag.PREFIX);
122 | 1 |
         }
123 |  |
124 |  |
         private final Scanner scanner;
125 |  |
         private Event currentEvent;
126 |  |
         private List<Integer> yamlVersion;
127 |  |
         private Map<String, String> tagHandles;
128 |  |
         private final ArrayStack<Production> states;
129 |  |
         private final ArrayStack<Mark> marks;
130 |  |
         private Production state;
131 |  |
132 | 3572 |
         public ParserImpl(StreamReader reader) {
133 | 3572 |
             this.scanner = new ScannerImpl(reader);
134 | 3572 |
             currentEvent = null;
135 | 3572 |
             yamlVersion = null;
136 | 3572 |
             tagHandles = new HashMap<String, String>();
137 | 3572 |
             states = new ArrayStack<Production>(100);
138 | 3572 |
             marks = new ArrayStack<Mark>(10);
139 | 3572 |
             state = new ParseStreamStart();
140 | 3572 |
         }
141 |  |
142 |  |
         /**
143 |  |
          * Check the type of the next event.
144 |  |
          */
145 |  |
         public boolean checkEvent(Event.ID choices) {
146 | 1093613 |
             peekEvent();
147 | 1093500 |
             if (currentEvent != null) {
148 | 1093500 |
                 if (currentEvent.is(choices)) {
149 | 398846 |
                     return true;
150 |  |
                 }
151 |  |
             }
152 | 694654 |
             return false;
153 |  |
         }
154 |  |
155 |  |
         /**
156 |  |
          * Get the next event.
157 |  |
          */
158 |  |
         public Event peekEvent() {
159 | 1962916 |
             if (currentEvent == null) {
160 | 455447 |
                 if (state != null) {
161 | 452798 |
                     currentEvent = state.produce();
162 |  |
                 }
163 |  |
             }
164 | 1962803 |
             return currentEvent;
165 |  |
         }
166 |  |
167 |  |
         /**
168 |  |
          * Get the next event and proceed further.
169 |  |
          */
170 |  |
         public Event getEvent() {
171 | 452483 |
             peekEvent();
172 | 452483 |
             Event value = currentEvent;
173 | 452483 |
             currentEvent = null;
174 | 452483 |
             return value;
175 |  |
         }
176 |  |
177 |  |
         /**
178 |  |
          * <pre>
179 |  |
          * stream    ::= STREAM-START implicit_document? explicit_document* STREAM-END
180 |  |
          * implicit_document ::= block_node DOCUMENT-END*
181 |  |
          * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
182 |  |
          * </pre>
183 |  |
          */
184 | 7144 |
         private class ParseStreamStart implements Production {
185 |  |
             public Event produce() {
186 |  |
                 // Parse the stream start.
187 | 3572 |
                 StreamStartToken token = (StreamStartToken) scanner.getToken();
188 | 3572 |
                 Event event = new StreamStartEvent(token.getStartMark(), token.getEndMark());
189 |  |
                 // Prepare the next state.
190 | 3572 |
                 state = new ParseImplicitDocumentStart();
191 | 3572 |
                 return event;
192 |  |
             }
193 |  |
         }
194 |  |
195 | 7144 |
         private class ParseImplicitDocumentStart implements Production {
196 |  |
             public Event produce() {
197 |  |
                 // Parse an implicit document.
198 | 3572 |
                 if (!scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart, Token.ID.StreamEnd)) {
199 | 1707 |
                     tagHandles = DEFAULT_TAGS;
200 | 1707 |
                     Token token = scanner.peekToken();
201 | 1707 |
                     Mark startMark = token.getStartMark();
202 | 1707 |
                     Mark endMark = startMark;
203 | 1707 |
                     Event event = new DocumentStartEvent(startMark, endMark, false, null, null);
204 |  |
                     // Prepare the next state.
205 | 1707 |
                     states.push(new ParseDocumentEnd());
206 | 1707 |
                     state = new ParseBlockNode();
207 | 1707 |
                     return event;
208 |  |
                 } else {
209 | 1825 |
                     Production p = new ParseDocumentStart();
210 | 1825 |
                     return p.produce();
211 |  |
                 }
212 |  |
             }
213 |  |
         }
214 |  |
215 | 11494 |
         private class ParseDocumentStart implements Production {
216 |  |
             @SuppressWarnings("unchecked")
217 |  |
             public Event produce() {
218 |  |
                 // Parse any extra document end indicators.
219 | 5711 |
                 while (scanner.checkToken(Token.ID.DocumentEnd)) {
220 | 4 |
                     scanner.getToken();
221 |  |
                 }
222 |  |
                 // Parse an explicit document.
223 |  |
                 Event event;
224 | 5707 |
                 if (!scanner.checkToken(Token.ID.StreamEnd)) {
225 | 2301 |
                     Token token = scanner.peekToken();
226 | 2301 |
                     Mark startMark = token.getStartMark();
227 | 2301 |
                     List<Object> version_tags = processDirectives();
228 | 2295 |
                     List<Object> version = (List<Object>) version_tags.get(0);
229 | 2295 |
                     Map<String, String> tags = (Map<String, String>) version_tags.get(1);
230 | 2295 |
                     if (!scanner.checkToken(Token.ID.DocumentStart)) {
231 | 6 |
                         throw new ParserException(null, null, "expected '<document start>', but found "
232 |  |
                                 + scanner.peekToken().getTokenId(), scanner.peekToken().getStartMark());
233 |  |
                     }
234 | 2289 |
                     token = scanner.getToken();
235 | 2289 |
                     Mark endMark = token.getEndMark();
236 |  |
                     Integer[] versionInteger;
237 | 2289 |
                     if (version != null) {
238 | 1615 |
                         versionInteger = new Integer[2];
239 | 1615 |
                         versionInteger = version.toArray(versionInteger);
240 |  |
                     } else {
241 | 674 |
                         versionInteger = null;
242 |  |
                     }
243 | 2289 |
                     event = new DocumentStartEvent(startMark, endMark, true, versionInteger, tags);
244 | 2289 |
                     states.push(new ParseDocumentEnd());
245 | 2289 |
                     state = new ParseDocumentContent();
246 | 2289 |
                 } else {
247 |  |
                     // Parse the end of the stream.
248 | 3406 |
                     StreamEndToken token = (StreamEndToken) scanner.getToken();
249 | 3406 |
                     event = new StreamEndEvent(token.getStartMark(), token.getEndMark());
250 | 3406 |
                     if (!states.isEmpty()) {
251 | 0 |
                         throw new YAMLException("Unexpected end of stream. States left: " + states);
252 |  |
                     }
253 | 3406 |
                     if (!marks.isEmpty()) {
254 | 0 |
                         throw new YAMLException("Unexpected end of stream. Marks left: " + marks);
255 |  |
                     }
256 | 3406 |
                     state = null;
257 |  |
                 }
258 | 5695 |
                 return event;
259 |  |
             }
260 |  |
         }
261 |  |
262 | 7992 |
         private class ParseDocumentEnd implements Production {
263 |  |
             public Event produce() {
264 |  |
                 // Parse the document end.
265 | 3922 |
                 Token token = scanner.peekToken();
266 | 3922 |
                 Mark startMark = token.getStartMark();
267 | 3922 |
                 Mark endMark = startMark;
268 | 3922 |
                 boolean explicit = false;
269 | 3922 |
                 if (scanner.checkToken(Token.ID.DocumentEnd)) {
270 | 122 |
                     token = scanner.getToken();
271 | 122 |
                     endMark = token.getEndMark();
272 | 122 |
                     explicit = true;
273 |  |
                 }
274 | 3922 |
                 Event event = new DocumentEndEvent(startMark, endMark, explicit);
275 |  |
                 // Prepare the next state.
276 | 3922 |
                 state = new ParseDocumentStart();
277 | 3922 |
                 return event;
278 |  |
             }
279 |  |
         }
280 |  |
281 | 4578 |
         private class ParseDocumentContent implements Production {
282 |  |
             public Event produce() {
283 |  |
                 Event event;
284 | 2284 |
                 if (scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart,
285 |  |
                         Token.ID.DocumentEnd, Token.ID.StreamEnd)) {
286 | 21 |
                     event = processEmptyScalar(scanner.peekToken().getStartMark());
287 | 21 |
                     state = states.pop();
288 | 21 |
                     return event;
289 |  |
                 } else {
290 | 2245 |
                     Production p = new ParseBlockNode();
291 | 2245 |
                     return p.produce();
292 |  |
                 }
293 |  |
             }
294 |  |
         }
295 |  |
296 |  |
         @SuppressWarnings("unchecked")
297 |  |
         private List<Object> processDirectives() {
298 | 2301 |
             yamlVersion = null;
299 | 2301 |
             tagHandles = new HashMap<String, String>();
300 | 4065 |
             while (scanner.checkToken(Token.ID.Directive)) {
301 |  |
                 @SuppressWarnings("rawtypes")
302 | 1770 |
                 DirectiveToken token = (DirectiveToken) scanner.getToken();
303 | 1770 |
                 if (token.getName().equals("YAML")) {
304 | 1623 |
                     if (yamlVersion != null) {
305 | 2 |
                         throw new ParserException(null, null, "found duplicate YAML directive",
306 |  |
                                 token.getStartMark());
307 |  |
                     }
308 | 1621 |
                     List<Integer> value = (List<Integer>) token.getValue();
309 | 1621 |
                     Integer major = value.get(0);
310 | 1621 |
                     if (major != 1) {
311 | 2 |
                         throw new ParserException(null, null,
312 |  |
                                 "found incompatible YAML document (version 1.* is required)",
313 |  |
                                 token.getStartMark());
314 |  |
                     }
315 | 1619 |
                     yamlVersion = (List<Integer>) token.getValue();
316 | 1619 |
                 } else if (token.getName().equals("TAG")) {
317 | 143 |
                     List<String> value = (List<String>) token.getValue();
318 | 143 |
                     String handle = value.get(0);
319 | 143 |
                     String prefix = value.get(1);
320 | 143 |
                     if (tagHandles.containsKey(handle)) {
321 | 2 |
                         throw new ParserException(null, null, "duplicate tag handle " + handle,
322 |  |
                                 token.getStartMark());
323 |  |
                     }
324 | 141 |
                     tagHandles.put(handle, prefix);
325 |  |
                 }
326 | 1764 |
             }
327 | 2295 |
             List<Object> value = new ArrayList<Object>(2);
328 | 2295 |
             value.add(yamlVersion);
329 | 2295 |
             if (!tagHandles.isEmpty()) {
330 | 92 |
                 value.add(new HashMap<String, String>(tagHandles));
331 |  |
             } else {
332 | 2203 |
                 value.add(new HashMap<String, String>());
333 |  |
             }
334 | 2295 |
             for (String key : DEFAULT_TAGS.keySet()) {
335 | 4590 |
                 if (!tagHandles.containsKey(key)) {
336 | 4513 |
                     tagHandles.put(key, DEFAULT_TAGS.get(key));
337 |  |
                 }
338 |  |
             }
339 | 2295 |
             return value;
340 |  |
         }
341 |  |
342 |  |
         /**
343 |  |
          * <pre>
344 |  |
          *  block_node_or_indentless_sequence ::= ALIAS
345 |  |
          *                | properties (block_content | indentless_block_sequence)?
346 |  |
          *                | block_content
347 |  |
          *                | indentless_block_sequence
348 |  |
          *  block_node    ::= ALIAS
349 |  |
          *                    | properties block_content?
350 |  |
          *                    | block_content
351 |  |
          *  flow_node     ::= ALIAS
352 |  |
          *                    | properties flow_content?
353 |  |
          *                    | flow_content
354 |  |
          *  properties    ::= TAG ANCHOR? | ANCHOR TAG?
355 |  |
          *  block_content     ::= block_collection | flow_collection | SCALAR
356 |  |
          *  flow_content      ::= flow_collection | SCALAR
357 |  |
          *  block_collection  ::= block_sequence | block_mapping
358 |  |
          *  flow_collection   ::= flow_sequence | flow_mapping
359 |  |
          * </pre>
360 |  |
          */
361 |  |
362 | 236932 |
         private class ParseBlockNode implements Production {
363 |  |
             public Event produce() {
364 | 118464 |
                 return parseNode(true, false);
365 |  |
             }
366 |  |
         }
367 |  |
368 |  |
         private Event parseFlowNode() {
369 | 10995 |
             return parseNode(false, false);
370 |  |
         }
371 |  |
372 |  |
         private Event parseBlockNodeOrIndentlessSequence() {
373 | 270836 |
             return parseNode(true, true);
374 |  |
         }
375 |  |
376 |  |
         private Event parseNode(boolean block, boolean indentlessSequence) {
377 |  |
             Event event;
378 | 400295 |
             Mark startMark = null;
379 | 400295 |
             Mark endMark = null;
380 | 400295 |
             Mark tagMark = null;
381 | 400295 |
             if (scanner.checkToken(Token.ID.Alias)) {
382 | 1414 |
                 AliasToken token = (AliasToken) scanner.getToken();
383 | 1414 |
                 event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark());
384 | 1414 |
                 state = states.pop();
385 | 1414 |
             } else {
386 | 398881 |
                 String anchor = null;
387 | 398881 |
                 TagTuple tagTokenTag = null;
388 | 398881 |
                 if (scanner.checkToken(Token.ID.Anchor)) {
389 | 1349 |
                     AnchorToken token = (AnchorToken) scanner.getToken();
390 | 1349 |
                     startMark = token.getStartMark();
391 | 1349 |
                     endMark = token.getEndMark();
392 | 1349 |
                     anchor = token.getValue();
393 | 1349 |
                     if (scanner.checkToken(Token.ID.Tag)) {
394 | 1242 |
                         TagToken tagToken = (TagToken) scanner.getToken();
395 | 1242 |
                         tagMark = tagToken.getStartMark();
396 | 1242 |
                         endMark = tagToken.getEndMark();
397 | 1242 |
                         tagTokenTag = tagToken.getValue();
398 |  |
                     }
399 | 1349 |
                 } else if (scanner.checkToken(Token.ID.Tag)) {
400 | 10866 |
                     TagToken tagToken = (TagToken) scanner.getToken();
401 | 10866 |
                     startMark = tagToken.getStartMark();
402 | 10866 |
                     tagMark = startMark;
403 | 10866 |
                     endMark = tagToken.getEndMark();
404 | 10866 |
                     tagTokenTag = tagToken.getValue();
405 | 10866 |
                     if (scanner.checkToken(Token.ID.Anchor)) {
406 | 10 |
                         AnchorToken token = (AnchorToken) scanner.getToken();
407 | 10 |
                         endMark = token.getEndMark();
408 | 10 |
                         anchor = token.getValue();
409 |  |
                     }
410 |  |
                 }
411 | 398881 |
                 String tag = null;
412 | 398881 |
                 if (tagTokenTag != null) {
413 | 12108 |
                     String handle = tagTokenTag.getHandle();
414 | 12108 |
                     String suffix = tagTokenTag.getSuffix();
415 | 12108 |
                     if (handle != null) {
416 | 9931 |
                         if (!tagHandles.containsKey(handle)) {
417 | 2 |
                             throw new ParserException("while parsing a node", startMark,
418 |  |
                                     "found undefined tag handle " + handle, tagMark);
419 |  |
                         }
420 | 9929 |
                         tag = tagHandles.get(handle) + suffix;
421 |  |
                     } else {
422 | 2177 |
                         tag = suffix;
423 |  |
                     }
424 |  |
                 }
425 | 398879 |
                 if (startMark == null) {
426 | 386666 |
                     startMark = scanner.peekToken().getStartMark();
427 | 386666 |
                     endMark = startMark;
428 |  |
                 }
429 | 398879 |
                 event = null;
430 | 398879 |
                 boolean implicit = (tag == null || tag.equals("!"));
431 | 398879 |
                 if (indentlessSequence && scanner.checkToken(Token.ID.BlockEntry)) {
432 | 10368 |
                     endMark = scanner.peekToken().getEndMark();
433 | 10368 |
                     event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
434 |  |
                             Boolean.FALSE);
435 | 10368 |
                     state = new ParseIndentlessSequenceEntry();
436 |  |
                 } else {
437 | 388511 |
                     if (scanner.checkToken(Token.ID.Scalar)) {
438 | 361428 |
                         ScalarToken token = (ScalarToken) scanner.getToken();
439 | 361428 |
                         endMark = token.getEndMark();
440 |  |
                         ImplicitTuple implicitValues;
441 | 361428 |
                         if ((token.getPlain() && tag == null) || "!".equals(tag)) {
442 | 153001 |
                             implicitValues = new ImplicitTuple(true, false);
443 | 208427 |
                         } else if (tag == null) {
444 | 202487 |
                             implicitValues = new ImplicitTuple(false, true);
445 |  |
                         } else {
446 | 5940 |
                             implicitValues = new ImplicitTuple(false, false);
447 |  |
                         }
448 | 361428 |
                         event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(),
449 |  |
                                 startMark, endMark, token.getStyle());
450 | 361428 |
                         state = states.pop();
451 | 361428 |
                     } else if (scanner.checkToken(Token.ID.FlowSequenceStart)) {
452 | 1074 |
                         endMark = scanner.peekToken().getEndMark();
453 | 1074 |
                         event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
454 |  |
                                 Boolean.TRUE);
455 | 1074 |
                         state = new ParseFlowSequenceFirstEntry();
456 | 26009 |
                     } else if (scanner.checkToken(Token.ID.FlowMappingStart)) {
457 | 2768 |
                         endMark = scanner.peekToken().getEndMark();
458 | 2768 |
                         event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
459 |  |
                                 Boolean.TRUE);
460 | 2768 |
                         state = new ParseFlowMappingFirstKey();
461 | 23241 |
                     } else if (block && scanner.checkToken(Token.ID.BlockSequenceStart)) {
462 | 562 |
                         endMark = scanner.peekToken().getStartMark();
463 | 562 |
                         event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
464 |  |
                                 Boolean.FALSE);
465 | 562 |
                         state = new ParseBlockSequenceFirstEntry();
466 | 22679 |
                     } else if (block && scanner.checkToken(Token.ID.BlockMappingStart)) {
467 | 22507 |
                         endMark = scanner.peekToken().getStartMark();
468 | 22507 |
                         event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
469 |  |
                                 Boolean.FALSE);
470 | 22507 |
                         state = new ParseBlockMappingFirstKey();
471 | 172 |
                     } else if (anchor != null || tag != null) {
472 |  |
                         // Empty scalars are allowed even if a tag or an anchor is
473 |  |
                         // specified.
474 | 168 |
                         event = new ScalarEvent(anchor, tag, new ImplicitTuple(implicit, false), "",
475 |  |
                                 startMark, endMark, (char) 0);
476 | 168 |
                         state = states.pop();
477 |  |
                     } else {
478 |  |
                         String node;
479 | 4 |
                         if (block) {
480 | 0 |
                             node = "block";
481 |  |
                         } else {
482 | 4 |
                             node = "flow";
483 |  |
                         }
484 | 4 |
                         Token token = scanner.peekToken();
485 | 4 |
                         throw new ParserException("while parsing a " + node + " node", startMark,
486 |  |
                                 "expected the node content, but found " + token.getTokenId(),
487 |  |
                                 token.getStartMark());
488 |  |
                     }
489 |  |
                 }
490 |  |
             }
491 | 400289 |
             return event;
492 |  |
         }
493 |  |
494 |  |
         // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
495 |  |
         // BLOCK-END
496 |  |
497 | 1124 |
         private class ParseBlockSequenceFirstEntry implements Production {
498 |  |
             public Event produce() {
499 | 562 |
                 Token token = scanner.getToken();
500 | 562 |
                 marks.push(token.getStartMark());
501 | 562 |
                 return new ParseBlockSequenceEntry().produce();
502 |  |
             }
503 |  |
         }
504 |  |
505 | 14878 |
         private class ParseBlockSequenceEntry implements Production {
506 |  |
             public Event produce() {
507 | 14308 |
                 if (scanner.checkToken(Token.ID.BlockEntry)) {
508 | 13762 |
                     BlockEntryToken token = (BlockEntryToken) scanner.getToken();
509 | 13762 |
                     if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.BlockEnd)) {
510 | 13743 |
                         states.push(new ParseBlockSequenceEntry());
511 | 13743 |
                         return new ParseBlockNode().produce();
512 |  |
                     } else {
513 | 11 |
                         state = new ParseBlockSequenceEntry();
514 | 11 |
                         return processEmptyScalar(token.getEndMark());
515 |  |
                     }
516 |  |
                 }
517 | 546 |
                 if (!scanner.checkToken(Token.ID.BlockEnd)) {
518 | 4 |
                     Token token = scanner.peekToken();
519 | 4 |
                     throw new ParserException("while parsing a block collection", marks.pop(),
520 |  |
                             "expected <block end>, but found " + token.getTokenId(),
521 |  |
                             token.getStartMark());
522 |  |
                 }
523 | 542 |
                 Token token = scanner.getToken();
524 | 542 |
                 Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
525 | 542 |
                 state = states.pop();
526 | 542 |
                 marks.pop();
527 | 542 |
                 return event;
528 |  |
             }
529 |  |
         }
530 |  |
531 |  |
         // indentless_sequence ::= (BLOCK-ENTRY block_node?)+
532 |  |
533 | 121507 |
         private class ParseIndentlessSequenceEntry implements Production {
534 |  |
             public Event produce() {
535 | 111139 |
                 if (scanner.checkToken(Token.ID.BlockEntry)) {
536 | 100771 |
                     Token token = scanner.getToken();
537 | 100771 |
                     if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.Key, Token.ID.Value,
538 |  |
                             Token.ID.BlockEnd)) {
539 | 100771 |
                         states.push(new ParseIndentlessSequenceEntry());
540 | 100771 |
                         return new ParseBlockNode().produce();
541 |  |
                     } else {
542 | 0 |
                         state = new ParseIndentlessSequenceEntry();
543 | 0 |
                         return processEmptyScalar(token.getEndMark());
544 |  |
                     }
545 |  |
                 }
546 | 10368 |
                 Token token = scanner.peekToken();
547 | 10368 |
                 Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
548 | 10368 |
                 state = states.pop();
549 | 10368 |
                 return event;
550 |  |
             }
551 |  |
         }
552 |  |
553 | 45014 |
         private class ParseBlockMappingFirstKey implements Production {
554 |  |
             public Event produce() {
555 | 22507 |
                 Token token = scanner.getToken();
556 | 22507 |
                 marks.push(token.getStartMark());
557 | 22507 |
                 return new ParseBlockMappingKey().produce();
558 |  |
             }
559 |  |
         }
560 |  |
561 | 315952 |
         private class ParseBlockMappingKey implements Production {
562 |  |
             public Event produce() {
563 | 157973 |
                 if (scanner.checkToken(Token.ID.Key)) {
564 | 135473 |
                     Token token = scanner.getToken();
565 | 135473 |
                     if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
566 | 135466 |
                         states.push(new ParseBlockMappingValue());
567 | 135466 |
                         return parseBlockNodeOrIndentlessSequence();
568 |  |
                     } else {
569 | 7 |
                         state = new ParseBlockMappingValue();
570 | 7 |
                         return processEmptyScalar(token.getEndMark());
571 |  |
                     }
572 |  |
                 }
573 | 22494 |
                 if (!scanner.checkToken(Token.ID.BlockEnd)) {
574 | 6 |
                     Token token = scanner.peekToken();
575 | 6 |
                     throw new ParserException("while parsing a block mapping", marks.pop(),
576 |  |
                             "expected <block end>, but found " + token.getTokenId(),
577 |  |
                             token.getStartMark());
578 |  |
                 }
579 | 22488 |
                 Token token = scanner.getToken();
580 | 22488 |
                 Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
581 | 22488 |
                 state = states.pop();
582 | 22488 |
                 marks.pop();
583 | 22488 |
                 return event;
584 |  |
             }
585 |  |
         }
586 |  |
587 | 270946 |
         private class ParseBlockMappingValue implements Production {
588 |  |
             public Event produce() {
589 | 135473 |
                 if (scanner.checkToken(Token.ID.Value)) {
590 | 135457 |
                     Token token = scanner.getToken();
591 | 135457 |
                     if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
592 | 135370 |
                         states.push(new ParseBlockMappingKey());
593 | 135370 |
                         return parseBlockNodeOrIndentlessSequence();
594 |  |
                     } else {
595 | 83 |
                         state = new ParseBlockMappingKey();
596 | 83 |
                         return processEmptyScalar(token.getEndMark());
597 |  |
                     }
598 |  |
                 }
599 | 16 |
                 state = new ParseBlockMappingKey();
600 | 16 |
                 Token token = scanner.peekToken();
601 | 16 |
                 return processEmptyScalar(token.getStartMark());
602 |  |
             }
603 |  |
         }
604 |  |
605 |  |
         /**
606 |  |
          * <pre>
607 |  |
          * flow_sequence     ::= FLOW-SEQUENCE-START
608 |  |
          *                       (flow_sequence_entry FLOW-ENTRY)*
609 |  |
          *                       flow_sequence_entry?
610 |  |
          *                       FLOW-SEQUENCE-END
611 |  |
          * flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
612 |  |
          * Note that while production rules for both flow_sequence_entry and
613 |  |
          * flow_mapping_entry are equal, their interpretations are different.
614 |  |
          * For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
615 |  |
          * generate an inline mapping (set syntax).
616 |  |
          * </pre>
617 |  |
          */
618 | 2148 |
         private class ParseFlowSequenceFirstEntry implements Production {
619 |  |
             public Event produce() {
620 | 1074 |
                 Token token = scanner.getToken();
621 | 1074 |
                 marks.push(token.getStartMark());
622 | 1074 |
                 return new ParseFlowSequenceEntry(true).produce();
623 |  |
             }
624 |  |
         }
625 |  |
626 |  |
         private class ParseFlowSequenceEntry implements Production {
627 | 3714 |
             private boolean first = false;
628 |  |
629 | 3714 |
             public ParseFlowSequenceEntry(boolean first) {
630 | 3714 |
                 this.first = first;
631 | 3714 |
             }
632 |  |
633 |  |
             public Event produce() {
634 | 3707 |
                 if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
635 | 2786 |
                     if (!first) {
636 | 1883 |
                         if (scanner.checkToken(Token.ID.FlowEntry)) {
637 | 1877 |
                             scanner.getToken();
638 |  |
                         } else {
639 | 6 |
                             Token token = scanner.peekToken();
640 | 6 |
                             throw new ParserException("while parsing a flow sequence", marks.pop(),
641 |  |
                                     "expected ',' or ']', but got " + token.getTokenId(),
642 |  |
                                     token.getStartMark());
643 |  |
                         }
644 |  |
                     }
645 | 2780 |
                     if (scanner.checkToken(Token.ID.Key)) {
646 | 41 |
                         Token token = scanner.peekToken();
647 | 41 |
                         Event event = new MappingStartEvent(null, null, true, token.getStartMark(),
648 |  |
                                 token.getEndMark(), Boolean.TRUE);
649 | 41 |
                         state = new ParseFlowSequenceEntryMappingKey();
650 | 41 |
                         return event;
651 | 2739 |
                     } else if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
652 | 2599 |
                         states.push(new ParseFlowSequenceEntry(false));
653 | 2599 |
                         return parseFlowNode();
654 |  |
                     }
655 |  |
                 }
656 | 1061 |
                 Token token = scanner.getToken();
657 | 1061 |
                 Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
658 | 1061 |
                 state = states.pop();
659 | 1061 |
                 marks.pop();
660 | 1061 |
                 return event;
661 |  |
             }
662 |  |
         }
663 |  |
664 | 82 |
         private class ParseFlowSequenceEntryMappingKey implements Production {
665 |  |
             public Event produce() {
666 | 41 |
                 Token token = scanner.getToken();
667 | 41 |
                 if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
668 | 41 |
                     states.push(new ParseFlowSequenceEntryMappingValue());
669 | 41 |
                     return parseFlowNode();
670 |  |
                 } else {
671 | 0 |
                     state = new ParseFlowSequenceEntryMappingValue();
672 | 0 |
                     return processEmptyScalar(token.getEndMark());
673 |  |
                 }
674 |  |
             }
675 |  |
         }
676 |  |
677 | 82 |
         private class ParseFlowSequenceEntryMappingValue implements Production {
678 |  |
             public Event produce() {
679 | 41 |
                 if (scanner.checkToken(Token.ID.Value)) {
680 | 37 |
                     Token token = scanner.getToken();
681 | 37 |
                     if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
682 | 29 |
                         states.push(new ParseFlowSequenceEntryMappingEnd());
683 | 29 |
                         return parseFlowNode();
684 |  |
                     } else {
685 | 8 |
                         state = new ParseFlowSequenceEntryMappingEnd();
686 | 8 |
                         return processEmptyScalar(token.getEndMark());
687 |  |
                     }
688 |  |
                 } else {
689 | 4 |
                     state = new ParseFlowSequenceEntryMappingEnd();
690 | 4 |
                     Token token = scanner.peekToken();
691 | 4 |
                     return processEmptyScalar(token.getStartMark());
692 |  |
                 }
693 |  |
             }
694 |  |
         }
695 |  |
696 | 82 |
         private class ParseFlowSequenceEntryMappingEnd implements Production {
697 |  |
             public Event produce() {
698 | 41 |
                 state = new ParseFlowSequenceEntry(false);
699 | 41 |
                 Token token = scanner.peekToken();
700 | 41 |
                 return new MappingEndEvent(token.getStartMark(), token.getEndMark());
701 |  |
             }
702 |  |
         }
703 |  |
704 |  |
         /**
705 |  |
          * <pre>
706 |  |
          *   flow_mapping  ::= FLOW-MAPPING-START
707 |  |
          *          (flow_mapping_entry FLOW-ENTRY)*
708 |  |
          *          flow_mapping_entry?
709 |  |
          *          FLOW-MAPPING-END
710 |  |
          *   flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?
711 |  |
          * </pre>
712 |  |
          */
713 | 5536 |
         private class ParseFlowMappingFirstKey implements Production {
714 |  |
             public Event produce() {
715 | 2768 |
                 Token token = scanner.getToken();
716 | 2768 |
                 marks.push(token.getStartMark());
717 | 2768 |
                 return new ParseFlowMappingKey(true).produce();
718 |  |
             }
719 |  |
         }
720 |  |
721 |  |
         private class ParseFlowMappingKey implements Production {
722 | 6953 |
             private boolean first = false;
723 |  |
724 | 6953 |
             public ParseFlowMappingKey(boolean first) {
725 | 6953 |
                 this.first = first;
726 | 6953 |
             }
727 |  |
728 |  |
             public Event produce() {
729 | 6953 |
                 if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
730 | 4352 |
                     if (!first) {
731 | 1632 |
                         if (scanner.checkToken(Token.ID.FlowEntry)) {
732 | 1629 |
                             scanner.getToken();
733 |  |
                         } else {
734 | 3 |
                             Token token = scanner.peekToken();
735 | 3 |
                             throw new ParserException("while parsing a flow mapping", marks.pop(),
736 |  |
                                     "expected ',' or '}', but got " + token.getTokenId(),
737 |  |
                                     token.getStartMark());
738 |  |
                         }
739 |  |
                     }
740 | 4349 |
                     if (scanner.checkToken(Token.ID.Key)) {
741 | 4168 |
                         Token token = scanner.getToken();
742 | 4168 |
                         if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry,
743 |  |
                                 Token.ID.FlowMappingEnd)) {
744 | 4160 |
                             states.push(new ParseFlowMappingValue());
745 | 4160 |
                             return parseFlowNode();
746 |  |
                         } else {
747 | 8 |
                             state = new ParseFlowMappingValue();
748 | 8 |
                             return processEmptyScalar(token.getEndMark());
749 |  |
                         }
750 | 181 |
                     } else if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
751 | 18 |
                         states.push(new ParseFlowMappingEmptyValue());
752 | 18 |
                         return parseFlowNode();
753 |  |
                     }
754 |  |
                 }
755 | 2764 |
                 Token token = scanner.getToken();
756 | 2764 |
                 Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
757 | 2764 |
                 state = states.pop();
758 | 2764 |
                 marks.pop();
759 | 2764 |
                 return event;
760 |  |
             }
761 |  |
         }
762 |  |
763 | 8336 |
         private class ParseFlowMappingValue implements Production {
764 |  |
             public Event produce() {
765 | 4168 |
                 if (scanner.checkToken(Token.ID.Value)) {
766 | 4164 |
                     Token token = scanner.getToken();
767 | 4164 |
                     if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowMappingEnd)) {
768 | 4148 |
                         states.push(new ParseFlowMappingKey(false));
769 | 4148 |
                         return parseFlowNode();
770 |  |
                     } else {
771 | 16 |
                         state = new ParseFlowMappingKey(false);
772 | 16 |
                         return processEmptyScalar(token.getEndMark());
773 |  |
                     }
774 |  |
                 } else {
775 | 4 |
                     state = new ParseFlowMappingKey(false);
776 | 4 |
                     Token token = scanner.peekToken();
777 | 4 |
                     return processEmptyScalar(token.getStartMark());
778 |  |
                 }
779 |  |
             }
780 |  |
         }
781 |  |
782 | 36 |
         private class ParseFlowMappingEmptyValue implements Production {
783 |  |
             public Event produce() {
784 | 17 |
                 state = new ParseFlowMappingKey(false);
785 | 17 |
                 return processEmptyScalar(scanner.peekToken().getStartMark());
786 |  |
             }
787 |  |
         }
788 |  |
789 |  |
         /**
790 |  |
          * <pre>
791 |  |
          * block_mapping     ::= BLOCK-MAPPING_START
792 |  |
          *           ((KEY block_node_or_indentless_sequence?)?
793 |  |
          *           (VALUE block_node_or_indentless_sequence?)?)*
794 |  |
          *           BLOCK-END
795 |  |
          * </pre>
796 |  |
          */
797 |  |
         private Event processEmptyScalar(Mark mark) {
798 | 195 |
             return new ScalarEvent(null, null, new ImplicitTuple(true, false), "", mark, mark, (char) 0);
799 |  |
         }
800 |  |
     }