#!/usr/bin/env python3
# copyright: ignore
#
# CAVEAT UTILITOR
#
#  This file was automatically generated by 竜TatSu vX.YY.Z
#
#     https://pypi.python.org/pypi/tatsu/
#
#  Any changes you make to it will be overwritten the next time
#  the file is generated.
#
# noqa # type: ignore # ruff: noqa
# fmt: off

from __future__ import annotations

from typing import Any

from tatsu import decorators as tatsu
from tatsu.config import ParserConfig
from tatsu.contexts import Ctx
from tatsu.parsing import Parser, generic_main
from tatsu.input.buffer import Buffer
from tatsu.input.textlines import TextLines

KEYWORDS: set[str] = set()


class LISPTokenizer(TextLines):
    def __init__(
        self,
        text, /,
        config: ParserConfig | None = None,
        **settings,
    ) -> None:
        config = ParserConfig.new(
            config=config,
            whitespace=None,
            nameguard=None,
            ignorecase=False,
            namechars='',
            parseinfo=False,
            comments=r'None',
            eol_comments=r'None',
            keywords=KEYWORDS,
            start='start',
        )
        assert isinstance(config, ParserConfig)
        config = config.override(**settings)

        super().__init__(text, config=config)


class LISPBuffer(Buffer):  # NOTE: backwards compatibility
    def __init__(
        self,
        text, /,
        config: ParserConfig | None = None,
        **settings,
    ) -> None:
        config = ParserConfig.new(
            config=config,
            whitespace=None,
            nameguard=None,
            ignorecase=False,
            namechars='',
            parseinfo=False,
            comments=r'None',
            eol_comments=r'None',
            keywords=KEYWORDS,
            start='start',
        )
        assert isinstance(config, ParserConfig)
        config = config.override(**settings)

        super().__init__(text, config=config)


class LISPParser(Parser):
    def __init__(self, /, config: ParserConfig | None = None, **settings):
        config = ParserConfig.new(config, **settings)
        rulessource = LISPRules()
        assert isinstance(config, ParserConfig)

        super().__init__(rulessource, config=config)


class LISPRules:
    def __init__(self, /, config: ParserConfig | None = None, **settings):
        config = ParserConfig.new(
            config=config,
            whitespace=None,
            nameguard=None,
            ignorecase=False,
            namechars='',
            parseinfo=False,
            comments=r'None',
            eol_comments=r'None',
            keywords=KEYWORDS,
            start='start',
        )
        assert isinstance(config, ParserConfig)
        config = config.override(**settings)
        self._config = config


    @tatsu.rule
    def start(self, ctx: Ctx) -> Any:
        self.lisp(ctx)

    @tatsu.rule
    def lisp(self, ctx: Ctx) -> Any:
        with ctx.choice() as α:
            @α.option
            def 〇(ctx: Ctx) -> Any:
                self.sexp(ctx)
            @α.option
            def 〇(ctx: Ctx) -> Any:
                self.list_(ctx)
            @α.option
            def 〇(ctx: Ctx) -> Any:
                self.symbol(ctx)
            @α.option
            def 〇(ctx: Ctx) -> Any:
                self.number(ctx)

    @tatsu.rule('SExp')
    def sexp(self, ctx: Ctx) -> Any:
        ctx.define(['cdr', 'cons'], [])
        ctx.token('(')
        with ctx.nameset('cons'):
            self.lisp(ctx)
        ctx.token('.')
        ctx.cut()
        with ctx.nameset('cdr'):
            self.lisp(ctx)
        ctx.token(')')

    @tatsu.rule('List')
    def list_(self, ctx: Ctx) -> Any:
        ctx.token('(')
        with ctx.nameset('@'):
            with ctx.loopopt() as cl:
                cl.expecting('<lisp>')

                @cl.exp
                def 〇(ctx: Ctx) -> Any:
                    self.lisp(ctx)
        ctx.token(')')

    @tatsu.rule('Symbol')
    def symbol(self, ctx: Ctx) -> Any:
        ctx.pattern(r'[_\w][_\w\d]*')

    @tatsu.rule('Number')
    def number(self, ctx: Ctx) -> Any:
        ctx.pattern(r'\d+(?:\.\d+)')


def main(filename, **kwargs):
    if not filename or filename == '-':
        import sys

        text = sys.stdin.read()
    else:
        import pathlib

        text = pathlib.Path(filename).read_text()

    parser = LISPParser()
    return parser.parse(text, filename=filename, **kwargs)


if __name__ == '__main__':
    import json
    from tatsu.util import asjson

    ast = generic_main(main, LISPParser, name='LISP')
    data = asjson(ast)
    print(json.dumps(data, indent=2))
