Skip to content

Fix GLR panic on optional empty branch#93

Merged
ehwan merged 2 commits into
ehwan:mainfrom
Nadrieril:copilot/fix-issue-89
Jun 29, 2026
Merged

Fix GLR panic on optional empty branch#93
ehwan merged 2 commits into
ehwan:mainfrom
Nadrieril:copilot/fix-issue-89

Conversation

@ehwan

@ehwan ehwan commented Jun 29, 2026

Copy link
Copy Markdown
Owner

close #89

Nadrieril#1

GLR parser panicked with assertion failed: self.node(node).is_leaf() when a grammar rule contained an optional branch (A B)? and the same lookahead token triggered both a shift and an ε-reduce simultaneously.

Root cause

In feed_location_impl, the prevent_leaf mechanism bumps node.child_count to prevent premature freeing during multi-reduce processing. When prepare_reduce_node is called with count=0 (empty rule) on a non-leaf node, it takes the i == node.len() path and calls add_child(node, new_child), incrementing child_count a second time. After the reduce loop restores child_count by 1, the node still has child_count=1. The shift code then mutates and pushes this non-leaf node to next_nodes, breaking the is_leaf() precondition on the next feed call.

Fix

  • rusty_lr_core/src/parser/nondeterministic/context.rs: Before performing the shift after the reduce loop, check is_leaf(). If the node has acquired children during reduce processing, allocate a fresh leaf child to carry the shift result — mirroring how prepare_reduce_node already handles the reduce branches. The original node becomes a shared prefix for both paths.
  • example/glr/src/main.rs: Three regression tests reproducing the grammar from the issue (amp self_kw, amp bool_kw, ident colon amp bool_kw).

@ehwan ehwan merged commit 218c03c into ehwan:main Jun 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Internal panic on optional branch

2 participants