Clean up some unused functions

This commit is contained in:
Emi Simpson 2023-03-06 12:03:15 -05:00
parent 6353522827
commit 57130c9233
Signed by: Emi
GPG key ID: A12F2C2FFDC3D847
3 changed files with 11 additions and 200 deletions

View file

@ -147,49 +147,6 @@ def _predict(
else:
return first_rhs
def oracle(
is_term: Callable[[A | B | C], TypeGuard[B]],
is_var: Callable[[A | B | C], TypeGuard[A]],
grammar: Sequence[Tuple[A, Sequence[A | B | C]]],
) -> Callable[[A, B], Collection[Sequence[A | B | C]]]:
"""
Show valid expansions of a variable based on the next terminal to be read
For valid LL(1) grammars, there should never be more than one valid expansion.
The inner method constructed is memoized for your convenience.
>>> is_tok = p_instance(Tok)
>>> is_var = p_instance(Variable)
>>> my_oracle = oracle(is_tok, is_var, GRAMMAR)
One valid expansion:
>>> my_oracle(Variable.Clauses_, Tok.Negate)
[[<Clause>, <Clauses>]]
One valid expansion, but it expands to epsilon:
>>> my_oracle(Variable.Clauses_, Tok.Eof)
[[]]
Zero valid expansions:
>>> my_oracle(Variable.Term, Tok.Newline)
[]
"""
is_not_c: Callable[[A | B | C], TypeGuard[A | B]] = lambda x: is_term(x) or is_var(x) #type:ignore
e_grammar: Sequence[Tuple[A, Sequence[A | B]]] = _erase_actions(grammar, is_not_c)
follow = _follow(is_term, e_grammar)
@wraps(oracle)
@cache
def inner(v: A, c: B) -> Collection[Sequence[A | B | C]]:
return [
handle
for (lhs, handle) in grammar
if lhs == v
and c in _predict(is_term, e_grammar, follow, lhs, _erase_actions_h(handle, is_not_c))
]
return inner
def oracle_table(
is_term: Callable[[A | B], TypeGuard[B]],
is_var: Callable[[A | B], TypeGuard[A]],
@ -218,142 +175,24 @@ def oracle_table(
"""
all_variables = { lhs for (lhs, rhs) in grammar }
all_terminals = { symbol for (lhs, rhs) in grammar for symbol in rhs if is_term(symbol) }
the_oracle = oracle(is_term, is_var, grammar)
is_not_c: Callable[[A | B | C], TypeGuard[A | B]] = lambda x: is_term(x) or is_var(x) #type:ignore
e_grammar: Sequence[Tuple[A, Sequence[A | B]]] = _erase_actions(grammar, is_not_c) #type:ignore
follow = _follow(is_term, e_grammar)
return {
v: {
t: the_oracle(v, t)
t: [
handle
for (lhs, handle) in grammar
if lhs == v
and t in _predict(is_term, e_grammar, follow, lhs, _erase_actions_h(handle, is_not_c)) #type:ignore
]
for t in all_terminals
}
for v in all_variables
}
def print_oracle_table(
oracle_table: Mapping[A, Mapping[B, Collection[Sequence[A | B]]]],
render: Callable[[A | B], str],
) -> str:
"""
Pretty prints an oracle table
The render function is expected to render terminals and variables. If the render
function produces valid python, then `print_oracle_table` will also produce valid
python.
### Example:
We generate a simple grammar:
>>> class SimpleVariable(IntEnum):
... Sum = auto()
... Sum_ = auto()
... Term = auto()
>>> class SimpleTerminal(IntEnum):
... Number = auto()
... Letter = auto()
... Plus = auto()
>>> grammar = [
... (SimpleVariable.Sum, [SimpleVariable.Term, SimpleVariable.Sum_]),
... (SimpleVariable.Sum_, [SimpleTerminal.Plus, SimpleVariable.Sum]),
... (SimpleVariable.Sum_, []),
... (SimpleVariable.Term, [SimpleTerminal.Number]),
... (SimpleVariable.Term, [SimpleTerminal.Letter]),
... ]
>>> is_tok = p_instance(SimpleTerminal)
>>> is_var = p_instance(SimpleVariable)
>>> my_oracle_table = oracle_table(is_tok, is_var, grammar)
>>> rendered_oracle_table = print_oracle_table(my_oracle_table, lambda e: f'{e.__class__.__name__}.{e.name}')
>>> print(rendered_oracle_table) #doctest: +NORMALIZE_WHITESPACE
{
SimpleVariable.Sum: {
SimpleTerminal.Number: [[SimpleVariable.Term, SimpleVariable.Sum_]],
SimpleTerminal.Letter: [[SimpleVariable.Term, SimpleVariable.Sum_]],
SimpleTerminal.Plus: []
},
SimpleVariable.Sum_: {
SimpleTerminal.Number: [],
SimpleTerminal.Letter: [],
SimpleTerminal.Plus: [[SimpleTerminal.Plus, SimpleVariable.Sum]]
},
SimpleVariable.Term: {
SimpleTerminal.Number: [[SimpleTerminal.Number]],
SimpleTerminal.Letter: [[SimpleTerminal.Letter]],
SimpleTerminal.Plus: []
}
}
"""
return '{\n' + ",\n".join([
f'{render(v)}: {"{"}\n' + ',\n'.join([
f'\t{render(t)}: [' + ', '.join([
'[' + ', '.join([
render(symbol)
for symbol in expansion
]) + ']'
for expansion in expansions
]) + ']'
for (t, expansions) in term_table.items()
]) + '\n}'
for (v, term_table) in oracle_table.items()
]) + '\n}'
EA = TypeVar('EA', bound=Enum)
EB = TypeVar('EB', bound=Enum)
def print_oracle_table_enum(
oracle_table: Mapping[A, Mapping[B, Collection[Sequence[A | B]]]]
) -> str:
"""
A special case of `print_oracle_table` where tokens and variables are enums
Always produces valid python.
### Example:
We generate a simple grammar:
>>> class SimpleVariable(IntEnum):
... Sum = auto()
... Sum_ = auto()
... Term = auto()
>>> class SimpleTerminal(IntEnum):
... Number = auto()
... Letter = auto()
... Plus = auto()
>>> grammar = [
... (SimpleVariable.Sum, [SimpleVariable.Term, SimpleVariable.Sum_]),
... (SimpleVariable.Sum_, [SimpleTerminal.Plus, SimpleVariable.Sum]),
... (SimpleVariable.Sum_, []),
... (SimpleVariable.Term, [SimpleTerminal.Number]),
... (SimpleVariable.Term, [SimpleTerminal.Letter]),
... ]
>>> is_tok = p_instance(SimpleTerminal)
>>> is_var = p_instance(SimpleVariable)
>>> my_oracle_table = oracle_table(is_tok, is_var, grammar)
>>> rendered_oracle_table = print_oracle_table_enum(my_oracle_table)
>>> print(rendered_oracle_table) #doctest: +NORMALIZE_WHITESPACE
{
SimpleVariable.Sum: {
SimpleTerminal.Number: [[SimpleVariable.Term, SimpleVariable.Sum_]],
SimpleTerminal.Letter: [[SimpleVariable.Term, SimpleVariable.Sum_]],
SimpleTerminal.Plus: []
},
SimpleVariable.Sum_: {
SimpleTerminal.Number: [],
SimpleTerminal.Letter: [],
SimpleTerminal.Plus: [[SimpleTerminal.Plus, SimpleVariable.Sum]]
},
SimpleVariable.Term: {
SimpleTerminal.Number: [[SimpleTerminal.Number]],
SimpleTerminal.Letter: [[SimpleTerminal.Letter]],
SimpleTerminal.Plus: []
}
}
"""
return print_oracle_table(oracle_table, lambda e: f'{e.__class__.__name__}.{e.name}') #type: ignore
if __name__ == '__main__':
import doctest
from grammar import GRAMMAR, Tok, Variable

View file

@ -1,15 +0,0 @@
#!/bin/bash
cat << EOF > oracle_table.py
from grammar import Tok, Variable
oracle_table = (
EOF
if python grammar.py >> oracle_table.py; then
echo ")" >> oracle_table.py
echo "Built oracle_table.py"
else
rm oracle_table.py
python build_oracle.py
fi

View file

@ -135,19 +135,6 @@ def derive2(kb1: KnowledgeBase_, kb2: KnowledgeBase_) -> KnowledgeBase:
for clause in merge_clauses(c1, c2)
)
is_false: Callable[[Clause_], bool] = c(p(eq, 0), len)
"""
Determines whether a clause is equivalent to false
This is only true for the empty clause.
>>> is_false([])
True
>>> is_false([IRProp('real')])
False
"""
false_clause: Clause = FSet()
"""
The clause which represents the logical condition False