def test_given_states_followed_by_terminals_then_complete_closure( self) -> None: grammar = Grammar(Rule('A', ['X', 'a']), Rule('A', ['A', 'X']), Rule('X', ['x'])) result = closure_for(grammar, RuleState(0, 1, {'$'}), RuleState(1, 2, {'$'})) self.assertEqual({RuleState(0, 1, {'$'}), RuleState(1, 2, {'$'})}, result)
def test_given_states_followed_by_recursion_then_closure_includes_all_lookaheads( self) -> None: grammar = Grammar(Rule('A', ['a', 'A']), Rule('A', ['A', 'A'])) result = closure_for(grammar, RuleState(0, 1, {'$'})) expected = { RuleState(0, 1, {'$'}), RuleState(1, 0, {'$', 'a'}), RuleState(0, 0, {'$', 'a'}) } self.assertEqual(expected, result)
def test_given_states_followed_by_references_then_closure_includes_references( self) -> None: grammar = Grammar(Rule('A', ['x', 'B']), Rule('B', ['C']), Rule('C', ['x'])) result = closure_for(grammar, RuleState(0, 1, {'$'})) expected = { RuleState(0, 1, {'$'}), RuleState(1, 0, {'$'}), RuleState(2, 0, {'$'}) } self.assertEqual(expected, result)
def test_given_lookaheads_then_closure_simplifies_lookaheads(self) -> None: grammar = Grammar(Rule('A', ['a']), Rule('A', ['B', 'B']), Rule('B', ['b']), Rule('B', ['A', 'B'])) result = closure_for(grammar, RuleState(1, 1, {'x', 'y'})) expected = { RuleState(1, 1, {'x', 'y'}), RuleState(2, 0, {'x', 'y', 'b', 'a'}), RuleState(3, 0, {'x', 'y', 'b', 'a'}), RuleState(0, 0, {'b', 'a'}), RuleState(1, 0, {'b', 'a'}) } self.assertEqual(expected, result)
def test_given_states_in_cycles_then_closure_includes_all_lookaheads( self) -> None: grammar = Grammar(Rule('C', ['A']), Rule('A', ['B', 'B']), Rule('B', ['C']), Rule('C', ['c']), Rule('A', ['a']), Rule('B', ['b'])) result = closure_for(grammar, RuleState(1, 1, {'$'})) expected = { RuleState(1, 1, {'$'}), RuleState(2, 0, {'$', 'c', 'a', 'b'}), RuleState(5, 0, {'$', 'c', 'a', 'b'}), RuleState(0, 0, {'$', 'c', 'a', 'b'}), RuleState(3, 0, {'$', 'c', 'a', 'b'}), RuleState(1, 0, {'$', 'c', 'a', 'b'}), RuleState(4, 0, {'$', 'c', 'a', 'b'}) } self.assertEqual(expected, result)
def graph_for(grammar: Grammar) -> ClosureGraph: from cmaj.parser.closure import closure_for, successors_for graph = ClosureGraph() fringe = {closure_for(grammar, RuleState.start(grammar))} while fringe: source = fringe.pop() graph.add_closure(source) successors = successors_for(grammar, source) fringe |= { target for target in successors.values() if target not in graph } for symbol, target in successors.items(): graph.add_edge(source, symbol, target) return graph
def test_given_state_followed_by_two_references_then_lookahead_of_reference( self) -> None: grammar = Grammar(Rule('A', ['B', 'B']), Rule('B', ['b'])) result = closure_for(grammar, RuleState(0, 0, {'$'})) self.assertEqual({RuleState(0, 0, {'$'}), RuleState(1, 0, {'b'})}, result)
def test_given_grammar_with_single_rule_then_complete_closure( self) -> None: grammar = Grammar(Rule('X', ['x'])) result = closure_for(grammar, RuleState(0, 0, {'$'})) self.assertEqual({RuleState(0, 0, {'$'})}, result)