Fix GLR panic on optional empty branch#93
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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, theprevent_leafmechanism bumpsnode.child_countto prevent premature freeing during multi-reduce processing. Whenprepare_reduce_nodeis called withcount=0(empty rule) on a non-leaf node, it takes thei == node.len()path and callsadd_child(node, new_child), incrementingchild_counta second time. After the reduce loop restoreschild_countby 1, the node still haschild_count=1. The shift code then mutates and pushes this non-leaf node tonext_nodes, breaking theis_leaf()precondition on the next feed call.Fix
rusty_lr_core/src/parser/nondeterministic/context.rs: Before performing the shift after the reduce loop, checkis_leaf(). If the node has acquired children during reduce processing, allocate a fresh leaf child to carry the shift result — mirroring howprepare_reduce_nodealready 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).