Skip to main content

rigsql_parser/grammar/
mod.rs

1mod ansi;
2mod postgres;
3mod tsql;
4
5pub use ansi::AnsiGrammar;
6pub use postgres::PostgresGrammar;
7pub use tsql::TsqlGrammar;
8
9use rigsql_core::{NodeSegment, Segment, SegmentType, Token, TokenKind, TokenSegment};
10
11use crate::context::ParseContext;
12
13// ── Grammar trait ────────────────────────────────────────────────
14
15/// Trait for dialect-specific SQL grammar.
16///
17/// Dialects implement `dispatch_statement` and `statement_keywords`.
18/// All shared ANSI parsing logic lives in default methods.
19pub trait Grammar: Send + Sync {
20    /// Return the set of keywords that can start a statement in this dialect.
21    fn statement_keywords(&self) -> &[&str];
22
23    /// Dispatch a single statement based on the current token.
24    /// Called from `parse_statement` after consuming leading trivia.
25    fn dispatch_statement(&self, ctx: &mut ParseContext) -> Option<Segment>;
26
27    /// Parse an optional table hint after a table reference.
28    /// Default returns `None` (ANSI has no table hints).
29    /// TSQL overrides this to handle `WITH(NOLOCK)` etc.
30    fn parse_table_hint(&self, _ctx: &mut ParseContext) -> Option<Segment> {
31        None
32    }
33
34    /// ANSI-only statement dispatch.  Dialect impls can call this as fallback.
35    fn dispatch_ansi_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
36        if ctx.peek_keyword("SELECT") || ctx.peek_keyword("WITH") {
37            self.parse_select_statement(ctx)
38        } else if ctx.peek_keyword("INSERT") {
39            self.parse_insert_statement(ctx)
40        } else if ctx.peek_keyword("UPDATE") {
41            self.parse_update_statement(ctx)
42        } else if ctx.peek_keyword("DELETE") {
43            self.parse_delete_statement(ctx)
44        } else if ctx.peek_keyword("CREATE") {
45            self.parse_create_statement(ctx)
46        } else if ctx.peek_keyword("DROP") {
47            self.parse_drop_statement(ctx)
48        } else if ctx.peek_keyword("ALTER") {
49            self.parse_alter_statement(ctx)
50        } else if ctx.peek_keyword("USE")
51            || ctx.peek_keyword("TRUNCATE")
52            || ctx.peek_keyword("OPEN")
53            || ctx.peek_keyword("CLOSE")
54            || ctx.peek_keyword("DEALLOCATE")
55            || ctx.peek_keyword("FETCH")
56            || ctx.peek_keyword("BREAK")
57            || ctx.peek_keyword("CONTINUE")
58            || ctx.peek_keyword("MERGE")
59        {
60            self.parse_simple_statement(ctx)
61        } else {
62            None
63        }
64    }
65
66    // ── Top-level ────────────────────────────────────────────────
67
68    /// Parse a complete SQL file: zero or more statements.
69    fn parse_file(&self, ctx: &mut ParseContext) -> Segment {
70        let mut children = Vec::new();
71        while !ctx.at_eof() {
72            children.extend(eat_trivia_segments(ctx));
73            if ctx.at_eof() {
74                break;
75            }
76            if let Some(stmt) = self.parse_statement(ctx) {
77                children.push(stmt);
78            } else {
79                // Error recovery: skip to the next statement boundary
80                // (semicolon or a recognised statement keyword) and wrap
81                // all skipped tokens in a single Unparsable node.
82                let error_offset = ctx
83                    .peek()
84                    .map(|t| t.span.start)
85                    .unwrap_or(ctx.source().len() as u32);
86                let mut unparsable_children = Vec::new();
87                // Always consume at least one token to guarantee forward
88                // progress and avoid infinite loops (e.g. when a statement
89                // keyword like WITH is not actually a valid statement start
90                // in this context, such as WITH(NOLOCK) table hints).
91                if let Some(token) = ctx.advance() {
92                    unparsable_children.push(any_token_segment(token));
93                }
94                while !ctx.at_eof() {
95                    // Stop before a semicolon — consume it as part of the
96                    // unparsable node so the next iteration starts cleanly.
97                    if ctx.peek_kind() == Some(TokenKind::Semicolon) {
98                        if let Some(semi) = ctx.advance() {
99                            unparsable_children.push(token_segment(semi, SegmentType::Semicolon));
100                        }
101                        break;
102                    }
103                    // Stop before a token that looks like it starts a new statement.
104                    if self.peek_statement_start(ctx) {
105                        break;
106                    }
107                    if let Some(token) = ctx.advance() {
108                        unparsable_children.push(any_token_segment(token));
109                    }
110                }
111                if !unparsable_children.is_empty() {
112                    children.push(Segment::Node(NodeSegment::new(
113                        SegmentType::Unparsable,
114                        unparsable_children,
115                    )));
116                    ctx.record_error_at(
117                        error_offset,
118                        "Unparsable segment: could not match any statement",
119                    );
120                }
121            }
122        }
123        Segment::Node(NodeSegment::new(SegmentType::File, children))
124    }
125
126    /// Parse a single statement (terminated by `;` or EOF).
127    fn parse_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
128        let save = ctx.save();
129        let mut children = Vec::new();
130        children.extend(eat_trivia_segments(ctx));
131
132        let inner = self.dispatch_statement(ctx);
133
134        match inner {
135            Some(stmt_seg) => {
136                children.push(stmt_seg);
137                // Optional trailing semicolon
138                children.extend(eat_trivia_segments(ctx));
139                if let Some(semi) = ctx.eat_kind(TokenKind::Semicolon) {
140                    children.push(token_segment(semi, SegmentType::Semicolon));
141                }
142                Some(Segment::Node(NodeSegment::new(
143                    SegmentType::Statement,
144                    children,
145                )))
146            }
147            None => {
148                ctx.restore(save);
149                None
150            }
151        }
152    }
153
154    // ── SELECT ───────────────────────────────────────────────────
155
156    fn parse_select_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
157        let mut children = Vec::new();
158
159        // WITH clause (optional)
160        if ctx.peek_keyword("WITH") {
161            if let Some(with) = self.parse_with_clause(ctx) {
162                children.push(with);
163                children.extend(eat_trivia_segments(ctx));
164            }
165        }
166
167        // SELECT clause (required)
168        let select = self.parse_select_clause(ctx)?;
169        children.push(select);
170
171        // FROM clause (optional)
172        children.extend(eat_trivia_segments(ctx));
173        if ctx.peek_keyword("FROM") {
174            if let Some(from) = self.parse_from_clause(ctx) {
175                children.push(from);
176            }
177        }
178
179        // WHERE clause (optional)
180        children.extend(eat_trivia_segments(ctx));
181        if ctx.peek_keyword("WHERE") {
182            if let Some(wh) = self.parse_where_clause(ctx) {
183                children.push(wh);
184            }
185        }
186
187        // GROUP BY clause (optional)
188        children.extend(eat_trivia_segments(ctx));
189        if ctx.peek_keywords(&["GROUP", "BY"]) {
190            if let Some(gb) = self.parse_group_by_clause(ctx) {
191                children.push(gb);
192            }
193        }
194
195        // HAVING clause (optional)
196        children.extend(eat_trivia_segments(ctx));
197        if ctx.peek_keyword("HAVING") {
198            if let Some(hav) = self.parse_having_clause(ctx) {
199                children.push(hav);
200            }
201        }
202
203        // ORDER BY clause (optional)
204        children.extend(eat_trivia_segments(ctx));
205        if ctx.peek_keywords(&["ORDER", "BY"]) {
206            if let Some(ob) = self.parse_order_by_clause(ctx) {
207                children.push(ob);
208            }
209        }
210
211        // LIMIT clause (optional)
212        children.extend(eat_trivia_segments(ctx));
213        if ctx.peek_keyword("LIMIT") {
214            if let Some(lim) = self.parse_limit_clause(ctx) {
215                children.push(lim);
216            }
217        }
218
219        // OFFSET clause (optional)
220        children.extend(eat_trivia_segments(ctx));
221        if ctx.peek_keyword("OFFSET") {
222            if let Some(off) = self.parse_offset_clause(ctx) {
223                children.push(off);
224            }
225        }
226
227        // UNION / INTERSECT / EXCEPT (optional, recursive)
228        children.extend(eat_trivia_segments(ctx));
229        if ctx.peek_keyword("UNION") || ctx.peek_keyword("INTERSECT") || ctx.peek_keyword("EXCEPT")
230        {
231            if let Some(set_op) = self.parse_set_operation(ctx) {
232                children.push(set_op);
233            }
234        }
235
236        Some(Segment::Node(NodeSegment::new(
237            SegmentType::SelectStatement,
238            children,
239        )))
240    }
241
242    fn parse_select_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
243        let mut children = Vec::new();
244
245        let kw = ctx.eat_keyword("SELECT")?;
246        children.push(token_segment(kw, SegmentType::Keyword));
247
248        children.extend(eat_trivia_segments(ctx));
249
250        // DISTINCT / ALL (optional)
251        if ctx.peek_keyword("DISTINCT") || ctx.peek_keyword("ALL") {
252            if let Some(token) = ctx.advance() {
253                children.push(token_segment(token, SegmentType::Keyword));
254                children.extend(eat_trivia_segments(ctx));
255            }
256        }
257
258        // TOP (N) / TOP N (TSQL)
259        if ctx.peek_keyword("TOP") {
260            if let Some(top_kw) = ctx.advance() {
261                children.push(token_segment(top_kw, SegmentType::Keyword));
262                children.extend(eat_trivia_segments(ctx));
263                // TOP (expr) or TOP N
264                if let Some(lparen) = ctx.eat_kind(TokenKind::LParen) {
265                    children.push(token_segment(lparen, SegmentType::LParen));
266                    children.extend(eat_trivia_segments(ctx));
267                    if let Some(expr) = self.parse_expression(ctx) {
268                        children.push(expr);
269                    }
270                    children.extend(eat_trivia_segments(ctx));
271                    if let Some(rparen) = ctx.eat_kind(TokenKind::RParen) {
272                        children.push(token_segment(rparen, SegmentType::RParen));
273                    }
274                } else if let Some(num) = ctx.eat_kind(TokenKind::NumberLiteral) {
275                    children.push(token_segment(num, SegmentType::Literal));
276                }
277                children.extend(eat_trivia_segments(ctx));
278            }
279        }
280
281        // Select targets (comma-separated expressions)
282        parse_comma_separated(ctx, &mut children, |c| self.parse_select_target(c));
283
284        Some(Segment::Node(NodeSegment::new(
285            SegmentType::SelectClause,
286            children,
287        )))
288    }
289
290    fn parse_select_target(&self, ctx: &mut ParseContext) -> Option<Segment> {
291        // Parse an expression, optionally followed by alias (AS alias_name or just alias_name)
292        let expr = self.parse_expression(ctx)?;
293
294        let save = ctx.save();
295        let trivia = eat_trivia_segments(ctx);
296
297        // Check for alias: AS name, or just a word that's not a keyword
298        if ctx.peek_keyword("AS") {
299            let mut children = vec![expr];
300            children.extend(trivia);
301            let as_kw = ctx.advance().unwrap();
302            children.push(token_segment(as_kw, SegmentType::Keyword));
303            children.extend(eat_trivia_segments(ctx));
304            // Alias can be an identifier or a string literal (e.g. AS '日本語名')
305            if let Some(alias) = self.parse_identifier(ctx) {
306                children.push(alias);
307            } else if ctx.peek_kind() == Some(TokenKind::StringLiteral) {
308                let token = ctx.advance().unwrap();
309                children.push(token_segment(token, SegmentType::StringLiteral));
310            }
311            return Some(Segment::Node(NodeSegment::new(
312                SegmentType::AliasExpression,
313                children,
314            )));
315        }
316
317        // Implicit alias: a bare word that's not a clause keyword
318        if let Some(t) = ctx.peek_non_trivia() {
319            if t.kind == TokenKind::Word && !is_clause_keyword(&t.text) {
320                let mut children = vec![expr];
321                children.extend(trivia);
322                if let Some(alias) = self.parse_identifier(ctx) {
323                    children.push(alias);
324                }
325                return Some(Segment::Node(NodeSegment::new(
326                    SegmentType::AliasExpression,
327                    children,
328                )));
329            }
330        }
331
332        ctx.restore(save);
333        // Re-eat trivia would happen naturally at calling site
334        Some(expr)
335    }
336
337    fn parse_from_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
338        let mut children = Vec::new();
339        let kw = ctx.eat_keyword("FROM")?;
340        children.push(token_segment(kw, SegmentType::Keyword));
341        children.extend(eat_trivia_segments(ctx));
342
343        // Table references (comma-separated)
344        parse_comma_separated(ctx, &mut children, |c| self.parse_table_reference(c));
345
346        // JOIN clauses
347        loop {
348            children.extend(eat_trivia_segments(ctx));
349            if peek_join_keyword(ctx) {
350                if let Some(join) = self.parse_join_clause(ctx) {
351                    children.push(join);
352                } else {
353                    break;
354                }
355            } else {
356                break;
357            }
358        }
359
360        Some(Segment::Node(NodeSegment::new(
361            SegmentType::FromClause,
362            children,
363        )))
364    }
365
366    fn parse_table_reference(&self, ctx: &mut ParseContext) -> Option<Segment> {
367        let table_ref = self.parse_table_reference_core(ctx)?;
368
369        // Optional table hint (e.g. TSQL WITH(NOLOCK))
370        let save_hint = ctx.save();
371        let trivia = eat_trivia_segments(ctx);
372        if let Some(hint) = self.parse_table_hint(ctx) {
373            // Wrap: table_ref + trivia + hint into a TableRef node
374            let children = vec![table_ref]
375                .into_iter()
376                .chain(trivia)
377                .chain(std::iter::once(hint))
378                .collect();
379            Some(Segment::Node(NodeSegment::new(
380                SegmentType::TableRef,
381                children,
382            )))
383        } else {
384            ctx.restore(save_hint);
385            Some(table_ref)
386        }
387    }
388
389    /// Core table reference parsing (name/subquery + optional alias),
390    /// without table hints.  Called by `parse_table_reference`.
391    fn parse_table_reference_core(&self, ctx: &mut ParseContext) -> Option<Segment> {
392        let save = ctx.save();
393
394        // Subquery in parens
395        if ctx.peek_kind() == Some(TokenKind::LParen) {
396            if let Some(subq) = self.parse_paren_subquery(ctx) {
397                // Optional alias
398                let save2 = ctx.save();
399                let trivia = eat_trivia_segments(ctx);
400                if ctx.peek_keyword("AS")
401                    || ctx
402                        .peek_non_trivia()
403                        .is_some_and(|t| t.kind == TokenKind::Word && !is_clause_keyword(&t.text))
404                {
405                    let mut children = vec![subq];
406                    children.extend(trivia);
407                    if ctx.peek_keyword("AS") {
408                        let kw = ctx.advance().unwrap();
409                        children.push(token_segment(kw, SegmentType::Keyword));
410                        children.extend(eat_trivia_segments(ctx));
411                    }
412                    if let Some(alias) = self.parse_identifier(ctx) {
413                        children.push(alias);
414                    }
415                    return Some(Segment::Node(NodeSegment::new(
416                        SegmentType::AliasExpression,
417                        children,
418                    )));
419                }
420                ctx.restore(save2);
421                return Some(subq);
422            }
423        }
424
425        // Table name (possibly qualified: schema.table)
426        let name = self.parse_qualified_name(ctx);
427        if name.is_none() {
428            ctx.restore(save);
429            return None;
430        }
431        let name = name.unwrap();
432
433        // Optional alias
434        let save2 = ctx.save();
435        let trivia = eat_trivia_segments(ctx);
436        if ctx.peek_keyword("AS") {
437            let mut children = vec![name];
438            children.extend(trivia);
439            let kw = ctx.advance().unwrap();
440            children.push(token_segment(kw, SegmentType::Keyword));
441            children.extend(eat_trivia_segments(ctx));
442            if let Some(alias) = self.parse_identifier(ctx) {
443                children.push(alias);
444            }
445            return Some(Segment::Node(NodeSegment::new(
446                SegmentType::AliasExpression,
447                children,
448            )));
449        }
450        if let Some(t) = ctx.peek_non_trivia() {
451            if t.kind == TokenKind::Word && !is_clause_keyword(&t.text) && !is_join_keyword(&t.text)
452            {
453                let mut children = vec![name];
454                children.extend(trivia);
455                if let Some(alias) = self.parse_identifier(ctx) {
456                    children.push(alias);
457                }
458                return Some(Segment::Node(NodeSegment::new(
459                    SegmentType::AliasExpression,
460                    children,
461                )));
462            }
463        }
464        ctx.restore(save2);
465        Some(name)
466    }
467
468    fn parse_where_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
469        let mut children = Vec::new();
470        let kw = ctx.eat_keyword("WHERE")?;
471        children.push(token_segment(kw, SegmentType::Keyword));
472        children.extend(eat_trivia_segments(ctx));
473        if let Some(expr) = self.parse_expression(ctx) {
474            children.push(expr);
475        }
476        Some(Segment::Node(NodeSegment::new(
477            SegmentType::WhereClause,
478            children,
479        )))
480    }
481
482    fn parse_group_by_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
483        let mut children = Vec::new();
484        let group_kw = ctx.eat_keyword("GROUP")?;
485        children.push(token_segment(group_kw, SegmentType::Keyword));
486        children.extend(eat_trivia_segments(ctx));
487        let by_kw = ctx.eat_keyword("BY")?;
488        children.push(token_segment(by_kw, SegmentType::Keyword));
489        children.extend(eat_trivia_segments(ctx));
490
491        // Comma-separated expressions
492        parse_comma_separated(ctx, &mut children, |c| self.parse_expression(c));
493
494        Some(Segment::Node(NodeSegment::new(
495            SegmentType::GroupByClause,
496            children,
497        )))
498    }
499
500    fn parse_having_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
501        let mut children = Vec::new();
502        let kw = ctx.eat_keyword("HAVING")?;
503        children.push(token_segment(kw, SegmentType::Keyword));
504        children.extend(eat_trivia_segments(ctx));
505        if let Some(expr) = self.parse_expression(ctx) {
506            children.push(expr);
507        }
508        Some(Segment::Node(NodeSegment::new(
509            SegmentType::HavingClause,
510            children,
511        )))
512    }
513
514    fn parse_order_by_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
515        let mut children = Vec::new();
516        let order_kw = ctx.eat_keyword("ORDER")?;
517        children.push(token_segment(order_kw, SegmentType::Keyword));
518        children.extend(eat_trivia_segments(ctx));
519        let by_kw = ctx.eat_keyword("BY")?;
520        children.push(token_segment(by_kw, SegmentType::Keyword));
521        children.extend(eat_trivia_segments(ctx));
522
523        // Comma-separated order expressions
524        parse_comma_separated(ctx, &mut children, |c| self.parse_order_expression(c));
525
526        Some(Segment::Node(NodeSegment::new(
527            SegmentType::OrderByClause,
528            children,
529        )))
530    }
531
532    fn parse_order_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
533        let mut children = Vec::new();
534        let expr = self.parse_expression(ctx)?;
535        children.push(expr);
536
537        let save = ctx.save();
538        let trivia = eat_trivia_segments(ctx);
539        if ctx.peek_keyword("ASC") || ctx.peek_keyword("DESC") {
540            children.extend(trivia);
541            let kw = ctx.advance().unwrap();
542            children.push(token_segment(kw, SegmentType::Keyword));
543        } else {
544            ctx.restore(save);
545        }
546
547        // NULLS FIRST / NULLS LAST
548        let save = ctx.save();
549        let trivia = eat_trivia_segments(ctx);
550        if ctx.peek_keyword("NULLS") {
551            children.extend(trivia);
552            let kw = ctx.advance().unwrap();
553            children.push(token_segment(kw, SegmentType::Keyword));
554            children.extend(eat_trivia_segments(ctx));
555            if ctx.peek_keyword("FIRST") || ctx.peek_keyword("LAST") {
556                let kw = ctx.advance().unwrap();
557                children.push(token_segment(kw, SegmentType::Keyword));
558            }
559        } else {
560            ctx.restore(save);
561        }
562
563        Some(Segment::Node(NodeSegment::new(
564            SegmentType::OrderByExpression,
565            children,
566        )))
567    }
568
569    fn parse_limit_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
570        let mut children = Vec::new();
571        let kw = ctx.eat_keyword("LIMIT")?;
572        children.push(token_segment(kw, SegmentType::Keyword));
573        children.extend(eat_trivia_segments(ctx));
574        if let Some(expr) = self.parse_expression(ctx) {
575            children.push(expr);
576        }
577        Some(Segment::Node(NodeSegment::new(
578            SegmentType::LimitClause,
579            children,
580        )))
581    }
582
583    fn parse_offset_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
584        let mut children = Vec::new();
585        let kw = ctx.eat_keyword("OFFSET")?;
586        children.push(token_segment(kw, SegmentType::Keyword));
587        children.extend(eat_trivia_segments(ctx));
588        if let Some(expr) = self.parse_expression(ctx) {
589            children.push(expr);
590        }
591        Some(Segment::Node(NodeSegment::new(
592            SegmentType::OffsetClause,
593            children,
594        )))
595    }
596
597    fn parse_with_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
598        let mut children = Vec::new();
599        let kw = ctx.eat_keyword("WITH")?;
600        children.push(token_segment(kw, SegmentType::Keyword));
601        children.extend(eat_trivia_segments(ctx));
602
603        // RECURSIVE (optional)
604        if ctx.peek_keyword("RECURSIVE") {
605            let kw = ctx.advance().unwrap();
606            children.push(token_segment(kw, SegmentType::Keyword));
607            children.extend(eat_trivia_segments(ctx));
608        }
609
610        // CTE definitions (comma-separated)
611        parse_comma_separated(ctx, &mut children, |c| self.parse_cte_definition(c));
612
613        Some(Segment::Node(NodeSegment::new(
614            SegmentType::WithClause,
615            children,
616        )))
617    }
618
619    fn parse_cte_definition(&self, ctx: &mut ParseContext) -> Option<Segment> {
620        let mut children = Vec::new();
621        let name = self.parse_identifier(ctx)?;
622        children.push(name);
623        children.extend(eat_trivia_segments(ctx));
624
625        // Optional column list
626        if ctx.peek_kind() == Some(TokenKind::LParen) {
627            if let Some(cols) = self.parse_paren_block(ctx) {
628                children.push(cols);
629                children.extend(eat_trivia_segments(ctx));
630            }
631        }
632
633        let as_kw = ctx.eat_keyword("AS")?;
634        children.push(token_segment(as_kw, SegmentType::Keyword));
635        children.extend(eat_trivia_segments(ctx));
636
637        // ( subquery )
638        if let Some(subq) = self.parse_paren_subquery(ctx) {
639            children.push(subq);
640        }
641
642        Some(Segment::Node(NodeSegment::new(
643            SegmentType::CteDefinition,
644            children,
645        )))
646    }
647
648    fn parse_set_operation(&self, ctx: &mut ParseContext) -> Option<Segment> {
649        let mut children = Vec::new();
650
651        // UNION / INTERSECT / EXCEPT
652        let kw = ctx.advance()?;
653        children.push(token_segment(kw, SegmentType::Keyword));
654        children.extend(eat_trivia_segments(ctx));
655
656        // ALL / DISTINCT (optional)
657        if ctx.peek_keyword("ALL") || ctx.peek_keyword("DISTINCT") {
658            let kw = ctx.advance().unwrap();
659            children.push(token_segment(kw, SegmentType::Keyword));
660            children.extend(eat_trivia_segments(ctx));
661        }
662
663        // Following select
664        if let Some(sel) = self.parse_select_statement(ctx) {
665            children.push(sel);
666        }
667
668        Some(Segment::Node(NodeSegment::new(
669            SegmentType::SelectStatement,
670            children,
671        )))
672    }
673
674    // ── JOIN ─────────────────────────────────────────────────────
675
676    fn parse_join_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
677        let mut children = Vec::new();
678
679        // Optional: INNER / LEFT / RIGHT / FULL / CROSS
680        if ctx.peek_keyword("INNER")
681            || ctx.peek_keyword("LEFT")
682            || ctx.peek_keyword("RIGHT")
683            || ctx.peek_keyword("FULL")
684            || ctx.peek_keyword("CROSS")
685        {
686            let kw = ctx.advance().unwrap();
687            children.push(token_segment(kw, SegmentType::Keyword));
688            children.extend(eat_trivia_segments(ctx));
689
690            // Optional: OUTER
691            if ctx.peek_keyword("OUTER") {
692                let kw = ctx.advance().unwrap();
693                children.push(token_segment(kw, SegmentType::Keyword));
694                children.extend(eat_trivia_segments(ctx));
695            }
696        }
697
698        let join_kw = ctx.eat_keyword("JOIN")?;
699        children.push(token_segment(join_kw, SegmentType::Keyword));
700        children.extend(eat_trivia_segments(ctx));
701
702        // Table reference
703        if let Some(tref) = self.parse_table_reference(ctx) {
704            children.push(tref);
705        }
706
707        // ON or USING
708        children.extend(eat_trivia_segments(ctx));
709        if ctx.peek_keyword("ON") {
710            let kw = ctx.advance().unwrap();
711            let mut on_children = vec![token_segment(kw, SegmentType::Keyword)];
712            on_children.extend(eat_trivia_segments(ctx));
713            if let Some(expr) = self.parse_expression(ctx) {
714                on_children.push(expr);
715            }
716            children.push(Segment::Node(NodeSegment::new(
717                SegmentType::OnClause,
718                on_children,
719            )));
720        } else if ctx.peek_keyword("USING") {
721            let kw = ctx.advance().unwrap();
722            let mut using_children = vec![token_segment(kw, SegmentType::Keyword)];
723            using_children.extend(eat_trivia_segments(ctx));
724            if let Some(paren) = self.parse_paren_block(ctx) {
725                using_children.push(paren);
726            }
727            children.push(Segment::Node(NodeSegment::new(
728                SegmentType::UsingClause,
729                using_children,
730            )));
731        }
732
733        Some(Segment::Node(NodeSegment::new(
734            SegmentType::JoinClause,
735            children,
736        )))
737    }
738
739    // ── INSERT ───────────────────────────────────────────────────
740
741    fn parse_insert_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
742        let mut children = Vec::new();
743        let kw = ctx.eat_keyword("INSERT")?;
744        children.push(token_segment(kw, SegmentType::Keyword));
745        children.extend(eat_trivia_segments(ctx));
746
747        let into_kw = ctx.eat_keyword("INTO")?;
748        children.push(token_segment(into_kw, SegmentType::Keyword));
749        children.extend(eat_trivia_segments(ctx));
750
751        // Table name
752        if let Some(name) = self.parse_qualified_name(ctx) {
753            children.push(name);
754        }
755        children.extend(eat_trivia_segments(ctx));
756
757        // Optional column list
758        if ctx.peek_kind() == Some(TokenKind::LParen) {
759            if let Some(cols) = self.parse_paren_block(ctx) {
760                children.push(cols);
761                children.extend(eat_trivia_segments(ctx));
762            }
763        }
764
765        // VALUES or SELECT
766        if ctx.peek_keyword("VALUES") {
767            if let Some(vals) = self.parse_values_clause(ctx) {
768                children.push(vals);
769            }
770        } else if ctx.peek_keyword("SELECT") || ctx.peek_keyword("WITH") {
771            if let Some(sel) = self.parse_select_statement(ctx) {
772                children.push(sel);
773            }
774        }
775
776        Some(Segment::Node(NodeSegment::new(
777            SegmentType::InsertStatement,
778            children,
779        )))
780    }
781
782    fn parse_values_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
783        let mut children = Vec::new();
784        let kw = ctx.eat_keyword("VALUES")?;
785        children.push(token_segment(kw, SegmentType::Keyword));
786        children.extend(eat_trivia_segments(ctx));
787
788        // Comma-separated (expr, expr, ...)
789        parse_comma_separated(ctx, &mut children, |c| self.parse_paren_block(c));
790
791        Some(Segment::Node(NodeSegment::new(
792            SegmentType::ValuesClause,
793            children,
794        )))
795    }
796
797    // ── UPDATE ───────────────────────────────────────────────────
798
799    fn parse_update_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
800        let mut children = Vec::new();
801        let kw = ctx.eat_keyword("UPDATE")?;
802        children.push(token_segment(kw, SegmentType::Keyword));
803        children.extend(eat_trivia_segments(ctx));
804
805        // Table name
806        if let Some(name) = self.parse_table_reference(ctx) {
807            children.push(name);
808        }
809        children.extend(eat_trivia_segments(ctx));
810
811        // SET clause
812        if ctx.peek_keyword("SET") {
813            if let Some(set) = self.parse_set_clause(ctx) {
814                children.push(set);
815            }
816        }
817
818        // WHERE clause
819        children.extend(eat_trivia_segments(ctx));
820        if ctx.peek_keyword("WHERE") {
821            if let Some(wh) = self.parse_where_clause(ctx) {
822                children.push(wh);
823            }
824        }
825
826        Some(Segment::Node(NodeSegment::new(
827            SegmentType::UpdateStatement,
828            children,
829        )))
830    }
831
832    fn parse_set_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
833        let mut children = Vec::new();
834        let kw = ctx.eat_keyword("SET")?;
835        children.push(token_segment(kw, SegmentType::Keyword));
836        children.extend(eat_trivia_segments(ctx));
837
838        // col = expr, ...
839        parse_comma_separated(ctx, &mut children, |c| self.parse_expression(c));
840
841        Some(Segment::Node(NodeSegment::new(
842            SegmentType::SetClause,
843            children,
844        )))
845    }
846
847    // ── DELETE ────────────────────────────────────────────────────
848
849    fn parse_delete_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
850        let mut children = Vec::new();
851        let kw = ctx.eat_keyword("DELETE")?;
852        children.push(token_segment(kw, SegmentType::Keyword));
853        children.extend(eat_trivia_segments(ctx));
854
855        // FROM
856        if ctx.peek_keyword("FROM") {
857            let from_kw = ctx.advance().unwrap();
858            children.push(token_segment(from_kw, SegmentType::Keyword));
859            children.extend(eat_trivia_segments(ctx));
860        }
861
862        // Table name
863        if let Some(name) = self.parse_qualified_name(ctx) {
864            children.push(name);
865        }
866
867        // WHERE clause
868        children.extend(eat_trivia_segments(ctx));
869        if ctx.peek_keyword("WHERE") {
870            if let Some(wh) = self.parse_where_clause(ctx) {
871                children.push(wh);
872            }
873        }
874
875        Some(Segment::Node(NodeSegment::new(
876            SegmentType::DeleteStatement,
877            children,
878        )))
879    }
880
881    // ── DDL ──────────────────────────────────────────────────────
882
883    fn parse_create_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
884        let mut children = Vec::new();
885        let kw = ctx.eat_keyword("CREATE")?;
886        children.push(token_segment(kw, SegmentType::Keyword));
887        children.extend(eat_trivia_segments(ctx));
888
889        if ctx.peek_keyword("TABLE") {
890            return self.parse_create_table_body(ctx, children);
891        }
892
893        // For other CREATE statements, consume until semicolon or EOF
894        self.consume_until_end(ctx, &mut children);
895        Some(Segment::Node(NodeSegment::new(
896            SegmentType::Statement,
897            children,
898        )))
899    }
900
901    fn parse_create_table_body(
902        &self,
903        ctx: &mut ParseContext,
904        mut children: Vec<Segment>,
905    ) -> Option<Segment> {
906        let kw = ctx.eat_keyword("TABLE")?;
907        children.push(token_segment(kw, SegmentType::Keyword));
908        children.extend(eat_trivia_segments(ctx));
909
910        // IF NOT EXISTS
911        if ctx.peek_keyword("IF") {
912            let kw = ctx.advance().unwrap();
913            children.push(token_segment(kw, SegmentType::Keyword));
914            children.extend(eat_trivia_segments(ctx));
915            if let Some(kw) = ctx.eat_keyword("NOT") {
916                children.push(token_segment(kw, SegmentType::Keyword));
917                children.extend(eat_trivia_segments(ctx));
918            }
919            if let Some(kw) = ctx.eat_keyword("EXISTS") {
920                children.push(token_segment(kw, SegmentType::Keyword));
921                children.extend(eat_trivia_segments(ctx));
922            }
923        }
924
925        // Table name
926        if let Some(name) = self.parse_qualified_name(ctx) {
927            children.push(name);
928        }
929        children.extend(eat_trivia_segments(ctx));
930
931        // Column definitions in parens
932        if ctx.peek_kind() == Some(TokenKind::LParen) {
933            if let Some(defs) = self.parse_paren_block(ctx) {
934                children.push(defs);
935            }
936        }
937
938        Some(Segment::Node(NodeSegment::new(
939            SegmentType::CreateTableStatement,
940            children,
941        )))
942    }
943
944    fn parse_drop_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
945        let mut children = Vec::new();
946        let kw = ctx.eat_keyword("DROP")?;
947        children.push(token_segment(kw, SegmentType::Keyword));
948        children.extend(eat_trivia_segments(ctx));
949
950        // Consume until semicolon
951        self.consume_until_end(ctx, &mut children);
952        Some(Segment::Node(NodeSegment::new(
953            SegmentType::DropStatement,
954            children,
955        )))
956    }
957
958    fn parse_alter_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
959        let mut children = Vec::new();
960        let kw = ctx.eat_keyword("ALTER")?;
961        children.push(token_segment(kw, SegmentType::Keyword));
962        children.extend(eat_trivia_segments(ctx));
963
964        self.consume_until_end(ctx, &mut children);
965        Some(Segment::Node(NodeSegment::new(
966            SegmentType::AlterTableStatement,
967            children,
968        )))
969    }
970
971    // ── Expression parsing ───────────────────────────────────────
972
973    /// Parse an expression. This uses a simple precedence climbing approach.
974    fn parse_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
975        self.parse_or_expression(ctx)
976    }
977
978    fn parse_or_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
979        let mut left = self.parse_and_expression(ctx)?;
980        loop {
981            let save = ctx.save();
982            let trivia = eat_trivia_segments(ctx);
983            if ctx.peek_keyword("OR") {
984                let op = ctx.advance().unwrap();
985                let mut children = vec![left];
986                children.extend(trivia);
987                children.push(token_segment(op, SegmentType::Keyword));
988                children.extend(eat_trivia_segments(ctx));
989                if let Some(right) = self.parse_and_expression(ctx) {
990                    children.push(right);
991                }
992                left = Segment::Node(NodeSegment::new(SegmentType::BinaryExpression, children));
993            } else {
994                ctx.restore(save);
995                break;
996            }
997        }
998        Some(left)
999    }
1000
1001    fn parse_and_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1002        let mut left = self.parse_not_expression(ctx)?;
1003        loop {
1004            let save = ctx.save();
1005            let trivia = eat_trivia_segments(ctx);
1006            if ctx.peek_keyword("AND") {
1007                let op = ctx.advance().unwrap();
1008                let mut children = vec![left];
1009                children.extend(trivia);
1010                children.push(token_segment(op, SegmentType::Keyword));
1011                children.extend(eat_trivia_segments(ctx));
1012                if let Some(right) = self.parse_not_expression(ctx) {
1013                    children.push(right);
1014                }
1015                left = Segment::Node(NodeSegment::new(SegmentType::BinaryExpression, children));
1016            } else {
1017                ctx.restore(save);
1018                break;
1019            }
1020        }
1021        Some(left)
1022    }
1023
1024    fn parse_not_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1025        if ctx.peek_keyword("NOT") {
1026            let mut children = Vec::new();
1027            let kw = ctx.advance().unwrap();
1028            children.push(token_segment(kw, SegmentType::Keyword));
1029            children.extend(eat_trivia_segments(ctx));
1030            if let Some(expr) = self.parse_not_expression(ctx) {
1031                children.push(expr);
1032            }
1033            return Some(Segment::Node(NodeSegment::new(
1034                SegmentType::UnaryExpression,
1035                children,
1036            )));
1037        }
1038        self.parse_comparison_expression(ctx)
1039    }
1040
1041    fn parse_comparison_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1042        let left = self.parse_addition_expression(ctx)?;
1043
1044        let save = ctx.save();
1045        let trivia = eat_trivia_segments(ctx);
1046
1047        // IS [NOT] NULL
1048        if ctx.peek_keyword("IS") {
1049            let is_kw = ctx.advance().unwrap();
1050            let mut children = vec![left];
1051            children.extend(trivia);
1052            children.push(token_segment(is_kw, SegmentType::Keyword));
1053            children.extend(eat_trivia_segments(ctx));
1054            if ctx.peek_keyword("NOT") {
1055                let not_kw = ctx.advance().unwrap();
1056                children.push(token_segment(not_kw, SegmentType::Keyword));
1057                children.extend(eat_trivia_segments(ctx));
1058            }
1059            if ctx.peek_keyword("NULL") {
1060                let null_kw = ctx.advance().unwrap();
1061                children.push(token_segment(null_kw, SegmentType::Keyword));
1062            }
1063            return Some(Segment::Node(NodeSegment::new(
1064                SegmentType::IsNullExpression,
1065                children,
1066            )));
1067        }
1068
1069        // [NOT] IN (...)
1070        if ctx.peek_keyword("IN") {
1071            let in_kw = ctx.advance().unwrap();
1072            let mut children = vec![left];
1073            children.extend(trivia);
1074            children.push(token_segment(in_kw, SegmentType::Keyword));
1075            children.extend(eat_trivia_segments(ctx));
1076            if ctx.peek_kind() == Some(TokenKind::LParen) {
1077                if let Some(list) = self.parse_paren_block(ctx) {
1078                    children.push(list);
1079                }
1080            }
1081            return Some(Segment::Node(NodeSegment::new(
1082                SegmentType::InExpression,
1083                children,
1084            )));
1085        }
1086
1087        // NOT IN / NOT BETWEEN / NOT LIKE
1088        if ctx.peek_keyword("NOT") {
1089            let save_not = ctx.save();
1090            let not_kw = ctx.advance().unwrap();
1091            let not_trivia = eat_trivia_segments(ctx);
1092
1093            if ctx.peek_keyword("IN") {
1094                let in_kw = ctx.advance().unwrap();
1095                let mut children = vec![left];
1096                children.extend(trivia);
1097                children.push(token_segment(not_kw, SegmentType::Keyword));
1098                children.extend(not_trivia);
1099                children.push(token_segment(in_kw, SegmentType::Keyword));
1100                children.extend(eat_trivia_segments(ctx));
1101                if ctx.peek_kind() == Some(TokenKind::LParen) {
1102                    if let Some(list) = self.parse_paren_block(ctx) {
1103                        children.push(list);
1104                    }
1105                }
1106                return Some(Segment::Node(NodeSegment::new(
1107                    SegmentType::InExpression,
1108                    children,
1109                )));
1110            }
1111            if ctx.peek_keyword("BETWEEN") {
1112                let kw = ctx.advance().unwrap();
1113                let mut children = vec![left];
1114                children.extend(trivia);
1115                children.push(token_segment(not_kw, SegmentType::Keyword));
1116                children.extend(not_trivia);
1117                children.push(token_segment(kw, SegmentType::Keyword));
1118                children.extend(eat_trivia_segments(ctx));
1119                if let Some(lo) = self.parse_addition_expression(ctx) {
1120                    children.push(lo);
1121                }
1122                children.extend(eat_trivia_segments(ctx));
1123                if let Some(and_kw) = ctx.eat_keyword("AND") {
1124                    children.push(token_segment(and_kw, SegmentType::Keyword));
1125                }
1126                children.extend(eat_trivia_segments(ctx));
1127                if let Some(hi) = self.parse_addition_expression(ctx) {
1128                    children.push(hi);
1129                }
1130                return Some(Segment::Node(NodeSegment::new(
1131                    SegmentType::BetweenExpression,
1132                    children,
1133                )));
1134            }
1135            if ctx.peek_keyword("LIKE") || ctx.peek_keyword("ILIKE") {
1136                let kw = ctx.advance().unwrap();
1137                let mut children = vec![left];
1138                children.extend(trivia);
1139                children.push(token_segment(not_kw, SegmentType::Keyword));
1140                children.extend(not_trivia);
1141                children.push(token_segment(kw, SegmentType::Keyword));
1142                children.extend(eat_trivia_segments(ctx));
1143                if let Some(pattern) = self.parse_addition_expression(ctx) {
1144                    children.push(pattern);
1145                }
1146                return Some(Segment::Node(NodeSegment::new(
1147                    SegmentType::LikeExpression,
1148                    children,
1149                )));
1150            }
1151
1152            // NOT was consumed but wasn't NOT IN/BETWEEN/LIKE — restore
1153            ctx.restore(save_not);
1154            ctx.restore(save);
1155            return Some(left);
1156        }
1157
1158        // BETWEEN ... AND ...
1159        if ctx.peek_keyword("BETWEEN") {
1160            let kw = ctx.advance().unwrap();
1161            let mut children = vec![left];
1162            children.extend(trivia);
1163            children.push(token_segment(kw, SegmentType::Keyword));
1164            children.extend(eat_trivia_segments(ctx));
1165            if let Some(lo) = self.parse_addition_expression(ctx) {
1166                children.push(lo);
1167            }
1168            children.extend(eat_trivia_segments(ctx));
1169            if let Some(and_kw) = ctx.eat_keyword("AND") {
1170                children.push(token_segment(and_kw, SegmentType::Keyword));
1171            }
1172            children.extend(eat_trivia_segments(ctx));
1173            if let Some(hi) = self.parse_addition_expression(ctx) {
1174                children.push(hi);
1175            }
1176            return Some(Segment::Node(NodeSegment::new(
1177                SegmentType::BetweenExpression,
1178                children,
1179            )));
1180        }
1181
1182        // LIKE / ILIKE
1183        if ctx.peek_keyword("LIKE") || ctx.peek_keyword("ILIKE") {
1184            let kw = ctx.advance().unwrap();
1185            let mut children = vec![left];
1186            children.extend(trivia);
1187            children.push(token_segment(kw, SegmentType::Keyword));
1188            children.extend(eat_trivia_segments(ctx));
1189            if let Some(pattern) = self.parse_addition_expression(ctx) {
1190                children.push(pattern);
1191            }
1192            return Some(Segment::Node(NodeSegment::new(
1193                SegmentType::LikeExpression,
1194                children,
1195            )));
1196        }
1197
1198        // Comparison operators: = <> != < > <= >=
1199        if let Some(kind) = ctx.peek_kind() {
1200            if matches!(
1201                kind,
1202                TokenKind::Eq
1203                    | TokenKind::Neq
1204                    | TokenKind::Lt
1205                    | TokenKind::Gt
1206                    | TokenKind::LtEq
1207                    | TokenKind::GtEq
1208            ) {
1209                let op = ctx.advance().unwrap();
1210                let mut children = vec![left];
1211                children.extend(trivia);
1212                children.push(token_segment(op, SegmentType::ComparisonOperator));
1213                children.extend(eat_trivia_segments(ctx));
1214                if let Some(right) = self.parse_addition_expression(ctx) {
1215                    children.push(right);
1216                }
1217                return Some(Segment::Node(NodeSegment::new(
1218                    SegmentType::BinaryExpression,
1219                    children,
1220                )));
1221            }
1222        }
1223
1224        ctx.restore(save);
1225        Some(left)
1226    }
1227
1228    fn parse_addition_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1229        let mut left = self.parse_multiplication_expression(ctx)?;
1230        loop {
1231            let save = ctx.save();
1232            let trivia = eat_trivia_segments(ctx);
1233            if let Some(kind) = ctx.peek_kind() {
1234                if matches!(kind, TokenKind::Plus | TokenKind::Minus | TokenKind::Concat) {
1235                    let op = ctx.advance().unwrap();
1236                    let mut children = vec![left];
1237                    children.extend(trivia);
1238                    children.push(token_segment(op, SegmentType::ArithmeticOperator));
1239                    children.extend(eat_trivia_segments(ctx));
1240                    if let Some(right) = self.parse_multiplication_expression(ctx) {
1241                        children.push(right);
1242                    }
1243                    left = Segment::Node(NodeSegment::new(SegmentType::BinaryExpression, children));
1244                    continue;
1245                }
1246            }
1247            ctx.restore(save);
1248            break;
1249        }
1250        Some(left)
1251    }
1252
1253    fn parse_multiplication_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1254        let mut left = self.parse_unary_expression(ctx)?;
1255        loop {
1256            let save = ctx.save();
1257            let trivia = eat_trivia_segments(ctx);
1258            if let Some(kind) = ctx.peek_kind() {
1259                if matches!(
1260                    kind,
1261                    TokenKind::Star | TokenKind::Slash | TokenKind::Percent
1262                ) {
1263                    let op = ctx.advance().unwrap();
1264                    let mut children = vec![left];
1265                    children.extend(trivia);
1266                    children.push(token_segment(op, SegmentType::ArithmeticOperator));
1267                    children.extend(eat_trivia_segments(ctx));
1268                    if let Some(right) = self.parse_unary_expression(ctx) {
1269                        children.push(right);
1270                    }
1271                    left = Segment::Node(NodeSegment::new(SegmentType::BinaryExpression, children));
1272                    continue;
1273                }
1274            }
1275            ctx.restore(save);
1276            break;
1277        }
1278        Some(left)
1279    }
1280
1281    fn parse_unary_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1282        if let Some(kind) = ctx.peek_kind() {
1283            if matches!(kind, TokenKind::Plus | TokenKind::Minus) {
1284                let op = ctx.advance().unwrap();
1285                let mut children = vec![token_segment(op, SegmentType::ArithmeticOperator)];
1286                children.extend(eat_trivia_segments(ctx));
1287                if let Some(expr) = self.parse_primary_expression(ctx) {
1288                    children.push(expr);
1289                }
1290                return Some(Segment::Node(NodeSegment::new(
1291                    SegmentType::UnaryExpression,
1292                    children,
1293                )));
1294            }
1295        }
1296        self.parse_primary_expression(ctx)
1297    }
1298
1299    fn parse_primary_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1300        match ctx.peek_kind()? {
1301            // Parenthesized expression or subquery
1302            TokenKind::LParen => {
1303                // Check if it's a subquery
1304                let save = ctx.save();
1305                if let Some(subq) = self.parse_paren_subquery(ctx) {
1306                    return Some(subq);
1307                }
1308                ctx.restore(save);
1309                self.parse_paren_expression(ctx)
1310            }
1311
1312            // Number literal
1313            TokenKind::NumberLiteral => {
1314                let token = ctx.advance().unwrap();
1315                Some(token_segment(token, SegmentType::NumericLiteral))
1316            }
1317
1318            // String literal
1319            TokenKind::StringLiteral => {
1320                let token = ctx.advance().unwrap();
1321                Some(token_segment(token, SegmentType::StringLiteral))
1322            }
1323
1324            // Star (e.g. SELECT *)
1325            TokenKind::Star => {
1326                let token = ctx.advance().unwrap();
1327                Some(token_segment(token, SegmentType::Star))
1328            }
1329
1330            // Placeholder
1331            TokenKind::Placeholder => {
1332                let token = ctx.advance().unwrap();
1333                Some(token_segment(token, SegmentType::Literal))
1334            }
1335
1336            // Quoted identifier
1337            TokenKind::QuotedIdentifier => {
1338                let token = ctx.advance().unwrap();
1339                Some(token_segment(token, SegmentType::QuotedIdentifier))
1340            }
1341
1342            // Word: keyword, function call, column ref, etc.
1343            TokenKind::Word => {
1344                let text = &ctx.peek().unwrap().text;
1345
1346                if text.eq_ignore_ascii_case("CASE") {
1347                    return self.parse_case_expression(ctx);
1348                }
1349                if text.eq_ignore_ascii_case("EXISTS") {
1350                    return self.parse_exists_expression(ctx);
1351                }
1352                if text.eq_ignore_ascii_case("CAST") {
1353                    return self.parse_cast_expression(ctx);
1354                }
1355                if text.eq_ignore_ascii_case("TRUE") || text.eq_ignore_ascii_case("FALSE") {
1356                    let token = ctx.advance().unwrap();
1357                    return Some(token_segment(token, SegmentType::BooleanLiteral));
1358                }
1359                if text.eq_ignore_ascii_case("NULL") {
1360                    let token = ctx.advance().unwrap();
1361                    return Some(token_segment(token, SegmentType::NullLiteral));
1362                }
1363
1364                self.parse_name_or_function(ctx)
1365            }
1366
1367            // @ variable (SQL Server)
1368            TokenKind::AtSign => {
1369                let token = ctx.advance().unwrap();
1370                Some(token_segment(token, SegmentType::Identifier))
1371            }
1372
1373            _ => None,
1374        }
1375    }
1376
1377    fn parse_paren_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1378        let mut children = Vec::new();
1379        let lp = ctx.eat_kind(TokenKind::LParen)?;
1380        children.push(token_segment(lp, SegmentType::LParen));
1381        children.extend(eat_trivia_segments(ctx));
1382
1383        if let Some(expr) = self.parse_expression(ctx) {
1384            children.push(expr);
1385        }
1386
1387        children.extend(eat_trivia_segments(ctx));
1388        if let Some(rp) = ctx.eat_kind(TokenKind::RParen) {
1389            children.push(token_segment(rp, SegmentType::RParen));
1390        }
1391
1392        Some(Segment::Node(NodeSegment::new(
1393            SegmentType::ParenExpression,
1394            children,
1395        )))
1396    }
1397
1398    fn parse_paren_subquery(&self, ctx: &mut ParseContext) -> Option<Segment> {
1399        let save = ctx.save();
1400        let mut children = Vec::new();
1401        let lp = ctx.eat_kind(TokenKind::LParen)?;
1402        children.push(token_segment(lp, SegmentType::LParen));
1403        children.extend(eat_trivia_segments(ctx));
1404
1405        // Check if it's a SELECT or WITH inside
1406        if !ctx.peek_keyword("SELECT") && !ctx.peek_keyword("WITH") {
1407            ctx.restore(save);
1408            return None;
1409        }
1410
1411        if let Some(sel) = self.parse_select_statement(ctx) {
1412            children.push(sel);
1413        } else {
1414            ctx.restore(save);
1415            return None;
1416        }
1417
1418        children.extend(eat_trivia_segments(ctx));
1419        if let Some(rp) = ctx.eat_kind(TokenKind::RParen) {
1420            children.push(token_segment(rp, SegmentType::RParen));
1421        }
1422
1423        Some(Segment::Node(NodeSegment::new(
1424            SegmentType::Subquery,
1425            children,
1426        )))
1427    }
1428
1429    fn parse_case_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1430        let mut children = Vec::new();
1431        let case_kw = ctx.eat_keyword("CASE")?;
1432        children.push(token_segment(case_kw, SegmentType::Keyword));
1433        children.extend(eat_trivia_segments(ctx));
1434
1435        // Simple CASE: CASE expr WHEN ...
1436        // Searched CASE: CASE WHEN ...
1437        if !ctx.peek_keyword("WHEN") {
1438            if let Some(expr) = self.parse_expression(ctx) {
1439                children.push(expr);
1440                children.extend(eat_trivia_segments(ctx));
1441            }
1442        }
1443
1444        // WHEN clauses
1445        while ctx.peek_keyword("WHEN") {
1446            if let Some(when) = self.parse_when_clause(ctx) {
1447                children.push(when);
1448                children.extend(eat_trivia_segments(ctx));
1449            }
1450        }
1451
1452        // ELSE clause
1453        if ctx.peek_keyword("ELSE") {
1454            let mut else_children = Vec::new();
1455            let kw = ctx.advance().unwrap();
1456            else_children.push(token_segment(kw, SegmentType::Keyword));
1457            else_children.extend(eat_trivia_segments(ctx));
1458            if let Some(expr) = self.parse_expression(ctx) {
1459                else_children.push(expr);
1460            }
1461            children.push(Segment::Node(NodeSegment::new(
1462                SegmentType::ElseClause,
1463                else_children,
1464            )));
1465            children.extend(eat_trivia_segments(ctx));
1466        }
1467
1468        // END
1469        if let Some(end_kw) = ctx.eat_keyword("END") {
1470            children.push(token_segment(end_kw, SegmentType::Keyword));
1471        }
1472
1473        Some(Segment::Node(NodeSegment::new(
1474            SegmentType::CaseExpression,
1475            children,
1476        )))
1477    }
1478
1479    fn parse_when_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
1480        let mut children = Vec::new();
1481        let kw = ctx.eat_keyword("WHEN")?;
1482        children.push(token_segment(kw, SegmentType::Keyword));
1483        children.extend(eat_trivia_segments(ctx));
1484
1485        if let Some(cond) = self.parse_expression(ctx) {
1486            children.push(cond);
1487        }
1488        children.extend(eat_trivia_segments(ctx));
1489
1490        if let Some(then_kw) = ctx.eat_keyword("THEN") {
1491            children.push(token_segment(then_kw, SegmentType::Keyword));
1492        }
1493        children.extend(eat_trivia_segments(ctx));
1494
1495        if let Some(result) = self.parse_expression(ctx) {
1496            children.push(result);
1497        }
1498
1499        Some(Segment::Node(NodeSegment::new(
1500            SegmentType::WhenClause,
1501            children,
1502        )))
1503    }
1504
1505    fn parse_exists_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1506        let mut children = Vec::new();
1507        let kw = ctx.eat_keyword("EXISTS")?;
1508        children.push(token_segment(kw, SegmentType::Keyword));
1509        children.extend(eat_trivia_segments(ctx));
1510
1511        if let Some(subq) = self.parse_paren_subquery(ctx) {
1512            children.push(subq);
1513        }
1514
1515        Some(Segment::Node(NodeSegment::new(
1516            SegmentType::ExistsExpression,
1517            children,
1518        )))
1519    }
1520
1521    fn parse_cast_expression(&self, ctx: &mut ParseContext) -> Option<Segment> {
1522        let mut children = Vec::new();
1523        let kw = ctx.eat_keyword("CAST")?;
1524        children.push(token_segment(kw, SegmentType::Keyword));
1525        children.extend(eat_trivia_segments(ctx));
1526
1527        let lp = ctx.eat_kind(TokenKind::LParen)?;
1528        children.push(token_segment(lp, SegmentType::LParen));
1529        children.extend(eat_trivia_segments(ctx));
1530
1531        if let Some(expr) = self.parse_expression(ctx) {
1532            children.push(expr);
1533        }
1534        children.extend(eat_trivia_segments(ctx));
1535
1536        if let Some(as_kw) = ctx.eat_keyword("AS") {
1537            children.push(token_segment(as_kw, SegmentType::Keyword));
1538        }
1539        children.extend(eat_trivia_segments(ctx));
1540
1541        // Data type
1542        if let Some(dt) = self.parse_data_type(ctx) {
1543            children.push(dt);
1544        }
1545        children.extend(eat_trivia_segments(ctx));
1546
1547        if let Some(rp) = ctx.eat_kind(TokenKind::RParen) {
1548            children.push(token_segment(rp, SegmentType::RParen));
1549        }
1550
1551        Some(Segment::Node(NodeSegment::new(
1552            SegmentType::CastExpression,
1553            children,
1554        )))
1555    }
1556
1557    fn parse_data_type(&self, ctx: &mut ParseContext) -> Option<Segment> {
1558        let mut children = Vec::new();
1559
1560        // Type name (may be multi-word like "DOUBLE PRECISION", "CHARACTER VARYING")
1561        let word = ctx.eat_kind(TokenKind::Word)?;
1562        children.push(token_segment(word, SegmentType::Keyword));
1563
1564        // Additional type words
1565        loop {
1566            let save = ctx.save();
1567            let trivia = eat_trivia_segments(ctx);
1568            if let Some(t) = ctx.peek() {
1569                if t.kind == TokenKind::Word && !is_clause_keyword(&t.text) {
1570                    children.extend(trivia);
1571                    let w = ctx.advance().unwrap();
1572                    children.push(token_segment(w, SegmentType::Keyword));
1573                    continue;
1574                }
1575            }
1576            ctx.restore(save);
1577            break;
1578        }
1579
1580        // Optional (precision, scale)
1581        let save = ctx.save();
1582        let trivia = eat_trivia_segments(ctx);
1583        if ctx.peek_kind() == Some(TokenKind::LParen) {
1584            children.extend(trivia);
1585            if let Some(params) = self.parse_paren_block(ctx) {
1586                children.push(params);
1587            }
1588        } else {
1589            ctx.restore(save);
1590        }
1591
1592        Some(Segment::Node(NodeSegment::new(
1593            SegmentType::DataType,
1594            children,
1595        )))
1596    }
1597
1598    // ── Identifiers & names ──────────────────────────────────────
1599
1600    fn parse_identifier(&self, ctx: &mut ParseContext) -> Option<Segment> {
1601        match ctx.peek_kind()? {
1602            TokenKind::Word => {
1603                let token = ctx.advance().unwrap();
1604                Some(token_segment(token, SegmentType::Identifier))
1605            }
1606            TokenKind::QuotedIdentifier => {
1607                let token = ctx.advance().unwrap();
1608                Some(token_segment(token, SegmentType::QuotedIdentifier))
1609            }
1610            // @variable / @@variable (TSQL table variables, system variables)
1611            TokenKind::AtSign => {
1612                let token = ctx.advance().unwrap();
1613                Some(token_segment(token, SegmentType::Identifier))
1614            }
1615            _ => None,
1616        }
1617    }
1618
1619    /// Parse a possibly qualified name: a, a.b, a.b.c
1620    fn parse_qualified_name(&self, ctx: &mut ParseContext) -> Option<Segment> {
1621        let first = self.parse_identifier(ctx)?;
1622
1623        let save = ctx.save();
1624        if ctx.peek_kind() == Some(TokenKind::Dot) {
1625            let mut children = vec![first];
1626            while ctx.peek_kind() == Some(TokenKind::Dot) {
1627                let dot = ctx.advance().unwrap();
1628                children.push(token_segment(dot, SegmentType::Dot));
1629                if let Some(part) = self.parse_identifier(ctx) {
1630                    children.push(part);
1631                } else {
1632                    // Star: schema.table.*
1633                    if ctx.peek_kind() == Some(TokenKind::Star) {
1634                        let star = ctx.advance().unwrap();
1635                        children.push(token_segment(star, SegmentType::Star));
1636                    }
1637                    break;
1638                }
1639            }
1640            Some(Segment::Node(NodeSegment::new(
1641                SegmentType::ColumnRef,
1642                children,
1643            )))
1644        } else {
1645            ctx.restore(save);
1646            Some(first)
1647        }
1648    }
1649
1650    fn parse_name_or_function(&self, ctx: &mut ParseContext) -> Option<Segment> {
1651        let name = self.parse_qualified_name(ctx)?;
1652
1653        // Check for function call: name(...)
1654        if ctx.peek_kind() == Some(TokenKind::LParen) {
1655            let mut children = vec![name];
1656            if let Some(args) = self.parse_paren_block(ctx) {
1657                children.push(args);
1658            }
1659            let func = Segment::Node(NodeSegment::new(SegmentType::FunctionCall, children));
1660
1661            // Check for OVER clause (window function)
1662            let save = ctx.save();
1663            let trivia = eat_trivia_segments(ctx);
1664            if ctx.peek_keyword("OVER") {
1665                let mut win_children = vec![func];
1666                win_children.extend(trivia);
1667                if let Some(over) = self.parse_over_clause(ctx) {
1668                    win_children.push(over);
1669                }
1670                return Some(Segment::Node(NodeSegment::new(
1671                    SegmentType::WindowExpression,
1672                    win_children,
1673                )));
1674            }
1675            ctx.restore(save);
1676
1677            return Some(func);
1678        }
1679
1680        Some(name)
1681    }
1682
1683    /// Parse OVER clause: `OVER (PARTITION BY ... ORDER BY ... ROWS/RANGE ...)`
1684    /// or `OVER window_name`
1685    fn parse_over_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
1686        let mut children = Vec::new();
1687        let over_kw = ctx.eat_keyword("OVER")?;
1688        children.push(token_segment(over_kw, SegmentType::Keyword));
1689        children.extend(eat_trivia_segments(ctx));
1690
1691        // OVER window_name (named window reference, no parens)
1692        if ctx.peek_kind() != Some(TokenKind::LParen) {
1693            if let Some(name) = self.parse_identifier(ctx) {
1694                children.push(name);
1695            }
1696            return Some(Segment::Node(NodeSegment::new(
1697                SegmentType::OverClause,
1698                children,
1699            )));
1700        }
1701
1702        // OVER ( ... )
1703        let lp = ctx.eat_kind(TokenKind::LParen)?;
1704        children.push(token_segment(lp, SegmentType::LParen));
1705        children.extend(eat_trivia_segments(ctx));
1706
1707        // PARTITION BY ...
1708        if ctx.peek_keyword("PARTITION") {
1709            if let Some(pb) = self.parse_partition_by_clause(ctx) {
1710                children.push(pb);
1711                children.extend(eat_trivia_segments(ctx));
1712            }
1713        }
1714
1715        // ORDER BY ...
1716        if ctx.peek_keywords(&["ORDER", "BY"]) {
1717            if let Some(ob) = self.parse_window_order_by(ctx) {
1718                children.push(ob);
1719                children.extend(eat_trivia_segments(ctx));
1720            }
1721        }
1722
1723        // Window frame: ROWS / RANGE / GROUPS
1724        if ctx.peek_keyword("ROWS") || ctx.peek_keyword("RANGE") || ctx.peek_keyword("GROUPS") {
1725            if let Some(frame) = self.parse_window_frame_clause(ctx) {
1726                children.push(frame);
1727                children.extend(eat_trivia_segments(ctx));
1728            }
1729        }
1730
1731        if let Some(rp) = ctx.eat_kind(TokenKind::RParen) {
1732            children.push(token_segment(rp, SegmentType::RParen));
1733        }
1734
1735        Some(Segment::Node(NodeSegment::new(
1736            SegmentType::OverClause,
1737            children,
1738        )))
1739    }
1740
1741    /// Parse PARTITION BY expr, expr, ...
1742    fn parse_partition_by_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
1743        let mut children = Vec::new();
1744        let part_kw = ctx.eat_keyword("PARTITION")?;
1745        children.push(token_segment(part_kw, SegmentType::Keyword));
1746        children.extend(eat_trivia_segments(ctx));
1747
1748        if let Some(by_kw) = ctx.eat_keyword("BY") {
1749            children.push(token_segment(by_kw, SegmentType::Keyword));
1750        }
1751        children.extend(eat_trivia_segments(ctx));
1752
1753        // Comma-separated expressions
1754        parse_comma_separated(ctx, &mut children, |c| self.parse_expression(c));
1755
1756        Some(Segment::Node(NodeSegment::new(
1757            SegmentType::PartitionByClause,
1758            children,
1759        )))
1760    }
1761
1762    /// Parse ORDER BY inside a window spec (reuses expression parsing).
1763    fn parse_window_order_by(&self, ctx: &mut ParseContext) -> Option<Segment> {
1764        // Delegate to the existing ORDER BY parser
1765        self.parse_order_by_clause(ctx)
1766    }
1767
1768    /// Parse window frame: ROWS/RANGE/GROUPS frame_spec
1769    fn parse_window_frame_clause(&self, ctx: &mut ParseContext) -> Option<Segment> {
1770        let mut children = Vec::new();
1771
1772        // ROWS | RANGE | GROUPS
1773        let frame_kw = ctx.advance()?;
1774        children.push(token_segment(frame_kw, SegmentType::Keyword));
1775        children.extend(eat_trivia_segments(ctx));
1776
1777        // BETWEEN ... AND ... or single bound
1778        if ctx.peek_keyword("BETWEEN") {
1779            let bw_kw = ctx.advance().unwrap();
1780            children.push(token_segment(bw_kw, SegmentType::Keyword));
1781            children.extend(eat_trivia_segments(ctx));
1782
1783            // start bound
1784            eat_frame_bound(ctx, &mut children);
1785            children.extend(eat_trivia_segments(ctx));
1786
1787            // AND
1788            if let Some(and_kw) = ctx.eat_keyword("AND") {
1789                children.push(token_segment(and_kw, SegmentType::Keyword));
1790                children.extend(eat_trivia_segments(ctx));
1791            }
1792
1793            // end bound
1794            eat_frame_bound(ctx, &mut children);
1795        } else {
1796            // Single bound (e.g. ROWS UNBOUNDED PRECEDING)
1797            eat_frame_bound(ctx, &mut children);
1798        }
1799
1800        Some(Segment::Node(NodeSegment::new(
1801            SegmentType::WindowFrameClause,
1802            children,
1803        )))
1804    }
1805
1806    // ── Simple statement ─────────────────────────────────────────
1807
1808    /// Parse a simple statement (USE, TRUNCATE, etc.) by consuming until end.
1809    fn parse_simple_statement(&self, ctx: &mut ParseContext) -> Option<Segment> {
1810        let mut children = Vec::new();
1811        let kw = ctx.advance()?;
1812        children.push(token_segment(kw, SegmentType::Keyword));
1813        children.extend(eat_trivia_segments(ctx));
1814        self.consume_until_statement_end(ctx, &mut children);
1815        Some(Segment::Node(NodeSegment::new(
1816            SegmentType::Statement,
1817            children,
1818        )))
1819    }
1820
1821    // ── Statement boundary helpers ──────────────────────────────
1822
1823    /// Check if current token looks like the start of a new statement.
1824    fn peek_statement_start(&self, ctx: &ParseContext) -> bool {
1825        if let Some(t) = ctx.peek_non_trivia() {
1826            if t.kind == TokenKind::Word {
1827                return self
1828                    .statement_keywords()
1829                    .iter()
1830                    .any(|kw| t.text.eq_ignore_ascii_case(kw));
1831            }
1832        }
1833        false
1834    }
1835
1836    /// Consume tokens until semicolon, EOF, or start of new statement.
1837    /// Consume tokens until semicolon, EOF, or start of a new statement.
1838    /// Tracks paren depth so that keywords inside subqueries (e.g. `SELECT`
1839    /// within `(SELECT ...)`) do not cause premature termination.
1840    fn consume_until_statement_end(&self, ctx: &mut ParseContext, children: &mut Vec<Segment>) {
1841        let mut paren_depth = 0u32;
1842        while !ctx.at_eof() {
1843            match ctx.peek_kind() {
1844                Some(TokenKind::Semicolon) if paren_depth == 0 => break,
1845                Some(TokenKind::LParen) => {
1846                    paren_depth += 1;
1847                    let token = ctx.advance().unwrap();
1848                    children.push(any_token_segment(token));
1849                }
1850                Some(TokenKind::RParen) => {
1851                    paren_depth = paren_depth.saturating_sub(1);
1852                    let token = ctx.advance().unwrap();
1853                    children.push(any_token_segment(token));
1854                }
1855                _ => {
1856                    if paren_depth == 0 && self.peek_statement_start(ctx) {
1857                        break;
1858                    }
1859                    let token = ctx.advance().unwrap();
1860                    children.push(any_token_segment(token));
1861                }
1862            }
1863        }
1864    }
1865
1866    // ── Utility parsing ──────────────────────────────────────────
1867
1868    /// Parse parenthesized content as a simple block.
1869    fn parse_paren_block(&self, ctx: &mut ParseContext) -> Option<Segment> {
1870        let mut children = Vec::new();
1871        let lp = ctx.eat_kind(TokenKind::LParen)?;
1872        children.push(token_segment(lp, SegmentType::LParen));
1873
1874        let mut depth = 1u32;
1875        while depth > 0 && !ctx.at_eof() {
1876            match ctx.peek_kind() {
1877                Some(TokenKind::LParen) => {
1878                    depth += 1;
1879                    let token = ctx.advance().unwrap();
1880                    children.push(any_token_segment(token));
1881                }
1882                Some(TokenKind::RParen) => {
1883                    depth -= 1;
1884                    let token = ctx.advance().unwrap();
1885                    if depth == 0 {
1886                        children.push(token_segment(token, SegmentType::RParen));
1887                    } else {
1888                        children.push(any_token_segment(token));
1889                    }
1890                }
1891                _ => {
1892                    let token = ctx.advance().unwrap();
1893                    children.push(any_token_segment(token));
1894                }
1895            }
1896        }
1897
1898        Some(Segment::Node(NodeSegment::new(
1899            SegmentType::ParenExpression,
1900            children,
1901        )))
1902    }
1903
1904    /// Consume tokens until the end of a statement.
1905    ///
1906    /// The ANSI default tracks paren and CASE/END depth, stopping at
1907    /// semicolons or EOF.  TSQL overrides this to additionally track
1908    /// BEGIN/END blocks and the GO batch separator.
1909    fn consume_until_end(&self, ctx: &mut ParseContext, children: &mut Vec<Segment>) {
1910        let mut paren_depth = 0u32;
1911        let mut case_depth = 0u32;
1912        while !ctx.at_eof() {
1913            match ctx.peek_kind() {
1914                Some(TokenKind::Semicolon) if paren_depth == 0 => break,
1915                Some(TokenKind::LParen) => {
1916                    paren_depth += 1;
1917                    let token = ctx.advance().unwrap();
1918                    children.push(any_token_segment(token));
1919                }
1920                Some(TokenKind::RParen) => {
1921                    paren_depth = paren_depth.saturating_sub(1);
1922                    let token = ctx.advance().unwrap();
1923                    children.push(any_token_segment(token));
1924                }
1925                _ => {
1926                    let t = ctx.peek().unwrap();
1927                    if t.kind == TokenKind::Word {
1928                        if t.text.eq_ignore_ascii_case("CASE") {
1929                            case_depth += 1;
1930                        } else if t.text.eq_ignore_ascii_case("END") && case_depth > 0 {
1931                            case_depth -= 1;
1932                        }
1933                    }
1934                    let token = ctx.advance().unwrap();
1935                    children.push(any_token_segment(token));
1936                }
1937            }
1938        }
1939    }
1940}
1941
1942// ── Free helper functions ────────────────────────────────────────
1943
1944pub fn token_segment(token: &Token, segment_type: SegmentType) -> Segment {
1945    Segment::Token(TokenSegment {
1946        token: token.clone(),
1947        segment_type,
1948    })
1949}
1950
1951pub fn any_token_segment(token: &Token) -> Segment {
1952    let st = match token.kind {
1953        TokenKind::Whitespace => SegmentType::Whitespace,
1954        TokenKind::Newline => SegmentType::Newline,
1955        TokenKind::LineComment => SegmentType::LineComment,
1956        TokenKind::BlockComment => SegmentType::BlockComment,
1957        TokenKind::Comma => SegmentType::Comma,
1958        TokenKind::Dot => SegmentType::Dot,
1959        TokenKind::Semicolon => SegmentType::Semicolon,
1960        TokenKind::Star => SegmentType::Star,
1961        TokenKind::LParen => SegmentType::LParen,
1962        TokenKind::RParen => SegmentType::RParen,
1963        TokenKind::NumberLiteral => SegmentType::NumericLiteral,
1964        TokenKind::StringLiteral => SegmentType::StringLiteral,
1965        TokenKind::Word => SegmentType::Keyword,
1966        TokenKind::QuotedIdentifier => SegmentType::QuotedIdentifier,
1967        _ => SegmentType::Operator,
1968    };
1969    token_segment(token, st)
1970}
1971
1972pub fn unparsable_token(token: &Token) -> Segment {
1973    Segment::Token(TokenSegment {
1974        token: token.clone(),
1975        segment_type: SegmentType::Unparsable,
1976    })
1977}
1978
1979pub fn eat_trivia_segments(ctx: &mut ParseContext) -> Vec<Segment> {
1980    ctx.eat_trivia()
1981        .into_iter()
1982        .map(any_token_segment)
1983        .collect()
1984}
1985
1986/// Parse statements until `is_end` returns true, consuming unparsable tokens as fallback.
1987pub fn parse_statement_list(
1988    grammar: &dyn Grammar,
1989    ctx: &mut ParseContext,
1990    children: &mut Vec<Segment>,
1991    is_end: impl Fn(&ParseContext) -> bool,
1992) {
1993    loop {
1994        children.extend(eat_trivia_segments(ctx));
1995        if ctx.at_eof() || is_end(ctx) {
1996            break;
1997        }
1998        if let Some(stmt) = grammar.parse_statement(ctx) {
1999            children.push(stmt);
2000        } else {
2001            children.extend(eat_trivia_segments(ctx));
2002            if !ctx.at_eof() && !is_end(ctx) {
2003                if let Some(token) = ctx.advance() {
2004                    children.push(unparsable_token(token));
2005                }
2006            }
2007        }
2008    }
2009}
2010
2011/// Parse a comma-separated list of items, appending them to `children`.
2012///
2013/// Parses the first item, then loops: save → eat trivia → comma? → parse next.
2014/// If no comma is found, restores to before the trivia and returns.
2015pub fn parse_comma_separated(
2016    ctx: &mut ParseContext,
2017    children: &mut Vec<Segment>,
2018    mut parse_one: impl FnMut(&mut ParseContext) -> Option<Segment>,
2019) {
2020    if let Some(item) = parse_one(ctx) {
2021        children.push(item);
2022    }
2023    loop {
2024        let save = ctx.save();
2025        let trivia = eat_trivia_segments(ctx);
2026        if let Some(comma) = ctx.eat_kind(TokenKind::Comma) {
2027            children.extend(trivia);
2028            children.push(token_segment(comma, SegmentType::Comma));
2029            children.extend(eat_trivia_segments(ctx));
2030            if let Some(item) = parse_one(ctx) {
2031                children.push(item);
2032            }
2033        } else {
2034            ctx.restore(save);
2035            break;
2036        }
2037    }
2038}
2039
2040fn peek_join_keyword(ctx: &ParseContext) -> bool {
2041    if let Some(t) = ctx.peek_non_trivia() {
2042        if t.kind == TokenKind::Word {
2043            return is_join_keyword(&t.text);
2044        }
2045    }
2046    false
2047}
2048
2049/// Consume a frame bound: UNBOUNDED PRECEDING/FOLLOWING, CURRENT ROW, N PRECEDING/FOLLOWING
2050fn eat_frame_bound(ctx: &mut ParseContext, children: &mut Vec<Segment>) {
2051    // CURRENT ROW
2052    if ctx.peek_keyword("CURRENT") {
2053        let kw = ctx.advance().unwrap();
2054        children.push(token_segment(kw, SegmentType::Keyword));
2055        children.extend(eat_trivia_segments(ctx));
2056        if ctx.peek_keyword("ROW") {
2057            let row_kw = ctx.advance().unwrap();
2058            children.push(token_segment(row_kw, SegmentType::Keyword));
2059        }
2060        return;
2061    }
2062
2063    // UNBOUNDED PRECEDING/FOLLOWING
2064    if ctx.peek_keyword("UNBOUNDED") {
2065        let kw = ctx.advance().unwrap();
2066        children.push(token_segment(kw, SegmentType::Keyword));
2067        children.extend(eat_trivia_segments(ctx));
2068        if ctx.peek_keyword("PRECEDING") || ctx.peek_keyword("FOLLOWING") {
2069            let dir = ctx.advance().unwrap();
2070            children.push(token_segment(dir, SegmentType::Keyword));
2071        }
2072        return;
2073    }
2074
2075    // N PRECEDING/FOLLOWING
2076    if ctx.peek_kind() == Some(TokenKind::NumberLiteral) {
2077        let num = ctx.advance().unwrap();
2078        children.push(token_segment(num, SegmentType::NumericLiteral));
2079        children.extend(eat_trivia_segments(ctx));
2080        if ctx.peek_keyword("PRECEDING") || ctx.peek_keyword("FOLLOWING") {
2081            let dir = ctx.advance().unwrap();
2082            children.push(token_segment(dir, SegmentType::Keyword));
2083        }
2084    }
2085}
2086
2087/// Sorted list of keywords that must NOT be consumed as implicit aliases.
2088const CLAUSE_KEYWORDS: &[&str] = &[
2089    "ALTER",
2090    "AND",
2091    "AS",
2092    "BEGIN",
2093    "BETWEEN",
2094    "BREAK",
2095    "CASE",
2096    "CATCH",
2097    "CLOSE",
2098    "COMMIT",
2099    "CONTINUE",
2100    "CREATE",
2101    "CROSS",
2102    "CURSOR",
2103    "DEALLOCATE",
2104    "DECLARE",
2105    "DELETE",
2106    "DROP",
2107    "ELSE",
2108    "END",
2109    "EXCEPT",
2110    "EXEC",
2111    "EXECUTE",
2112    "EXISTS",
2113    "FETCH",
2114    "FOR",
2115    "FROM",
2116    "FULL",
2117    "GO",
2118    "GOTO",
2119    "GROUP",
2120    "HAVING",
2121    "IF",
2122    "IN",
2123    "INNER",
2124    "INSERT",
2125    "INTERSECT",
2126    "INTO",
2127    "IS",
2128    "JOIN",
2129    "LEFT",
2130    "LIKE",
2131    "LIMIT",
2132    "MERGE",
2133    "NEXT",
2134    "NOT",
2135    "OFFSET",
2136    "ON",
2137    "OPEN",
2138    "OR",
2139    "ORDER",
2140    "OUTPUT",
2141    "OVER",
2142    "PARTITION",
2143    "PRINT",
2144    "RAISERROR",
2145    "RETURN",
2146    "RETURNING",
2147    "RIGHT",
2148    "ROLLBACK",
2149    "SELECT",
2150    "SET",
2151    "TABLE",
2152    "THEN",
2153    "THROW",
2154    "TRUNCATE",
2155    "TRY",
2156    "UNION",
2157    "UPDATE",
2158    "USING",
2159    "VALUES",
2160    "WHEN",
2161    "WHERE",
2162    "WHILE",
2163    "WITH",
2164];
2165
2166/// Case-insensitive binary search on a sorted uppercase keyword list.
2167/// Zero allocations — compares byte-by-byte.
2168fn binary_search_keyword(list: &[&str], word: &str) -> bool {
2169    list.binary_search_by(|kw| {
2170        kw.as_bytes()
2171            .iter()
2172            .copied()
2173            .cmp(word.as_bytes().iter().map(|b| b.to_ascii_uppercase()))
2174    })
2175    .is_ok()
2176}
2177
2178pub fn is_clause_keyword(word: &str) -> bool {
2179    binary_search_keyword(CLAUSE_KEYWORDS, word)
2180}
2181
2182const JOIN_KEYWORDS: &[&str] = &["CROSS", "FULL", "INNER", "JOIN", "LEFT", "RIGHT"];
2183
2184pub fn is_join_keyword(word: &str) -> bool {
2185    binary_search_keyword(JOIN_KEYWORDS, word) || word.eq_ignore_ascii_case("CROSS")
2186}