From f566a3618b45340a9b5b0591f36796fea415ff46 Mon Sep 17 00:00:00 2001 From: Erez Sh Date: Mon, 7 Oct 2019 12:14:10 +0300 Subject: [PATCH] Bugfix: Lark now throws an error for recursive terminals (Issue #264) --- lark/load_grammar.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lark/load_grammar.py b/lark/load_grammar.py index 90911fd..1b4ab65 100644 --- a/lark/load_grammar.py +++ b/lark/load_grammar.py @@ -479,7 +479,7 @@ class Grammar: # =================== # Convert terminal-trees to strings/regexps - transformer = PrepareLiterals() * TerminalTreeToPattern() + for name, (term_tree, priority) in term_defs: if term_tree is None: # Terminal added through %declare continue @@ -487,7 +487,8 @@ class Grammar: if len(expansions) == 1 and not expansions[0].children: raise GrammarError("Terminals cannot be empty (%s)" % name) - terminals = [TerminalDef(name, transformer.transform(term_tree), priority) + transformer = PrepareLiterals() * TerminalTreeToPattern() + terminals = [TerminalDef(name, transformer.transform( term_tree ), priority) for name, (term_tree, priority) in term_defs if term_tree] # ================= @@ -638,11 +639,10 @@ def import_from_grammar_into_namespace(grammar, namespace, aliases): def resolve_term_references(term_defs): - # TODO Cycles detection # TODO Solve with transitive closure (maybe) - token_dict = {k:t for k, (t,_p) in term_defs} - assert len(token_dict) == len(term_defs), "Same name defined twice?" + term_dict = {k:t for k, (t,_p) in term_defs} + assert len(term_dict) == len(term_defs), "Same name defined twice?" while True: changed = False @@ -655,11 +655,19 @@ def resolve_term_references(term_defs): if item.type == 'RULE': raise GrammarError("Rules aren't allowed inside terminals (%s in %s)" % (item, name)) if item.type == 'TERMINAL': - exp.children[0] = token_dict[item] + term_value = term_dict[item] + exp.children[0] = term_value changed = True if not changed: break + for name, term in term_dict.items(): + for child in term.children: + ids = [id(x) for x in child.iter_subtrees()] + if id(term) in ids: + raise GrammarError("Recursion in terminal '%s' (recursion is only allowed in rules, not terminals)" % name) + + def options_from_rule(name, *x): if len(x) > 1: priority, expansions = x