builtup4/bu4/parsing/parser.py
2021-07-24 15:10:11 +03:00

81 lines
2.7 KiB
Python

# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from io import BytesIO
from bu4.parsing.abstractparser import AbstractParser
from bu4.parsing.codes import *
from bu4.parsing.constructs.linked import Parsed
from bu4.parsing.constructs.llambda import PLambda
from bu4.parsing.constructs.lname import PName
from bu4.parsing.constructs.lnull import PNull
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.states.pscall import pscall
from bu4.parsing.states.psfinal import PSFinal
from bu4.parsing.states.psread import PSRead
from bu4.parsing.targets.pschain import PSChain
from bu4.parsing.targets.psendswith import PSEndsWith
from bu4.parsing.targets.pslambda import PSLambda
__all__ = ('Parser',)
class Parser(AbstractParser):
def __init__(self, s: bytes):
self.__s = BytesIO(s)
def read(self) -> int:
bytes_ = self.__s.read(1)
return bytes_[0] if bytes_ else 0
def parse_name(self) -> bytes:
s = BytesIO()
while True:
c = self.read()
if not c:
return s.getvalue()
s.write(bytes([c]))
def _state_read(self, state: PSAfter):
c = self.read()
if c == CODE_NULL:
state.state = PSFinal(PNull())
elif c == CODE_CALL:
state.state = pscall
elif c == CODE_MAKE:
state.state = (lambda name: PSAfter(
PSRead(),
PSLambda(
lambda value: PSFinal(PLambda(name, value))
)
))(self.parse_name())
elif c == CODE_NAME:
state.state = PSFinal(PName(self.parse_name()))
elif c == CODE_SKIP:
pass
elif c == CODE_QUOT:
state.target = PSChain(PSEndsWith(self, CODE_QUOT, "quot expected"), state.target)
elif c == CODE_QOPN:
state.target = PSChain(PSEndsWith(self, CODE_QCLS, "qcls expected"), state.target)
else:
raise ValueError(f"unknown control: {hex(c)}")
return state
def _state_next(self, state: PSAfter):
if isinstance(state.state, PSAfter):
state.state, state.target = state.state.state, PSChain(state.state.target, state.target)
elif isinstance(state.state, PSFinal):
state = state.target.given(state.state.parsed)
elif isinstance(state.state, PSRead):
state = self._state_read(state)
return state
def parse(self) -> Parsed:
state = PSAfter(PSRead(), PSLambda(lambda parsed: PSFinal(parsed)))
while True:
if isinstance(state, PSFinal):
return state.parsed
elif isinstance(state, PSAfter):
state = self._state_next(state)
else:
raise TypeError