parser extensions

This commit is contained in:
AF 2021-08-20 05:41:23 +03:00
parent 03d46253c5
commit e3ca0d396d
15 changed files with 216 additions and 35 deletions

View File

@ -18,7 +18,7 @@ class LLambda(Linked):
def evaluable(self, env: envtype) -> Evaluable:
return ELambda(
{name: container for name, container in env.items() if name in self.future},
{name: env[name] for name in self.future},
self.name,
self.value
)

View File

@ -1,8 +1,12 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
__all__ = ('AbstractParser',)
class AbstractParser:
def read(self) -> int:
raise NotImplementedError
def parse_name(self) -> bytes:
raise NotImplementedError

View File

@ -0,0 +1,23 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.abstractparser import AbstractParser
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
__all__ = ('Extension',)
class Extension:
code: int
def __init_subclass__(cls, /, code: int = None, **kwargs):
super().__init_subclass__(**kwargs)
if code is None:
raise TypeError
cls.code = code
def __init__(self, parser: AbstractParser):
self.parser = parser
def apply(self, state: PSAfter) -> ParseState:
raise NotImplementedError

View File

@ -0,0 +1,15 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_CALL
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.states.pscall import pscall
__all__ = ('XCall',)
class XCall(Extension, code=CODE_CALL):
def apply(self, state: PSAfter) -> ParseState:
state.state = pscall()
return state

View File

@ -0,0 +1,25 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_MAKE
from bu4.parsing.constructs.plambda import PLambda
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.states.psfinal import PSFinal
from bu4.parsing.states.psread import PSRead
__all__ = ('XMake',)
from bu4.parsing.targets.pslambda import PSLambda
class XMake(Extension, code=CODE_MAKE):
def apply(self, state: PSAfter) -> ParseState:
name = self.parser.parse_name()
state.state = PSAfter(
PSRead(),
PSLambda(
lambda value: PSFinal(PLambda(name, value))
)
)
return state

View File

@ -0,0 +1,16 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_NAME
from bu4.parsing.constructs.pname import PName
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.states.psfinal import PSFinal
__all__ = ('XName',)
class XName(Extension, code=CODE_NAME):
def apply(self, state: PSAfter) -> ParseState:
state.state = PSFinal(PName(self.parser.parse_name()))
return state

View File

@ -0,0 +1,16 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_NULL
from bu4.parsing.constructs.pnull import PNull
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.states.psfinal import PSFinal
__all__ = ('XNull',)
class XNull(Extension, code=CODE_NULL):
def apply(self, state: PSAfter) -> ParseState:
state.state = PSFinal(PNull())
return state

View File

@ -0,0 +1,16 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_QOPN, CODE_QCLS
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.targets.pschain import PSChain
from bu4.parsing.targets.psendswith import PSEndsWith
__all__ = ('XQopn',)
class XQopn(Extension, code=CODE_QOPN):
def apply(self, state: PSAfter) -> ParseState:
state.target = PSChain(PSEndsWith(self.parser, CODE_QCLS, 'quot expected'), state.target)
return state

View File

@ -0,0 +1,16 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_QUOT
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
from bu4.parsing.targets.pschain import PSChain
from bu4.parsing.targets.psendswith import PSEndsWith
__all__ = ('XQuot',)
class XQuot(Extension, code=CODE_QUOT):
def apply(self, state: PSAfter) -> ParseState:
state.target = PSChain(PSEndsWith(self.parser, CODE_QUOT, 'quot expected'), state.target)
return state

View File

@ -0,0 +1,13 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.codes import CODE_SKIP
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
from bu4.parsing.states.psafter import PSAfter
__all__ = ('XSkip',)
class XSkip(Extension, code=CODE_SKIP):
def apply(self, state: PSAfter) -> ParseState:
return state

View File

@ -1,34 +1,35 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from io import BytesIO
from typing import Iterable, Type
from bu4.parsing.abstractparser import AbstractParser
from bu4.parsing.codes import *
from bu4.parsing.constructs.parsed import Parsed
from bu4.parsing.constructs.plambda import PLambda
from bu4.parsing.constructs.pname import PName
from bu4.parsing.constructs.pnull import PNull
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.states.parsestate import ParseState
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, source: bytes):
def __init__(self, source: bytes, extensions: Iterable[Type[Extension]]):
self.__source = BytesIO(source)
self.__extensions: dict[int, Extension] = {}
for extension in extensions:
if extension.code in self.__extensions:
raise ValueError('code overload')
self.__extensions[extension.code] = extension(self)
def read(self) -> int:
bytes_ = self.__source.read(1)
return bytes_[0] if bytes_ else 0
def _parse_name(self) -> bytes:
def parse_name(self) -> bytes:
s = BytesIO()
while True:
c = self.read()
@ -37,29 +38,11 @@ class Parser(AbstractParser):
s.write(bytes([c]))
def _state_read(self, state: PSAfter) -> ParseState:
c = self.read()
if c == CODE_NULL:
state.state = PSFinal(PNull())
elif c == CODE_CALL:
state.state = pscall()
elif c == CODE_MAKE:
name = self._parse_name()
state.state = PSAfter(
PSRead(),
PSLambda(
lambda value: PSFinal(PLambda(name, value))
)
)
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)}")
code = self.read()
extension = self.__extensions.get(code)
if extension is None:
raise ValueError(f'unknown control: {hex(code)}')
state = extension.apply(state)
return state
def _state_next(self, state: PSAfter) -> ParseState:

View File

@ -1,10 +1,16 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from typing import Iterable, Type
from bu4.parsing.constructs.parsed import Parsed
from bu4.parsing.extensions.extension import Extension
from bu4.parsing.parser import Parser
__all__ = ('parse',)
def parse(source: bytes) -> Parsed:
return Parser(source).parse()
def parse(source: bytes, extensions: Iterable[Type[Extension]]) -> Parsed:
return Parser(
source,
extensions
).parse()

View File

@ -0,0 +1,21 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.parsing.extensions.xcall import XCall
from bu4.parsing.extensions.xmake import XMake
from bu4.parsing.extensions.xname import XName
from bu4.parsing.extensions.xnull import XNull
from bu4.parsing.extensions.xqopn import XQopn
from bu4.parsing.extensions.xquot import XQuot
from bu4.parsing.extensions.xskip import XSkip
__all__ = ('standard_extension',)
standard_extension = (
XNull,
XCall,
XMake,
XName,
XSkip,
XQuot,
XQopn,
)

View File

@ -4,6 +4,7 @@ from bu4.evaluation.constructs.evalue import EValue
from bu4.evaluation.sync import sync
from bu4.linking.evaluable_from_parsed import evaluable_from_parsed
from bu4.parsing.toolchain.parse import parse
from bu4.parsing.toolchain.stdext import standard_extension
from bu4.parsing.toolchain.transply import transply
__all__ = ('synced',)
@ -11,6 +12,6 @@ __all__ = ('synced',)
def synced(source: str) -> EValue:
bsource = transply(source)
parsed = parse(bsource)
parsed = parse(bsource, standard_extension)
evaluable = evaluable_from_parsed({}, parsed)
return sync(evaluable)

26
manual/extensions.md Normal file
View File

@ -0,0 +1,26 @@
Application (essential):
* Call
Abstraction:
* Lambda
* Name
Common:
* Null (=exception/undefined)
* Quot
* Qopn-Qcls
* Skip
Special:
* Namespaces (E- inputs)
* String literals (=exceptions)
* Trace/probes
* Classes (named lambda constructs)
* Methods (statically typed, optionally explicitly)
* Factories (statically typed, optionally explicitly)
* Await/after constructs with callbacks (and mutability/io quasimonads)
* Speculative execution (anychronousity and multithreading)
* Index-based linking (more static)
* Hashes (v13 extension)
* Bitstring call protocol (v13 extension)
* Evaluable to parsed