From 878ca0a64f00d699c184dece89cc102b5e5f5169 Mon Sep 17 00:00:00 2001 From: cdamours Date: Fri, 26 Jun 2026 10:26:17 -0400 Subject: [PATCH] Stop greedy choice after full input match A most-greedy Choice selects the valid alternative that advances furthest through the input. Once an alternative reaches the end of the input, no later alternative can produce a longer match. This improves grammars with large Choice elements where an early alternative fully matches a complete statement. The parser can avoid walking the remaining alternatives while preserving most-greedy semantics. --- pyleri/choice.py | 2 ++ test/test_choice.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/pyleri/choice.py b/pyleri/choice.py index 9026fd9..3a6e8fe 100644 --- a/pyleri/choice.py +++ b/pyleri/choice.py @@ -37,6 +37,8 @@ def _most_greedy_result(self, root, tree, rule, s, node): if is_valid and pos > mg_pos: node.children = children mg_is_valid, mg_pos = is_valid, pos + if pos == root._len_string: + break if mg_is_valid: root._append_tree(tree, node, mg_pos) diff --git a/test/test_choice.py b/test/test_choice.py index 105fc7b..4db8566 100644 --- a/test/test_choice.py +++ b/test/test_choice.py @@ -7,10 +7,12 @@ from pyleri import ( KeywordError, create_grammar, + Repeat, Sequence, Choice, Keyword, Regex, + Token, ) # nopep8 @@ -28,6 +30,20 @@ def test_choice_most_greedy(self): self.assertTrue(grammar.parse(' hi iris ').is_valid) self.assertFalse(grammar.parse(' hi sasha ').is_valid) + def test_choice_most_greedy_selects_full_match(self): + short = Token('a') + long = Token('aa') + grammar = create_grammar(Repeat(Choice(short, long))) + + result = grammar.parse('aa') + repeat_node = result.tree.children[0] + choice_node = repeat_node.children[0] + + self.assertTrue(result.is_valid) + self.assertEqual(len(repeat_node.children), 1) + self.assertEqual(choice_node.children[0].element, long) + self.assertEqual(choice_node.children[0].string, 'aa') + def test_choice_first_match(self): k_hi = Keyword('hi') k_iris = Keyword('iris')