| @@ -12,18 +12,18 @@ from lark.reconstruct import Reconstructor | |||||
| from .json_parser import json_grammar | from .json_parser import json_grammar | ||||
| def test(): | |||||
| test_json = ''' | |||||
| { | |||||
| "empty_object" : {}, | |||||
| "empty_array" : [], | |||||
| "booleans" : { "YES" : true, "NO" : false }, | |||||
| "numbers" : [ 0, 1, -2, 3.3, 4.4e5, 6.6e-7 ], | |||||
| "strings" : [ "This", [ "And" , "That" ] ], | |||||
| "nothing" : null | |||||
| } | |||||
| ''' | |||||
| test_json = ''' | |||||
| { | |||||
| "empty_object" : {}, | |||||
| "empty_array" : [], | |||||
| "booleans" : { "YES" : true, "NO" : false }, | |||||
| "numbers" : [ 0, 1, -2, 3.3, 4.4e5, 6.6e-7 ], | |||||
| "strings" : [ "This", [ "And" , "That", "And a \\"b" ] ], | |||||
| "nothing" : null | |||||
| } | |||||
| ''' | |||||
| def test_scanless(): | |||||
| json_parser = Lark(json_grammar) | json_parser = Lark(json_grammar) | ||||
| tree = json_parser.parse(test_json) | tree = json_parser.parse(test_json) | ||||
| @@ -38,4 +38,15 @@ def test(): | |||||
| print (new_json) | print (new_json) | ||||
| print (json.loads(new_json) == json.loads(test_json)) | print (json.loads(new_json) == json.loads(test_json)) | ||||
| test() | |||||
| def test_lalr(): | |||||
| json_parser = Lark(json_grammar, parser='lalr') | |||||
| tree = json_parser.parse(test_json) | |||||
| new_json = Reconstructor(json_parser).reconstruct(tree) | |||||
| print (new_json) | |||||
| print (json.loads(new_json) == json.loads(test_json)) | |||||
| test_scanless() | |||||
| test_lalr() | |||||
| @@ -380,7 +380,7 @@ class Grammar: | |||||
| if name.startswith('_'): | if name.startswith('_'): | ||||
| options = RuleOptions.new_from(options, filter_out=True) | options = RuleOptions.new_from(options, filter_out=True) | ||||
| else: | else: | ||||
| options = RuleOptions.new_from(options, join_children=True) | |||||
| options = RuleOptions.new_from(options, create_token=name) | |||||
| name = tokens_to_convert.get(name, name) | name = tokens_to_convert.get(name, name) | ||||
| for exp in chain( tree.find_data('expansion'), tree.find_data('expr') ): | for exp in chain( tree.find_data('expansion'), tree.find_data('expr') ): | ||||
| @@ -454,10 +454,10 @@ class Grammar: | |||||
| class RuleOptions: | class RuleOptions: | ||||
| def __init__(self, keep_all_tokens=False, expand1=False, join_children=False, filter_out=False): | |||||
| def __init__(self, keep_all_tokens=False, expand1=False, create_token=None, filter_out=False): | |||||
| self.keep_all_tokens = keep_all_tokens | self.keep_all_tokens = keep_all_tokens | ||||
| self.expand1 = expand1 | self.expand1 = expand1 | ||||
| self.join_children = join_children # used for scanless postprocessing | |||||
| self.create_token = create_token # used for scanless postprocessing | |||||
| self.filter_out = filter_out # remove this rule from the tree | self.filter_out = filter_out # remove this rule from the tree | ||||
| # used for "token"-rules in scanless | # used for "token"-rules in scanless | ||||
| @@ -1,4 +1,5 @@ | |||||
| from .common import is_terminal, GrammarError | from .common import is_terminal, GrammarError | ||||
| from .lexer import Token | |||||
| class Callback(object): | class Callback(object): | ||||
| pass | pass | ||||
| @@ -12,9 +13,9 @@ def create_expand1_tree_builder_function(tree_builder): | |||||
| return tree_builder(children) | return tree_builder(children) | ||||
| return expand1 | return expand1 | ||||
| def create_join_children(tree_builder): | |||||
| def create_token_wrapper(tree_builder, name): | |||||
| def join_children(children): | def join_children(children): | ||||
| children = [''.join(children)] | |||||
| children = [Token(name, ''.join(children))] | |||||
| return tree_builder(children) | return tree_builder(children) | ||||
| return join_children | return join_children | ||||
| @@ -67,7 +68,7 @@ class ParseTreeBuilder: | |||||
| for origin, (expansions, options) in rules.items(): | for origin, (expansions, options) in rules.items(): | ||||
| keep_all_tokens = options.keep_all_tokens if options else False | keep_all_tokens = options.keep_all_tokens if options else False | ||||
| expand1 = options.expand1 if options else False | expand1 = options.expand1 if options else False | ||||
| join_children = options.join_children if options else False | |||||
| create_token = options.create_token if options else False | |||||
| _origin = origin | _origin = origin | ||||
| @@ -85,8 +86,8 @@ class ParseTreeBuilder: | |||||
| if expand1: | if expand1: | ||||
| f = create_expand1_tree_builder_function(f) | f = create_expand1_tree_builder_function(f) | ||||
| if join_children: | |||||
| f = create_join_children(f) | |||||
| if create_token: | |||||
| f = create_token_wrapper(f, create_token) | |||||
| alias_handler = create_rule_handler(expansion, f, keep_all_tokens, filter_out) | alias_handler = create_rule_handler(expansion, f, keep_all_tokens, filter_out) | ||||
| @@ -20,8 +20,11 @@ def is_iter_empty(i): | |||||
| class Reconstructor: | class Reconstructor: | ||||
| def __init__(self, parser): | def __init__(self, parser): | ||||
| tokens = {t.name:t for t in parser.lexer_conf.tokens} | |||||
| token_res = {t.name:re.compile(t.pattern.to_regexp()) for t in parser.lexer_conf.tokens} | |||||
| # Recreate the rules to assume a standard lexer | |||||
| _tokens, rules, _grammar_extra = parser.grammar.compile(lexer='standard', start='whatever') | |||||
| tokens = {t.name:t for t in _tokens} | |||||
| token_res = {t.name:re.compile(t.pattern.to_regexp()) for t in _tokens} | |||||
| class MatchData(object): | class MatchData(object): | ||||
| def __init__(self, data): | def __init__(self, data): | ||||
| @@ -71,9 +74,6 @@ class Reconstructor: | |||||
| return to_write | return to_write | ||||
| # Recreate the rules to assume a standard lexer | |||||
| _tokens, rules, _grammar_extra = parser.grammar.compile(lexer='standard', start='whatever') | |||||
| d = defaultdict(list) | d = defaultdict(list) | ||||
| for name, (expansions, _o) in rules.items(): | for name, (expansions, _o) in rules.items(): | ||||
| for expansion, alias in expansions: | for expansion, alias in expansions: | ||||