Use an action type alias rather than class

This commit is contained in:
Emi Simpson 2023-03-04 20:00:00 -05:00
parent f692e8dcca
commit b8b6ba708f
Signed by: Emi
GPG key ID: A12F2C2FFDC3D847

View file

@ -3,18 +3,7 @@ from emis_funky_funktions import *
from dataclasses import dataclass
from functools import wraps
from operator import contains
from typing import Callable, Collection, Mapping, TypeGuard
@dataclass(frozen=True)
class Action(Generic[A]):
"""
Denotes an action annotation.
See `parser()`
"""
f: Callable[[Sequence[A]], Sequence[A]]
def __call__(self, i: Sequence[A]) -> Sequence[A]:
return self.f(i)
from typing import Callable, Collection, Mapping, TypeGuard, TypeAlias
def _expected(row: Mapping[B, Collection[Sequence[Any]]]) -> Collection[B]:
"""
@ -26,8 +15,9 @@ def _expected(row: Mapping[B, Collection[Sequence[Any]]]) -> Collection[B]:
if len(expansions)
]
Action: TypeAlias = Callable[[Sequence[C | D]], Sequence[C | D]]
def parser(
oracle: Mapping[A, Mapping[B, Collection[Sequence[A | B | Action[C | D]]]]],
oracle: Mapping[A, Mapping[B, Collection[Sequence[A | B | Action]]]],
identify_lexeme: Callable[[D], B],
start_symbol: A,
) -> Callable[[Sequence[D]], Result[Sequence[C | D], Tuple[D, Collection[B]]]]:
@ -69,10 +59,10 @@ def parser(
... Eof = auto()
... def __repr__(self):
... return self.name
>>> build_S = Action(lambda x: x[1:])
>>> build_Sum = Action(lambda x: (x[0](x[1][1]), *x[2:]))
>>> build_Sum_1 = Action(lambda x: (lambda y: x[0] + y, *x[2:]))
>>> build_Sum_2 = Action(lambda x: (lambda y: y, *x))
>>> build_S = lambda x: x[1:]
>>> build_Sum = lambda x: (x[0](x[1][1]), *x[2:])
>>> build_Sum_1 = lambda x: (lambda y: x[0] + y, *x[2:])
>>> build_Sum_2 = lambda x: (lambda y: y, *x)
>>> grammar = [
... (SimpleVariable.S, [SimpleVariable.Sum, SimpleTerminal.Eof, build_S]),
... (SimpleVariable.Sum, [SimpleTerminal.Number, SimpleVariable.Sum_, build_Sum]),
@ -106,14 +96,11 @@ def parser(
is_var: Callable[[Any], TypeGuard[A]] = p_instance(start_symbol.__class__)
is_tok: Callable[[Any], TypeGuard[B]] = p_instance(next(iter(oracle[start_symbol].keys())).__class__)
def inner(
stack: Sequence[A | B | Action[C | D]],
stack: Sequence[A | B | Action],
ast_stack: Sequence[C | D],
lexemes: Sequence[D],
) -> Result[Sequence[C | D], Tuple[D, Collection[B]]]:
match stack:
# Action
case [Action(f), *popped_stack]:
return inner(popped_stack, f(ast_stack), lexemes)
# A [Variable]
case [top_of_stack, *popped_stack] if is_var(top_of_stack):
expansions = oracle[top_of_stack][identify_lexeme(lexemes[0])]
@ -125,12 +112,16 @@ def parser(
case _:
raise Exception('Not an LL(1) grammar!!!')
# B [Token] (match)
case [top_of_stack, *popped_stack] if top_of_stack == identify_lexeme(lexemes[0]):
case [top_of_stack, *popped_stack] if is_tok(top_of_stack) and top_of_stack == identify_lexeme(lexemes[0]):
return inner(popped_stack, (lexemes[0], *ast_stack), lexemes[1:])
# B [Token] (no match)
case [top_of_stack, *popped_stack]:
case [top_of_stack, *popped_stack] if is_tok(top_of_stack):
assert is_tok(top_of_stack)
return Err((lexemes[0], (top_of_stack,)))
# Action
case [f, *popped_stack]:
assert hasattr(f, '__call__')
return inner(popped_stack, f(ast_stack), lexemes)
# Empty stack (finished parsing)
case []:
if len(lexemes):