예제 #1
0
 def test_given_non_lr1_when_collision_then_error(self) -> None:
     from cmaj.parser.grammar import augment
     from cmaj.parser.graph import graph_for
     grammar = Grammar(Rule('X', ['0', 'X', '0']), Rule('X', ['1', 'X', '1']), Rule('X', ['0']), Rule('X', ['1']))
     grammar = augment(grammar, 'X')
     graph = graph_for(grammar)
     self.assertRaises(ConflictError, table_for, grammar, graph)
예제 #2
0
 def test_given_grammar_with_terminal_and_valid_token_then_ast(
         self) -> None:
     grammar = augment(Grammar(Rule('A', ['a'])), 'A')
     graph = graph_for(grammar)
     table = table_for(grammar, graph)
     actual_root = parse(tokens('a'), grammar, table)
     self._assert_correct_tree(('A', ('a', )), actual_root)
     self.assertRaises(ParserError, parse, tokens('aa'), grammar, table)
예제 #3
0
 def test_given_count_grammar_when_00001111_then_ast(self) -> None:
     grammar = augment(
         Grammar(Rule('X', ['0', 'X', '1']), Rule('X', ['0', '1'])), 'X')
     graph = graph_for(grammar)
     table = table_for(grammar, graph)
     actual_root = parse(tokens('00001111'), grammar, table)
     expected_tree = ('X', '0', ('X', '0', ('X', '0', ('X', '0', '1'), '1'),
                                 '1'), '1')
     self._assert_correct_tree(expected_tree, actual_root)
     self.assertRaises(ParserError, parse, tokens('001'), grammar, table)
예제 #4
0
    def test_given_slr_grammar_then_correct_table(self) -> None:
        from cmaj.parser.grammar import augment
        from cmaj.parser.graph import graph_for
        grammar = augment(Grammar(Rule('S', ['X', 'X']), Rule('X', ['a', 'X']), Rule('X', ['b'])), 'S')
        graph = graph_for(grammar)
        table = table_for(grammar, graph)

        s = [row_of(graph, 0, 0, Grammar.AUGMENTED_EOF),
             row_of(graph, 3, 1, Grammar.AUGMENTED_EOF),
             row_of(graph, 0, 1, Grammar.AUGMENTED_EOF),
             row_of(graph, 1, 1, 'a'),
             row_of(graph, 2, 1, 'a'),
             row_of(graph, 0, 2, Grammar.AUGMENTED_EOF),
             row_of(graph, 1, 1, Grammar.AUGMENTED_EOF),
             row_of(graph, 2, 1, Grammar.AUGMENTED_EOF),
             row_of(graph, 1, 2, 'a'),
             row_of(graph, 1, 2, Grammar.AUGMENTED_EOF)]

        count = sum(1 for row in range(10) for column in ['S', 'X', 'a', 'b', Grammar.AUGMENTED_EOF]
                    if table.action(row, column) is None)
        self.assertEqual(29, count)

        self.assertEqual(Action.shift(s[3]), table.action(s[0], 'a'))
        self.assertEqual(Action.shift(s[4]), table.action(s[0], 'b'))
        self.assertEqual(Action.goto(s[1]), table.action(s[0], 'S'))
        self.assertEqual(Action.goto(s[2]), table.action(s[0], 'X'))

        self.assertEqual(Action.accept(3), table.action(s[1], Grammar.AUGMENTED_EOF))

        self.assertEqual(Action.shift(s[6]), table.action(s[2], 'a'))
        self.assertEqual(Action.shift(s[7]), table.action(s[2], 'b'))
        self.assertEqual(Action.goto(s[5]), table.action(s[2], 'X'))

        self.assertEqual(Action.shift(s[3]), table.action(s[3], 'a'))
        self.assertEqual(Action.shift(s[4]), table.action(s[3], 'b'))
        self.assertEqual(Action.goto(s[8]), table.action(s[3], 'X'))

        self.assertEqual(Action.reduce(2), table.action(s[4], 'a'))
        self.assertEqual(Action.reduce(2), table.action(s[4], 'b'))

        self.assertEqual(Action.reduce(0), table.action(s[5], Grammar.AUGMENTED_EOF))

        self.assertEqual(Action.shift(s[6]), table.action(s[6], 'a'))
        self.assertEqual(Action.shift(s[7]), table.action(s[6], 'b'))
        self.assertEqual(Action.goto(s[9]), table.action(s[6], 'X'))

        self.assertEqual(Action.reduce(2), table.action(s[7], Grammar.AUGMENTED_EOF))

        self.assertEqual(Action.reduce(1), table.action(s[8], 'a'))
        self.assertEqual(Action.reduce(1), table.action(s[8], 'b'))

        self.assertEqual(Action.reduce(1), table.action(s[9], Grammar.AUGMENTED_EOF))
예제 #5
0
def meta_grammar() -> Grammar:
    from cmaj.parser.grammar import Rule, augment
    grammar = Grammar(Rule('GRAMMAR', ['LINE', 'GRAMMAR']),
                      Rule('GRAMMAR', ['LINE']),
                      Rule('LINE', ['DEFINITION', 'eol']),
                      Rule('LINE', ['comment', 'eol']), Rule('LINE', ['eol']),
                      Rule('DEFINITION', ['identifier', '=', 'OPTION']),
                      Rule('OPTION', ['SEQUENCE', '|', 'OPTION']),
                      Rule('OPTION', ['SEQUENCE']),
                      Rule('SEQUENCE', ['ANCHOR', 'SEQUENCE']),
                      Rule('SEQUENCE', ['ANCHOR']), Rule('ANCHOR', ['string']),
                      Rule('ANCHOR', ['identifier']))
    return augment(grammar, 'GRAMMAR')
예제 #6
0
    def test_given_grammar_and_graph_then_table_with_num_closures_rows_and_num_symbols_columns(self) -> None:
        from cmaj.parser.grammar import augment
        from cmaj.testing.closure import closure
        grammar = augment(Grammar(Rule('A', ['a']), Rule('B', ['b'])), 'A')

        graph = ClosureGraph()
        c1 = closure((0, 0, '$'))
        c2 = closure((1, 0, '$'))
        graph.add_edge(c1, 'a', c2)
        graph.add_edge(c2, 'b', c1)

        table = table_for(grammar, graph)
        self.assertEqual(2, table.num_rows)
        self.assertEqual(5, table.num_columns)
예제 #7
0
 def test_given_arithmetic_grammar_when_1add1add1mul1add1_then_ast(
         self) -> None:
     grammar = augment(
         Grammar(Rule('ADD', ['ADD', '+', 'MUL']), Rule('ADD', ['MUL']),
                 Rule('MUL', ['MUL', '*', '1']), Rule('MUL', ['1'])), 'ADD')
     graph = graph_for(grammar)
     table = table_for(grammar, graph)
     actual_root = parse(tokens('1+1+1*1+1'), grammar, table)
     mul_one = ('MUL', '1')
     add_one = ('ADD', mul_one)
     expected_tree = ('ADD', ('ADD', ('ADD', add_one, '+', mul_one), '+',
                              ('MUL', mul_one, '*', '1')), '+', mul_one)
     self._assert_correct_tree(expected_tree, actual_root)
     self.assertRaises(ParserError, parse, tokens('11+1'), grammar, table)
예제 #8
0
    def _given_grammar_then_correct_graph(self, grammar: Grammar, start: str,
                                          expected_closures: List[Closure],
                                          expected_edges: List[Tuple[int, str, int]]) -> None:
        from cmaj.parser.grammar import augment
        actual_graph = graph_for(augment(grammar, start))

        self.assertEqual(len(expected_closures), actual_graph.num_closures)
        self.assertEqual(len(expected_edges), actual_graph.num_edges)
        self.assertEqual(0, actual_graph.index(expected_closures[0]))  # Initial state contains start symbol.

        for c in expected_closures:
            self.assertIn(c, actual_graph.closures)

        for i, symbol, j in expected_edges:
            source = actual_graph.index(expected_closures[i])
            target = actual_graph.index(expected_closures[j])
            self.assertEqual(target, actual_graph.successor(source, symbol))
예제 #9
0
 def test_given_augmented_grammar_then_augmented_rule_is_last(self) -> None:
     from cmaj.parser.grammar import augment
     grammar = augment(Grammar(Rule('S', ['s'])), 'S')
     self.assertEqual(Rule(grammar.AUGMENTED_START, ['S']), grammar.rule_at(-1))