source: pyyaml/trunk/lib/yaml/parser.py @ 302

Revision 302, 24.8 KB checked in by xi, 6 years ago (diff)

Removed a stale comment; fixes #102.

RevLine 
[43]1
[198]2# The following YAML grammar is LL(1) and is parsed by a recursive descent
3# parser.
[51]4#
[118]5# stream            ::= STREAM-START implicit_document? explicit_document* STREAM-END
[198]6# implicit_document ::= block_node DOCUMENT-END*
7# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
8# block_node_or_indentless_sequence ::=
9#                       ALIAS
10#                       | properties (block_content | indentless_block_sequence)?
11#                       | block_content
12#                       | indentless_block_sequence
13# block_node        ::= ALIAS
14#                       | properties block_content?
15#                       | block_content
16# flow_node         ::= ALIAS
17#                       | properties flow_content?
18#                       | flow_content
19# properties        ::= TAG ANCHOR? | ANCHOR TAG?
[43]20# block_content     ::= block_collection | flow_collection | SCALAR
21# flow_content      ::= flow_collection | SCALAR
22# block_collection  ::= block_sequence | block_mapping
[198]23# flow_collection   ::= flow_sequence | flow_mapping
[51]24# block_sequence    ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
[198]25# indentless_sequence   ::= (BLOCK-ENTRY block_node?)+
26# block_mapping     ::= BLOCK-MAPPING_START
27#                       ((KEY block_node_or_indentless_sequence?)?
28#                       (VALUE block_node_or_indentless_sequence?)?)*
29#                       BLOCK-END
30# flow_sequence     ::= FLOW-SEQUENCE-START
31#                       (flow_sequence_entry FLOW-ENTRY)*
32#                       flow_sequence_entry?
33#                       FLOW-SEQUENCE-END
[51]34# flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
[198]35# flow_mapping      ::= FLOW-MAPPING-START
36#                       (flow_mapping_entry FLOW-ENTRY)*
37#                       flow_mapping_entry?
38#                       FLOW-MAPPING-END
[51]39# flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?
[198]40#
[51]41# FIRST sets:
[198]42#
[118]43# stream: { STREAM-START }
[43]44# explicit_document: { DIRECTIVE DOCUMENT-START }
[51]45# implicit_document: FIRST(block_node)
[43]46# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
47# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
48# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
49# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
50# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
51# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
52# block_sequence: { BLOCK-SEQUENCE-START }
53# block_mapping: { BLOCK-MAPPING-START }
[51]54# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
[43]55# indentless_sequence: { ENTRY }
56# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
57# flow_sequence: { FLOW-SEQUENCE-START }
58# flow_mapping: { FLOW-MAPPING-START }
59# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
60# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
61
[57]62__all__ = ['Parser', 'ParserError']
63
[52]64from error import MarkedYAMLError
[46]65from tokens import *
[51]66from events import *
[136]67from scanner import *
[44]68
[52]69class ParserError(MarkedYAMLError):
70    pass
[44]71
[222]72class Parser(object):
[136]73    # Since writing a recursive-descendant parser is a straightforward task, we
74    # do not give many comments here.
[44]75
[51]76    DEFAULT_TAGS = {
77        u'!':   u'!',
78        u'!!':  u'tag:yaml.org,2002:',
79    }
[44]80
[136]81    def __init__(self):
[51]82        self.current_event = None
83        self.yaml_version = None
84        self.tag_handles = {}
[198]85        self.states = []
86        self.marks = []
87        self.state = self.parse_stream_start
[43]88
[136]89    def check_event(self, *choices):
[51]90        # Check the type of the next event.
91        if self.current_event is None:
[198]92            if self.state:
93                self.current_event = self.state()
[51]94        if self.current_event is not None:
[136]95            if not choices:
96                return True
[51]97            for choice in choices:
98                if isinstance(self.current_event, choice):
99                    return True
[44]100        return False
101
[136]102    def peek_event(self):
[53]103        # Get the next event.
104        if self.current_event is None:
[198]105            if self.state:
106                self.current_event = self.state()
[53]107        return self.current_event
108
[136]109    def get_event(self):
[198]110        # Get the next event and proceed further.
[51]111        if self.current_event is None:
[198]112            if self.state:
113                self.current_event = self.state()
[51]114        value = self.current_event
115        self.current_event = None
116        return value
[44]117
[198]118    # stream    ::= STREAM-START implicit_document? explicit_document* STREAM-END
119    # implicit_document ::= block_node DOCUMENT-END*
120    # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
[44]121
[198]122    def parse_stream_start(self):
[51]123
[198]124        # Parse the stream start.
[136]125        token = self.get_token()
[198]126        event = StreamStartEvent(token.start_mark, token.end_mark,
[130]127                encoding=token.encoding)
[118]128
[198]129        # Prepare the next state.
130        self.state = self.parse_implicit_document_start
131
132        return event
133
134    def parse_implicit_document_start(self):
135
136        # Parse an implicit document.
[136]137        if not self.check_token(DirectiveToken, DocumentStartToken,
[51]138                StreamEndToken):
139            self.tag_handles = self.DEFAULT_TAGS
[136]140            token = self.peek_token()
[118]141            start_mark = end_mark = token.start_mark
[198]142            event = DocumentStartEvent(start_mark, end_mark,
[132]143                    explicit=False)
[51]144
[198]145            # Prepare the next state.
146            self.states.append(self.parse_document_end)
147            self.state = self.parse_block_node
148
149            return event
150
151        else:
152            return self.parse_document_start()
153
154    def parse_document_start(self):
155
[249]156        # Parse any extra document end indicators.
157        while self.check_token(DocumentEndToken):
158            self.get_token()
159
[198]160        # Parse an explicit document.
161        if not self.check_token(StreamEndToken):
[136]162            token = self.peek_token()
[118]163            start_mark = token.start_mark
[130]164            version, tags = self.process_directives()
[136]165            if not self.check_token(DocumentStartToken):
[51]166                raise ParserError(None, None,
167                        "expected '<document start>', but found %r"
[136]168                        % self.peek_token().id,
169                        self.peek_token().start_mark)
170            token = self.get_token()
[118]171            end_mark = token.end_mark
[198]172            event = DocumentStartEvent(start_mark, end_mark,
[132]173                    explicit=True, version=version, tags=tags)
[198]174            self.states.append(self.parse_document_end)
175            self.state = self.parse_document_content
176        else:
177            # Parse the end of the stream.
178            token = self.get_token()
179            event = StreamEndEvent(token.start_mark, token.end_mark)
180            assert not self.states
181            assert not self.marks
182            self.state = None
183        return event
[43]184
[198]185    def parse_document_end(self):
[51]186
[198]187        # Parse the document end.
188        token = self.peek_token()
189        start_mark = end_mark = token.start_mark
190        explicit = False
[249]191        if self.check_token(DocumentEndToken):
[198]192            token = self.get_token()
193            end_mark = token.end_mark
194            explicit = True
195        event = DocumentEndEvent(start_mark, end_mark,
196                explicit=explicit)
197
198        # Prepare the next state.
199        self.state = self.parse_document_start
200
201        return event
202
203    def parse_document_content(self):
204        if self.check_token(DirectiveToken,
205                DocumentStartToken, DocumentEndToken, StreamEndToken):
206            event = self.process_empty_scalar(self.peek_token().start_mark)
207            self.state = self.states.pop()
208            return event
209        else:
210            return self.parse_block_node()
211
[51]212    def process_directives(self):
213        self.yaml_version = None
214        self.tag_handles = {}
[136]215        while self.check_token(DirectiveToken):
216            token = self.get_token()
[51]217            if token.name == u'YAML':
218                if self.yaml_version is not None:
219                    raise ParserError(None, None,
[116]220                            "found duplicate YAML directive", token.start_mark)
[51]221                major, minor = token.value
222                if major != 1:
223                    raise ParserError(None, None,
224                            "found incompatible YAML document (version 1.* is required)",
[116]225                            token.start_mark)
[51]226                self.yaml_version = token.value
227            elif token.name == u'TAG':
228                handle, prefix = token.value
229                if handle in self.tag_handles:
230                    raise ParserError(None, None,
231                            "duplicate tag handle %r" % handle.encode('utf-8'),
[116]232                            token.start_mark)
[51]233                self.tag_handles[handle] = prefix
[130]234        if self.tag_handles:
235            value = self.yaml_version, self.tag_handles.copy()
236        else:
237            value = self.yaml_version, None
[51]238        for key in self.DEFAULT_TAGS:
239            if key not in self.tag_handles:
240                self.tag_handles[key] = self.DEFAULT_TAGS[key]
[130]241        return value
[51]242
[198]243    # block_node_or_indentless_sequence ::= ALIAS
244    #               | properties (block_content | indentless_block_sequence)?
245    #               | block_content
246    #               | indentless_block_sequence
247    # block_node    ::= ALIAS
248    #                   | properties block_content?
249    #                   | block_content
250    # flow_node     ::= ALIAS
251    #                   | properties flow_content?
252    #                   | flow_content
253    # properties    ::= TAG ANCHOR? | ANCHOR TAG?
254    # block_content     ::= block_collection | flow_collection | SCALAR
255    # flow_content      ::= flow_collection | SCALAR
256    # block_collection  ::= block_sequence | block_mapping
257    # flow_collection   ::= flow_sequence | flow_mapping
258
[43]259    def parse_block_node(self):
[44]260        return self.parse_node(block=True)
[43]261
262    def parse_flow_node(self):
[44]263        return self.parse_node()
[43]264
265    def parse_block_node_or_indentless_sequence(self):
[44]266        return self.parse_node(block=True, indentless_sequence=True)
[43]267
[44]268    def parse_node(self, block=False, indentless_sequence=False):
[136]269        if self.check_token(AliasToken):
270            token = self.get_token()
[198]271            event = AliasEvent(token.value, token.start_mark, token.end_mark)
272            self.state = self.states.pop()
[44]273        else:
[51]274            anchor = None
275            tag = None
[116]276            start_mark = end_mark = tag_mark = None
[136]277            if self.check_token(AnchorToken):
278                token = self.get_token()
[130]279                start_mark = token.start_mark
280                end_mark = token.end_mark
[51]281                anchor = token.value
[136]282                if self.check_token(TagToken):
283                    token = self.get_token()
[130]284                    tag_mark = token.start_mark
285                    end_mark = token.end_mark
[51]286                    tag = token.value
[136]287            elif self.check_token(TagToken):
288                token = self.get_token()
[130]289                start_mark = tag_mark = token.start_mark
290                end_mark = token.end_mark
[51]291                tag = token.value
[136]292                if self.check_token(AnchorToken):
293                    token = self.get_token()
[130]294                    end_mark = token.end_mark
[51]295                    anchor = token.value
[235]296            if tag is not None:
[51]297                handle, suffix = tag
298                if handle is not None:
299                    if handle not in self.tag_handles:
[116]300                        raise ParserError("while parsing a node", start_mark,
[51]301                                "found undefined tag handle %r" % handle.encode('utf-8'),
[116]302                                tag_mark)
[51]303                    tag = self.tag_handles[handle]+suffix
304                else:
305                    tag = suffix
[136]306            #if tag == u'!':
307            #    raise ParserError("while parsing a node", start_mark,
308            #            "found non-specific tag '!'", tag_mark,
309            #            "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")
[116]310            if start_mark is None:
[136]311                start_mark = end_mark = self.peek_token().start_mark
[51]312            event = None
[137]313            implicit = (tag is None or tag == u'!')
[136]314            if indentless_sequence and self.check_token(BlockEntryToken):
315                end_mark = self.peek_token().end_mark
[137]316                event = SequenceStartEvent(anchor, tag, implicit,
317                        start_mark, end_mark)
[198]318                self.state = self.parse_indentless_sequence_entry
[44]319            else:
[136]320                if self.check_token(ScalarToken):
321                    token = self.get_token()
[116]322                    end_mark = token.end_mark
[137]323                    if (token.plain and tag is None) or tag == u'!':
324                        implicit = (True, False)
325                    elif tag is None:
326                        implicit = (False, True)
327                    else:
328                        implicit = (False, False)
[136]329                    event = ScalarEvent(anchor, tag, implicit, token.value,
330                            start_mark, end_mark, style=token.style)
[198]331                    self.state = self.states.pop()
[136]332                elif self.check_token(FlowSequenceStartToken):
333                    end_mark = self.peek_token().end_mark
[137]334                    event = SequenceStartEvent(anchor, tag, implicit,
335                            start_mark, end_mark, flow_style=True)
[198]336                    self.state = self.parse_flow_sequence_first_entry
[136]337                elif self.check_token(FlowMappingStartToken):
338                    end_mark = self.peek_token().end_mark
[137]339                    event = MappingStartEvent(anchor, tag, implicit,
340                            start_mark, end_mark, flow_style=True)
[198]341                    self.state = self.parse_flow_mapping_first_key
[136]342                elif block and self.check_token(BlockSequenceStartToken):
343                    end_mark = self.peek_token().start_mark
[137]344                    event = SequenceStartEvent(anchor, tag, implicit,
345                            start_mark, end_mark, flow_style=False)
[198]346                    self.state = self.parse_block_sequence_first_entry
[136]347                elif block and self.check_token(BlockMappingStartToken):
348                    end_mark = self.peek_token().start_mark
[137]349                    event = MappingStartEvent(anchor, tag, implicit,
350                            start_mark, end_mark, flow_style=False)
[198]351                    self.state = self.parse_block_mapping_first_key
[130]352                elif anchor is not None or tag is not None:
353                    # Empty scalars are allowed even if a tag or an anchor is
354                    # specified.
[137]355                    event = ScalarEvent(anchor, tag, (implicit, False), u'',
[136]356                            start_mark, end_mark)
[198]357                    self.state = self.states.pop()
[51]358                else:
359                    if block:
360                        node = 'block'
361                    else:
362                        node = 'flow'
[136]363                    token = self.peek_token()
[204]364                    raise ParserError("while parsing a %s node" % node, start_mark,
[51]365                            "expected the node content, but found %r" % token.id,
[116]366                            token.start_mark)
[198]367        return event
[44]368
[198]369    # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
370
371    def parse_block_sequence_first_entry(self):
[136]372        token = self.get_token()
[198]373        self.marks.append(token.start_mark)
374        return self.parse_block_sequence_entry()
375
376    def parse_block_sequence_entry(self):
377        if self.check_token(BlockEntryToken):
[136]378            token = self.get_token()
379            if not self.check_token(BlockEntryToken, BlockEndToken):
[198]380                self.states.append(self.parse_block_sequence_entry)
381                return self.parse_block_node()
[43]382            else:
[198]383                self.state = self.parse_block_sequence_entry
384                return self.process_empty_scalar(token.end_mark)
[136]385        if not self.check_token(BlockEndToken):
386            token = self.peek_token()
[204]387            raise ParserError("while parsing a block collection", self.marks[-1],
[116]388                    "expected <block end>, but found %r" % token.id, token.start_mark)
[136]389        token = self.get_token()
[198]390        event = SequenceEndEvent(token.start_mark, token.end_mark)
391        self.state = self.states.pop()
392        self.marks.pop()
393        return event
[43]394
[198]395    # indentless_sequence ::= (BLOCK-ENTRY block_node?)+
396
397    def parse_indentless_sequence_entry(self):
398        if self.check_token(BlockEntryToken):
[136]399            token = self.get_token()
400            if not self.check_token(BlockEntryToken,
[51]401                    KeyToken, ValueToken, BlockEndToken):
[198]402                self.states.append(self.parse_indentless_sequence_entry)
403                return self.parse_block_node()
[43]404            else:
[198]405                self.state = self.parse_indentless_sequence_entry
406                return self.process_empty_scalar(token.end_mark)
[136]407        token = self.peek_token()
[198]408        event = SequenceEndEvent(token.start_mark, token.start_mark)
409        self.state = self.states.pop()
410        return event
[43]411
[198]412    # block_mapping     ::= BLOCK-MAPPING_START
413    #                       ((KEY block_node_or_indentless_sequence?)?
414    #                       (VALUE block_node_or_indentless_sequence?)?)*
415    #                       BLOCK-END
416
417    def parse_block_mapping_first_key(self):
[136]418        token = self.get_token()
[198]419        self.marks.append(token.start_mark)
420        return self.parse_block_mapping_key()
421
422    def parse_block_mapping_key(self):
423        if self.check_token(KeyToken):
424            token = self.get_token()
425            if not self.check_token(KeyToken, ValueToken, BlockEndToken):
426                self.states.append(self.parse_block_mapping_value)
427                return self.parse_block_node_or_indentless_sequence()
[51]428            else:
[198]429                self.state = self.parse_block_mapping_value
430                return self.process_empty_scalar(token.end_mark)
[136]431        if not self.check_token(BlockEndToken):
432            token = self.peek_token()
[204]433            raise ParserError("while parsing a block mapping", self.marks[-1],
[116]434                    "expected <block end>, but found %r" % token.id, token.start_mark)
[136]435        token = self.get_token()
[198]436        event = MappingEndEvent(token.start_mark, token.end_mark)
437        self.state = self.states.pop()
438        self.marks.pop()
439        return event
[43]440
[198]441    def parse_block_mapping_value(self):
442        if self.check_token(ValueToken):
443            token = self.get_token()
444            if not self.check_token(KeyToken, ValueToken, BlockEndToken):
445                self.states.append(self.parse_block_mapping_key)
446                return self.parse_block_node_or_indentless_sequence()
447            else:
448                self.state = self.parse_block_mapping_key
449                return self.process_empty_scalar(token.end_mark)
450        else:
451            self.state = self.parse_block_mapping_key
452            token = self.peek_token()
453            return self.process_empty_scalar(token.start_mark)
454
455    # flow_sequence     ::= FLOW-SEQUENCE-START
456    #                       (flow_sequence_entry FLOW-ENTRY)*
457    #                       flow_sequence_entry?
458    #                       FLOW-SEQUENCE-END
459    # flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
460    #
461    # Note that while production rules for both flow_sequence_entry and
462    # flow_mapping_entry are equal, their interpretations are different.
463    # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
464    # generate an inline mapping (set syntax).
465
466    def parse_flow_sequence_first_entry(self):
[136]467        token = self.get_token()
[198]468        self.marks.append(token.start_mark)
469        return self.parse_flow_sequence_entry(first=True)
470
471    def parse_flow_sequence_entry(self, first=False):
472        if not self.check_token(FlowSequenceEndToken):
473            if not first:
474                if self.check_token(FlowEntryToken):
475                    self.get_token()
476                else:
477                    token = self.peek_token()
[204]478                    raise ParserError("while parsing a flow sequence", self.marks[-1],
[198]479                            "expected ',' or ']', but got %r" % token.id, token.start_mark)
480           
[136]481            if self.check_token(KeyToken):
[204]482                token = self.peek_token()
[198]483                event = MappingStartEvent(None, None, True,
[130]484                        token.start_mark, token.end_mark,
485                        flow_style=True)
[198]486                self.state = self.parse_flow_sequence_entry_mapping_key
487                return event
488            elif not self.check_token(FlowSequenceEndToken):
489                self.states.append(self.parse_flow_sequence_entry)
490                return self.parse_flow_node()
491        token = self.get_token()
492        event = SequenceEndEvent(token.start_mark, token.end_mark)
493        self.state = self.states.pop()
494        self.marks.pop()
495        return event
496
497    def parse_flow_sequence_entry_mapping_key(self):
[204]498        token = self.get_token()
[198]499        if not self.check_token(ValueToken,
500                FlowEntryToken, FlowSequenceEndToken):
501            self.states.append(self.parse_flow_sequence_entry_mapping_value)
502            return self.parse_flow_node()
503        else:
504            self.state = self.parse_flow_sequence_entry_mapping_value
505            return self.process_empty_scalar(token.end_mark)
506
507    def parse_flow_sequence_entry_mapping_value(self):
508        if self.check_token(ValueToken):
509            token = self.get_token()
510            if not self.check_token(FlowEntryToken, FlowSequenceEndToken):
511                self.states.append(self.parse_flow_sequence_entry_mapping_end)
512                return self.parse_flow_node()
[43]513            else:
[198]514                self.state = self.parse_flow_sequence_entry_mapping_end
515                return self.process_empty_scalar(token.end_mark)
516        else:
517            self.state = self.parse_flow_sequence_entry_mapping_end
518            token = self.peek_token()
519            return self.process_empty_scalar(token.start_mark)
520
521    def parse_flow_sequence_entry_mapping_end(self):
522        self.state = self.parse_flow_sequence_entry
523        token = self.peek_token()
524        return MappingEndEvent(token.start_mark, token.start_mark)
525
526    # flow_mapping  ::= FLOW-MAPPING-START
527    #                   (flow_mapping_entry FLOW-ENTRY)*
528    #                   flow_mapping_entry?
529    #                   FLOW-MAPPING-END
530    # flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?
531
532    def parse_flow_mapping_first_key(self):
[136]533        token = self.get_token()
[198]534        self.marks.append(token.start_mark)
535        return self.parse_flow_mapping_key(first=True)
[43]536
[198]537    def parse_flow_mapping_key(self, first=False):
538        if not self.check_token(FlowMappingEndToken):
539            if not first:
540                if self.check_token(FlowEntryToken):
541                    self.get_token()
542                else:
543                    token = self.peek_token()
[204]544                    raise ParserError("while parsing a flow mapping", self.marks[-1],
[198]545                            "expected ',' or '}', but got %r" % token.id, token.start_mark)
[136]546            if self.check_token(KeyToken):
547                token = self.get_token()
548                if not self.check_token(ValueToken,
[51]549                        FlowEntryToken, FlowMappingEndToken):
[198]550                    self.states.append(self.parse_flow_mapping_value)
551                    return self.parse_flow_node()
[51]552                else:
[198]553                    self.state = self.parse_flow_mapping_value
554                    return self.process_empty_scalar(token.end_mark)
555            elif not self.check_token(FlowMappingEndToken):
556                self.states.append(self.parse_flow_mapping_empty_value)
557                return self.parse_flow_node()
558        token = self.get_token()
559        event = MappingEndEvent(token.start_mark, token.end_mark)
560        self.state = self.states.pop()
561        self.marks.pop()
562        return event
563
564    def parse_flow_mapping_value(self):
565        if self.check_token(ValueToken):
566            token = self.get_token()
567            if not self.check_token(FlowEntryToken, FlowMappingEndToken):
568                self.states.append(self.parse_flow_mapping_key)
569                return self.parse_flow_node()
[43]570            else:
[198]571                self.state = self.parse_flow_mapping_key
572                return self.process_empty_scalar(token.end_mark)
573        else:
574            self.state = self.parse_flow_mapping_key
[136]575            token = self.peek_token()
[198]576            return self.process_empty_scalar(token.start_mark)
[43]577
[198]578    def parse_flow_mapping_empty_value(self):
579        self.state = self.parse_flow_mapping_key
580        return self.process_empty_scalar(self.peek_token().start_mark)
581
[116]582    def process_empty_scalar(self, mark):
[137]583        return ScalarEvent(None, None, (True, False), u'', mark, mark)
[43]584
Note: See TracBrowser for help on using the repository browser.