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