Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
parser.py863 linesDownload Raw Back to yaml
1 2from __future__ import annotations3 4# The following YAML grammar is LL(1) and is parsed by a recursive descent5# parser.6#7# stream            ::= STREAM-START implicit_document? explicit_document*8#                                                                   STREAM-END9# implicit_document ::= block_node DOCUMENT-END*10# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*11# block_node_or_indentless_sequence ::=12#                       ALIAS13#                       | properties (block_content |14#                                                   indentless_block_sequence)?15#                       | block_content16#                       | indentless_block_sequence17# block_node        ::= ALIAS18#                       | properties block_content?19#                       | block_content20# flow_node         ::= ALIAS21#                       | properties flow_content?22#                       | flow_content23# properties        ::= TAG ANCHOR? | ANCHOR TAG?24# block_content     ::= block_collection | flow_collection | SCALAR25# flow_content      ::= flow_collection | SCALAR26# block_collection  ::= block_sequence | block_mapping27# flow_collection   ::= flow_sequence | flow_mapping28# block_sequence    ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*29#                                                                   BLOCK-END30# indentless_sequence   ::= (BLOCK-ENTRY block_node?)+31# block_mapping     ::= BLOCK-MAPPING_START32#                       ((KEY block_node_or_indentless_sequence?)?33#                       (VALUE block_node_or_indentless_sequence?)?)*34#                       BLOCK-END35# flow_sequence     ::= FLOW-SEQUENCE-START36#                       (flow_sequence_entry FLOW-ENTRY)*37#                       flow_sequence_entry?38#                       FLOW-SEQUENCE-END39# flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?40# flow_mapping      ::= FLOW-MAPPING-START41#                       (flow_mapping_entry FLOW-ENTRY)*42#                       flow_mapping_entry?43#                       FLOW-MAPPING-END44# flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?45#46# FIRST sets:47#48# stream: { STREAM-START <}49# explicit_document: { DIRECTIVE DOCUMENT-START }50# implicit_document: FIRST(block_node)51# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START52#                  BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }53# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }54# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START55#                               FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }56# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }57# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }58# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }59# block_sequence: { BLOCK-SEQUENCE-START }60# block_mapping: { BLOCK-MAPPING-START }61# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR62#               BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START63#               FLOW-MAPPING-START BLOCK-ENTRY }64# indentless_sequence: { ENTRY }65# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }66# flow_sequence: { FLOW-SEQUENCE-START }67# flow_mapping: { FLOW-MAPPING-START }68# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START69#                                                    FLOW-MAPPING-START KEY }70# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START71#                                                    FLOW-MAPPING-START KEY }72 73# need to have full path with import, as pkg_resources tries to load parser.py in __init__.py74# only to not do anything with the package afterwards75# and for Jython too76 77 78from ruamel.yaml.error import MarkedYAMLError79from ruamel.yaml.tokens import *  # NOQA80from ruamel.yaml.events import *  # NOQA81from ruamel.yaml.scanner import Scanner, RoundTripScanner, ScannerError  # NOQA82from ruamel.yaml.scanner import BlankLineComment83from ruamel.yaml.comments import C_PRE, C_POST, C_SPLIT_ON_FIRST_BLANK84from ruamel.yaml.compat import nprint, nprintf  # NOQA85from ruamel.yaml.tag import Tag86 87if False:  # MYPY88    from typing import Any, Dict, Optional, List, Optional  # NOQA89 90__all__ = ['Parser', 'RoundTripParser', 'ParserError']91 92 93def xprintf(*args: Any, **kw: Any) -> Any:94    return nprintf(*args, **kw)95    pass96 97 98class ParserError(MarkedYAMLError):99    pass100 101 102class Parser:103    # Since writing a recursive-descendant parser is a straightforward task, we104    # do not give many comments here.105 106    DEFAULT_TAGS = {'!': '!', '!!': 'tag:yaml.org,2002:'}107 108    def __init__(self, loader: Any) -> None:109        self.loader = loader110        if self.loader is not None and getattr(self.loader, '_parser', None) is None:111            self.loader._parser = self112        self.reset_parser()113 114    def reset_parser(self) -> None:115        # Reset the state attributes (to clear self-references)116        self.current_event = self.last_event = None117        self.tag_handles: Dict[Any, Any] = {}118        self.states: List[Any] = []119        self.marks: List[Any] = []120        self.state: Any = self.parse_stream_start121 122    def dispose(self) -> None:123        self.reset_parser()124 125    @property126    def scanner(self) -> Any:127        if hasattr(self.loader, 'typ'):128            return self.loader.scanner129        return self.loader._scanner130 131    @property132    def resolver(self) -> Any:133        if hasattr(self.loader, 'typ'):134            return self.loader.resolver135        return self.loader._resolver136 137    def check_event(self, *choices: Any) -> bool:138        # Check the type of the next event.139        if self.current_event is None:140            if self.state:141                self.current_event = self.state()142        if self.current_event is not None:143            if not choices:144                return True145            for choice in choices:146                if isinstance(self.current_event, choice):147                    return True148        return False149 150    def peek_event(self) -> Any:151        # Get the next event.152        if self.current_event is None:153            if self.state:154                self.current_event = self.state()155        return self.current_event156 157    def get_event(self) -> Any:158        # Get the next event and proceed further.159        if self.current_event is None:160            if self.state:161                self.current_event = self.state()162        # assert self.current_event is not None163        # if self.current_event.end_mark.line != self.peek_event().start_mark.line:164        # xprintf('get_event', repr(self.current_event), self.peek_event().start_mark.line)165        self.last_event = value = self.current_event166        self.current_event = None167        return value168 169    # stream    ::= STREAM-START implicit_document? explicit_document*170    #                                                               STREAM-END171    # implicit_document ::= block_node DOCUMENT-END*172    # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*173 174    def parse_stream_start(self) -> Any:175        # Parse the stream start.176        token = self.scanner.get_token()177        self.move_token_comment(token)178        event = StreamStartEvent(token.start_mark, token.end_mark, encoding=token.encoding)179 180        # Prepare the next state.181        self.state = self.parse_implicit_document_start182 183        return event184 185    def parse_implicit_document_start(self) -> Any:186        # Parse an implicit document.187        if not self.scanner.check_token(DirectiveToken, DocumentStartToken, StreamEndToken):188            # don't need copy, as an implicit tag doesn't add tag_handles189            self.tag_handles = self.DEFAULT_TAGS190            token = self.scanner.peek_token()191            start_mark = end_mark = token.start_mark192            event = DocumentStartEvent(start_mark, end_mark, explicit=False)193 194            # Prepare the next state.195            self.states.append(self.parse_document_end)196            self.state = self.parse_block_node197 198            return event199 200        else:201            return self.parse_document_start()202 203    def parse_document_start(self) -> Any:204        # Parse any extra document end indicators.205        while self.scanner.check_token(DocumentEndToken):206            self.scanner.get_token()207        # Parse an explicit document.208        if not self.scanner.check_token(StreamEndToken):209            version, tags = self.process_directives()210            if not self.scanner.check_token(DocumentStartToken):211                raise ParserError(212                    None,213                    None,214                    "expected '<document start>', "215                    f'but found {self.scanner.peek_token().id,!r}',216                    self.scanner.peek_token().start_mark,217                )218            token = self.scanner.get_token()219            start_mark = token.start_mark220            end_mark = token.end_mark221            # if self.loader is not None and \222            #    end_mark.line != self.scanner.peek_token().start_mark.line:223            #     self.loader.scalar_after_indicator = False224            event: Any = DocumentStartEvent(225                start_mark,226                end_mark,227                explicit=True,228                version=version,229                tags=tags,230                comment=token.comment,231            )232            self.states.append(self.parse_document_end)233            self.state = self.parse_document_content234        else:235            # Parse the end of the stream.236            token = self.scanner.get_token()237            event = StreamEndEvent(token.start_mark, token.end_mark, comment=token.comment)238            assert not self.states239            assert not self.marks240            self.state = None241        return event242 243    def parse_document_end(self) -> Any:244        # Parse the document end.245        token = self.scanner.peek_token()246        start_mark = end_mark = token.start_mark247        explicit = False248        if self.scanner.check_token(DocumentEndToken):249            token = self.scanner.get_token()250            # if token.end_mark.line != self.peek_event().start_mark.line:251            pt = self.scanner.peek_token()252            if not isinstance(pt, StreamEndToken) and (253                token.end_mark.line == pt.start_mark.line254            ):255                raise ParserError(256                    None,257                    None,258                    'found non-comment content after document end marker, '259                    f'{self.scanner.peek_token().id,!r}',260                    self.scanner.peek_token().start_mark,261                )262            end_mark = token.end_mark263            explicit = True264        event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)265 266        # Prepare the next state.267        if self.resolver.processing_version == (1, 1):268            self.state = self.parse_document_start269        else:270            if explicit:271                # found a document end marker, can be followed by implicit document272                self.state = self.parse_implicit_document_start273            else:274                self.state = self.parse_document_start275 276        return event277 278    def parse_document_content(self) -> Any:279        if self.scanner.check_token(280            DirectiveToken, DocumentStartToken, DocumentEndToken, StreamEndToken,281        ):282            event = self.process_empty_scalar(self.scanner.peek_token().start_mark)283            self.state = self.states.pop()284            return event285        else:286            return self.parse_block_node()287 288    def process_directives(self) -> Any:289        yaml_version = None290        self.tag_handles = {}291        while self.scanner.check_token(DirectiveToken):292            token = self.scanner.get_token()293            if token.name == 'YAML':294                if yaml_version is not None:295                    raise ParserError(296                        None, None, 'found duplicate YAML directive', token.start_mark,297                    )298                major, minor = token.value299                if major != 1:300                    raise ParserError(301                        None,302                        None,303                        'found incompatible YAML document (version 1.* is required)',304                        token.start_mark,305                    )306                yaml_version = token.value307            elif token.name == 'TAG':308                handle, prefix = token.value309                if handle in self.tag_handles:310                    raise ParserError(311                        None, None, f'duplicate tag handle {handle!r}', token.start_mark,312                    )313                self.tag_handles[handle] = prefix314        if bool(self.tag_handles):315            value: Any = (yaml_version, self.tag_handles.copy())316        else:317            value = yaml_version, None318        if self.loader is not None and hasattr(self.loader, 'tags'):319            # ToDo: this is used to keep a single loaded file from losing its version320            # info, but  it affects following versions that have no explicit directive321            self.loader.version = yaml_version322            if self.loader.tags is None:323                self.loader.tags = {}324            for k in self.tag_handles:325                self.loader.tags[k] = self.tag_handles[k]326                self.loader.doc_infos[-1].tags.append((k, self.tag_handles[k]))327        for key in self.DEFAULT_TAGS:328            if key not in self.tag_handles:329                self.tag_handles[key] = self.DEFAULT_TAGS[key]330        return value331 332    # block_node_or_indentless_sequence ::= ALIAS333    #               | properties (block_content | indentless_block_sequence)?334    #               | block_content335    #               | indentless_block_sequence336    # block_node    ::= ALIAS337    #                   | properties block_content?338    #                   | block_content339    # flow_node     ::= ALIAS340    #                   | properties flow_content?341    #                   | flow_content342    # properties    ::= TAG ANCHOR? | ANCHOR TAG?343    # block_content     ::= block_collection | flow_collection | SCALAR344    # flow_content      ::= flow_collection | SCALAR345    # block_collection  ::= block_sequence | block_mapping346    # flow_collection   ::= flow_sequence | flow_mapping347 348    def parse_block_node(self) -> Any:349        return self.parse_node(block=True)350 351    def parse_flow_node(self) -> Any:352        return self.parse_node()353 354    def parse_block_node_or_indentless_sequence(self) -> Any:355        return self.parse_node(block=True, indentless_sequence=True)356 357    # def transform_tag(self, handle: Any, suffix: Any) -> Any:358    #     return self.tag_handles[handle] + suffix359 360    def select_tag_transform(self, tag: Tag) -> None:361        if tag is None:362            return363        tag.select_transform(False)364 365    def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> Any:366        if self.scanner.check_token(AliasToken):367            token = self.scanner.get_token()368            event: Any = AliasEvent(token.value, token.start_mark, token.end_mark)369            self.state = self.states.pop()370            return event371 372        anchor = None373        tag = None374        start_mark = end_mark = tag_mark = None375        if self.scanner.check_token(AnchorToken):376            token = self.scanner.get_token()377            self.move_token_comment(token)378            start_mark = token.start_mark379            end_mark = token.end_mark380            anchor = token.value381            if self.scanner.check_token(TagToken):382                token = self.scanner.get_token()383                tag_mark = token.start_mark384                end_mark = token.end_mark385                # tag = token.value386                tag = Tag(387                    handle=token.value[0], suffix=token.value[1], handles=self.tag_handles,388                )389        elif self.scanner.check_token(TagToken):390            token = self.scanner.get_token()391            try:392                self.move_token_comment(token)393            except NotImplementedError:394                pass395            start_mark = tag_mark = token.start_mark396            end_mark = token.end_mark397            # tag = token.value398            tag = Tag(handle=token.value[0], suffix=token.value[1], handles=self.tag_handles)399            if self.scanner.check_token(AnchorToken):400                token = self.scanner.get_token()401                start_mark = tag_mark = token.start_mark402                end_mark = token.end_mark403                anchor = token.value404        if tag is not None:405            self.select_tag_transform(tag)406            if tag.check_handle():407                raise ParserError(408                    'while parsing a node',409                    start_mark,410                    f'found undefined tag handle {tag.handle!r}',411                    tag_mark,412                )413        if start_mark is None:414            start_mark = end_mark = self.scanner.peek_token().start_mark415        event = None416        implicit = tag is None or str(tag) == '!'417        if indentless_sequence and self.scanner.check_token(BlockEntryToken):418            comment = None419            pt = self.scanner.peek_token()420            if self.loader and self.loader.comment_handling is None:421                if pt.comment and pt.comment[0]:422                    comment = [pt.comment[0], []]423                    pt.comment[0] = None424                elif pt.comment and pt.comment[0] is None and pt.comment[1]:425                    comment = [None, pt.comment[1]]426                    pt.comment[1] = None427            elif self.loader:428                if pt.comment:429                    comment = pt.comment430            end_mark = self.scanner.peek_token().end_mark431            event = SequenceStartEvent(432                anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,433            )434            self.state = self.parse_indentless_sequence_entry435            return event436 437        if self.scanner.check_token(ScalarToken):438            token = self.scanner.get_token()439            # self.scanner.peek_token_same_line_comment(token)440            end_mark = token.end_mark441            if (token.plain and tag is None) or str(tag) == '!':442                dimplicit = (True, False)443            elif tag is None:444                dimplicit = (False, True)445            else:446                dimplicit = (False, False)447            event = ScalarEvent(448                anchor,449                tag,450                dimplicit,451                token.value,452                start_mark,453                end_mark,454                style=token.style,455                comment=token.comment,456            )457            self.state = self.states.pop()458        elif self.scanner.check_token(FlowSequenceStartToken):459            pt = self.scanner.peek_token()460            end_mark = pt.end_mark461            event = SequenceStartEvent(462                anchor,463                tag,464                implicit,465                start_mark,466                end_mark,467                flow_style=True,468                comment=pt.comment,469            )470            self.state = self.parse_flow_sequence_first_entry471        elif self.scanner.check_token(FlowMappingStartToken):472            pt = self.scanner.peek_token()473            end_mark = pt.end_mark474            event = MappingStartEvent(475                anchor,476                tag,477                implicit,478                start_mark,479                end_mark,480                flow_style=True,481                comment=pt.comment,482            )483            self.state = self.parse_flow_mapping_first_key484        elif block and self.scanner.check_token(BlockSequenceStartToken):485            end_mark = self.scanner.peek_token().start_mark486            # should inserting the comment be dependent on the487            # indentation?488            pt = self.scanner.peek_token()489            comment = pt.comment490            # nprint('pt0', type(pt))491            if comment is None or comment[1] is None:492                comment = pt.split_old_comment()493            # nprint('pt1', comment)494            event = SequenceStartEvent(495                anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,496            )497            self.state = self.parse_block_sequence_first_entry498        elif block and self.scanner.check_token(BlockMappingStartToken):499            end_mark = self.scanner.peek_token().start_mark500            comment = self.scanner.peek_token().comment501            event = MappingStartEvent(502                anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,503            )504            self.state = self.parse_block_mapping_first_key505        elif anchor is not None or tag is not None:506            # Empty scalars are allowed even if a tag or an anchor is507            # specified.508            event = ScalarEvent(anchor, tag, (implicit, False), "", start_mark, end_mark)509            self.state = self.states.pop()510        else:511            if block:512                node = 'block'513            else:514                node = 'flow'515            token = self.scanner.peek_token()516            raise ParserError(517                f'while parsing a {node!s} node',518                start_mark,519                f'expected the node content, but found {token.id!r}',520                token.start_mark,521            )522        return event523 524    # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*525    #                                                               BLOCK-END526 527    def parse_block_sequence_first_entry(self) -> Any:528        token = self.scanner.get_token()529        # move any comment from start token530        # self.move_token_comment(token)531        self.marks.append(token.start_mark)532        return self.parse_block_sequence_entry()533 534    def parse_block_sequence_entry(self) -> Any:535        if self.scanner.check_token(BlockEntryToken):536            token = self.scanner.get_token()537            self.move_token_comment(token)538            if not self.scanner.check_token(BlockEntryToken, BlockEndToken):539                self.states.append(self.parse_block_sequence_entry)540                return self.parse_block_node()541            else:542                self.state = self.parse_block_sequence_entry543                return self.process_empty_scalar(token.end_mark)544        if not self.scanner.check_token(BlockEndToken):545            token = self.scanner.peek_token()546            raise ParserError(547                'while parsing a block collection',548                self.marks[-1],549                f'expected <block end>, but found {token.id!r}',550                token.start_mark,551            )552        token = self.scanner.get_token()  # BlockEndToken553        event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)554        self.state = self.states.pop()555        self.marks.pop()556        return event557 558    # indentless_sequence ::= (BLOCK-ENTRY block_node?)+559 560    # indentless_sequence?561    # sequence:562    # - entry563    #  - nested564 565    def parse_indentless_sequence_entry(self) -> Any:566        if self.scanner.check_token(BlockEntryToken):567            token = self.scanner.get_token()568            self.move_token_comment(token)569            if not self.scanner.check_token(570                BlockEntryToken, KeyToken, ValueToken, BlockEndToken,571            ):572                self.states.append(self.parse_indentless_sequence_entry)573                return self.parse_block_node()574            else:575                self.state = self.parse_indentless_sequence_entry576                return self.process_empty_scalar(token.end_mark)577        token = self.scanner.peek_token()578        c = None579        if self.loader and self.loader.comment_handling is None:580            c = token.comment581            start_mark = token.start_mark582        else:583            start_mark = self.last_event.end_mark  # type: ignore584            c = self.distribute_comment(token.comment, start_mark.line)  # type: ignore585        event = SequenceEndEvent(start_mark, start_mark, comment=c)586        self.state = self.states.pop()587        return event588 589    # block_mapping     ::= BLOCK-MAPPING_START590    #                       ((KEY block_node_or_indentless_sequence?)?591    #                       (VALUE block_node_or_indentless_sequence?)?)*592    #                       BLOCK-END593 594    def parse_block_mapping_first_key(self) -> Any:595        token = self.scanner.get_token()596        self.marks.append(token.start_mark)597        return self.parse_block_mapping_key()598 599    def parse_block_mapping_key(self) -> Any:600        if self.scanner.check_token(KeyToken):601            token = self.scanner.get_token()602            self.move_token_comment(token)603            if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):604                self.states.append(self.parse_block_mapping_value)605                return self.parse_block_node_or_indentless_sequence()606            else:607                self.state = self.parse_block_mapping_value608                return self.process_empty_scalar(token.end_mark)609        if self.resolver.processing_version > (1, 1) and self.scanner.check_token(ValueToken):610            self.state = self.parse_block_mapping_value611            return self.process_empty_scalar(self.scanner.peek_token().start_mark)612        if not self.scanner.check_token(BlockEndToken):613            token = self.scanner.peek_token()614            raise ParserError(615                'while parsing a block mapping',616                self.marks[-1],617                f'expected <block end>, but found {token.id!r}',618                token.start_mark,619            )620        token = self.scanner.get_token()621        self.move_token_comment(token)622        event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)623        self.state = self.states.pop()624        self.marks.pop()625        return event626 627    def parse_block_mapping_value(self) -> Any:628        if self.scanner.check_token(ValueToken):629            token = self.scanner.get_token()630            # value token might have post comment move it to e.g. block631            if self.scanner.check_token(ValueToken):632                self.move_token_comment(token)633            else:634                if not self.scanner.check_token(KeyToken):635                    self.move_token_comment(token, empty=True)636                # else: empty value for this key cannot move token.comment637            if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):638                self.states.append(self.parse_block_mapping_key)639                return self.parse_block_node_or_indentless_sequence()640            else:641                self.state = self.parse_block_mapping_key642                comment = token.comment643                if comment is None:644                    token = self.scanner.peek_token()645                    comment = token.comment646                    if comment:647                        token._comment = [None, comment[1]]648                        comment = [comment[0], None]649                return self.process_empty_scalar(token.end_mark, comment=comment)650        else:651            self.state = self.parse_block_mapping_key652            token = self.scanner.peek_token()653            return self.process_empty_scalar(token.start_mark)654 655    # flow_sequence     ::= FLOW-SEQUENCE-START656    #                       (flow_sequence_entry FLOW-ENTRY)*657    #                       flow_sequence_entry?658    #                       FLOW-SEQUENCE-END659    # flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?660    #661    # Note that while production rules for both flow_sequence_entry and662    # flow_mapping_entry are equal, their interpretations are different.663    # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`664    # generate an inline mapping (set syntax).665 666    def parse_flow_sequence_first_entry(self) -> Any:667        token = self.scanner.get_token()668        self.marks.append(token.start_mark)669        return self.parse_flow_sequence_entry(first=True)670 671    def parse_flow_sequence_entry(self, first: bool = False) -> Any:672        if not self.scanner.check_token(FlowSequenceEndToken):673            if not first:674                if self.scanner.check_token(FlowEntryToken):675                    self.scanner.get_token()676                else:677                    token = self.scanner.peek_token()678                    raise ParserError(679                        'while parsing a flow sequence',680                        self.marks[-1],681                        f"expected ',' or ']', but got {token.id!r}",682                        token.start_mark,683                    )684 685            if self.scanner.check_token(KeyToken):686                token = self.scanner.peek_token()687                event: Any = MappingStartEvent(688                    None, None, True, token.start_mark, token.end_mark, flow_style=True,689                )690                self.state = self.parse_flow_sequence_entry_mapping_key691                return event692            elif not self.scanner.check_token(FlowSequenceEndToken):693                self.states.append(self.parse_flow_sequence_entry)694                return self.parse_flow_node()695        token = self.scanner.get_token()696        event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)697        self.state = self.states.pop()698        self.marks.pop()699        return event700 701    def parse_flow_sequence_entry_mapping_key(self) -> Any:702        token = self.scanner.get_token()703        if not self.scanner.check_token(ValueToken, FlowEntryToken, FlowSequenceEndToken):704            self.states.append(self.parse_flow_sequence_entry_mapping_value)705            return self.parse_flow_node()706        else:707            self.state = self.parse_flow_sequence_entry_mapping_value708            return self.process_empty_scalar(token.end_mark)709 710    def parse_flow_sequence_entry_mapping_value(self) -> Any:711        if self.scanner.check_token(ValueToken):712            token = self.scanner.get_token()713            if not self.scanner.check_token(FlowEntryToken, FlowSequenceEndToken):714                self.states.append(self.parse_flow_sequence_entry_mapping_end)715                return self.parse_flow_node()716            else:717                self.state = self.parse_flow_sequence_entry_mapping_end718                return self.process_empty_scalar(token.end_mark)719        else:720            self.state = self.parse_flow_sequence_entry_mapping_end721            token = self.scanner.peek_token()722            return self.process_empty_scalar(token.start_mark)723 724    def parse_flow_sequence_entry_mapping_end(self) -> Any:725        self.state = self.parse_flow_sequence_entry726        token = self.scanner.peek_token()727        return MappingEndEvent(token.start_mark, token.start_mark)728 729    # flow_mapping  ::= FLOW-MAPPING-START730    #                   (flow_mapping_entry FLOW-ENTRY)*731    #                   flow_mapping_entry?732    #                   FLOW-MAPPING-END733    # flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?734 735    def parse_flow_mapping_first_key(self) -> Any:736        token = self.scanner.get_token()737        self.marks.append(token.start_mark)738        return self.parse_flow_mapping_key(first=True)739 740    def parse_flow_mapping_key(self, first: Any = False) -> Any:741        if not self.scanner.check_token(FlowMappingEndToken):742            if not first:743                if self.scanner.check_token(FlowEntryToken):744                    self.scanner.get_token()745                else:746                    token = self.scanner.peek_token()747                    raise ParserError(748                        'while parsing a flow mapping',749                        self.marks[-1],750                        f"expected ',' or '}}', but got {token.id!r}",751                        token.start_mark,752                    )753            if self.scanner.check_token(KeyToken):754                token = self.scanner.get_token()755                if not self.scanner.check_token(756                    ValueToken, FlowEntryToken, FlowMappingEndToken,757                ):758                    self.states.append(self.parse_flow_mapping_value)759                    return self.parse_flow_node()760                else:761                    self.state = self.parse_flow_mapping_value762                    return self.process_empty_scalar(token.end_mark)763            elif self.resolver.processing_version > (1, 1) and self.scanner.check_token(764                ValueToken,765            ):766                self.state = self.parse_flow_mapping_value767                return self.process_empty_scalar(self.scanner.peek_token().end_mark)768            elif not self.scanner.check_token(FlowMappingEndToken):769                self.states.append(self.parse_flow_mapping_empty_value)770                return self.parse_flow_node()771        token = self.scanner.get_token()772        event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)773        self.state = self.states.pop()774        self.marks.pop()775        return event776 777    def parse_flow_mapping_value(self) -> Any:778        if self.scanner.check_token(ValueToken):779            token = self.scanner.get_token()780            if not self.scanner.check_token(FlowEntryToken, FlowMappingEndToken):781                self.states.append(self.parse_flow_mapping_key)782                return self.parse_flow_node()783            else:784                self.state = self.parse_flow_mapping_key785                return self.process_empty_scalar(token.end_mark)786        else:787            self.state = self.parse_flow_mapping_key788            token = self.scanner.peek_token()789            return self.process_empty_scalar(token.start_mark)790 791    def parse_flow_mapping_empty_value(self) -> Any:792        self.state = self.parse_flow_mapping_key793        return self.process_empty_scalar(self.scanner.peek_token().start_mark)794 795    def process_empty_scalar(self, mark: Any, comment: Any = None) -> Any:796        return ScalarEvent(None, None, (True, False), "", mark, mark, comment=comment)797 798    def move_token_comment(799        self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,800    ) -> Any:801        pass802 803 804class RoundTripParser(Parser):805    """roundtrip is a safe loader, that wants to see the unmangled tag"""806 807    def select_tag_transform(self, tag: Tag) -> None:808        if tag is None:809            return810        tag.select_transform(True)811 812    def move_token_comment(813        self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,814    ) -> Any:815        token.move_old_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)816 817 818class RoundTripParserSC(RoundTripParser):819    """roundtrip is a safe loader, that wants to see the unmangled tag"""820 821    # some of the differences are based on the superclass testing822    # if self.loader.comment_handling is not None823 824    def move_token_comment(825        self: Any, token: Any, nt: Any = None, empty: Optional[bool] = False,826    ) -> None:827        token.move_new_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)828 829    def distribute_comment(self, comment: Any, line: Any) -> Any:830        # ToDo, look at indentation of the comment to determine attachment831        if comment is None:832            return None833        if not comment[0]:834            return None835        # if comment[0][0] != line + 1:836        #     nprintf('>>>dcxxx', comment, line)837        assert comment[0][0] == line + 1838        # if comment[0] - line > 1:839        #     return840        typ = self.loader.comment_handling & 0b11841        # nprintf('>>>dca', comment, line, typ)842        if typ == C_POST:843            return None844        if typ == C_PRE:845            c = [None, None, comment[0]]846            comment[0] = None847            return c848        # nprintf('>>>dcb', comment[0])849        for _idx, cmntidx in enumerate(comment[0]):850            # nprintf('>>>dcb', cmntidx)851            if isinstance(self.scanner.comments[cmntidx], BlankLineComment):852                break853        else:854            return None  # no space found855        if _idx == 0:856            return None  # first line was blank857        # nprintf('>>>dcc', idx)858        if typ == C_SPLIT_ON_FIRST_BLANK:859            c = [None, None, comment[0][:_idx]]860            comment[0] = comment[0][_idx:]861            return c862        raise NotImplementedError  # reserved863 
codekingpro/portable-devtools · Team Ai