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