# 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