from __future__ import absolute_import
_D = ' expected <block end>, but found %r '
_C = True
_B = False
_A = None
from . error import MarkedYAMLError
from . tokens import *
from . events import *
from . scanner import Scanner , RoundTripScanner , ScannerError
from . compat import utf8 , nprint , nprintf
if _B : from typing import Any , Dict , Optional , List
__all__ = [ ' Parser ' , ' RoundTripParser ' , ' ParserError ' ]
class ParserError ( MarkedYAMLError ) : 0
class Parser :
DEFAULT_TAGS = { ' ! ' : ' ! ' , ' !! ' : ' tag:yaml.org,2002: ' }
def __init__ ( self , loader ) :
self . loader = loader
if self . loader is not _A and getattr ( self . loader , ' _parser ' , _A ) is _A : self . loader . _parser = self
self . reset_parser ( )
def reset_parser ( self ) : self . current_event = _A ; self . tag_handles = { } ; self . states = [ ] ; self . marks = [ ] ; self . state = self . parse_stream_start
def dispose ( self ) : self . reset_parser ( )
@property
def scanner ( self ) :
if hasattr ( self . loader , ' typ ' ) : return self . loader . scanner
return self . loader . _scanner
@property
def resolver ( self ) :
if hasattr ( self . loader , ' typ ' ) : return self . loader . resolver
return self . loader . _resolver
def check_event ( self , * choices ) :
if self . current_event is _A :
if self . state : self . current_event = self . state ( )
if self . current_event is not _A :
if not choices : return _C
for choice in choices :
if isinstance ( self . current_event , choice ) : return _C
return _B
def peek_event ( self ) :
if self . current_event is _A :
if self . state : self . current_event = self . state ( )
return self . current_event
def get_event ( self ) :
if self . current_event is _A :
if self . state : self . current_event = self . state ( )
value = self . current_event ; self . current_event = _A ; return value
def parse_stream_start ( self ) : token = self . scanner . get_token ( ) ; token . move_comment ( self . scanner . peek_token ( ) ) ; event = StreamStartEvent ( token . start_mark , token . end_mark , encoding = token . encoding ) ; self . state = self . parse_implicit_document_start ; return event
def parse_implicit_document_start ( self ) :
if not self . scanner . check_token ( DirectiveToken , DocumentStartToken , StreamEndToken ) : self . tag_handles = self . DEFAULT_TAGS ; token = self . scanner . peek_token ( ) ; start_mark = end_mark = token . start_mark ; event = DocumentStartEvent ( start_mark , end_mark , explicit = _B ) ; self . states . append ( self . parse_document_end ) ; self . state = self . parse_block_node ; return event
else : return self . parse_document_start ( )
def parse_document_start ( self ) :
while self . scanner . check_token ( DocumentEndToken ) : self . scanner . get_token ( )
if not self . scanner . check_token ( StreamEndToken ) :
token = self . scanner . peek_token ( ) ; start_mark = token . start_mark ; version , tags = self . process_directives ( )
if not self . scanner . check_token ( DocumentStartToken ) : raise ParserError ( _A , _A , " expected ' <document start> ' , but found %r " % self . scanner . peek_token ( ) . id , self . scanner . peek_token ( ) . start_mark )
token = self . scanner . get_token ( ) ; end_mark = token . end_mark ; event = DocumentStartEvent ( start_mark , end_mark , explicit = _C , version = version , tags = tags ) ; self . states . append ( self . parse_document_end ) ; self . state = self . parse_document_content
else : token = self . scanner . get_token ( ) ; event = StreamEndEvent ( token . start_mark , token . end_mark , comment = token . comment ) ; assert not self . states ; assert not self . marks ; self . state = _A
return event
def parse_document_end ( self ) :
token = self . scanner . peek_token ( ) ; start_mark = end_mark = token . start_mark ; explicit = _B
if self . scanner . check_token ( DocumentEndToken ) : token = self . scanner . get_token ( ) ; end_mark = token . end_mark ; explicit = _C
event = DocumentEndEvent ( start_mark , end_mark , explicit = explicit )
if self . resolver . processing_version == ( 1 , 1 ) : self . state = self . parse_document_start
else : self . state = self . parse_implicit_document_start
return event
def parse_document_content ( self ) :
if self . scanner . check_token ( DirectiveToken , DocumentStartToken , DocumentEndToken , StreamEndToken ) : event = self . process_empty_scalar ( self . scanner . peek_token ( ) . start_mark ) ; self . state = self . states . pop ( ) ; return event
else : return self . parse_block_node ( )
def process_directives ( self ) :
yaml_version = _A ; self . tag_handles = { }
while self . scanner . check_token ( DirectiveToken ) :
token = self . scanner . get_token ( )
if token . name == ' YAML ' :
if yaml_version is not _A : raise ParserError ( _A , _A , ' found duplicate YAML directive ' , token . start_mark )
major , minor = token . value
if major != 1 : raise ParserError ( _A , _A , ' found incompatible YAML document (version 1.* is required) ' , token . start_mark )
yaml_version = token . value
elif token . name == ' TAG ' :
handle , prefix = token . value
if handle in self . tag_handles : raise ParserError ( _A , _A , ' duplicate tag handle %r ' % utf8 ( handle ) , token . start_mark )
self . tag_handles [ handle ] = prefix
if bool ( self . tag_handles ) : value = yaml_version , self . tag_handles . copy ( )
else : value = yaml_version , _A
if self . loader is not _A and hasattr ( self . loader , ' tags ' ) :
self . loader . version = yaml_version
if self . loader . tags is _A : self . loader . tags = { }
for k in self . tag_handles : self . loader . tags [ k ] = self . tag_handles [ k ]
for key in self . DEFAULT_TAGS :
if key not in self . tag_handles : self . tag_handles [ key ] = self . DEFAULT_TAGS [ key ]
return value
def parse_block_node ( self ) : return self . parse_node ( block = _C )
def parse_flow_node ( self ) : return self . parse_node ( )
def parse_block_node_or_indentless_sequence ( self ) : return self . parse_node ( block = _C , indentless_sequence = _C )
def transform_tag ( self , handle , suffix ) : return self . tag_handles [ handle ] + suffix
def parse_node ( self , block = _B , indentless_sequence = _B ) :
if self . scanner . check_token ( AliasToken ) : token = self . scanner . get_token ( ) ; event = AliasEvent ( token . value , token . start_mark , token . end_mark ) ; self . state = self . states . pop ( ) ; return event
anchor = _A ; tag = _A ; start_mark = end_mark = tag_mark = _A
if self . scanner . check_token ( AnchorToken ) :
token = self . scanner . get_token ( ) ; start_mark = token . start_mark ; end_mark = token . end_mark ; anchor = token . value
if self . scanner . check_token ( TagToken ) : token = self . scanner . get_token ( ) ; tag_mark = token . start_mark ; end_mark = token . end_mark ; tag = token . value
elif self . scanner . check_token ( TagToken ) :
token = self . scanner . get_token ( ) ; start_mark = tag_mark = token . start_mark ; end_mark = token . end_mark ; tag = token . value
if self . scanner . check_token ( AnchorToken ) : token = self . scanner . get_token ( ) ; start_mark = tag_mark = token . start_mark ; end_mark = token . end_mark ; anchor = token . value
if tag is not _A :
handle , suffix = tag
if handle is not _A :
if handle not in self . tag_handles : raise ParserError ( ' while parsing a node ' , start_mark , ' found undefined tag handle %r ' % utf8 ( handle ) , tag_mark )
tag = self . transform_tag ( handle , suffix )
else : tag = suffix
if start_mark is _A : start_mark = end_mark = self . scanner . peek_token ( ) . start_mark
event = _A ; implicit = tag is _A or tag == ' ! '
if indentless_sequence and self . scanner . check_token ( BlockEntryToken ) :
comment = _A ; pt = self . scanner . peek_token ( )
if pt . comment and pt . comment [ 0 ] : comment = [ pt . comment [ 0 ] , [ ] ] ; pt . comment [ 0 ] = _A
end_mark = self . scanner . peek_token ( ) . end_mark ; event = SequenceStartEvent ( anchor , tag , implicit , start_mark , end_mark , flow_style = _B , comment = comment ) ; self . state = self . parse_indentless_sequence_entry ; return event
if self . scanner . check_token ( ScalarToken ) :
token = self . scanner . get_token ( ) ; end_mark = token . end_mark
if token . plain and tag is _A or tag == ' ! ' : implicit = _C , _B
elif tag is _A : implicit = _B , _C
else : implicit = _B , _B
event = ScalarEvent ( anchor , tag , implicit , token . value , start_mark , end_mark , style = token . style , comment = token . comment ) ; self . state = self . states . pop ( )
elif self . scanner . check_token ( FlowSequenceStartToken ) : pt = self . scanner . peek_token ( ) ; end_mark = pt . end_mark ; event = SequenceStartEvent ( anchor , tag , implicit , start_mark , end_mark , flow_style = _C , comment = pt . comment ) ; self . state = self . parse_flow_sequence_first_entry
elif self . scanner . check_token ( FlowMappingStartToken ) : pt = self . scanner . peek_token ( ) ; end_mark = pt . end_mark ; event = MappingStartEvent ( anchor , tag , implicit , start_mark , end_mark , flow_style = _C , comment = pt . comment ) ; self . state = self . parse_flow_mapping_first_key
elif block and self . scanner . check_token ( BlockSequenceStartToken ) :
end_mark = self . scanner . peek_token ( ) . start_mark ; pt = self . scanner . peek_token ( ) ; comment = pt . comment
if comment is _A or comment [ 1 ] is _A : comment = pt . split_comment ( )
event = SequenceStartEvent ( anchor , tag , implicit , start_mark , end_mark , flow_style = _B , comment = comment ) ; self . state = self . parse_block_sequence_first_entry
elif block and self . scanner . check_token ( BlockMappingStartToken ) : end_mark = self . scanner . peek_token ( ) . start_mark ; comment = self . scanner . peek_token ( ) . comment ; event = MappingStartEvent ( anchor , tag , implicit , start_mark , end_mark , flow_style = _B , comment = comment ) ; self . state = self . parse_block_mapping_first_key
elif anchor is not _A or tag is not _A : event = ScalarEvent ( anchor , tag , ( implicit , _B ) , ' ' , start_mark , end_mark ) ; self . state = self . states . pop ( )
else :
if block : node = ' block '
else : node = ' flow '
token = self . scanner . peek_token ( ) ; raise ParserError ( ' while parsing a %s node ' % node , start_mark , ' expected the node content, but found %r ' % token . id , token . start_mark )
return event
def parse_block_sequence_first_entry ( self ) : token = self . scanner . get_token ( ) ; self . marks . append ( token . start_mark ) ; return self . parse_block_sequence_entry ( )
def parse_block_sequence_entry ( self ) :
if self . scanner . check_token ( BlockEntryToken ) :
token = self . scanner . get_token ( ) ; token . move_comment ( self . scanner . peek_token ( ) )
if not self . scanner . check_token ( BlockEntryToken , BlockEndToken ) : self . states . append ( self . parse_block_sequence_entry ) ; return self . parse_block_node ( )
else : self . state = self . parse_block_sequence_entry ; return self . process_empty_scalar ( token . end_mark )
if not self . scanner . check_token ( BlockEndToken ) : token = self . scanner . peek_token ( ) ; raise ParserError ( ' while parsing a block collection ' , self . marks [ - 1 ] , _D % token . id , token . start_mark )
token = self . scanner . get_token ( ) ; event = SequenceEndEvent ( token . start_mark , token . end_mark , comment = token . comment ) ; self . state = self . states . pop ( ) ; self . marks . pop ( ) ; return event
def parse_indentless_sequence_entry ( self ) :
if self . scanner . check_token ( BlockEntryToken ) :
token = self . scanner . get_token ( ) ; token . move_comment ( self . scanner . peek_token ( ) )
if not self . scanner . check_token ( BlockEntryToken , KeyToken , ValueToken , BlockEndToken ) : self . states . append ( self . parse_indentless_sequence_entry ) ; return self . parse_block_node ( )
else : self . state = self . parse_indentless_sequence_entry ; return self . process_empty_scalar ( token . end_mark )
token = self . scanner . peek_token ( ) ; event = SequenceEndEvent ( token . start_mark , token . start_mark , comment = token . comment ) ; self . state = self . states . pop ( ) ; return event
def parse_block_mapping_first_key ( self ) : token = self . scanner . get_token ( ) ; self . marks . append ( token . start_mark ) ; return self . parse_block_mapping_key ( )
def parse_block_mapping_key ( self ) :
if self . scanner . check_token ( KeyToken ) :
token = self . scanner . get_token ( ) ; token . move_comment ( self . scanner . peek_token ( ) )
if not self . scanner . check_token ( KeyToken , ValueToken , BlockEndToken ) : self . states . append ( self . parse_block_mapping_value ) ; return self . parse_block_node_or_indentless_sequence ( )
else : self . state = self . parse_block_mapping_value ; return self . process_empty_scalar ( token . end_mark )
if self . resolver . processing_version > ( 1 , 1 ) and self . scanner . check_token ( ValueToken ) : self . state = self . parse_block_mapping_value ; return self . process_empty_scalar ( self . scanner . peek_token ( ) . start_mark )
if not self . scanner . check_token ( BlockEndToken ) : token = self . scanner . peek_token ( ) ; raise ParserError ( ' while parsing a block mapping ' , self . marks [ - 1 ] , _D % token . id , token . start_mark )
token = self . scanner . get_token ( ) ; token . move_comment ( self . scanner . peek_token ( ) ) ; event = MappingEndEvent ( token . start_mark , token . end_mark , comment = token . comment ) ; self . state = self . states . pop ( ) ; self . marks . pop ( ) ; return event
def parse_block_mapping_value ( self ) :
if self . scanner . check_token ( ValueToken ) :
token = self . scanner . get_token ( )
if self . scanner . check_token ( ValueToken ) : token . move_comment ( self . scanner . peek_token ( ) )
elif not self . scanner . check_token ( KeyToken ) : token . move_comment ( self . scanner . peek_token ( ) , empty = _C )
if not self . scanner . check_token ( KeyToken , ValueToken , BlockEndToken ) : self . states . append ( self . parse_block_mapping_key ) ; return self . parse_block_node_or_indentless_sequence ( )
else :
self . state = self . parse_block_mapping_key ; comment = token . comment
if comment is _A :
token = self . scanner . peek_token ( ) ; comment = token . comment
if comment : token . _comment = [ _A , comment [ 1 ] ] ; comment = [ comment [ 0 ] , _A ]
return self . process_empty_scalar ( token . end_mark , comment = comment )
else : self . state = self . parse_block_mapping_key ; token = self . scanner . peek_token ( ) ; return self . process_empty_scalar ( token . start_mark )
def parse_flow_sequence_first_entry ( self ) : token = self . scanner . get_token ( ) ; self . marks . append ( token . start_mark ) ; return self . parse_flow_sequence_entry ( first = _C )
def parse_flow_sequence_entry ( self , first = _B ) :
if not self . scanner . check_token ( FlowSequenceEndToken ) :
if not first :
if self . scanner . check_token ( FlowEntryToken ) : self . scanner . get_token ( )
else : token = self . scanner . peek_token ( ) ; raise ParserError ( ' while parsing a flow sequence ' , self . marks [ - 1 ] , " expected ' , ' or ' ] ' , but got %r " % token . id , token . start_mark )
if self . scanner . check_token ( KeyToken ) : token = self . scanner . peek_token ( ) ; event = MappingStartEvent ( _A , _A , _C , token . start_mark , token . end_mark , flow_style = _C ) ; self . state = self . parse_flow_sequence_entry_mapping_key ; return event
elif not self . scanner . check_token ( FlowSequenceEndToken ) : self . states . append ( self . parse_flow_sequence_entry ) ; return self . parse_flow_node ( )
token = self . scanner . get_token ( ) ; event = SequenceEndEvent ( token . start_mark , token . end_mark , comment = token . comment ) ; self . state = self . states . pop ( ) ; self . marks . pop ( ) ; return event
def parse_flow_sequence_entry_mapping_key ( self ) :
token = self . scanner . get_token ( )
if not self . scanner . check_token ( ValueToken , FlowEntryToken , FlowSequenceEndToken ) : self . states . append ( self . parse_flow_sequence_entry_mapping_value ) ; return self . parse_flow_node ( )
else : self . state = self . parse_flow_sequence_entry_mapping_value ; return self . process_empty_scalar ( token . end_mark )
def parse_flow_sequence_entry_mapping_value ( self ) :
if self . scanner . check_token ( ValueToken ) :
token = self . scanner . get_token ( )
if not self . scanner . check_token ( FlowEntryToken , FlowSequenceEndToken ) : self . states . append ( self . parse_flow_sequence_entry_mapping_end ) ; return self . parse_flow_node ( )
else : self . state = self . parse_flow_sequence_entry_mapping_end ; return self . process_empty_scalar ( token . end_mark )
else : self . state = self . parse_flow_sequence_entry_mapping_end ; token = self . scanner . peek_token ( ) ; return self . process_empty_scalar ( token . start_mark )
def parse_flow_sequence_entry_mapping_end ( self ) : self . state = self . parse_flow_sequence_entry ; token = self . scanner . peek_token ( ) ; return MappingEndEvent ( token . start_mark , token . start_mark )
def parse_flow_mapping_first_key ( self ) : token = self . scanner . get_token ( ) ; self . marks . append ( token . start_mark ) ; return self . parse_flow_mapping_key ( first = _C )
def parse_flow_mapping_key ( self , first = _B ) :
if not self . scanner . check_token ( FlowMappingEndToken ) :
if not first :
if self . scanner . check_token ( FlowEntryToken ) : self . scanner . get_token ( )
else : token = self . scanner . peek_token ( ) ; raise ParserError ( ' while parsing a flow mapping ' , self . marks [ - 1 ] , " expected ' , ' or ' } ' , but got %r " % token . id , token . start_mark )
if self . scanner . check_token ( KeyToken ) :
token = self . scanner . get_token ( )
if not self . scanner . check_token ( ValueToken , FlowEntryToken , FlowMappingEndToken ) : self . states . append ( self . parse_flow_mapping_value ) ; return self . parse_flow_node ( )
else : self . state = self . parse_flow_mapping_value ; return self . process_empty_scalar ( token . end_mark )
elif self . resolver . processing_version > ( 1 , 1 ) and self . scanner . check_token ( ValueToken ) : self . state = self . parse_flow_mapping_value ; return self . process_empty_scalar ( self . scanner . peek_token ( ) . end_mark )
elif not self . scanner . check_token ( FlowMappingEndToken ) : self . states . append ( self . parse_flow_mapping_empty_value ) ; return self . parse_flow_node ( )
token = self . scanner . get_token ( ) ; event = MappingEndEvent ( token . start_mark , token . end_mark , comment = token . comment ) ; self . state = self . states . pop ( ) ; self . marks . pop ( ) ; return event
def parse_flow_mapping_value ( self ) :
if self . scanner . check_token ( ValueToken ) :
token = self . scanner . get_token ( )
if not self . scanner . check_token ( FlowEntryToken , FlowMappingEndToken ) : self . states . append ( self . parse_flow_mapping_key ) ; return self . parse_flow_node ( )
else : self . state = self . parse_flow_mapping_key ; return self . process_empty_scalar ( token . end_mark )
else : self . state = self . parse_flow_mapping_key ; token = self . scanner . peek_token ( ) ; return self . process_empty_scalar ( token . start_mark )
def parse_flow_mapping_empty_value ( self ) : self . state = self . parse_flow_mapping_key ; return self . process_empty_scalar ( self . scanner . peek_token ( ) . start_mark )
def process_empty_scalar ( self , mark , comment = _A ) : return ScalarEvent ( _A , _A , ( _C , _B ) , ' ' , mark , mark , comment = comment )
class RoundTripParser ( Parser ) :
def transform_tag ( self , handle , suffix ) :
if handle == ' !! ' and suffix in ( ' null ' , ' bool ' , ' int ' , ' float ' , ' binary ' , ' timestamp ' , ' omap ' , ' pairs ' , ' set ' , ' str ' , ' seq ' , ' map ' ) : return Parser . transform_tag ( self , handle , suffix )
return handle + suffix