def test_extend_grammar(): grammar1 = Grammar() grammar1.add_pattern(grammar1.add_token('A'), 'a+') grammar1.add_pattern(grammar1.add_token('B'), 'b+') grammar1.add_pattern(grammar1.add_token('C'), 'c+') grammar1.add_parselet('expr', kind=ParseletKind.Pratt) grammar2 = Grammar() grammar2.add_pattern(grammar2.add_token('A'), '_a+') grammar2.add_pattern(grammar2.add_token('B'), '_b+') grammar2.add_parselet('expr', kind=ParseletKind.Pratt) result = Grammar() initial_count = len(result.symbols) result.extend(grammar1) result.extend(grammar2) assert 'A' in result.tokens assert 'B' in result.tokens assert 'C' in result.tokens assert len(result.symbols) == initial_count + 4 assert len(result.parselets) == 1 assert len(result.patterns) == 5 assert {pattern.pattern.pattern for pattern in result.patterns } == {'a+', '_a+', 'b+', '_b+', 'c+'}
def test_extend_implicit_grammar(): grammar1 = Grammar() grammar1.add_implicit('(') result = Grammar() result.extend(grammar1) assert result.patterns[0].token_id == result.tokens['('] assert result.patterns[0].priority == -len('(') assert result.patterns[0].is_implicit
def create_combinator_grammar() -> Grammar: """ Create grammar for parse combinator definition P.S. This grammar is used for bootstrap process of initial grammar, e.g. definition of combinators in grammar """ grammar = Grammar() grammar.extend(create_core_grammar()) # tokens name_id = grammar.tokens['Name'] string_id = grammar.tokens['String'] number_id = grammar.tokens['Integer'] colon_id = grammar.add_implicit(':') parent_open_id = grammar.tokens['('] parent_close_id = grammar.tokens[')'] square_open_id = grammar.tokens['['] square_close_id = grammar.tokens[']'] curly_open_id = grammar.tokens['{'] curly_close_id = grammar.tokens['}'] less_id = grammar.tokens['<'] great_id = grammar.tokens['>'] # parse combinator definition comb_id = grammar.add_parselet('combinator', result_type=CombinatorNode) seq_id = grammar.add_parselet('combinator_sequence', result_type=SequenceNode) # combinator := name: Name ":" combinator=combinator ; named variable grammar.add_parser( comb_id, make_sequence(make_named('name', name_id), colon_id, make_named('combinator', comb_id)), make_ctor(NamedNode) ) # combinator := name: Name [ '<' priority: Number '>' ] ; reference to parselet or token grammar.add_parser( comb_id, make_sequence(make_named('name', name_id), make_optional(less_id, make_named('priority', number_id), great_id)), make_ctor(ReferenceNode) ) # combinator := value: String ; reference to implicit token grammar.add_parser(comb_id, make_named('value', string_id), make_ctor(ImplicitNode)) # combinator := '[' combinator: combinator_sequence ']' ; optional combinator grammar.add_parser( comb_id, make_sequence(square_open_id, make_named('combinator', seq_id), square_close_id), make_ctor(OptionalNode) ) # combinator := '{' combinator: combinator_sequence '}' ; repeat combinator grammar.add_parser( comb_id, make_sequence(curly_open_id, make_named('combinator', seq_id), curly_close_id), make_ctor(RepeatNode) ) # combinator := '(' combinator: combinator_sequence ')' ; parenthesis combinator grammar.add_parser( comb_id, make_sequence(parent_open_id, make_named('combinator', seq_id), parent_close_id), make_return_variable('combinator') ) # combinator_sequence := combinators:combinator combinators:{ combinator } ; sequence combinator grammar.add_parser( seq_id, make_sequence(make_named('combinators', comb_id), make_named('combinators', make_repeat(comb_id))), make_ctor(SequenceNode) ) return grammar