walker: add Subgrammar node + recursion-depth cap (ADR-0026 step 1)
New `Node::Subgrammar(&'static Node)` variant lets a named static grammar fragment recurse through a reference — `Seq` / `Choice` embed children by value and cannot close a cycle, but a `&'static Node` can point back at an enclosing fragment. This is the mechanism the stratified WHERE-expression grammar (ADR-0026 §2) recurses through. The walker counts active Subgrammar frames in `WalkContext::subgrammar_depth` and refuses past `MAX_SUBGRAMMAR_DEPTH` (64), surfacing a friendly `parse.custom.expression_too_deep` error instead of a stack overflow. Depth is saved/restored per frame so a speculatively-walked-then-rolled-back Choice branch leaves no residue. No grammar references the node yet; covered by walker unit tests with a small recursive `( x )` test grammar.
This commit is contained in:
@@ -75,6 +75,13 @@ pub struct WalkContext<'a> {
|
||||
/// skipped from the value list because the dispatch path
|
||||
/// auto-fills them).
|
||||
pub user_listed_columns: Option<Vec<String>>,
|
||||
/// Count of active `Node::Subgrammar` frames on the walk
|
||||
/// stack (ADR-0026 §2). The walker increments on entry to a
|
||||
/// `Subgrammar`, restores the saved value on exit, and
|
||||
/// refuses past `driver::MAX_SUBGRAMMAR_DEPTH` so a
|
||||
/// pathologically nested expression fails with a friendly
|
||||
/// error instead of overflowing the process stack.
|
||||
pub subgrammar_depth: usize,
|
||||
}
|
||||
|
||||
impl<'a> WalkContext<'a> {
|
||||
@@ -100,6 +107,7 @@ impl<'a> WalkContext<'a> {
|
||||
pending_value_column: None,
|
||||
pending_hint_mode: None,
|
||||
user_listed_columns: None,
|
||||
subgrammar_depth: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user