parser extensions
This commit is contained in:
parent
03d46253c5
commit
e3ca0d396d
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
|
23
bu4/parsing/extensions/extension.py
Normal file
23
bu4/parsing/extensions/extension.py
Normal 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
|
15
bu4/parsing/extensions/xcall.py
Normal file
15
bu4/parsing/extensions/xcall.py
Normal 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
|
25
bu4/parsing/extensions/xmake.py
Normal file
25
bu4/parsing/extensions/xmake.py
Normal 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
|
16
bu4/parsing/extensions/xname.py
Normal file
16
bu4/parsing/extensions/xname.py
Normal 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
|
16
bu4/parsing/extensions/xnull.py
Normal file
16
bu4/parsing/extensions/xnull.py
Normal 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
|
16
bu4/parsing/extensions/xqopn.py
Normal file
16
bu4/parsing/extensions/xqopn.py
Normal 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
|
16
bu4/parsing/extensions/xquot.py
Normal file
16
bu4/parsing/extensions/xquot.py
Normal 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
|
13
bu4/parsing/extensions/xskip.py
Normal file
13
bu4/parsing/extensions/xskip.py
Normal 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
|
@ -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:
|
||||
|
@ -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()
|
||||
|
21
bu4/parsing/toolchain/stdext.py
Normal file
21
bu4/parsing/toolchain/stdext.py
Normal 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,
|
||||
)
|
@ -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
26
manual/extensions.md
Normal 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
|
Loading…
Reference in New Issue
Block a user