diff --git a/build_oracle.py b/build_oracle.py index 429dbca..9b3239d 100644 --- a/build_oracle.py +++ b/build_oracle.py @@ -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) - [[, ]] - - 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 diff --git a/build_oracle.sh b/build_oracle.sh deleted file mode 100644 index 8d7aa39..0000000 --- a/build_oracle.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/resolution.py b/resolution.py index 9539e06..2a5c34e 100644 --- a/resolution.py +++ b/resolution.py @@ -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