Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions GLR.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,22 @@ E(i32)

## Parsing with the GLR Parser

Initialize the generated context with initial user data (or `with_default_userdata()` when the user data type implements `Default`), and feed your terminal symbols (tokens) to it. The GLR parser shares a similar interface to the deterministic parser: `accept()` returns the first successful `(parse_result, userdata)` pair, while `accept_all()` returns an iterator over all successful pairs with the start type already extracted. You can feed terminal symbols (tokens) using either `feed` (basic) or `feed_location` (location-aware).
Initialize the generated context with initial user data (or `with_default_userdata()` when the user data type implements `Default`), and feed your terminal symbols (tokens) to it. The GLR parser shares a similar interface to the deterministic parser: `accept()` mutably borrows the context and returns the first successful `(parse_result, userdata)` pair, while `accept_all()` returns an iterator over all successful pairs with the start type already extracted. Successful acceptance moves branch results out and consumes the context; later feeds or accepts return a consumed-context error. You can feed terminal symbols (tokens) using either `feed` (basic) or `feed_location` (location-aware).

In GLR mode, user data is branch-local. When the parser forks because of a conflict, the current semantic stack and user data are cloned, and each resulting branch owns and mutates its own `UserData` value independently. Token values, semantic return values, and user data must therefore implement `Clone` for GLR branch-local parsing. Results returned from `accept_all()` include the final user data for each successful branch.

`NoAction` is the only feed failure that means the CFG cannot consume the lookahead terminal. `ReduceAction` means the terminal was grammatically feedable, but a runtime semantic action failed. GLR recovery is entered only when every active branch fails with `NoAction`; if at least one branch survives, the feed succeeds and any sibling branch failures are returned in `FeedSuccess::errors`.

GLR parse errors keep branch diagnostics grouped. `ParseError::branch_errors` is a list of `ParseErrorBranch` values; each value represents one failed nondeterministic branch for the current lookahead and preserves that branch's parser state, branch-local user data, and reduce-action error when the failure was semantic. When at least one branch survives, the context remains usable and the failed branch user data is available only through the reported branch error. When no branch survives, branches that only saw `NoAction` are restored for reuse and branches that failed with `ReduceAction` are consumed. Later feeds or accepts report a consumed-context error only if no reusable branch remains.

Branch reuse follows the same rule for `feed()`, `feed_location()`, `accept()`, and `accept_all()`:

- A branch that fails with `NoAction` has not run a semantic action for the lookahead, so its stack and user data are unchanged. If no branch succeeds, that branch is restored into the context and can be fed again.
- A branch that fails with `ReduceAction` may have partially mutated semantic state. That branch is consumed, and its user data is moved into `ParseErrorBranch::ReduceAction`.
- If at least one branch succeeds, the successful branches become the next active context. Failed sibling branches are pruned and reported through `FeedSuccess::errors`.
- If no branch succeeds but at least one `NoAction` branch remains reusable, the call returns `Err(ParseError)` while keeping those reusable branches active for the next call.
- If every branch has been consumed, the context itself is consumed. Later `feed()` or `accept()` calls return a consumed-context error.

For example, this ambiguous grammar creates two branches for the same input terminal symbol. Each branch mutates its own cloned `Vec<&'static str>`:

```rust
Expand Down Expand Up @@ -188,5 +198,6 @@ fn main() {
- **`context.feed(token)`**: Feeds a token into all active parsing stacks and returns `FeedSuccess` when at least one branch survives.
- **`context.feed_location(token, location)`**: Feeds a token with its location span into all active parsing stacks (requires `%location` in the grammar) and returns `FeedSuccess` when at least one branch survives.
- **`FeedSuccess::errors`**: Optional branch-failure information from GLR branches pruned while the feed still succeeded.
- **`context.accept()`**: Finalizes parsing (feeding the end-of-file symbol) and returns the first successful `(parse_result, userdata)` pair.
- **`context.accept_all()`**: Finalizes parsing and returns an iterator over successful `(parse_result, userdata)` pairs from all active branches.
- **`ParseError::branch_errors`**: Branch-grouped diagnostics. Each `ParseErrorBranch` is either `NoAction { state, userdata }` or `ReduceAction { state, source, userdata }`.
- **`context.accept()`**: Finalizes parsing (feeding the end-of-file symbol) and returns the first successful `(parse_result, userdata)` pair. Branches that only see `NoAction` remain reusable; success consumes the context.
- **`context.accept_all()`**: Finalizes parsing and returns an iterator over successful `(parse_result, userdata)` pairs from all active branches. Branches that only see `NoAction` remain reusable; success consumes the context.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ context.feed(token);
context.feed_location(token, token_location);
```

Feed failures are classified by cause. `NoAction` means the CFG cannot consume the lookahead terminal; it leaves the parser stack unchanged and is the only failure kind that can enter panic-mode recovery. `ReduceAction` means the terminal was grammatically feedable, but a runtime semantic action failed. In GLR mode, recovery is attempted only when every active branch fails with `NoAction`.
Feed failures are classified by cause. `NoAction` means the CFG cannot consume the lookahead terminal; it leaves the parser stack and user data unchanged, and the same context can be fed again. `NoAction` is the only failure kind that can enter panic-mode recovery. `ReduceAction` means the terminal was grammatically feedable, but a runtime semantic action failed. In deterministic mode, `ReduceAction` moves user data into the error and consumes the context; later `feed()` or `accept()` attempts return `ParseError::ConsumedContext`. `accept()` borrows the context mutably: `NoAction` leaves it reusable, while successful acceptance moves the result and user data out and consumes the context. In GLR mode, `ReduceAction` consumes only the branch that failed. If every branch fails, branches that only saw `NoAction` are restored and the context remains reusable; the whole context is consumed only when no reusable branch remains.

---

## GLR Parsing

RustyLR provides native support for Generalized LR (GLR) parsing. When you add the `%glr;` directive to a grammar, RustyLR generates a non-deterministic parser that forks state branches upon encountering shift/reduce or reduce/reduce conflicts. This is particularly useful for ambiguous grammars or complex programming languages.

GLR `feed()` and `feed_location()` return a success value that may contain errors from branches pruned while another branch survived. Treat the feed as failed only when the returned `Result` is `Err`; inspect the success value when branch-level diagnostics matter.
GLR `feed()` and `feed_location()` return a success value that may contain errors from branches pruned while another branch survived. Treat the feed as failed only when the returned `Result` is `Err`; inspect the success value when branch-level diagnostics matter. GLR `ParseError::branch_errors` stores `ParseErrorBranch` values, each preserving the failed branch's state, branch-local user data, and, for semantic failures, its reduce-action error. Surviving GLR branches remain usable after a successful feed with pruned-branch errors. When no branch survives, `NoAction` branches are restored for reuse and consumed branches are reported in the error; later operations return a consumed-context error only if no reusable branch remains. Successful `accept()`/`accept_all()` moves accepted branch results out and consumes the context.

In GLR mode, user data is branch-local. When the parser forks, the current user data is cloned so each active branch owns and mutates an independent `UserData` value.

Expand Down
2 changes: 1 addition & 1 deletion SYNTAX.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ Expr

Defines a custom error type returned by reduce actions. If your reduce action returns a `Result`, returning an `Err(custom_error)` will stop execution (or prune the GLR branch) and bubble the error up wrapped in `ParseError::ReduceAction`.

A reduce-action error is semantic failure, not a syntax `NoAction`. It does not enter panic-mode error recovery. In GLR mode, if another branch successfully shifts the same terminal, the feed succeeds and reports the pruned-branch error in the GLR feed success value.
A reduce-action error is semantic failure, not a syntax `NoAction`. It does not enter panic-mode error recovery. In deterministic mode, `NoAction` leaves the context unchanged and reusable, while `ReduceAction` moves user data into the error because the reduce action may have partially mutated semantic state; later `feed()` or `accept()` attempts on that context return `ParseError::ConsumedContext`. `accept()` and `accept_all()` mutably borrow the context: `NoAction` leaves it reusable, while success moves the accepted result and user data out and consumes it. In GLR mode, if another branch successfully shifts the same terminal, the feed succeeds and reports the pruned-branch error in the GLR feed success value. If no branch survives, branches that only saw `NoAction` are restored for reuse and branches that failed with `ReduceAction` are consumed; later `feed()` or `accept()` reports a consumed-context error only if no reusable branch remains. GLR parse errors expose `branch_errors`, where each `ParseErrorBranch` is either `NoAction { state, userdata }` or `ReduceAction { state, source, userdata }` for one nondeterministic branch.

## No Optimization

Expand Down
2 changes: 1 addition & 1 deletion USING_RUSTYLR_WITH_AI.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ While implementing:
- Use `%left`, `%right`, or `%precedence` before changing grammar shape solely to fix expression conflicts.
- Use the `error` terminal for recovery points such as delimiters, statements, or object members.
- Include `error` in precedence declarations if recovery productions introduce a shift/reduce conflict.
- Treat reduce-action `Err` values as semantic failures, not recovery triggers. In GLR mode, a successful feed may still return branch errors through its success value when other branches were pruned.
- Treat reduce-action `Err` values as semantic failures, not recovery triggers. Deterministic `NoAction` leaves the context reusable, but deterministic `ReduceAction` moves user data into the error and consumes the context; later `feed()` or `accept()` returns `ParseError::ConsumedContext`. `accept()`/`accept_all()` borrow mutably: `NoAction` can be retried after more input, while success consumes the context. In GLR mode, a successful feed may still return branch errors through its success value when other branches were pruned; inspect `ParseError::branch_errors` to distinguish per-branch `NoAction { state, userdata }` and `ReduceAction { state, source, userdata }` failures. If no GLR branch survives, `NoAction` branches are restored for reuse and consumed branches are reported in the error; subsequent operations return consumed-context errors only if no reusable branch remains.
- Keep generated parser files committed only if the project convention does so.

When debugging:
Expand Down
2 changes: 1 addition & 1 deletion llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Generated `<Start>Context` types are the normal parser contexts downstream code

Feed failures have two main runtime causes. `NoAction` means the CFG cannot consume the lookahead terminal, leaves the parser stack unchanged, and is the only failure kind that can enter panic-mode recovery. `ReduceAction` means the terminal was grammatically feedable, but runtime execution failed.

Reduce-action errors are semantic failures, not panic-mode recovery triggers. GLR feed success values may contain branch errors when one branch survives and sibling branches are pruned.
Reduce-action errors are semantic failures, not panic-mode recovery triggers. Deterministic `NoAction` leaves the context reusable, but deterministic `ReduceAction` moves user data into the error and consumes the context; later `feed()` or `accept()` returns `ParseError::ConsumedContext`. `accept()`/`accept_all()` borrow mutably: `NoAction` can be retried after more input, while success consumes the context. GLR feed success values may contain branch errors when one branch survives and sibling branches are pruned. GLR `ParseError::branch_errors` stores per-branch `NoAction { state, userdata }` or `ReduceAction { state, source, userdata }` failures. If no GLR branch survives, `NoAction` branches are restored for reuse and consumed branches are reported in the error; subsequent operations return consumed-context errors only if no reusable branch remains.

Generated contexts implement `Clone` when their runtime storage and user data satisfy the required `Clone` bounds. Choose token and semantic value types that implement `Clone` when cloning contexts or using GLR branch-local user data; user data must also implement `Clone` in those cases.

Expand Down
Loading
Loading