Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
parser.py590 linesDownload Raw Back to yaml
1 2# The following YAML grammar is LL(1) and is parsed by a recursive descent3# parser.4#5# stream            ::= STREAM-START implicit_document? explicit_document* STREAM-END6# implicit_document ::= block_node DOCUMENT-END*7# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*8# block_node_or_indentless_sequence ::=9#                       ALIAS10#                       | properties (block_content | indentless_block_sequence)?11#                       | block_content12#                       | indentless_block_sequence13# block_node        ::= ALIAS14#                       | properties block_content?15#                       | block_content16# flow_node         ::= ALIAS17#                       | properties flow_content?18#                       | flow_content19# properties        ::= TAG ANCHOR? | ANCHOR TAG?20# block_content     ::= block_collection | flow_collection | SCALAR21# flow_content      ::= flow_collection | SCALAR22# block_collection  ::= block_sequence | block_mapping23# flow_collection   ::= flow_sequence | flow_mapping24# block_sequence    ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END25# indentless_sequence   ::= (BLOCK-ENTRY block_node?)+26# block_mapping     ::= BLOCK-MAPPING_START27#                       ((KEY block_node_or_indentless_sequence?)?28#                       (VALUE block_node_or_indentless_sequence?)?)*29#                       BLOCK-END30# flow_sequence     ::= FLOW-SEQUENCE-START31#                       (flow_sequence_entry FLOW-ENTRY)*32#                       flow_sequence_entry?33#                       FLOW-SEQUENCE-END34# flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?35# flow_mapping      ::= FLOW-MAPPING-START36#                       (flow_mapping_entry FLOW-ENTRY)*37#                       flow_mapping_entry?38#                       FLOW-MAPPING-END39# flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?40#41# FIRST sets:42#43# stream: { STREAM-START }44# explicit_document: { DIRECTIVE DOCUMENT-START }45# implicit_document: FIRST(block_node)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 }54# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }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 62__all__ = ['Parser', 'ParserError']63 64from .error import MarkedYAMLError65from .tokens import *66from .events import *67from .scanner import *68 69class ParserError(MarkedYAMLError):70    pass71 72class Parser:73    # Since writing a recursive-descendant parser is a straightforward task, we74    # do not give many comments here.75 76    DEFAULT_TAGS = {77        '!':   '!',78        '!!':  'tag:yaml.org,2002:',79    }80 81    def __init__(self):82        self.current_event = None83        self.yaml_version = None84        self.tag_handles = {}85        self.states = []86        self.marks = []87        self.state = self.parse_stream_start88 89    def dispose(self):90        # Reset the state attributes (to clear self-references)91        self.states = []92        self.state = None93 94    def check_event(self, *choices):95        # Check the type of the next event.96        if self.current_event is None:97            if self.state:98                self.current_event = self.state()99        if self.current_event is not None:100            if not choices:101                return True102            for choice in choices:103                if isinstance(self.current_event, choice):104                    return True105        return False106 107    def peek_event(self):108        # Get the next event.109        if self.current_event is None:110            if self.state:111                self.current_event = self.state()112        return self.current_event113 114    def get_event(self):115        # Get the next event and proceed further.116        if self.current_event is None:117            if self.state:118                self.current_event = self.state()119        value = self.current_event120        self.current_event = None121        return value122 123    # stream    ::= STREAM-START implicit_document? explicit_document* STREAM-END124    # implicit_document ::= block_node DOCUMENT-END*125    # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*126 127    def parse_stream_start(self):128 129        # Parse the stream start.130        token = self.get_token()131        event = StreamStartEvent(token.start_mark, token.end_mark,132                encoding=token.encoding)133 134        # Prepare the next state.135        self.state = self.parse_implicit_document_start136 137        return event138 139    def parse_implicit_document_start(self):140 141        # Parse an implicit document.142        if not self.check_token(DirectiveToken, DocumentStartToken,143                StreamEndToken):144            self.tag_handles = self.DEFAULT_TAGS145            token = self.peek_token()146            start_mark = end_mark = token.start_mark147            event = DocumentStartEvent(start_mark, end_mark,148                    explicit=False)149 150            # Prepare the next state.151            self.states.append(self.parse_document_end)152            self.state = self.parse_block_node153 154            return event155 156        else:157            return self.parse_document_start()158 159    def parse_document_start(self):160 161        # Parse any extra document end indicators.162        while self.check_token(DocumentEndToken):163            self.get_token()164 165        # Parse an explicit document.166        if not self.check_token(StreamEndToken):167            token = self.peek_token()168            start_mark = token.start_mark169            version, tags = self.process_directives()170            if not self.check_token(DocumentStartToken):171                raise ParserError(None, None,172                        "expected '<document start>', but found %r"173                        % self.peek_token().id,174                        self.peek_token().start_mark)175            token = self.get_token()176            end_mark = token.end_mark177            event = DocumentStartEvent(start_mark, end_mark,178                    explicit=True, version=version, tags=tags)179            self.states.append(self.parse_document_end)180            self.state = self.parse_document_content181        else:182            # Parse the end of the stream.183            token = self.get_token()184            event = StreamEndEvent(token.start_mark, token.end_mark)185            assert not self.states186            assert not self.marks187            self.state = None188        return event189 190    def parse_document_end(self):191 192        # Parse the document end.193        token = self.peek_token()194        start_mark = end_mark = token.start_mark195        explicit = False196        if self.check_token(DocumentEndToken):197            token = self.get_token()198            end_mark = token.end_mark199            explicit = True200        event = DocumentEndEvent(start_mark, end_mark,201                explicit=explicit)202 203        # Prepare the next state.204        self.state = self.parse_document_start205 206        return event207 208    def parse_document_content(self):209        if self.check_token(DirectiveToken,210                DocumentStartToken, DocumentEndToken, StreamEndToken):211            event = self.process_empty_scalar(self.peek_token().start_mark)212            self.state = self.states.pop()213            return event214        else:215            return self.parse_block_node()216 217    def process_directives(self):218        self.yaml_version = None219        self.tag_handles = {}220        while self.check_token(DirectiveToken):221            token = self.get_token()222            if token.name == 'YAML':223                if self.yaml_version is not None:224                    raise ParserError(None, None,225                            "found duplicate YAML directive", token.start_mark)226                major, minor = token.value227                if major != 1:228                    raise ParserError(None, None,229                            "found incompatible YAML document (version 1.* is required)",230                            token.start_mark)231                self.yaml_version = token.value232            elif token.name == 'TAG':233                handle, prefix = token.value234                if handle in self.tag_handles:235                    raise ParserError(None, None,236                            "duplicate tag handle %r" % handle,237                            token.start_mark)238                self.tag_handles[handle] = prefix239        if self.tag_handles:240            value = self.yaml_version, self.tag_handles.copy()241        else:242            value = self.yaml_version, None243        for key in self.DEFAULT_TAGS:244            if key not in self.tag_handles:245                self.tag_handles[key] = self.DEFAULT_TAGS[key]246        return value247 248    # block_node_or_indentless_sequence ::= ALIAS249    #               | properties (block_content | indentless_block_sequence)?250    #               | block_content251    #               | indentless_block_sequence252    # block_node    ::= ALIAS253    #                   | properties block_content?254    #                   | block_content255    # flow_node     ::= ALIAS256    #                   | properties flow_content?257    #                   | flow_content258    # properties    ::= TAG ANCHOR? | ANCHOR TAG?259    # block_content     ::= block_collection | flow_collection | SCALAR260    # flow_content      ::= flow_collection | SCALAR261    # block_collection  ::= block_sequence | block_mapping262    # flow_collection   ::= flow_sequence | flow_mapping263 264    def parse_block_node(self):265        return self.parse_node(block=True)266 267    def parse_flow_node(self):268        return self.parse_node()269 270    def parse_block_node_or_indentless_sequence(self):271        return self.parse_node(block=True, indentless_sequence=True)272 273    def parse_node(self, block=False, indentless_sequence=False):274        if self.check_token(AliasToken):275            token = self.get_token()276            event = AliasEvent(token.value, token.start_mark, token.end_mark)277            self.state = self.states.pop()278        else:279            anchor = None280            tag = None281            start_mark = end_mark = tag_mark = None282            if self.check_token(AnchorToken):283                token = self.get_token()284                start_mark = token.start_mark285                end_mark = token.end_mark286                anchor = token.value287                if self.check_token(TagToken):288                    token = self.get_token()289                    tag_mark = token.start_mark290                    end_mark = token.end_mark291                    tag = token.value292            elif self.check_token(TagToken):293                token = self.get_token()294                start_mark = tag_mark = token.start_mark295                end_mark = token.end_mark296                tag = token.value297                if self.check_token(AnchorToken):298                    token = self.get_token()299                    end_mark = token.end_mark300                    anchor = token.value301            if tag is not None:302                handle, suffix = tag303                if handle is not None:304                    if handle not in self.tag_handles:305                        raise ParserError("while parsing a node", start_mark,306                                "found undefined tag handle %r" % handle,307                                tag_mark)308                    tag = self.tag_handles[handle]+suffix309                else:310                    tag = suffix311            #if tag == '!':312            #    raise ParserError("while parsing a node", start_mark,313            #            "found non-specific tag '!'", tag_mark,314            #            "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")315            if start_mark is None:316                start_mark = end_mark = self.peek_token().start_mark317            event = None318            implicit = (tag is None or tag == '!')319            if indentless_sequence and self.check_token(BlockEntryToken):320                end_mark = self.peek_token().end_mark321                event = SequenceStartEvent(anchor, tag, implicit,322                        start_mark, end_mark)323                self.state = self.parse_indentless_sequence_entry324            else:325                if self.check_token(ScalarToken):326                    token = self.get_token()327                    end_mark = token.end_mark328                    if (token.plain and tag is None) or tag == '!':329                        implicit = (True, False)330                    elif tag is None:331                        implicit = (False, True)332                    else:333                        implicit = (False, False)334                    event = ScalarEvent(anchor, tag, implicit, token.value,335                            start_mark, end_mark, style=token.style)336                    self.state = self.states.pop()337                elif self.check_token(FlowSequenceStartToken):338                    end_mark = self.peek_token().end_mark339                    event = SequenceStartEvent(anchor, tag, implicit,340                            start_mark, end_mark, flow_style=True)341                    self.state = self.parse_flow_sequence_first_entry342                elif self.check_token(FlowMappingStartToken):343                    end_mark = self.peek_token().end_mark344                    event = MappingStartEvent(anchor, tag, implicit,345                            start_mark, end_mark, flow_style=True)346                    self.state = self.parse_flow_mapping_first_key347                elif block and self.check_token(BlockSequenceStartToken):348                    end_mark = self.peek_token().start_mark349                    event = SequenceStartEvent(anchor, tag, implicit,350                            start_mark, end_mark, flow_style=False)351                    self.state = self.parse_block_sequence_first_entry352                elif block and self.check_token(BlockMappingStartToken):353                    end_mark = self.peek_token().start_mark354                    event = MappingStartEvent(anchor, tag, implicit,355                            start_mark, end_mark, flow_style=False)356                    self.state = self.parse_block_mapping_first_key357                elif anchor is not None or tag is not None:358                    # Empty scalars are allowed even if a tag or an anchor is359                    # specified.360                    event = ScalarEvent(anchor, tag, (implicit, False), '',361                            start_mark, end_mark)362                    self.state = self.states.pop()363                else:364                    if block:365                        node = 'block'366                    else:367                        node = 'flow'368                    token = self.peek_token()369                    raise ParserError("while parsing a %s node" % node, start_mark,370                            "expected the node content, but found %r" % token.id,371                            token.start_mark)372        return event373 374    # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END375 376    def parse_block_sequence_first_entry(self):377        token = self.get_token()378        self.marks.append(token.start_mark)379        return self.parse_block_sequence_entry()380 381    def parse_block_sequence_entry(self):382        if self.check_token(BlockEntryToken):383            token = self.get_token()384            if not self.check_token(BlockEntryToken, BlockEndToken):385                self.states.append(self.parse_block_sequence_entry)386                return self.parse_block_node()387            else:388                self.state = self.parse_block_sequence_entry389                return self.process_empty_scalar(token.end_mark)390        if not self.check_token(BlockEndToken):391            token = self.peek_token()392            raise ParserError("while parsing a block collection", self.marks[-1],393                    "expected <block end>, but found %r" % token.id, token.start_mark)394        token = self.get_token()395        event = SequenceEndEvent(token.start_mark, token.end_mark)396        self.state = self.states.pop()397        self.marks.pop()398        return event399 400    # indentless_sequence ::= (BLOCK-ENTRY block_node?)+401 402    def parse_indentless_sequence_entry(self):403        if self.check_token(BlockEntryToken):404            token = self.get_token()405            if not self.check_token(BlockEntryToken,406                    KeyToken, ValueToken, BlockEndToken):407                self.states.append(self.parse_indentless_sequence_entry)408                return self.parse_block_node()409            else:410                self.state = self.parse_indentless_sequence_entry411                return self.process_empty_scalar(token.end_mark)412        token = self.peek_token()413        event = SequenceEndEvent(token.start_mark, token.start_mark)414        self.state = self.states.pop()415        return event416 417    # block_mapping     ::= BLOCK-MAPPING_START418    #                       ((KEY block_node_or_indentless_sequence?)?419    #                       (VALUE block_node_or_indentless_sequence?)?)*420    #                       BLOCK-END421 422    def parse_block_mapping_first_key(self):423        token = self.get_token()424        self.marks.append(token.start_mark)425        return self.parse_block_mapping_key()426 427    def parse_block_mapping_key(self):428        if self.check_token(KeyToken):429            token = self.get_token()430            if not self.check_token(KeyToken, ValueToken, BlockEndToken):431                self.states.append(self.parse_block_mapping_value)432                return self.parse_block_node_or_indentless_sequence()433            else:434                self.state = self.parse_block_mapping_value435                return self.process_empty_scalar(token.end_mark)436        if not self.check_token(BlockEndToken):437            token = self.peek_token()438            raise ParserError("while parsing a block mapping", self.marks[-1],439                    "expected <block end>, but found %r" % token.id, token.start_mark)440        token = self.get_token()441        event = MappingEndEvent(token.start_mark, token.end_mark)442        self.state = self.states.pop()443        self.marks.pop()444        return event445 446    def parse_block_mapping_value(self):447        if self.check_token(ValueToken):448            token = self.get_token()449            if not self.check_token(KeyToken, ValueToken, BlockEndToken):450                self.states.append(self.parse_block_mapping_key)451                return self.parse_block_node_or_indentless_sequence()452            else:453                self.state = self.parse_block_mapping_key454                return self.process_empty_scalar(token.end_mark)455        else:456            self.state = self.parse_block_mapping_key457            token = self.peek_token()458            return self.process_empty_scalar(token.start_mark)459 460    # flow_sequence     ::= FLOW-SEQUENCE-START461    #                       (flow_sequence_entry FLOW-ENTRY)*462    #                       flow_sequence_entry?463    #                       FLOW-SEQUENCE-END464    # flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?465    #466    # Note that while production rules for both flow_sequence_entry and467    # flow_mapping_entry are equal, their interpretations are different.468    # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`469    # generate an inline mapping (set syntax).470 471    def parse_flow_sequence_first_entry(self):472        token = self.get_token()473        self.marks.append(token.start_mark)474        return self.parse_flow_sequence_entry(first=True)475 476    def parse_flow_sequence_entry(self, first=False):477        if not self.check_token(FlowSequenceEndToken):478            if not first:479                if self.check_token(FlowEntryToken):480                    self.get_token()481                else:482                    token = self.peek_token()483                    raise ParserError("while parsing a flow sequence", self.marks[-1],484                            "expected ',' or ']', but got %r" % token.id, token.start_mark)485            486            if self.check_token(KeyToken):487                token = self.peek_token()488                event = MappingStartEvent(None, None, True,489                        token.start_mark, token.end_mark,490                        flow_style=True)491                self.state = self.parse_flow_sequence_entry_mapping_key492                return event493            elif not self.check_token(FlowSequenceEndToken):494                self.states.append(self.parse_flow_sequence_entry)495                return self.parse_flow_node()496        token = self.get_token()497        event = SequenceEndEvent(token.start_mark, token.end_mark)498        self.state = self.states.pop()499        self.marks.pop()500        return event501 502    def parse_flow_sequence_entry_mapping_key(self):503        token = self.get_token()504        if not self.check_token(ValueToken,505                FlowEntryToken, FlowSequenceEndToken):506            self.states.append(self.parse_flow_sequence_entry_mapping_value)507            return self.parse_flow_node()508        else:509            self.state = self.parse_flow_sequence_entry_mapping_value510            return self.process_empty_scalar(token.end_mark)511 512    def parse_flow_sequence_entry_mapping_value(self):513        if self.check_token(ValueToken):514            token = self.get_token()515            if not self.check_token(FlowEntryToken, FlowSequenceEndToken):516                self.states.append(self.parse_flow_sequence_entry_mapping_end)517                return self.parse_flow_node()518            else:519                self.state = self.parse_flow_sequence_entry_mapping_end520                return self.process_empty_scalar(token.end_mark)521        else:522            self.state = self.parse_flow_sequence_entry_mapping_end523            token = self.peek_token()524            return self.process_empty_scalar(token.start_mark)525 526    def parse_flow_sequence_entry_mapping_end(self):527        self.state = self.parse_flow_sequence_entry528        token = self.peek_token()529        return MappingEndEvent(token.start_mark, token.start_mark)530 531    # flow_mapping  ::= FLOW-MAPPING-START532    #                   (flow_mapping_entry FLOW-ENTRY)*533    #                   flow_mapping_entry?534    #                   FLOW-MAPPING-END535    # flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?536 537    def parse_flow_mapping_first_key(self):538        token = self.get_token()539        self.marks.append(token.start_mark)540        return self.parse_flow_mapping_key(first=True)541 542    def parse_flow_mapping_key(self, first=False):543        if not self.check_token(FlowMappingEndToken):544            if not first:545                if self.check_token(FlowEntryToken):546                    self.get_token()547                else:548                    token = self.peek_token()549                    raise ParserError("while parsing a flow mapping", self.marks[-1],550                            "expected ',' or '}', but got %r" % token.id, token.start_mark)551            if self.check_token(KeyToken):552                token = self.get_token()553                if not self.check_token(ValueToken,554                        FlowEntryToken, FlowMappingEndToken):555                    self.states.append(self.parse_flow_mapping_value)556                    return self.parse_flow_node()557                else:558                    self.state = self.parse_flow_mapping_value559                    return self.process_empty_scalar(token.end_mark)560            elif not self.check_token(FlowMappingEndToken):561                self.states.append(self.parse_flow_mapping_empty_value)562                return self.parse_flow_node()563        token = self.get_token()564        event = MappingEndEvent(token.start_mark, token.end_mark)565        self.state = self.states.pop()566        self.marks.pop()567        return event568 569    def parse_flow_mapping_value(self):570        if self.check_token(ValueToken):571            token = self.get_token()572            if not self.check_token(FlowEntryToken, FlowMappingEndToken):573                self.states.append(self.parse_flow_mapping_key)574                return self.parse_flow_node()575            else:576                self.state = self.parse_flow_mapping_key577                return self.process_empty_scalar(token.end_mark)578        else:579            self.state = self.parse_flow_mapping_key580            token = self.peek_token()581            return self.process_empty_scalar(token.start_mark)582 583    def parse_flow_mapping_empty_value(self):584        self.state = self.parse_flow_mapping_key585        return self.process_empty_scalar(self.peek_token().start_mark)586 587    def process_empty_scalar(self, mark):588        return ScalarEvent(None, None, (True, False), '', mark, mark)589 590 
codekingpro/portable-devtools · Team Ai