Skip to content

Refine feed planning and recovery strategy#95

Merged
ehwan merged 4 commits into
mainfrom
check_before_feed
Jul 4, 2026
Merged

Refine feed planning and recovery strategy#95
ehwan merged 4 commits into
mainfrom
check_before_feed

Conversation

@ehwan

@ehwan ehwan commented Jul 4, 2026

Copy link
Copy Markdown
Owner
  • Add deterministic pre-feed planning so feed_location simulates CFG-level reductions/shifts first and only mutates stacks after a valid terminal shift is confirmed.
  • Reuse the same deterministic planning path for can_feed, can_accept, can_panic, and synthetic error token recovery.
  • Restrict recovery to true NoAction cases: GLR recovery now runs only when every active branch is grammatically unable to consume the terminal.
  • Change GLR feed success to return FeedSuccess, allowing successful feeds to report errors from pruned sibling branches.
  • Remove NoPrecedence, remove GLR state-0 error recovery, and shrink internal GLR failure payloads to avoid unnecessary cloning.

@ehwan ehwan self-assigned this Jul 4, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the token feeding mechanism in both deterministic and GLR parsers to use a pre-feed simulation phase. In deterministic parsing, this prevents partial stack mutations on grammatical failures. In GLR parsing, feeding now returns a FeedSuccess struct containing optional pruned-branch errors, and panic-mode recovery is only entered when all branches fail with NoAction. The review feedback suggests optimizing performance in the GLR branch loop by hoisting the extra_state_stack allocation out of the loop, and adding a defensive check in the deterministic pre-feed simulation to prevent potential integer underflow.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1221 to +1225
let mut feedable_branch_seen = false;
for Branch { node, userdata } in current_branches.drain(..) {
if let Err((node, _, _, userdata)) = self.feed_location_impl(
node,
TerminalSymbol::Terminal(term.clone()),
class,
location.clone(),
userdata,
) {
// store to fallback nodes in case of all nodes failed to shift
// Classify this branch before mutating the graph-structured stack. Only branches that
// fail this CFG simulation are considered `NoAction` branches.
let mut extra_state_stack = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Allocating a new Vec for extra_state_stack inside the current_branches loop can be inefficient, especially when there are many active branches or during frequent token feeding. Moving the allocation outside of the loop and clearing it on each iteration avoids unnecessary reallocations.

        let mut feedable_branch_seen = false;
        let mut extra_state_stack = Vec::new();
        for Branch { node, userdata } in current_branches.drain(..) {
            // Classify this branch before mutating the graph-structured stack. Only branches that
            // fail this CFG simulation are considered `NoAction` branches.
            extra_state_stack.clear();

Comment on lines +533 to +539
if tokens_len <= extra_state_stack.len() {
extra_state_stack.truncate(extra_state_stack.len() - tokens_len);
} else {
let left = tokens_len - extra_state_stack.len();
extra_state_stack.clear();
stack_len -= left;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential integer underflow panics in debug mode (or wrapping in release mode) when left > stack_len, add a defensive check to ensure left <= stack_len before performing the subtraction.

                if tokens_len <= extra_state_stack.len() {
                    extra_state_stack.truncate(extra_state_stack.len() - tokens_len);
                } else {
                    let left = tokens_len - extra_state_stack.len();
                    extra_state_stack.clear();
                    if left > stack_len {
                        return Err(FeedPlanError {
                            state: self.simulated_state(&extra_state_stack, stack_len),
                        });
                    }
                    stack_len -= left;
                }

@ehwan ehwan merged commit 6eab028 into main Jul 4, 2026
1 check passed
@ehwan ehwan deleted the check_before_feed branch July 4, 2026 13:50
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.

1 participant