fork of https://github.com/tree-sitter/tree-sitter-graph
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("global") {
295 self.consume_whitespace();
296 let global = self.parse_global()?;
297 file.globals.push(global);
298 } else if let Ok(_) = self.consume_token("attribute") {
299 self.consume_whitespace();
300 let shorthand = self.parse_shorthand()?;
301 file.shorthands.add(shorthand);
302 } else {
303 let stanza = self.parse_stanza(file.language)?;
304 file.stanzas.push(stanza);
305 }
306 self.consume_whitespace();
307 }
308 // we can unwrap here because all queries have already been parsed before
309 file.query = Some(Query::new(file.language, &self.query_source).unwrap());
310 Ok(())
311 }
312
313 fn parse_global(&mut self) -> Result<ast::Global, ParseError> {
314 let location = self.location;
315 let name = self.parse_identifier("global variable")?;
316 let quantifier = self.parse_quantifier()?;
317 let mut default = None;
318 self.consume_whitespace();
319 if let Ok(_) = self.consume_token("=") {
320 self.consume_whitespace();
321 default = Some(self.parse_string()?);
322 }
323 Ok(ast::Global {
324 name,
325 quantifier,
326 default,
327 location,
328 })
329 }
330
331 fn parse_shorthand(&mut self) -> Result<ast::AttributeShorthand, ParseError> {
332 let location = self.location;
333 let name = self.parse_identifier("shorthand name")?;
334 self.consume_whitespace();
335 self.consume_token("=")?;
336 self.consume_whitespace();
337 let variable = self.parse_unscoped_variable()?;
338 self.consume_whitespace();
339 self.consume_token("=>")?;
340 self.consume_whitespace();
341 let attributes = self.parse_attributes()?;
342 Ok(ast::AttributeShorthand {
343 name,
344 variable,
345 attributes,
346 location,
347 })
348 }
349
350 fn parse_quantifier(&mut self) -> Result<CaptureQuantifier, ParseError> {
351 let mut quantifier = One;
352 if let Some(c) = self.try_peek() {
353 self.skip().unwrap();
354 if c == '?' {
355 quantifier = ZeroOrOne;
356 } else if c == '*' {
357 quantifier = ZeroOrMore;
358 } else if c == '+' {
359 quantifier = OneOrMore;
360 } else if !c.is_whitespace() {
361 return Err(ParseError::ExpectedQuantifier(self.location));
362 }
363 }
364 Ok(quantifier)
365 }
366
367 fn parse_stanza(&mut self, language: Language) -> Result<ast::Stanza, ParseError> {
368 let start = self.location;
369 let (query, full_match_stanza_capture_index) = self.parse_query(language)?;
370 self.consume_whitespace();
371 let statements = self.parse_statements()?;
372 let end = self.location;
373 let range = Range { start, end };
374 Ok(ast::Stanza {
375 query,
376 statements,
377 full_match_stanza_capture_index,
378 full_match_file_capture_index: usize::MAX, // set in checker
379 range,
380 })
381 }
382
383 fn parse_query(&mut self, language: Language) -> Result<(Query, usize), ParseError> {
384 let location = self.location;
385 let query_start = self.offset;
386 self.skip_query()?;
387 let query_end = self.offset;
388 let query_source = self.source[query_start..query_end].to_owned() + "@" + FULL_MATCH;
389 // If tree-sitter allowed us to incrementally add patterns to a query, we wouldn't need
390 // the global query_source.
391 self.query_source += &query_source;
392 self.query_source += "\n";
393 let query = Query::new(language, &query_source).map_err(|mut e| {
394 // the column of the first row of a query pattern must be shifted by the whitespace
395 // that was already consumed
396 if e.row == 0 {
397 // must come before we update e.row!
398 e.column += location.column;
399 }
400 e.row += location.row;
401 e.offset += query_start;
402 e
403 })?;
404 if query.pattern_count() > 1 {
405 return Err(ParseError::UnexpectedQueryPatterns(location));
406 }
407 let full_match_capture_index = query
408 .capture_index_for_name(FULL_MATCH)
409 .expect("missing capture index for full match")
410 as usize;
411 Ok((query, full_match_capture_index))
412 }
413
414 fn skip_query(&mut self) -> Result<(), ParseError> {
415 let mut paren_depth = 0;
416 let mut in_string = false;
417 let mut in_escape = false;
418 let mut in_comment = false;
419 loop {
420 let ch = self.peek()?;
421 if in_escape {
422 in_escape = false;
423 } else if in_string {
424 match ch {
425 '\\' => {
426 in_escape = true;
427 }
428 '"' | '\n' => {
429 in_string = false;
430 }
431 _ => {}
432 }
433 } else if in_comment {
434 if ch == '\n' {
435 in_comment = false;
436 }
437 } else {
438 match ch {
439 '"' => in_string = true,
440 '(' => paren_depth += 1,
441 ')' => {
442 if paren_depth > 0 {
443 paren_depth -= 1;
444 }
445 }
446 '{' => return Ok(()),
447 ';' => in_comment = true,
448 _ => {}
449 }
450 }
451 self.skip().unwrap();
452 }
453 }
454
455 fn parse_statements(&mut self) -> Result<Vec<ast::Statement>, ParseError> {
456 self.consume_token("{")?;
457 let mut statements = Vec::new();
458 self.consume_whitespace();
459 while self.peek()? != '}' {
460 let statement = self.parse_statement()?;
461 statements.push(statement);
462 self.consume_whitespace();
463 }
464 self.consume_token("}")?;
465 Ok(statements)
466 }
467
468 fn parse_name(&mut self, within: &'static str) -> Result<&'a str, ParseError> {
469 let start = self.offset;
470 let ch = self.next()?;
471 if !is_ident_start(ch) {
472 return Err(ParseError::UnexpectedCharacter(ch, within, self.location));
473 }
474 self.consume_while(is_ident);
475 let end = self.offset;
476 Ok(&self.source[start..end])
477 }
478
479 fn parse_statement(&mut self) -> Result<ast::Statement, ParseError> {
480 let keyword_location = self.location;
481 let keyword = self.parse_name("keyword")?;
482 self.consume_whitespace();
483 if keyword == "let" {
484 let variable = self.parse_variable()?;
485 self.consume_whitespace();
486 self.consume_token("=")?;
487 self.consume_whitespace();
488 let value = self.parse_expression()?;
489 Ok(ast::DeclareImmutable {
490 variable,
491 value,
492 location: keyword_location,
493 }
494 .into())
495 } else if keyword == "var" {
496 let variable = self.parse_variable()?;
497 self.consume_whitespace();
498 self.consume_token("=")?;
499 self.consume_whitespace();
500 let value = self.parse_expression()?;
501 Ok(ast::DeclareMutable {
502 variable,
503 value,
504 location: keyword_location,
505 }
506 .into())
507 } else if keyword == "set" {
508 let variable = self.parse_variable()?;
509 self.consume_whitespace();
510 self.consume_token("=")?;
511 self.consume_whitespace();
512 let value = self.parse_expression()?;
513 Ok(ast::Assign {
514 variable,
515 value,
516 location: keyword_location,
517 }
518 .into())
519 } else if keyword == "node" {
520 let node = self.parse_variable()?;
521 Ok(ast::CreateGraphNode {
522 node,
523 location: keyword_location,
524 }
525 .into())
526 } else if keyword == "edge" {
527 let source = self.parse_expression()?;
528 self.consume_whitespace();
529 self.consume_token("->")?;
530 self.consume_whitespace();
531 let sink = self.parse_expression()?;
532 Ok(ast::CreateEdge {
533 source,
534 sink,
535 location: keyword_location,
536 }
537 .into())
538 } else if keyword == "attr" {
539 self.consume_token("(")?;
540 self.consume_whitespace();
541 let node_or_source = self.parse_expression()?;
542 self.consume_whitespace();
543
544 if self.peek()? == '-' {
545 let source = node_or_source;
546 self.consume_token("->")?;
547 self.consume_whitespace();
548 let sink = self.parse_expression()?;
549 self.consume_whitespace();
550 self.consume_token(")")?;
551 self.consume_whitespace();
552 let attributes = self.parse_attributes()?;
553 Ok(ast::AddEdgeAttribute {
554 source,
555 sink,
556 attributes,
557 location: keyword_location,
558 }
559 .into())
560 } else {
561 let node = node_or_source;
562 self.consume_whitespace();
563 self.consume_token(")")?;
564 self.consume_whitespace();
565 let attributes = self.parse_attributes()?;
566 Ok(ast::AddGraphNodeAttribute {
567 node,
568 attributes,
569 location: keyword_location,
570 }
571 .into())
572 }
573 } else if keyword == "print" {
574 let mut values = vec![self.parse_expression()?];
575 self.consume_whitespace();
576 while self.try_peek() == Some(',') {
577 self.consume_token(",")?;
578 self.consume_whitespace();
579 values.push(self.parse_expression()?);
580 self.consume_whitespace();
581 }
582 self.consume_whitespace();
583 Ok(ast::Print {
584 values,
585 location: keyword_location,
586 }
587 .into())
588 } else if keyword == "scan" {
589 let value = self.parse_expression()?;
590 self.consume_whitespace();
591 self.consume_token("{")?;
592 self.consume_whitespace();
593 let mut arms = Vec::new();
594 while self.peek()? != '}' {
595 let pattern_location = self.location;
596 let pattern = self.parse_string()?;
597 let regex = Regex::new(&pattern)
598 .map_err(|_| ParseError::InvalidRegex(pattern.into(), pattern_location))?;
599 self.consume_whitespace();
600 let statements = self.parse_statements()?;
601 arms.push(ast::ScanArm {
602 regex,
603 statements,
604 location: keyword_location,
605 });
606 self.consume_whitespace();
607 }
608 self.consume_token("}")?;
609 Ok(ast::Scan {
610 value,
611 arms,
612 location: keyword_location,
613 }
614 .into())
615 } else if keyword == "if" {
616 let mut arms = Vec::new();
617
618 // if
619 let location = keyword_location;
620 self.consume_whitespace();
621 let conditions = self.parse_conditions()?;
622 self.consume_whitespace();
623 let statements = self.parse_statements()?;
624 self.consume_whitespace();
625 arms.push(ast::IfArm {
626 conditions,
627 statements,
628 location,
629 });
630
631 // elif
632 let mut location = self.location;
633 while let Ok(_) = self.consume_token("elif") {
634 self.consume_whitespace();
635 let conditions = self.parse_conditions()?;
636 self.consume_whitespace();
637 let statements = self.parse_statements()?;
638 self.consume_whitespace();
639 arms.push(ast::IfArm {
640 conditions,
641 statements,
642 location,
643 });
644 self.consume_whitespace();
645 location = self.location;
646 }
647
648 // else
649 let location = self.location;
650 if let Ok(_) = self.consume_token("else") {
651 let conditions = vec![];
652 self.consume_whitespace();
653 let statements = self.parse_statements()?;
654 self.consume_whitespace();
655 arms.push(ast::IfArm {
656 conditions,
657 statements,
658 location,
659 });
660 self.consume_whitespace();
661 }
662
663 Ok(ast::If {
664 arms,
665 location: keyword_location,
666 }
667 .into())
668 } else if keyword == "for" {
669 self.consume_whitespace();
670 let variable = self.parse_unscoped_variable()?;
671 self.consume_whitespace();
672 self.consume_token("in")?;
673 self.consume_whitespace();
674 let value = self.parse_expression()?;
675 self.consume_whitespace();
676 let statements = self.parse_statements()?;
677 Ok(ast::ForIn {
678 variable,
679 value,
680 statements,
681 location: keyword_location,
682 }
683 .into())
684 } else {
685 Err(ParseError::UnexpectedKeyword(
686 keyword.into(),
687 keyword_location,
688 ))
689 }
690 }
691
692 fn parse_conditions(&mut self) -> Result<Vec<ast::Condition>, ParseError> {
693 let mut conditions = Vec::new();
694 let mut has_next = true;
695 while has_next {
696 conditions.push(self.parse_condition()?);
697 self.consume_whitespace();
698 if let Some(',') = self.try_peek() {
699 self.consume_token(",")?;
700 self.consume_whitespace();
701 has_next = true;
702 } else {
703 has_next = false;
704 }
705 }
706 Ok(conditions)
707 }
708
709 fn parse_condition(&mut self) -> Result<ast::Condition, ParseError> {
710 let location = self.location;
711 let condition = if let Ok(_) = self.consume_token("some") {
712 self.consume_whitespace();
713 let value = self.parse_expression()?;
714 ast::Condition::Some { value, location }
715 } else if let Ok(_) = self.consume_token("none") {
716 self.consume_whitespace();
717 let value = self.parse_expression()?;
718 ast::Condition::None { value, location }
719 } else if let Ok(value) = self.parse_expression() {
720 self.consume_whitespace();
721 ast::Condition::Bool { value, location }
722 } else {
723 return Err(ParseError::ExpectedToken(
724 "(some|none)? EXPRESSION",
725 location,
726 ));
727 };
728 self.consume_whitespace();
729 Ok(condition)
730 }
731
732 fn parse_identifier(&mut self, within: &'static str) -> Result<Identifier, ParseError> {
733 let content = self.parse_name(within)?;
734 Ok(Identifier::from(content))
735 }
736
737 fn parse_string(&mut self) -> Result<String, ParseError> {
738 self.consume_token("\"")?;
739 let mut escape = false;
740 let mut value = String::new();
741 loop {
742 let ch = self.next()?;
743 if escape {
744 escape = false;
745 value.push(match ch {
746 '0' => '\0',
747 'n' => '\n',
748 'r' => '\r',
749 't' => '\t',
750 _ => ch,
751 });
752 } else {
753 match ch {
754 '"' => return Ok(value),
755 '\\' => escape = true,
756 _ => value.push(ch),
757 }
758 }
759 }
760 }
761
762 fn parse_expression(&mut self) -> Result<ast::Expression, ParseError> {
763 let mut expression = match self.peek()? {
764 '#' => self.parse_literal()?,
765 '"' => self.parse_string()?.into(),
766 '@' => self.parse_capture()?.into(),
767 '$' => self.parse_regex_capture()?.into(),
768 '(' => self.parse_call()?,
769 '[' => self.parse_list()?,
770 '{' => self.parse_set()?,
771 ch if ch.is_ascii_digit() => self.parse_integer_constant()?,
772 ch if is_ident_start(ch) => {
773 let location = self.location;
774 let name = self.parse_identifier("variable name")?;
775 ast::UnscopedVariable { name, location }.into()
776 }
777 ch => {
778 return Err(ParseError::UnexpectedCharacter(
779 ch,
780 "expression",
781 self.location,
782 ))
783 }
784 };
785 self.consume_whitespace();
786 while self.try_peek() == Some('.') {
787 self.skip().unwrap();
788 self.consume_whitespace();
789 let location = self.location;
790 let scope = Box::new(expression);
791 let name = self.parse_identifier("scoped variable name")?;
792 self.consume_whitespace();
793 expression = ast::ScopedVariable {
794 scope,
795 name,
796 location,
797 }
798 .into();
799 }
800 Ok(expression)
801 }
802
803 fn parse_call(&mut self) -> Result<ast::Expression, ParseError> {
804 self.consume_token("(")?;
805 self.consume_whitespace();
806 let function = self.parse_identifier("function name")?;
807 self.consume_whitespace();
808 let mut parameters = Vec::new();
809 while self.peek()? != ')' {
810 parameters.push(self.parse_expression()?);
811 self.consume_whitespace();
812 }
813 self.consume_token(")")?;
814 Ok(ast::Call {
815 function,
816 parameters,
817 }
818 .into())
819 }
820
821 fn parse_sequence(&mut self, end_marker: char) -> Result<Vec<ast::Expression>, ParseError> {
822 let mut elements = Vec::new();
823 while self.peek()? != end_marker {
824 elements.push(self.parse_expression()?);
825 self.consume_whitespace();
826 if self.peek()? != end_marker {
827 self.consume_token(",")?;
828 self.consume_whitespace();
829 }
830 }
831 Ok(elements)
832 }
833
834 fn parse_list(&mut self) -> Result<ast::Expression, ParseError> {
835 let location = self.location;
836 self.consume_token("[")?;
837 self.consume_whitespace();
838 if let Ok(_) = self.consume_token("]") {
839 return Ok(ast::ListLiteral { elements: vec![] }.into());
840 }
841 let first_element = self.parse_expression()?;
842 self.consume_whitespace();
843 if let Ok(_) = self.consume_token("]") {
844 let elements = vec![first_element];
845 Ok(ast::ListLiteral { elements }.into())
846 } else if let Ok(_) = self.consume_token(",") {
847 self.consume_whitespace();
848 let mut elements = self.parse_sequence(']')?;
849 self.consume_whitespace();
850 self.consume_token("]")?;
851 elements.insert(0, first_element);
852 Ok(ast::ListLiteral { elements }.into())
853 } else {
854 self.consume_token("for")?;
855 self.consume_whitespace();
856 let variable = self.parse_unscoped_variable()?;
857 self.consume_whitespace();
858 self.consume_token("in")?;
859 self.consume_whitespace();
860 let value = self.parse_expression()?;
861 self.consume_whitespace();
862 self.consume_token("]")?;
863 Ok(ast::ListComprehension {
864 element: first_element.into(),
865 variable,
866 value: value.into(),
867 location,
868 }
869 .into())
870 }
871 }
872
873 fn parse_set(&mut self) -> Result<ast::Expression, ParseError> {
874 let location = self.location;
875 self.consume_token("{")?;
876 self.consume_whitespace();
877 if let Ok(_) = self.consume_token("}") {
878 return Ok(ast::SetLiteral { elements: vec![] }.into());
879 }
880 let first_element = self.parse_expression()?;
881 self.consume_whitespace();
882 if let Ok(_) = self.consume_token("}") {
883 let elements = vec![first_element];
884 Ok(ast::SetLiteral { elements }.into())
885 } else if let Ok(_) = self.consume_token(",") {
886 self.consume_whitespace();
887 let mut elements = self.parse_sequence('}')?;
888 self.consume_whitespace();
889 self.consume_token("}")?;
890 elements.insert(0, first_element);
891 Ok(ast::SetLiteral { elements }.into())
892 } else {
893 self.consume_token("for")?;
894 self.consume_whitespace();
895 let variable = self.parse_unscoped_variable()?;
896 self.consume_whitespace();
897 self.consume_token("in")?;
898 self.consume_whitespace();
899 let value = self.parse_expression()?;
900 self.consume_whitespace();
901 self.consume_token("}")?;
902 Ok(ast::SetComprehension {
903 element: first_element.into(),
904 variable,
905 value: value.into(),
906 location,
907 }
908 .into())
909 }
910 }
911
912 fn parse_capture(&mut self) -> Result<ast::Capture, ParseError> {
913 let location = self.location;
914 let start = self.offset;
915 self.consume_token("@")?;
916 let ch = self.next()?;
917 if !is_ident_start(ch) {
918 return Err(ParseError::UnexpectedCharacter(
919 ch,
920 "query capture",
921 self.location,
922 ));
923 }
924 self.consume_while(is_ident);
925 let end = self.offset;
926 let name = Identifier::from(&self.source[start + 1..end]);
927 Ok(ast::Capture {
928 name,
929 quantifier: Zero, // set in checker
930 file_capture_index: usize::MAX, // set in checker
931 stanza_capture_index: usize::MAX, // set in checker
932 location,
933 }
934 .into())
935 }
936
937 fn parse_integer_constant(&mut self) -> Result<ast::Expression, ParseError> {
938 // We'll have already verified that the next digit is an integer.
939 let start = self.offset;
940 self.consume_while(|ch| ch.is_ascii_digit());
941 let end = self.offset;
942 let value = u32::from_str_radix(&self.source[start..end], 10).unwrap();
943 Ok(ast::IntegerConstant { value }.into())
944 }
945
946 fn parse_literal(&mut self) -> Result<ast::Expression, ParseError> {
947 let literal_location = self.location;
948 self.consume_token("#")?;
949 let literal = self.parse_name("literal")?;
950 if literal == "false" {
951 return Ok(ast::Expression::FalseLiteral);
952 } else if literal == "null" {
953 return Ok(ast::Expression::NullLiteral);
954 } else if literal == "true" {
955 return Ok(ast::Expression::TrueLiteral);
956 } else {
957 Err(ParseError::UnexpectedLiteral(
958 literal.into(),
959 literal_location,
960 ))
961 }
962 }
963
964 fn parse_regex_capture(&mut self) -> Result<ast::RegexCapture, ParseError> {
965 let regex_capture_location = self.location;
966 self.consume_token("$")?;
967 let start = self.offset;
968 self.consume_while(|ch| ch.is_ascii_digit());
969 let end = self.offset;
970 if start == end {
971 return Err(ParseError::InvalidRegexCapture(regex_capture_location));
972 }
973 let match_index = usize::from_str_radix(&self.source[start..end], 10).unwrap();
974 Ok(ast::RegexCapture { match_index }.into())
975 }
976
977 fn parse_attributes(&mut self) -> Result<Vec<ast::Attribute>, ParseError> {
978 let mut attributes = vec![self.parse_attribute()?];
979 self.consume_whitespace();
980 while self.try_peek() == Some(',') {
981 self.skip().unwrap();
982 self.consume_whitespace();
983 attributes.push(self.parse_attribute()?);
984 self.consume_whitespace();
985 }
986 Ok(attributes)
987 }
988
989 fn parse_attribute(&mut self) -> Result<ast::Attribute, ParseError> {
990 let name = self.parse_identifier("attribute name")?;
991 self.consume_whitespace();
992 let value = if self.try_peek() == Some('=') {
993 self.consume_token("=")?;
994 self.consume_whitespace();
995 self.parse_expression()?
996 } else {
997 ast::Expression::TrueLiteral
998 };
999 Ok(ast::Attribute { name, value })
1000 }
1001
1002 fn parse_variable(&mut self) -> Result<ast::Variable, ParseError> {
1003 let expression_location = self.location;
1004 match self.parse_expression()? {
1005 ast::Expression::Variable(variable) => Ok(variable),
1006 _ => Err(ParseError::ExpectedVariable(expression_location)),
1007 }
1008 }
1009
1010 fn parse_unscoped_variable(&mut self) -> Result<ast::UnscopedVariable, ParseError> {
1011 match self.parse_variable()? {
1012 ast::Variable::Unscoped(variable) => Ok(variable),
1013 ast::Variable::Scoped(variable) => {
1014 Err(ParseError::ExpectedUnscopedVariable(variable.location))
1015 }
1016 }
1017 }
1018}