#!/usr/bin/env python3.8
# @generated by pegen from pyasdl/static/asdl.gram


from typing import Any, List, Optional, Union

from pegen.parser import Parser, memoize

from pyasdl.grammar import (
    Constructor,
    Field,
    FieldQualifier,
    Module,
    Product,
    Sum,
    Type,
)

TypeList = List[Type]
FieldList = List[Field]
ConstructorList = List[Constructor]
ProductOrSum = Union[Product, Sum]

# Keywords and soft keywords are listed at the end of the parser definition.
class GeneratedParser(Parser):
    @memoize
    def start(self) -> Optional[Module]:
        # start: "module" NAME NEWLINE? "{" definitions "}"
        mark = self._mark()
        if (
            (literal := self.expect("module"))
            and (name := self.name())
            and (opt := self.expect("NEWLINE"),)
            and (literal_1 := self.expect("{"))
            and (body := self.definitions())
            and (literal_2 := self.expect("}"))
        ):
            return Module(name.string, body)
        self._reset(mark)
        return None

    @memoize
    def definitions(self) -> Optional[TypeList]:
        # definitions: definition definitions | definition
        mark = self._mark()
        if (definition := self.definition()) and (
            definitions := self.definitions()
        ):
            return [definition] + definitions
        self._reset(mark)
        if definition := self.definition():
            return [definition]
        self._reset(mark)
        return None

    @memoize
    def definition(self) -> Optional[Type]:
        # definition: NAME "=" define
        mark = self._mark()
        if (
            (name := self.name())
            and (literal := self.expect("="))
            and (define := self.define())
        ):
            return Type(name.string, define)
        self._reset(mark)
        return None

    @memoize
    def define(self) -> Optional[ProductOrSum]:
        # define: sum_body attributes? | fields attributes?
        mark = self._mark()
        if (sum_body := self.sum_body()) and (attrs := self.attributes(),):
            return Sum(sum_body, attrs or [])
        self._reset(mark)
        if (fields := self.fields()) and (attrs := self.attributes(),):
            return Product(fields, attrs or [])
        self._reset(mark)
        return None

    @memoize
    def sum_body(self) -> Optional[ConstructorList]:
        # sum_body: constructor !"|" | "|".constructor+
        mark = self._mark()
        if (constructor := self.constructor()) and self.negative_lookahead(
            self.expect, "|"
        ):
            return [constructor]
        self._reset(mark)
        if constructors := self._gather_1():
            return constructors
        self._reset(mark)
        return None

    @memoize
    def constructor(self) -> Optional[Constructor]:
        # constructor: NAME fields?
        mark = self._mark()
        if (name := self.name()) and (fields := self.fields(),):
            return Constructor(name.string, fields or [])
        self._reset(mark)
        return None

    @memoize
    def fields(self) -> Optional[FieldList]:
        # fields: "(" fields_body? ")"
        mark = self._mark()
        if (
            (literal := self.expect("("))
            and (body := self.fields_body(),)
            and (literal_1 := self.expect(")"))
        ):
            return body
        self._reset(mark)
        return None

    @memoize
    def fields_body(self) -> Optional[FieldList]:
        # fields_body: field !"," | ",".field+
        mark = self._mark()
        if (field := self.field()) and self.negative_lookahead(
            self.expect, ","
        ):
            return [field]
        self._reset(mark)
        if fields := self._gather_3():
            return fields
        self._reset(mark)
        return None

    @memoize
    def field(self) -> Optional[Field]:
        # field: NAME field_qualifier? NAME
        mark = self._mark()
        if (
            (type := self.name())
            and (qualifier := self.field_qualifier(),)
            and (name := self.name())
        ):
            return Field(type.string, name.string, qualifier)
        self._reset(mark)
        return None

    @memoize
    def field_qualifier(self) -> Optional[FieldQualifier]:
        # field_qualifier: "?" | "*"
        mark = self._mark()
        if literal := self.expect("?"):
            return FieldQualifier.OPTIONAL
        self._reset(mark)
        if literal := self.expect("*"):
            return FieldQualifier.SEQUENCE
        self._reset(mark)
        return None

    @memoize
    def attributes(self) -> Optional[FieldList]:
        # attributes: "attributes" fields
        mark = self._mark()
        if (literal := self.expect("attributes")) and (
            fields := self.fields()
        ):
            return fields
        self._reset(mark)
        return None

    @memoize
    def _loop0_2(self) -> Optional[Any]:
        # _loop0_2: "|" constructor
        mark = self._mark()
        children = []
        while (literal := self.expect("|")) and (elem := self.constructor()):
            children.append(elem)
            mark = self._mark()
        self._reset(mark)
        return children

    @memoize
    def _gather_1(self) -> Optional[Any]:
        # _gather_1: constructor _loop0_2
        mark = self._mark()
        if (elem := self.constructor()) is not None and (
            seq := self._loop0_2()
        ) is not None:
            return [elem] + seq
        self._reset(mark)
        return None

    @memoize
    def _loop0_4(self) -> Optional[Any]:
        # _loop0_4: "," field
        mark = self._mark()
        children = []
        while (literal := self.expect(",")) and (elem := self.field()):
            children.append(elem)
            mark = self._mark()
        self._reset(mark)
        return children

    @memoize
    def _gather_3(self) -> Optional[Any]:
        # _gather_3: field _loop0_4
        mark = self._mark()
        if (elem := self.field()) is not None and (
            seq := self._loop0_4()
        ) is not None:
            return [elem] + seq
        self._reset(mark)
        return None

    KEYWORDS = ()
    SOFT_KEYWORDS = ("attributes", "module")


if __name__ == "__main__":
    from pegen.parser import simple_parser_main

    simple_parser_main(GeneratedParser)
