fork of https://github.com/tree-sitter/tree-sitter-graph
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 912825c4f3d4c2b9c25a71400cf5e2d59dd30f33 1018 lines 35 kB view raw
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}