tree_sitter_graph/
parser.rs

1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2021, tree-sitter authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8use std::fmt::Display;
9use std::iter::Peekable;
10use std::path::Path;
11use std::str::Chars;
12
13use regex::Regex;
14use thiserror::Error;
15use tree_sitter::CaptureQuantifier;
16use tree_sitter::CaptureQuantifier::One;
17use tree_sitter::CaptureQuantifier::OneOrMore;
18use tree_sitter::CaptureQuantifier::Zero;
19use tree_sitter::CaptureQuantifier::ZeroOrMore;
20use tree_sitter::CaptureQuantifier::ZeroOrOne;
21use tree_sitter::Language;
22use tree_sitter::Query;
23use tree_sitter::QueryError;
24
25use crate::ast;
26use crate::parse_error::Excerpt;
27use crate::Identifier;
28
29pub const FULL_MATCH: &str = "__tsg__full_match";
30
31impl ast::File {
32    /// Parses a graph DSL file, returning a new `File` instance.
33    pub fn from_str(language: Language, source: &str) -> Result<Self, ParseError> {
34        let mut file = ast::File::new(language);
35        #[allow(deprecated)]
36        file.parse(source)?;
37        file.check()?;
38        Ok(file)
39    }
40
41    /// Parses a graph DSL file, adding its content to an existing `File` instance.
42    #[deprecated(
43        note = "Parsing multiple times into the same `File` instance is unsound. Use `File::from_str` instead."
44    )]
45    pub fn parse(&mut self, content: &str) -> Result<(), ParseError> {
46        Parser::new(content).parse_into_file(self)
47    }
48}
49
50// ----------------------------------------------------------------------------
51// Parse errors
52
53/// An error that can occur while parsing a graph DSL file
54#[derive(Debug, Error)]
55pub enum ParseError {
56    #[error("Expected quantifier at {0}")]
57    ExpectedQuantifier(Location),
58    #[error("Expected '{0}' at {1}")]
59    ExpectedToken(&'static str, Location),
60    #[error("Expected variable name at {0}")]
61    ExpectedVariable(Location),
62    #[error("Expected unscoped variable at {0}")]
63    ExpectedUnscopedVariable(Location),
64    #[error("Invalid regular expression /{0}/ at {1}")]
65    InvalidRegex(String, Location),
66    #[error("Expected integer constant in regex capture at {0}")]
67    InvalidRegexCapture(Location),
68    #[error("Invalid query pattern: {}", _0.message)]
69    QueryError(#[from] QueryError),
70    #[error("Unexpected character '{0}' in {1} at {2}")]
71    UnexpectedCharacter(char, &'static str, Location),
72    #[error("Unexpected end of file at {0}")]
73    UnexpectedEOF(Location),
74    #[error("Unexpected keyword '{0}' at {1}")]
75    UnexpectedKeyword(String, Location),
76    #[error("Unexpected literal '#{0}' at {1}")]
77    UnexpectedLiteral(String, Location),
78    #[error("Query contains multiple patterns at {0}")]
79    UnexpectedQueryPatterns(Location),
80    #[error(transparent)]
81    Check(#[from] crate::checker::CheckError),
82}
83
84impl ParseError {
85    pub fn display_pretty<'a>(
86        &'a self,
87        path: &'a Path,
88        source: &'a str,
89    ) -> impl std::fmt::Display + 'a {
90        DisplayParseErrorPretty {
91            error: self,
92            path,
93            source,
94        }
95    }
96}
97
98struct DisplayParseErrorPretty<'a> {
99    error: &'a ParseError,
100    path: &'a Path,
101    source: &'a str,
102}
103
104impl std::fmt::Display for DisplayParseErrorPretty<'_> {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        let location = match self.error {
107            ParseError::ExpectedQuantifier(location) => *location,
108            ParseError::ExpectedToken(_, location) => *location,
109            ParseError::ExpectedVariable(location) => *location,
110            ParseError::ExpectedUnscopedVariable(location) => *location,
111            ParseError::InvalidRegex(_, location) => *location,
112            ParseError::InvalidRegexCapture(location) => *location,
113            ParseError::QueryError(err) => Location {
114                row: err.row,
115                column: err.column,
116            },
117            ParseError::UnexpectedCharacter(_, _, location) => *location,
118            ParseError::UnexpectedEOF(location) => *location,
119            ParseError::UnexpectedKeyword(_, location) => *location,
120            ParseError::UnexpectedLiteral(_, location) => *location,
121            ParseError::UnexpectedQueryPatterns(location) => *location,
122            ParseError::Check(err) => {
123                write!(f, "{}", err.display_pretty(self.path, self.source))?;
124                return Ok(());
125            }
126        };
127        writeln!(f, "{}", self.error)?;
128        write!(
129            f,
130            "{}",
131            Excerpt::from_source(
132                self.path,
133                self.source,
134                location.row,
135                location.to_column_range(),
136                0
137            )
138        )?;
139        Ok(())
140    }
141}
142
143// ----------------------------------------------------------------------------
144// Location
145
146/// The location of a graph DSL entity within its file
147#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
148pub struct Location {
149    pub row: usize,
150    pub column: usize,
151}
152
153impl Location {
154    fn advance(&mut self, ch: char) {
155        if ch == '\n' {
156            self.row += 1;
157            self.column = 0;
158        } else {
159            self.column += 1;
160        }
161    }
162
163    pub(crate) fn to_column_range(&self) -> std::ops::Range<usize> {
164        self.column..self.column + 1
165    }
166}
167
168impl Display for Location {
169    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
170        write!(f, "({}, {})", self.row + 1, self.column + 1)
171    }
172}
173
174// ----------------------------------------------------------------------------
175// Range
176
177/// The range of a graph DSL entity within its file
178#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
179pub struct Range {
180    pub start: Location,
181    pub end: Location,
182}
183
184impl Display for Range {
185    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
186        write!(f, "{} - {}", self.start, self.end)
187    }
188}
189
190// ----------------------------------------------------------------------------
191// Parser
192
193struct Parser<'a> {
194    source: &'a str,
195    chars: Peekable<Chars<'a>>,
196    offset: usize,
197    location: Location,
198    query_source: String,
199}
200
201fn is_ident_start(c: char) -> bool {
202    c == '_' || c.is_alphabetic()
203}
204
205fn is_ident(c: char) -> bool {
206    c == '_' || c == '-' || c.is_alphanumeric()
207}
208
209impl<'a> Parser<'a> {
210    fn new(source: &'a str) -> Parser<'a> {
211        let chars = source.chars().peekable();
212        let query_source = String::with_capacity(source.len());
213        Parser {
214            source,
215            chars,
216            offset: 0,
217            location: Location::default(),
218            query_source,
219        }
220    }
221}
222
223impl<'a> Parser<'a> {
224    fn peek(&mut self) -> Result<char, ParseError> {
225        self.chars
226            .peek()
227            .copied()
228            .ok_or_else(|| ParseError::UnexpectedEOF(self.location))
229    }
230
231    fn try_peek(&mut self) -> Option<char> {
232        self.peek().ok()
233    }
234
235    fn next(&mut self) -> Result<char, ParseError> {
236        let ch = self
237            .chars
238            .next()
239            .ok_or_else(|| ParseError::UnexpectedEOF(self.location))?;
240        self.offset += ch.len_utf8();
241        self.location.advance(ch);
242        Ok(ch)
243    }
244
245    fn skip(&mut self) -> Result<(), ParseError> {
246        self.next().map(|_| ())
247    }
248
249    fn consume_whitespace(&mut self) {
250        let mut in_comment = false;
251        while let Some(ch) = self.try_peek() {
252            if in_comment {
253                if ch == '\n' {
254                    in_comment = false;
255                }
256            } else {
257                if ch == ';' {
258                    in_comment = true;
259                } else if !ch.is_whitespace() {
260                    return;
261                }
262            }
263            self.skip().unwrap();
264        }
265    }
266
267    fn consume_while(&mut self, mut f: impl FnMut(char) -> bool) {
268        while let Some(ch) = self.try_peek() {
269            if !f(ch) {
270                return;
271            }
272            self.skip().unwrap();
273        }
274    }
275
276    fn consume_n(&mut self, count: usize) -> Result<(), ParseError> {
277        for _ in 0..count {
278            self.next()?;
279        }
280        Ok(())
281    }
282
283    fn consume_token(&mut self, token: &'static str) -> Result<(), ParseError> {
284        if self.source[self.offset..].starts_with(token) {
285            self.consume_n(token.len())
286        } else {
287            Err(ParseError::ExpectedToken(token, self.location))
288        }
289    }
290
291    fn parse_into_file(&mut self, file: &mut ast::File) -> Result<(), ParseError> {
292        self.consume_whitespace();
293        while self.try_peek().is_some() {
294            if let Ok(_) = self.consume_token("attribute") {
295                self.consume_whitespace();
296                let shorthand = self.parse_shorthand()?;
297                file.shorthands.add(shorthand);
298            } else if let Ok(_) = self.consume_token("global") {
299                self.consume_whitespace();
300                let global = self.parse_global()?;
301                file.globals.push(global);
302            } else if let Ok(_) = self.consume_token("inherit") {
303                self.consume_whitespace();
304                self.consume_token(".")?;
305                let name = self.parse_identifier("inherit")?;
306                file.inherited_variables.insert(name);
307            } else {
308                let stanza = self.parse_stanza(&file.language)?;
309                file.stanzas.push(stanza);
310            }
311            self.consume_whitespace();
312        }
313        // we can unwrap here because all queries have already been parsed before
314        file.query = Some(Query::new(&file.language, &self.query_source).unwrap());
315        Ok(())
316    }
317
318    fn parse_global(&mut self) -> Result<ast::Global, ParseError> {
319        let location = self.location;
320        let name = self.parse_identifier("global variable")?;
321        let quantifier = self.parse_quantifier()?;
322        let mut default = None;
323        self.consume_whitespace();
324        if let Ok(_) = self.consume_token("=") {
325            self.consume_whitespace();
326            default = Some(self.parse_string()?);
327        }
328        Ok(ast::Global {
329            name,
330            quantifier,
331            default,
332            location,
333        })
334    }
335
336    fn parse_shorthand(&mut self) -> Result<ast::AttributeShorthand, ParseError> {
337        let location = self.location;
338        let name = self.parse_identifier("shorthand name")?;
339        self.consume_whitespace();
340        self.consume_token("=")?;
341        self.consume_whitespace();
342        let variable = self.parse_unscoped_variable()?;
343        self.consume_whitespace();
344        self.consume_token("=>")?;
345        self.consume_whitespace();
346        let attributes = self.parse_attributes()?;
347        Ok(ast::AttributeShorthand {
348            name,
349            variable,
350            attributes,
351            location,
352        })
353    }
354
355    fn parse_quantifier(&mut self) -> Result<CaptureQuantifier, ParseError> {
356        let mut quantifier = One;
357        if let Some(c) = self.try_peek() {
358            self.skip().unwrap();
359            if c == '?' {
360                quantifier = ZeroOrOne;
361            } else if c == '*' {
362                quantifier = ZeroOrMore;
363            } else if c == '+' {
364                quantifier = OneOrMore;
365            } else if !c.is_whitespace() {
366                return Err(ParseError::ExpectedQuantifier(self.location));
367            }
368        }
369        Ok(quantifier)
370    }
371
372    fn parse_stanza(&mut self, language: &Language) -> Result<ast::Stanza, ParseError> {
373        let start = self.location;
374        let (query, full_match_stanza_capture_index) = self.parse_query(language)?;
375        self.consume_whitespace();
376        let statements = self.parse_statements()?;
377        let end = self.location;
378        let range = Range { start, end };
379        Ok(ast::Stanza {
380            query,
381            statements,
382            full_match_stanza_capture_index,
383            full_match_file_capture_index: usize::MAX, // set in checker
384            range,
385        })
386    }
387
388    fn parse_query(&mut self, language: &Language) -> Result<(Query, usize), ParseError> {
389        let location = self.location;
390        let query_start = self.offset;
391        self.skip_query()?;
392        let query_end = self.offset;
393        let query_source = self.source[query_start..query_end].to_owned() + "@" + FULL_MATCH;
394        // If tree-sitter allowed us to incrementally add patterns to a query, we wouldn't need
395        // the global query_source.
396        self.query_source += &query_source;
397        self.query_source += "\n";
398        let query = Query::new(language, &query_source).map_err(|mut e| {
399            // the column of the first row of a query pattern must be shifted by the whitespace
400            // that was already consumed
401            if e.row == 0 {
402                // must come before we update e.row!
403                e.column += location.column;
404            }
405            e.row += location.row;
406            e.offset += query_start;
407            e
408        })?;
409        if query.pattern_count() > 1 {
410            return Err(ParseError::UnexpectedQueryPatterns(location));
411        }
412        let full_match_capture_index = query
413            .capture_index_for_name(FULL_MATCH)
414            .expect("missing capture index for full match")
415            as usize;
416        Ok((query, full_match_capture_index))
417    }
418
419    fn skip_query(&mut self) -> Result<(), ParseError> {
420        let mut paren_depth = 0;
421        let mut in_string = false;
422        let mut in_escape = false;
423        let mut in_comment = false;
424        loop {
425            let ch = self.peek()?;
426            if in_escape {
427                in_escape = false;
428            } else if in_string {
429                match ch {
430                    '\\' => {
431                        in_escape = true;
432                    }
433                    '"' | '\n' => {
434                        in_string = false;
435                    }
436                    _ => {}
437                }
438            } else if in_comment {
439                if ch == '\n' {
440                    in_comment = false;
441                }
442            } else {
443                match ch {
444                    '"' => in_string = true,
445                    '(' => paren_depth += 1,
446                    ')' => {
447                        if paren_depth > 0 {
448                            paren_depth -= 1;
449                        }
450                    }
451                    '{' => return Ok(()),
452                    ';' => in_comment = true,
453                    _ => {}
454                }
455            }
456            self.skip().unwrap();
457        }
458    }
459
460    fn parse_statements(&mut self) -> Result<Vec<ast::Statement>, ParseError> {
461        self.consume_token("{")?;
462        let mut statements = Vec::new();
463        self.consume_whitespace();
464        while self.peek()? != '}' {
465            let statement = self.parse_statement()?;
466            statements.push(statement);
467            self.consume_whitespace();
468        }
469        self.consume_token("}")?;
470        Ok(statements)
471    }
472
473    fn parse_name(&mut self, within: &'static str) -> Result<&'a str, ParseError> {
474        let start = self.offset;
475        let ch = self.next()?;
476        if !is_ident_start(ch) {
477            return Err(ParseError::UnexpectedCharacter(ch, within, self.location));
478        }
479        self.consume_while(is_ident);
480        let end = self.offset;
481        Ok(&self.source[start..end])
482    }
483
484    fn parse_statement(&mut self) -> Result<ast::Statement, ParseError> {
485        let keyword_location = self.location;
486        let keyword = self.parse_name("keyword")?;
487        self.consume_whitespace();
488        if keyword == "let" {
489            let variable = self.parse_variable()?;
490            self.consume_whitespace();
491            self.consume_token("=")?;
492            self.consume_whitespace();
493            let value = self.parse_expression()?;
494            Ok(ast::DeclareImmutable {
495                variable,
496                value,
497                location: keyword_location,
498            }
499            .into())
500        } else if keyword == "var" {
501            let variable = self.parse_variable()?;
502            self.consume_whitespace();
503            self.consume_token("=")?;
504            self.consume_whitespace();
505            let value = self.parse_expression()?;
506            Ok(ast::DeclareMutable {
507                variable,
508                value,
509                location: keyword_location,
510            }
511            .into())
512        } else if keyword == "set" {
513            let variable = self.parse_variable()?;
514            self.consume_whitespace();
515            self.consume_token("=")?;
516            self.consume_whitespace();
517            let value = self.parse_expression()?;
518            Ok(ast::Assign {
519                variable,
520                value,
521                location: keyword_location,
522            }
523            .into())
524        } else if keyword == "node" {
525            let node = self.parse_variable()?;
526            Ok(ast::CreateGraphNode {
527                node,
528                location: keyword_location,
529            }
530            .into())
531        } else if keyword == "edge" {
532            let source = self.parse_expression()?;
533            self.consume_whitespace();
534            self.consume_token("->")?;
535            self.consume_whitespace();
536            let sink = self.parse_expression()?;
537            Ok(ast::CreateEdge {
538                source,
539                sink,
540                location: keyword_location,
541            }
542            .into())
543        } else if keyword == "attr" {
544            self.consume_token("(")?;
545            self.consume_whitespace();
546            let node_or_source = self.parse_expression()?;
547            self.consume_whitespace();
548
549            if self.peek()? == '-' {
550                let source = node_or_source;
551                self.consume_token("->")?;
552                self.consume_whitespace();
553                let sink = self.parse_expression()?;
554                self.consume_whitespace();
555                self.consume_token(")")?;
556                self.consume_whitespace();
557                let attributes = self.parse_attributes()?;
558                Ok(ast::AddEdgeAttribute {
559                    source,
560                    sink,
561                    attributes,
562                    location: keyword_location,
563                }
564                .into())
565            } else {
566                let node = node_or_source;
567                self.consume_whitespace();
568                self.consume_token(")")?;
569                self.consume_whitespace();
570                let attributes = self.parse_attributes()?;
571                Ok(ast::AddGraphNodeAttribute {
572                    node,
573                    attributes,
574                    location: keyword_location,
575                }
576                .into())
577            }
578        } else if keyword == "print" {
579            let mut values = vec![self.parse_expression()?];
580            self.consume_whitespace();
581            while self.try_peek() == Some(',') {
582                self.consume_token(",")?;
583                self.consume_whitespace();
584                values.push(self.parse_expression()?);
585                self.consume_whitespace();
586            }
587            self.consume_whitespace();
588            Ok(ast::Print {
589                values,
590                location: keyword_location,
591            }
592            .into())
593        } else if keyword == "scan" {
594            let value = self.parse_expression()?;
595            self.consume_whitespace();
596            self.consume_token("{")?;
597            self.consume_whitespace();
598            let mut arms = Vec::new();
599            while self.peek()? != '}' {
600                let pattern_location = self.location;
601                let pattern = self.parse_string()?;
602                let regex = Regex::new(&pattern)
603                    .map_err(|_| ParseError::InvalidRegex(pattern.into(), pattern_location))?;
604                self.consume_whitespace();
605                let statements = self.parse_statements()?;
606                arms.push(ast::ScanArm {
607                    regex,
608                    statements,
609                    location: keyword_location,
610                });
611                self.consume_whitespace();
612            }
613            self.consume_token("}")?;
614            Ok(ast::Scan {
615                value,
616                arms,
617                location: keyword_location,
618            }
619            .into())
620        } else if keyword == "if" {
621            let mut arms = Vec::new();
622
623            // if
624            let location = keyword_location;
625            self.consume_whitespace();
626            let conditions = self.parse_conditions()?;
627            self.consume_whitespace();
628            let statements = self.parse_statements()?;
629            self.consume_whitespace();
630            arms.push(ast::IfArm {
631                conditions,
632                statements,
633                location,
634            });
635
636            // elif
637            let mut location = self.location;
638            while let Ok(_) = self.consume_token("elif") {
639                self.consume_whitespace();
640                let conditions = self.parse_conditions()?;
641                self.consume_whitespace();
642                let statements = self.parse_statements()?;
643                self.consume_whitespace();
644                arms.push(ast::IfArm {
645                    conditions,
646                    statements,
647                    location,
648                });
649                self.consume_whitespace();
650                location = self.location;
651            }
652
653            // else
654            let location = self.location;
655            if let Ok(_) = self.consume_token("else") {
656                let conditions = vec![];
657                self.consume_whitespace();
658                let statements = self.parse_statements()?;
659                self.consume_whitespace();
660                arms.push(ast::IfArm {
661                    conditions,
662                    statements,
663                    location,
664                });
665                self.consume_whitespace();
666            }
667
668            Ok(ast::If {
669                arms,
670                location: keyword_location,
671            }
672            .into())
673        } else if keyword == "for" {
674            self.consume_whitespace();
675            let variable = self.parse_unscoped_variable()?;
676            self.consume_whitespace();
677            self.consume_token("in")?;
678            self.consume_whitespace();
679            let value = self.parse_expression()?;
680            self.consume_whitespace();
681            let statements = self.parse_statements()?;
682            Ok(ast::ForIn {
683                variable,
684                value,
685                statements,
686                location: keyword_location,
687            }
688            .into())
689        } else {
690            Err(ParseError::UnexpectedKeyword(
691                keyword.into(),
692                keyword_location,
693            ))
694        }
695    }
696
697    fn parse_conditions(&mut self) -> Result<Vec<ast::Condition>, ParseError> {
698        let mut conditions = Vec::new();
699        let mut has_next = true;
700        while has_next {
701            conditions.push(self.parse_condition()?);
702            self.consume_whitespace();
703            if let Some(',') = self.try_peek() {
704                self.consume_token(",")?;
705                self.consume_whitespace();
706                has_next = true;
707            } else {
708                has_next = false;
709            }
710        }
711        Ok(conditions)
712    }
713
714    fn parse_condition(&mut self) -> Result<ast::Condition, ParseError> {
715        let location = self.location;
716        let condition = if let Ok(_) = self.consume_token("some") {
717            self.consume_whitespace();
718            let value = self.parse_expression()?;
719            ast::Condition::Some { value, location }
720        } else if let Ok(_) = self.consume_token("none") {
721            self.consume_whitespace();
722            let value = self.parse_expression()?;
723            ast::Condition::None { value, location }
724        } else if let Ok(value) = self.parse_expression() {
725            self.consume_whitespace();
726            ast::Condition::Bool { value, location }
727        } else {
728            return Err(ParseError::ExpectedToken(
729                "(some|none)? EXPRESSION",
730                location,
731            ));
732        };
733        self.consume_whitespace();
734        Ok(condition)
735    }
736
737    fn parse_identifier(&mut self, within: &'static str) -> Result<Identifier, ParseError> {
738        let content = self.parse_name(within)?;
739        Ok(Identifier::from(content))
740    }
741
742    fn parse_string(&mut self) -> Result<String, ParseError> {
743        self.consume_token("\"")?;
744        let mut escape = false;
745        let mut value = String::new();
746        loop {
747            let ch = self.next()?;
748            if escape {
749                escape = false;
750                value.push(match ch {
751                    '0' => '\0',
752                    'n' => '\n',
753                    'r' => '\r',
754                    't' => '\t',
755                    _ => ch,
756                });
757            } else {
758                match ch {
759                    '"' => return Ok(value),
760                    '\\' => escape = true,
761                    _ => value.push(ch),
762                }
763            }
764        }
765    }
766
767    fn parse_expression(&mut self) -> Result<ast::Expression, ParseError> {
768        let mut expression = match self.peek()? {
769            '#' => self.parse_literal()?,
770            '"' => self.parse_string()?.into(),
771            '@' => self.parse_capture()?.into(),
772            '$' => self.parse_regex_capture()?.into(),
773            '(' => self.parse_call()?,
774            '[' => self.parse_list()?,
775            '{' => self.parse_set()?,
776            ch if ch.is_ascii_digit() => self.parse_integer_constant()?,
777            ch if is_ident_start(ch) => {
778                let location = self.location;
779                let name = self.parse_identifier("variable name")?;
780                ast::UnscopedVariable { name, location }.into()
781            }
782            ch => {
783                return Err(ParseError::UnexpectedCharacter(
784                    ch,
785                    "expression",
786                    self.location,
787                ))
788            }
789        };
790        self.consume_whitespace();
791        while self.try_peek() == Some('.') {
792            self.skip().unwrap();
793            self.consume_whitespace();
794            let location = self.location;
795            let scope = Box::new(expression);
796            let name = self.parse_identifier("scoped variable name")?;
797            self.consume_whitespace();
798            expression = ast::ScopedVariable {
799                scope,
800                name,
801                location,
802            }
803            .into();
804        }
805        Ok(expression)
806    }
807
808    fn parse_call(&mut self) -> Result<ast::Expression, ParseError> {
809        self.consume_token("(")?;
810        self.consume_whitespace();
811        let function = self.parse_identifier("function name")?;
812        self.consume_whitespace();
813        let mut parameters = Vec::new();
814        while self.peek()? != ')' {
815            parameters.push(self.parse_expression()?);
816            self.consume_whitespace();
817        }
818        self.consume_token(")")?;
819        Ok(ast::Call {
820            function,
821            parameters,
822        }
823        .into())
824    }
825
826    fn parse_sequence(&mut self, end_marker: char) -> Result<Vec<ast::Expression>, ParseError> {
827        let mut elements = Vec::new();
828        while self.peek()? != end_marker {
829            elements.push(self.parse_expression()?);
830            self.consume_whitespace();
831            if self.peek()? != end_marker {
832                self.consume_token(",")?;
833                self.consume_whitespace();
834            }
835        }
836        Ok(elements)
837    }
838
839    fn parse_list(&mut self) -> Result<ast::Expression, ParseError> {
840        let location = self.location;
841        self.consume_token("[")?;
842        self.consume_whitespace();
843        if let Ok(_) = self.consume_token("]") {
844            return Ok(ast::ListLiteral { elements: vec![] }.into());
845        }
846        let first_element = self.parse_expression()?;
847        self.consume_whitespace();
848        if let Ok(_) = self.consume_token("]") {
849            let elements = vec![first_element];
850            Ok(ast::ListLiteral { elements }.into())
851        } else if let Ok(_) = self.consume_token(",") {
852            self.consume_whitespace();
853            let mut elements = self.parse_sequence(']')?;
854            self.consume_whitespace();
855            self.consume_token("]")?;
856            elements.insert(0, first_element);
857            Ok(ast::ListLiteral { elements }.into())
858        } else {
859            self.consume_token("for")?;
860            self.consume_whitespace();
861            let variable = self.parse_unscoped_variable()?;
862            self.consume_whitespace();
863            self.consume_token("in")?;
864            self.consume_whitespace();
865            let value = self.parse_expression()?;
866            self.consume_whitespace();
867            self.consume_token("]")?;
868            Ok(ast::ListComprehension {
869                element: first_element.into(),
870                variable,
871                value: value.into(),
872                location,
873            }
874            .into())
875        }
876    }
877
878    fn parse_set(&mut self) -> Result<ast::Expression, ParseError> {
879        let location = self.location;
880        self.consume_token("{")?;
881        self.consume_whitespace();
882        if let Ok(_) = self.consume_token("}") {
883            return Ok(ast::SetLiteral { elements: vec![] }.into());
884        }
885        let first_element = self.parse_expression()?;
886        self.consume_whitespace();
887        if let Ok(_) = self.consume_token("}") {
888            let elements = vec![first_element];
889            Ok(ast::SetLiteral { elements }.into())
890        } else if let Ok(_) = self.consume_token(",") {
891            self.consume_whitespace();
892            let mut elements = self.parse_sequence('}')?;
893            self.consume_whitespace();
894            self.consume_token("}")?;
895            elements.insert(0, first_element);
896            Ok(ast::SetLiteral { elements }.into())
897        } else {
898            self.consume_token("for")?;
899            self.consume_whitespace();
900            let variable = self.parse_unscoped_variable()?;
901            self.consume_whitespace();
902            self.consume_token("in")?;
903            self.consume_whitespace();
904            let value = self.parse_expression()?;
905            self.consume_whitespace();
906            self.consume_token("}")?;
907            Ok(ast::SetComprehension {
908                element: first_element.into(),
909                variable,
910                value: value.into(),
911                location,
912            }
913            .into())
914        }
915    }
916
917    fn parse_capture(&mut self) -> Result<ast::Capture, ParseError> {
918        let location = self.location;
919        let start = self.offset;
920        self.consume_token("@")?;
921        let ch = self.next()?;
922        if !is_ident_start(ch) {
923            return Err(ParseError::UnexpectedCharacter(
924                ch,
925                "query capture",
926                self.location,
927            ));
928        }
929        self.consume_while(is_ident);
930        let end = self.offset;
931        let name = Identifier::from(&self.source[start + 1..end]);
932        Ok(ast::Capture {
933            name,
934            quantifier: Zero,                 // set in checker
935            file_capture_index: usize::MAX,   // set in checker
936            stanza_capture_index: usize::MAX, // set in checker
937            location,
938        }
939        .into())
940    }
941
942    fn parse_integer_constant(&mut self) -> Result<ast::Expression, ParseError> {
943        // We'll have already verified that the next digit is an integer.
944        let start = self.offset;
945        self.consume_while(|ch| ch.is_ascii_digit());
946        let end = self.offset;
947        let value = u32::from_str_radix(&self.source[start..end], 10).unwrap();
948        Ok(ast::IntegerConstant { value }.into())
949    }
950
951    fn parse_literal(&mut self) -> Result<ast::Expression, ParseError> {
952        let literal_location = self.location;
953        self.consume_token("#")?;
954        let literal = self.parse_name("literal")?;
955        if literal == "false" {
956            return Ok(ast::Expression::FalseLiteral);
957        } else if literal == "null" {
958            return Ok(ast::Expression::NullLiteral);
959        } else if literal == "true" {
960            return Ok(ast::Expression::TrueLiteral);
961        } else {
962            Err(ParseError::UnexpectedLiteral(
963                literal.into(),
964                literal_location,
965            ))
966        }
967    }
968
969    fn parse_regex_capture(&mut self) -> Result<ast::RegexCapture, ParseError> {
970        let regex_capture_location = self.location;
971        self.consume_token("$")?;
972        let start = self.offset;
973        self.consume_while(|ch| ch.is_ascii_digit());
974        let end = self.offset;
975        if start == end {
976            return Err(ParseError::InvalidRegexCapture(regex_capture_location));
977        }
978        let match_index = usize::from_str_radix(&self.source[start..end], 10).unwrap();
979        Ok(ast::RegexCapture { match_index }.into())
980    }
981
982    fn parse_attributes(&mut self) -> Result<Vec<ast::Attribute>, ParseError> {
983        let mut attributes = vec![self.parse_attribute()?];
984        self.consume_whitespace();
985        while self.try_peek() == Some(',') {
986            self.skip().unwrap();
987            self.consume_whitespace();
988            attributes.push(self.parse_attribute()?);
989            self.consume_whitespace();
990        }
991        Ok(attributes)
992    }
993
994    fn parse_attribute(&mut self) -> Result<ast::Attribute, ParseError> {
995        let name = self.parse_identifier("attribute name")?;
996        self.consume_whitespace();
997        let value = if self.try_peek() == Some('=') {
998            self.consume_token("=")?;
999            self.consume_whitespace();
1000            self.parse_expression()?
1001        } else {
1002            ast::Expression::TrueLiteral
1003        };
1004        Ok(ast::Attribute { name, value })
1005    }
1006
1007    fn parse_variable(&mut self) -> Result<ast::Variable, ParseError> {
1008        let expression_location = self.location;
1009        match self.parse_expression()? {
1010            ast::Expression::Variable(variable) => Ok(variable),
1011            _ => Err(ParseError::ExpectedVariable(expression_location)),
1012        }
1013    }
1014
1015    fn parse_unscoped_variable(&mut self) -> Result<ast::UnscopedVariable, ParseError> {
1016        match self.parse_variable()? {
1017            ast::Variable::Unscoped(variable) => Ok(variable),
1018            ast::Variable::Scoped(variable) => {
1019                Err(ParseError::ExpectedUnscopedVariable(variable.location))
1020            }
1021        }
1022    }
1023}