Skip to main content

hawdb_sql_syntax/
parser.rs

1// Copyright 2026 Nowledge
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::{
16    ExpressionSyntax, GraphEdgeDirection, GraphEdgePatternSyntax, GraphElementPatternSyntax,
17    GraphPathFactorSyntax, GraphPathPrimarySyntax, GraphPathSyntax, GraphPatternQuantifier,
18    GraphPatternSyntax, GraphTable, GraphTableColumn, Identifier, LabeledExpressionSyntax,
19    PgqStatement, PostgresSelectSyntax, PostgresStatementSyntax, QualifiedName, Span, SyntaxError,
20    SyntaxErrorCode, TableAlias, Token, TokenKind,
21};
22
23mod expression;
24mod frontend;
25mod property_graph;
26mod select;
27
28pub fn parse_postgres_statement(input: &str) -> Result<PostgresStatementSyntax, SyntaxError> {
29    match frontend::parse(input, "SqlInput")? {
30        frontend::Output::Select(select) => Ok(PostgresStatementSyntax::Select(select)),
31        frontend::Output::Create(create) => {
32            Ok(PostgresStatementSyntax::CreatePropertyGraph(*create))
33        }
34        frontend::Output::Explain { .. } | frontend::Output::GraphTable(_) => {
35            unreachable!("SQL entry excludes standalone GRAPH_TABLE")
36        }
37    }
38}
39
40/// Parses the executable relational SELECT and EXPLAIN SELECT families.
41pub fn parse_relational_statement(
42    input: &str,
43) -> Result<crate::RelationalStatementSyntax, SyntaxError> {
44    match frontend::parse(input, "RelationalStatementInput")? {
45        frontend::Output::Select(select) => Ok(crate::RelationalStatementSyntax::Select(select)),
46        frontend::Output::Explain { analyze, select } => {
47            Ok(crate::RelationalStatementSyntax::Explain { analyze, select })
48        }
49        _ => unreachable!("relational entry returns SELECT or EXPLAIN SELECT"),
50    }
51}
52
53pub fn parse_postgres_select(input: &str) -> Result<PostgresSelectSyntax, SyntaxError> {
54    let frontend::Output::Select(select) = frontend::parse(input, "SelectInput")? else {
55        unreachable!("SELECT entry produces a SELECT AST")
56    };
57    Ok(*select)
58}
59
60pub fn parse_pgq_statement(input: &str) -> Result<PgqStatement, SyntaxError> {
61    let frontend::Output::Create(create) = frontend::parse(input, "PgqInput")? else {
62        unreachable!("PGQ entry produces CREATE PROPERTY GRAPH")
63    };
64    Ok(PgqStatement::CreatePropertyGraph(*create))
65}
66
67pub fn parse_graph_table(input: &str) -> Result<GraphTable, SyntaxError> {
68    let frontend::Output::GraphTable(table) = frontend::parse(input, "GraphTableInput")? else {
69        unreachable!("GRAPH_TABLE entry produces a GRAPH_TABLE AST")
70    };
71    Ok(*table)
72}
73
74const MAX_GRAPH_PATTERN_NESTING: usize = 128;
75const MAX_EXPRESSION_NESTING: usize = 128;
76
77struct Parser<'a> {
78    input: &'a str,
79    tokens: &'a [Token],
80    position: usize,
81    graph_pattern_nesting: usize,
82}
83
84struct ParsedGraphElementFields {
85    variable: Option<Identifier>,
86    labels: Vec<Identifier>,
87    predicate: Option<ExpressionSyntax>,
88}
89
90impl<'a> Parser<'a> {
91    fn new(input: &'a str, tokens: &'a [Token]) -> Self {
92        Self {
93            input,
94            tokens,
95            position: 0,
96            graph_pattern_nesting: 0,
97        }
98    }
99
100    fn parse_identifier_list(&mut self) -> Result<Vec<Identifier>, SyntaxError> {
101        self.expect_kind(TokenKind::LeftParen, "(")?;
102        let identifiers = self.parse_nonempty_comma_separated(
103            TokenKind::RightParen,
104            Self::parse_identifier,
105            "at least one identifier",
106        )?;
107        self.expect_kind(TokenKind::RightParen, ")")?;
108        Ok(identifiers)
109    }
110
111    fn parse_labeled_expressions(
112        &mut self,
113        expected: &'static str,
114    ) -> Result<Vec<LabeledExpressionSyntax>, SyntaxError> {
115        if self.current().kind == TokenKind::RightParen {
116            return Err(self.unexpected(expected));
117        }
118        let mut expressions = Vec::new();
119        loop {
120            let start_position = self.position;
121            let end_position = self.scan_to_top_level_delimiter()?;
122            expressions.push(self.labeled_expression_from_range(start_position, end_position)?);
123            if !self.consume_kind(TokenKind::Comma) {
124                break;
125            }
126        }
127        Ok(expressions)
128    }
129
130    fn parse_graph_pattern(&mut self) -> Result<GraphPatternSyntax, SyntaxError> {
131        let start = self.current().span.start;
132        let mut paths = vec![self.parse_graph_path()?];
133        while self.consume_kind(TokenKind::Comma) {
134            paths.push(self.parse_graph_path()?);
135        }
136        let predicate = if self.consume_keyword("WHERE") {
137            Some(self.parse_expression_until_keyword("COLUMNS", "an expression after WHERE")?)
138        } else {
139            None
140        };
141        let end = predicate.as_ref().map_or_else(
142            || paths.last().expect("graph path exists").span.end,
143            |value| value.span.end,
144        );
145        Ok(GraphPatternSyntax {
146            paths,
147            predicate,
148            span: Span::new(start, end),
149        })
150    }
151
152    fn parse_graph_path(&mut self) -> Result<GraphPathSyntax, SyntaxError> {
153        let start = self.current().span.start;
154        let mut factors = Vec::new();
155        while self.can_start_graph_primary() {
156            factors.push(self.parse_graph_path_factor()?);
157        }
158        if factors.is_empty() {
159            return Err(self.unexpected("a graph path pattern"));
160        }
161        Ok(GraphPathSyntax {
162            span: Span::new(start, self.previous_end()),
163            factors,
164        })
165    }
166
167    fn parse_graph_path_factor(&mut self) -> Result<GraphPathFactorSyntax, SyntaxError> {
168        let start = self.current().span.start;
169        let primary = self.parse_graph_path_primary()?;
170        let quantifier = self.parse_optional_graph_quantifier()?;
171        Ok(GraphPathFactorSyntax {
172            primary,
173            quantifier,
174            span: Span::new(start, self.previous_end()),
175        })
176    }
177
178    fn parse_graph_path_primary(&mut self) -> Result<GraphPathPrimarySyntax, SyntaxError> {
179        if self.current().kind == TokenKind::LeftParen {
180            return self.parse_parenthesized_or_vertex_pattern();
181        }
182        self.parse_graph_edge_pattern()
183            .map(GraphPathPrimarySyntax::Edge)
184    }
185
186    fn parse_parenthesized_or_vertex_pattern(
187        &mut self,
188    ) -> Result<GraphPathPrimarySyntax, SyntaxError> {
189        let start = self.expect_kind(TokenKind::LeftParen, "(")?.span.start;
190        if self.can_start_graph_primary() {
191            if self.graph_pattern_nesting >= MAX_GRAPH_PATTERN_NESTING {
192                return Err(SyntaxError::new(
193                    SyntaxErrorCode::GraphPatternNestingLimitExceeded,
194                    Span::new(start, self.current().span.end),
195                ));
196            }
197            self.graph_pattern_nesting += 1;
198            let nested = self.parse_nested_graph_path(start);
199            self.graph_pattern_nesting -= 1;
200            return nested;
201        }
202
203        let fields = self.parse_graph_element_fields(TokenKind::RightParen)?;
204        self.expect_kind(TokenKind::RightParen, ")")?;
205        Ok(GraphPathPrimarySyntax::Vertex(GraphElementPatternSyntax {
206            variable: fields.variable,
207            labels: fields.labels,
208            predicate: fields.predicate,
209            span: Span::new(start, self.previous_end()),
210        }))
211    }
212
213    fn parse_nested_graph_path(
214        &mut self,
215        start: usize,
216    ) -> Result<GraphPathPrimarySyntax, SyntaxError> {
217        let path = Box::new(self.parse_graph_path()?);
218        let predicate =
219            if self.consume_keyword("WHERE") {
220                Some(self.parse_expression_until_kind(
221                    TokenKind::RightParen,
222                    "an expression after WHERE",
223                )?)
224            } else {
225                None
226            };
227        self.expect_kind(TokenKind::RightParen, ")")?;
228        Ok(GraphPathPrimarySyntax::Parenthesized {
229            path,
230            predicate,
231            span: Span::new(start, self.previous_end()),
232        })
233    }
234
235    fn parse_graph_edge_pattern(&mut self) -> Result<GraphEdgePatternSyntax, SyntaxError> {
236        let start = self.current().span.start;
237        match self.current().kind {
238            TokenKind::ArrowLeft => {
239                self.advance();
240                self.parse_left_edge_tail(start)
241            }
242            TokenKind::Less => {
243                self.advance();
244                self.expect_kind(TokenKind::Minus, "- after <")?;
245                self.parse_left_edge_tail(start)
246            }
247            TokenKind::ArrowRight => {
248                self.advance();
249                Ok(self.abbreviated_edge(start, GraphEdgeDirection::Right))
250            }
251            TokenKind::Minus => {
252                self.advance();
253                if self.consume_kind(TokenKind::LeftBracket) {
254                    let fields = self.parse_graph_element_fields(TokenKind::RightBracket)?;
255                    self.expect_kind(TokenKind::RightBracket, "]")?;
256                    let direction = if self.consume_kind(TokenKind::ArrowRight) {
257                        GraphEdgeDirection::Right
258                    } else {
259                        self.expect_kind(TokenKind::Minus, "- or -> after edge pattern")?;
260                        if self.consume_kind(TokenKind::Greater) {
261                            GraphEdgeDirection::Right
262                        } else {
263                            GraphEdgeDirection::Any
264                        }
265                    };
266                    Ok(GraphEdgePatternSyntax {
267                        direction,
268                        variable: fields.variable,
269                        labels: fields.labels,
270                        predicate: fields.predicate,
271                        abbreviated: false,
272                        span: Span::new(start, self.previous_end()),
273                    })
274                } else {
275                    let direction = if self.consume_kind(TokenKind::Greater) {
276                        GraphEdgeDirection::Right
277                    } else {
278                        GraphEdgeDirection::Any
279                    };
280                    Ok(self.abbreviated_edge(start, direction))
281                }
282            }
283            _ => Err(self.unexpected("a graph vertex or edge pattern")),
284        }
285    }
286
287    fn parse_left_edge_tail(
288        &mut self,
289        start: usize,
290    ) -> Result<GraphEdgePatternSyntax, SyntaxError> {
291        if !self.consume_kind(TokenKind::LeftBracket) {
292            return Ok(self.abbreviated_edge(start, GraphEdgeDirection::Left));
293        }
294        let fields = self.parse_graph_element_fields(TokenKind::RightBracket)?;
295        self.expect_kind(TokenKind::RightBracket, "]")?;
296        self.expect_kind(TokenKind::Minus, "- after left edge pattern")?;
297        Ok(GraphEdgePatternSyntax {
298            direction: GraphEdgeDirection::Left,
299            variable: fields.variable,
300            labels: fields.labels,
301            predicate: fields.predicate,
302            abbreviated: false,
303            span: Span::new(start, self.previous_end()),
304        })
305    }
306
307    fn abbreviated_edge(
308        &self,
309        start: usize,
310        direction: GraphEdgeDirection,
311    ) -> GraphEdgePatternSyntax {
312        GraphEdgePatternSyntax {
313            direction,
314            variable: None,
315            labels: Vec::new(),
316            predicate: None,
317            abbreviated: true,
318            span: Span::new(start, self.previous_end()),
319        }
320    }
321
322    fn parse_graph_element_fields(
323        &mut self,
324        terminator: TokenKind,
325    ) -> Result<ParsedGraphElementFields, SyntaxError> {
326        let variable = if is_identifier_kind(self.current().kind)
327            && !self.at_keyword("IS")
328            && !self.at_keyword("WHERE")
329        {
330            Some(self.parse_identifier()?)
331        } else {
332            None
333        };
334        let labels = if self.consume_keyword("IS") {
335            let mut labels = vec![self.parse_identifier()?];
336            while self.consume_kind(TokenKind::Pipe) {
337                labels.push(self.parse_identifier()?);
338            }
339            labels
340        } else {
341            Vec::new()
342        };
343        let predicate = if self.consume_keyword("WHERE") {
344            Some(self.parse_expression_until_kind(terminator, "an expression after WHERE")?)
345        } else {
346            None
347        };
348        Ok(ParsedGraphElementFields {
349            variable,
350            labels,
351            predicate,
352        })
353    }
354
355    fn parse_optional_graph_quantifier(
356        &mut self,
357    ) -> Result<Option<GraphPatternQuantifier>, SyntaxError> {
358        if !self.consume_kind(TokenKind::LeftBrace) {
359            return Ok(None);
360        }
361        let start = self.tokens[self.position - 1].span.start;
362        let (min, max) = if self.consume_kind(TokenKind::Comma) {
363            (0, self.parse_nonnegative_integer()?)
364        } else {
365            let min = self.parse_nonnegative_integer()?;
366            if self.consume_kind(TokenKind::RightBrace) {
367                return Ok(Some(GraphPatternQuantifier {
368                    min,
369                    max: min,
370                    span: Span::new(start, self.previous_end()),
371                }));
372            }
373            self.expect_kind(TokenKind::Comma, ", or } in graph pattern quantifier")?;
374            (min, self.parse_nonnegative_integer()?)
375        };
376        self.expect_kind(TokenKind::RightBrace, "}")?;
377        Ok(Some(GraphPatternQuantifier {
378            min,
379            max,
380            span: Span::new(start, self.previous_end()),
381        }))
382    }
383
384    fn parse_nonnegative_integer(&mut self) -> Result<u32, SyntaxError> {
385        let token = self.current();
386        if token.kind != TokenKind::Number {
387            return Err(self.unexpected("a non-negative integer"));
388        }
389        let value = token
390            .text(self.input)
391            .parse::<u32>()
392            .map_err(|_| self.unexpected("a non-negative integer"))?;
393        self.advance();
394        Ok(value)
395    }
396
397    fn can_start_graph_primary(&self) -> bool {
398        matches!(
399            self.current().kind,
400            TokenKind::LeftParen
401                | TokenKind::ArrowLeft
402                | TokenKind::ArrowRight
403                | TokenKind::Less
404                | TokenKind::Minus
405        )
406    }
407
408    fn parse_graph_table_columns(&mut self) -> Result<Vec<GraphTableColumn>, SyntaxError> {
409        if self.current().kind == TokenKind::RightParen {
410            return Err(self.unexpected("at least one GRAPH_TABLE column"));
411        }
412        let mut columns = Vec::new();
413        loop {
414            let start_position = self.position;
415            let end_position = self.scan_to_top_level_delimiter()?;
416            columns.push(self.graph_table_column_from_range(start_position, end_position)?);
417            if !self.consume_kind(TokenKind::Comma) {
418                break;
419            }
420        }
421        Ok(columns)
422    }
423
424    fn graph_table_column_from_range(
425        &self,
426        start_position: usize,
427        end_position: usize,
428    ) -> Result<GraphTableColumn, SyntaxError> {
429        let expression = self.labeled_expression_from_range(start_position, end_position)?;
430        Ok(GraphTableColumn {
431            expression: expression.expression,
432            alias: expression.alias,
433            span: expression.span,
434        })
435    }
436
437    fn labeled_expression_from_range(
438        &self,
439        start_position: usize,
440        end_position: usize,
441    ) -> Result<LabeledExpressionSyntax, SyntaxError> {
442        if start_position == end_position {
443            return Err(self.unexpected("an expression"));
444        }
445        let mut alias_position = None;
446        let mut depths = Depths::default();
447        for position in start_position..end_position {
448            let token = self.tokens[position];
449            self.update_expression_depths(&mut depths, token)?;
450            if depths.is_zero() && token.is_keyword(self.input, "AS") {
451                alias_position = Some(position);
452            }
453        }
454        let (expression_end_position, alias) = if let Some(as_position) = alias_position {
455            let alias_token = self.tokens.get(as_position + 1).copied().ok_or_else(|| {
456                SyntaxError::new(SyntaxErrorCode::UnexpectedEnd, self.current().span)
457                    .expected("a GRAPH_TABLE column alias")
458            })?;
459            if as_position + 2 != end_position || !is_identifier_kind(alias_token.kind) {
460                return Err(
461                    SyntaxError::new(SyntaxErrorCode::UnexpectedToken, alias_token.span)
462                        .expected("one column alias after AS")
463                        .found(alias_token.text(self.input)),
464                );
465            }
466            (as_position, Some(identifier_from_token(alias_token)))
467        } else {
468            (end_position, None)
469        };
470        let start = self.tokens[start_position].span.start;
471        let end = self.tokens[end_position - 1].span.end;
472        if start_position == expression_end_position {
473            return Err(
474                SyntaxError::new(SyntaxErrorCode::UnexpectedToken, Span::new(start, end))
475                    .expected("an expression before AS"),
476            );
477        }
478        Ok(LabeledExpressionSyntax {
479            expression: self.parse_expression_range(start_position, expression_end_position)?,
480            alias,
481            span: Span::new(start, end),
482        })
483    }
484
485    fn parse_optional_table_alias(&mut self) -> Result<Option<TableAlias>, SyntaxError> {
486        let has_as = self.consume_keyword("AS");
487        if !has_as && (!is_identifier_kind(self.current().kind) || self.at_table_alias_boundary()) {
488            return Ok(None);
489        }
490        if has_as && self.at_table_alias_boundary() {
491            return Err(self.unexpected("a table alias"));
492        }
493        let start = self.current().span.start;
494        let name = self.parse_identifier()?;
495        let columns = if self.current().kind == TokenKind::LeftParen {
496            self.parse_identifier_list()?
497        } else {
498            Vec::new()
499        };
500        Ok(Some(TableAlias {
501            name,
502            columns,
503            span: Span::new(start, self.previous_end()),
504        }))
505    }
506
507    fn at_table_alias_boundary(&self) -> bool {
508        matches!(
509            self.current().kind,
510            TokenKind::Comma | TokenKind::RightParen | TokenKind::Semicolon | TokenKind::End
511        ) || [
512            "WHERE",
513            "GROUP",
514            "HAVING",
515            "ORDER",
516            "LIMIT",
517            "OFFSET",
518            "FETCH",
519            "FOR",
520            "JOIN",
521            "INNER",
522            "LEFT",
523            "RIGHT",
524            "FULL",
525            "CROSS",
526            "ON",
527            "USING",
528            "NATURAL",
529            "UNION",
530            "EXCEPT",
531            "INTERSECT",
532            "LATERAL",
533            "TABLESAMPLE",
534            "WINDOW",
535        ]
536        .into_iter()
537        .any(|keyword| self.at_keyword(keyword))
538    }
539
540    fn parse_expression_until_keyword(
541        &mut self,
542        keyword: &'static str,
543        expected: &'static str,
544    ) -> Result<ExpressionSyntax, SyntaxError> {
545        let start_position = self.position;
546        let mut depths = Depths::default();
547        while self.current().kind != TokenKind::End {
548            if depths.is_zero() && self.at_keyword(keyword) {
549                if start_position == self.position {
550                    return Err(self.unexpected(expected));
551                }
552                return self.parse_expression_range(start_position, self.position);
553            }
554            self.update_expression_depths(&mut depths, self.current())?;
555            self.advance();
556        }
557        if !depths.is_zero() {
558            return Err(self.unclosed_expression_error(&depths));
559        }
560        Err(SyntaxError::new(SyntaxErrorCode::UnexpectedEnd, self.current().span).expected(keyword))
561    }
562
563    fn parse_expression_until_kind(
564        &mut self,
565        terminator: TokenKind,
566        expected: &'static str,
567    ) -> Result<ExpressionSyntax, SyntaxError> {
568        let start_position = self.position;
569        let mut depths = Depths::default();
570        while self.current().kind != TokenKind::End {
571            if depths.is_zero() && self.current().kind == terminator {
572                if start_position == self.position {
573                    return Err(self.unexpected(expected));
574                }
575                return self.parse_expression_range(start_position, self.position);
576            }
577            self.update_expression_depths(&mut depths, self.current())?;
578            self.advance();
579        }
580        if !depths.is_zero() {
581            return Err(self.unclosed_expression_error(&depths));
582        }
583        Err(
584            SyntaxError::new(SyntaxErrorCode::UnexpectedEnd, self.current().span)
585                .expected("a closing graph element delimiter"),
586        )
587    }
588
589    fn scan_to_top_level_delimiter(&mut self) -> Result<usize, SyntaxError> {
590        let mut depths = Depths::default();
591        while self.current().kind != TokenKind::End {
592            if depths.is_zero()
593                && matches!(
594                    self.current().kind,
595                    TokenKind::Comma | TokenKind::RightParen
596                )
597            {
598                return Ok(self.position);
599            }
600            self.update_expression_depths(&mut depths, self.current())?;
601            self.advance();
602        }
603        if !depths.is_zero() {
604            return Err(self.unclosed_expression_error(&depths));
605        }
606        Err(
607            SyntaxError::new(SyntaxErrorCode::UnexpectedEnd, self.current().span)
608                .expected("a comma or closing parenthesis"),
609        )
610    }
611
612    fn parse_qualified_name(&mut self) -> Result<QualifiedName, SyntaxError> {
613        let first = self.parse_identifier()?;
614        let start = first.span.start;
615        let mut end = first.span.end;
616        let mut parts = vec![first];
617        while self.consume_kind(TokenKind::Dot) {
618            let part = self.parse_identifier()?;
619            end = part.span.end;
620            parts.push(part);
621        }
622        Ok(QualifiedName {
623            parts,
624            span: Span::new(start, end),
625        })
626    }
627
628    fn parse_identifier(&mut self) -> Result<Identifier, SyntaxError> {
629        let token = self.current();
630        if !is_identifier_kind(token.kind) {
631            return Err(self.unexpected("an identifier"));
632        }
633        self.advance();
634        Ok(identifier_from_token(token))
635    }
636
637    fn parse_comma_separated<T>(
638        &mut self,
639        terminator: TokenKind,
640        parse_item: fn(&mut Self) -> Result<T, SyntaxError>,
641    ) -> Result<Vec<T>, SyntaxError> {
642        if self.current().kind == terminator {
643            return Ok(Vec::new());
644        }
645        let mut items = Vec::new();
646        loop {
647            items.push(parse_item(self)?);
648            if !self.consume_kind(TokenKind::Comma) {
649                break;
650            }
651        }
652        Ok(items)
653    }
654
655    fn parse_nonempty_comma_separated<T>(
656        &mut self,
657        terminator: TokenKind,
658        parse_item: fn(&mut Self) -> Result<T, SyntaxError>,
659        expected: &'static str,
660    ) -> Result<Vec<T>, SyntaxError> {
661        if self.current().kind == terminator {
662            return Err(self.unexpected(expected));
663        }
664        self.parse_comma_separated(terminator, parse_item)
665    }
666
667    fn current(&self) -> Token {
668        self.tokens
669            .get(self.position)
670            .copied()
671            .unwrap_or(Token::new(
672                TokenKind::End,
673                Span::new(self.input.len(), self.input.len()),
674            ))
675    }
676
677    fn previous_end(&self) -> usize {
678        self.position
679            .checked_sub(1)
680            .and_then(|position| self.tokens.get(position))
681            .map_or(0, |token| token.span.end)
682    }
683
684    fn advance(&mut self) -> Token {
685        let token = self.current();
686        if token.kind != TokenKind::End {
687            self.position += 1;
688        }
689        token
690    }
691
692    fn at_keyword(&self, keyword: &str) -> bool {
693        self.current().is_keyword(self.input, keyword)
694    }
695
696    fn consume_keyword(&mut self, keyword: &str) -> bool {
697        if self.at_keyword(keyword) {
698            self.advance();
699            true
700        } else {
701            false
702        }
703    }
704
705    fn expect_keyword(&mut self, keyword: &'static str) -> Result<Token, SyntaxError> {
706        if self.at_keyword(keyword) {
707            Ok(self.advance())
708        } else {
709            Err(self.unexpected(keyword))
710        }
711    }
712
713    fn consume_kind(&mut self, kind: TokenKind) -> bool {
714        if self.current().kind == kind {
715            self.advance();
716            true
717        } else {
718            false
719        }
720    }
721
722    fn expect_kind(
723        &mut self,
724        kind: TokenKind,
725        expected: &'static str,
726    ) -> Result<Token, SyntaxError> {
727        if self.current().kind == kind {
728            Ok(self.advance())
729        } else {
730            Err(self.unexpected(expected))
731        }
732    }
733
734    fn unexpected(&self, expected: &'static str) -> SyntaxError {
735        let token = self.current();
736        let code = if token.kind == TokenKind::End {
737            SyntaxErrorCode::UnexpectedEnd
738        } else {
739            SyntaxErrorCode::UnexpectedToken
740        };
741        SyntaxError::new(code, token.span)
742            .expected(expected)
743            .found(token.text(self.input))
744    }
745
746    fn update_expression_depths(
747        &self,
748        depths: &mut Depths,
749        token: Token,
750    ) -> Result<(), SyntaxError> {
751        depths.update(token.kind).map_err(|error| match error {
752            DepthError::MismatchedDelimiter(expected) => {
753                SyntaxError::new(SyntaxErrorCode::UnexpectedToken, token.span)
754                    .expected(expected)
755                    .found(token.text(self.input))
756            }
757            DepthError::NestingLimitExceeded => {
758                SyntaxError::new(SyntaxErrorCode::ExpressionNestingLimitExceeded, token.span)
759                    .expected("expression nesting within the configured parser limit")
760            }
761        })
762    }
763
764    fn unclosed_expression_error(&self, depths: &Depths) -> SyntaxError {
765        SyntaxError::new(SyntaxErrorCode::UnexpectedEnd, self.current().span)
766            .expected(depths.expected_closing().unwrap_or("a closing delimiter"))
767    }
768}
769
770#[derive(Debug)]
771struct Depths {
772    closing_delimiters: [TokenKind; MAX_EXPRESSION_NESTING],
773    len: usize,
774}
775
776impl Default for Depths {
777    fn default() -> Self {
778        Self {
779            closing_delimiters: [TokenKind::End; MAX_EXPRESSION_NESTING],
780            len: 0,
781        }
782    }
783}
784
785enum DepthError {
786    MismatchedDelimiter(&'static str),
787    NestingLimitExceeded,
788}
789
790impl Depths {
791    fn update(&mut self, kind: TokenKind) -> Result<(), DepthError> {
792        match kind {
793            TokenKind::LeftParen => self.push(TokenKind::RightParen)?,
794            TokenKind::LeftBracket => self.push(TokenKind::RightBracket)?,
795            TokenKind::LeftBrace => self.push(TokenKind::RightBrace)?,
796            TokenKind::RightParen | TokenKind::RightBracket | TokenKind::RightBrace => {
797                if self.last() != Some(kind) {
798                    return Err(DepthError::MismatchedDelimiter(
799                        self.expected_closing().unwrap_or("an opening delimiter"),
800                    ));
801                }
802                self.len -= 1;
803            }
804            _ => return Ok(()),
805        }
806        Ok(())
807    }
808
809    fn is_zero(&self) -> bool {
810        self.len == 0
811    }
812
813    fn expected_closing(&self) -> Option<&'static str> {
814        match self.last() {
815            Some(TokenKind::RightParen) => Some(")"),
816            Some(TokenKind::RightBracket) => Some("]"),
817            Some(TokenKind::RightBrace) => Some("}"),
818            _ => None,
819        }
820    }
821
822    fn last(&self) -> Option<TokenKind> {
823        self.len
824            .checked_sub(1)
825            .map(|position| self.closing_delimiters[position])
826    }
827
828    fn push(&mut self, kind: TokenKind) -> Result<(), DepthError> {
829        if self.len == MAX_EXPRESSION_NESTING {
830            return Err(DepthError::NestingLimitExceeded);
831        }
832        self.closing_delimiters[self.len] = kind;
833        self.len += 1;
834        Ok(())
835    }
836}
837
838fn is_identifier_kind(kind: TokenKind) -> bool {
839    matches!(kind, TokenKind::Word | TokenKind::QuotedIdentifier)
840}
841
842fn identifier_from_token(token: Token) -> Identifier {
843    Identifier {
844        span: token.span,
845        quoted: token.kind == TokenKind::QuotedIdentifier,
846    }
847}