just playing with tangled
at docs-prerelease 1799 lines 65 kB view raw
1// Copyright 2021-2024 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#![allow(missing_docs)] 16 17use std::collections::HashSet; 18use std::error; 19use std::mem; 20use std::str::FromStr; 21 22use itertools::Itertools as _; 23use once_cell::sync::Lazy; 24use pest::iterators::Pair; 25use pest::iterators::Pairs; 26use pest::pratt_parser::Assoc; 27use pest::pratt_parser::Op; 28use pest::pratt_parser::PrattParser; 29use pest::Parser; 30use pest_derive::Parser; 31use thiserror::Error; 32 33use crate::dsl_util; 34use crate::dsl_util::collect_similar; 35use crate::dsl_util::AliasDeclaration; 36use crate::dsl_util::AliasDeclarationParser; 37use crate::dsl_util::AliasDefinitionParser; 38use crate::dsl_util::AliasExpandError; 39use crate::dsl_util::AliasExpandableExpression; 40use crate::dsl_util::AliasId; 41use crate::dsl_util::AliasesMap; 42use crate::dsl_util::Diagnostics; 43use crate::dsl_util::ExpressionFolder; 44use crate::dsl_util::FoldableExpression; 45use crate::dsl_util::FunctionCallParser; 46use crate::dsl_util::InvalidArguments; 47use crate::dsl_util::StringLiteralParser; 48 49#[derive(Parser)] 50#[grammar = "revset.pest"] 51struct RevsetParser; 52 53const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser { 54 content_rule: Rule::string_content, 55 escape_rule: Rule::string_escape, 56}; 57const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser { 58 function_name_rule: Rule::function_name, 59 function_arguments_rule: Rule::function_arguments, 60 keyword_argument_rule: Rule::keyword_argument, 61 argument_name_rule: Rule::strict_identifier, 62 argument_value_rule: Rule::expression, 63}; 64 65impl Rule { 66 /// Whether this is a placeholder rule for compatibility with the other 67 /// systems. 68 fn is_compat(&self) -> bool { 69 matches!( 70 self, 71 Rule::compat_parents_op 72 | Rule::compat_dag_range_op 73 | Rule::compat_dag_range_pre_op 74 | Rule::compat_dag_range_post_op 75 | Rule::compat_add_op 76 | Rule::compat_sub_op 77 ) 78 } 79 80 fn to_symbol(self) -> Option<&'static str> { 81 match self { 82 Rule::EOI => None, 83 Rule::whitespace => None, 84 Rule::identifier_part => None, 85 Rule::identifier => None, 86 Rule::strict_identifier_part => None, 87 Rule::strict_identifier => None, 88 Rule::symbol => None, 89 Rule::string_escape => None, 90 Rule::string_content_char => None, 91 Rule::string_content => None, 92 Rule::string_literal => None, 93 Rule::raw_string_content => None, 94 Rule::raw_string_literal => None, 95 Rule::at_op => Some("@"), 96 Rule::pattern_kind_op => Some(":"), 97 Rule::parents_op => Some("-"), 98 Rule::children_op => Some("+"), 99 Rule::compat_parents_op => Some("^"), 100 Rule::dag_range_op 101 | Rule::dag_range_pre_op 102 | Rule::dag_range_post_op 103 | Rule::dag_range_all_op => Some("::"), 104 Rule::compat_dag_range_op 105 | Rule::compat_dag_range_pre_op 106 | Rule::compat_dag_range_post_op => Some(":"), 107 Rule::range_op => Some(".."), 108 Rule::range_pre_op | Rule::range_post_op | Rule::range_all_op => Some(".."), 109 Rule::range_ops => None, 110 Rule::range_pre_ops => None, 111 Rule::range_post_ops => None, 112 Rule::range_all_ops => None, 113 Rule::negate_op => Some("~"), 114 Rule::union_op => Some("|"), 115 Rule::intersection_op => Some("&"), 116 Rule::difference_op => Some("~"), 117 Rule::compat_add_op => Some("+"), 118 Rule::compat_sub_op => Some("-"), 119 Rule::infix_op => None, 120 Rule::function => None, 121 Rule::function_name => None, 122 Rule::keyword_argument => None, 123 Rule::argument => None, 124 Rule::function_arguments => None, 125 Rule::formal_parameters => None, 126 Rule::string_pattern => None, 127 Rule::primary => None, 128 Rule::neighbors_expression => None, 129 Rule::range_expression => None, 130 Rule::expression => None, 131 Rule::program_modifier => None, 132 Rule::program => None, 133 Rule::function_alias_declaration => None, 134 Rule::alias_declaration => None, 135 } 136 } 137} 138 139/// Manages diagnostic messages emitted during revset parsing and function-call 140/// resolution. 141pub type RevsetDiagnostics = Diagnostics<RevsetParseError>; 142 143#[derive(Debug, Error)] 144#[error("{pest_error}")] 145pub struct RevsetParseError { 146 kind: RevsetParseErrorKind, 147 pest_error: Box<pest::error::Error<Rule>>, 148 source: Option<Box<dyn error::Error + Send + Sync>>, 149} 150 151#[derive(Debug, Error, PartialEq, Eq)] 152pub enum RevsetParseErrorKind { 153 #[error("Syntax error")] 154 SyntaxError, 155 #[error("`{op}` is not a prefix operator")] 156 NotPrefixOperator { 157 op: String, 158 similar_op: String, 159 description: String, 160 }, 161 #[error("`{op}` is not a postfix operator")] 162 NotPostfixOperator { 163 op: String, 164 similar_op: String, 165 description: String, 166 }, 167 #[error("`{op}` is not an infix operator")] 168 NotInfixOperator { 169 op: String, 170 similar_op: String, 171 description: String, 172 }, 173 #[error("Modifier `{0}` doesn't exist")] 174 NoSuchModifier(String), 175 #[error("Function `{name}` doesn't exist")] 176 NoSuchFunction { 177 name: String, 178 candidates: Vec<String>, 179 }, 180 #[error("Function `{name}`: {message}")] 181 InvalidFunctionArguments { name: String, message: String }, 182 #[error("Cannot resolve file pattern without workspace")] 183 FsPathWithoutWorkspace, 184 #[error("Cannot resolve `@` without workspace")] 185 WorkingCopyWithoutWorkspace, 186 #[error("Redefinition of function parameter")] 187 RedefinedFunctionParameter, 188 #[error("{0}")] 189 Expression(String), 190 #[error("In alias `{0}`")] 191 InAliasExpansion(String), 192 #[error("In function parameter `{0}`")] 193 InParameterExpansion(String), 194 #[error("Alias `{0}` expanded recursively")] 195 RecursiveAlias(String), 196} 197 198impl RevsetParseError { 199 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self { 200 let message = kind.to_string(); 201 let pest_error = Box::new(pest::error::Error::new_from_span( 202 pest::error::ErrorVariant::CustomError { message }, 203 span, 204 )); 205 RevsetParseError { 206 kind, 207 pest_error, 208 source: None, 209 } 210 } 211 212 pub(super) fn with_source( 213 mut self, 214 source: impl Into<Box<dyn error::Error + Send + Sync>>, 215 ) -> Self { 216 self.source = Some(source.into()); 217 self 218 } 219 220 /// Some other expression error. 221 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self { 222 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span) 223 } 224 225 /// If this is a `NoSuchFunction` error, expands the candidates list with 226 /// the given `other_functions`. 227 pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self 228 where 229 I: IntoIterator, 230 I::Item: AsRef<str>, 231 { 232 if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind { 233 let other_candidates = collect_similar(name, other_functions); 234 *candidates = itertools::merge(mem::take(candidates), other_candidates) 235 .dedup() 236 .collect(); 237 } 238 self 239 } 240 241 pub fn kind(&self) -> &RevsetParseErrorKind { 242 &self.kind 243 } 244 245 /// Original parsing error which typically occurred in an alias expression. 246 pub fn origin(&self) -> Option<&Self> { 247 self.source.as_ref().and_then(|e| e.downcast_ref()) 248 } 249} 250 251impl AliasExpandError for RevsetParseError { 252 fn invalid_arguments(err: InvalidArguments<'_>) -> Self { 253 err.into() 254 } 255 256 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self { 257 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span) 258 } 259 260 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self { 261 let kind = match id { 262 AliasId::Symbol(_) | AliasId::Function(..) => { 263 RevsetParseErrorKind::InAliasExpansion(id.to_string()) 264 } 265 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()), 266 }; 267 Self::with_span(kind, span).with_source(self) 268 } 269} 270 271impl From<pest::error::Error<Rule>> for RevsetParseError { 272 fn from(err: pest::error::Error<Rule>) -> Self { 273 RevsetParseError { 274 kind: RevsetParseErrorKind::SyntaxError, 275 pest_error: Box::new(rename_rules_in_pest_error(err)), 276 source: None, 277 } 278 } 279} 280 281impl From<InvalidArguments<'_>> for RevsetParseError { 282 fn from(err: InvalidArguments<'_>) -> Self { 283 let kind = RevsetParseErrorKind::InvalidFunctionArguments { 284 name: err.name.to_owned(), 285 message: err.message, 286 }; 287 Self::with_span(kind, err.span) 288 } 289} 290 291fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> { 292 let pest::error::ErrorVariant::ParsingError { 293 positives, 294 negatives, 295 } = &mut err.variant 296 else { 297 return err; 298 }; 299 300 // Remove duplicated symbols. Compat symbols are also removed from the 301 // (positive) suggestion. 302 let mut known_syms = HashSet::new(); 303 positives.retain(|rule| { 304 !rule.is_compat() && rule.to_symbol().map_or(true, |sym| known_syms.insert(sym)) 305 }); 306 let mut known_syms = HashSet::new(); 307 negatives.retain(|rule| rule.to_symbol().map_or(true, |sym| known_syms.insert(sym))); 308 err.renamed_rules(|rule| { 309 rule.to_symbol() 310 .map(|sym| format!("`{sym}`")) 311 .unwrap_or_else(|| format!("<{rule:?}>")) 312 }) 313} 314 315#[derive(Clone, Debug, Eq, PartialEq)] 316pub enum ExpressionKind<'i> { 317 /// Unquoted symbol. 318 Identifier(&'i str), 319 /// Quoted symbol or string. 320 String(String), 321 /// `<kind>:<value>` 322 StringPattern { 323 kind: &'i str, 324 value: String, 325 }, 326 /// `<name>@<remote>` 327 RemoteSymbol { 328 name: String, 329 remote: String, 330 }, 331 /// `<workspace_id>@` 332 AtWorkspace(String), 333 /// `@` 334 AtCurrentWorkspace, 335 /// `::` 336 DagRangeAll, 337 /// `..` 338 RangeAll, 339 Unary(UnaryOp, Box<ExpressionNode<'i>>), 340 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>), 341 /// `x | y | ..` 342 UnionAll(Vec<ExpressionNode<'i>>), 343 FunctionCall(Box<FunctionCallNode<'i>>), 344 /// `name: body` 345 Modifier(Box<ModifierNode<'i>>), 346 /// Identity node to preserve the span in the source text. 347 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>), 348} 349 350impl<'i> FoldableExpression<'i> for ExpressionKind<'i> { 351 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error> 352 where 353 F: ExpressionFolder<'i, Self> + ?Sized, 354 { 355 match self { 356 ExpressionKind::Identifier(name) => folder.fold_identifier(name, span), 357 ExpressionKind::String(_) 358 | ExpressionKind::StringPattern { .. } 359 | ExpressionKind::RemoteSymbol { .. } 360 | ExpressionKind::AtWorkspace(_) 361 | ExpressionKind::AtCurrentWorkspace 362 | ExpressionKind::DagRangeAll 363 | ExpressionKind::RangeAll => Ok(self), 364 ExpressionKind::Unary(op, arg) => { 365 let arg = Box::new(folder.fold_expression(*arg)?); 366 Ok(ExpressionKind::Unary(op, arg)) 367 } 368 ExpressionKind::Binary(op, lhs, rhs) => { 369 let lhs = Box::new(folder.fold_expression(*lhs)?); 370 let rhs = Box::new(folder.fold_expression(*rhs)?); 371 Ok(ExpressionKind::Binary(op, lhs, rhs)) 372 } 373 ExpressionKind::UnionAll(nodes) => { 374 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?; 375 Ok(ExpressionKind::UnionAll(nodes)) 376 } 377 ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span), 378 ExpressionKind::Modifier(modifier) => { 379 let modifier = Box::new(ModifierNode { 380 name: modifier.name, 381 name_span: modifier.name_span, 382 body: folder.fold_expression(modifier.body)?, 383 }); 384 Ok(ExpressionKind::Modifier(modifier)) 385 } 386 ExpressionKind::AliasExpanded(id, subst) => { 387 let subst = Box::new(folder.fold_expression(*subst)?); 388 Ok(ExpressionKind::AliasExpanded(id, subst)) 389 } 390 } 391 } 392} 393 394impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> { 395 fn identifier(name: &'i str) -> Self { 396 ExpressionKind::Identifier(name) 397 } 398 399 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self { 400 ExpressionKind::FunctionCall(function) 401 } 402 403 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self { 404 ExpressionKind::AliasExpanded(id, subst) 405 } 406} 407 408#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 409pub enum UnaryOp { 410 /// `~x` 411 Negate, 412 /// `::x` 413 DagRangePre, 414 /// `x::` 415 DagRangePost, 416 /// `..x` 417 RangePre, 418 /// `x..` 419 RangePost, 420 /// `x-` 421 Parents, 422 /// `x+` 423 Children, 424} 425 426#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 427pub enum BinaryOp { 428 /// `&` 429 Intersection, 430 /// `~` 431 Difference, 432 /// `::` 433 DagRange, 434 /// `..` 435 Range, 436} 437 438pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>; 439pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>; 440 441/// Expression with modifier `name: body`. 442#[derive(Clone, Debug, Eq, PartialEq)] 443pub struct ModifierNode<'i> { 444 /// Modifier name. 445 pub name: &'i str, 446 /// Span of the modifier name. 447 pub name_span: pest::Span<'i>, 448 /// Expression body. 449 pub body: ExpressionNode<'i>, 450} 451 452fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> { 453 let span = lhs.span.start_pos().span(&rhs.span.end_pos()); 454 let expr = match lhs.kind { 455 // Flatten "x | y | z" to save recursion stack. Machine-generated query 456 // might have long chain of unions. 457 ExpressionKind::UnionAll(mut nodes) => { 458 nodes.push(rhs); 459 ExpressionKind::UnionAll(nodes) 460 } 461 _ => ExpressionKind::UnionAll(vec![lhs, rhs]), 462 }; 463 ExpressionNode::new(expr, span) 464} 465 466pub(super) fn parse_program(revset_str: &str) -> Result<ExpressionNode, RevsetParseError> { 467 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?; 468 let first = pairs.next().unwrap(); 469 match first.as_rule() { 470 Rule::expression => parse_expression_node(first.into_inner()), 471 Rule::program_modifier => { 472 let (lhs, op) = first.into_inner().collect_tuple().unwrap(); 473 let rhs = pairs.next().unwrap(); 474 assert_eq!(lhs.as_rule(), Rule::strict_identifier); 475 assert_eq!(op.as_rule(), Rule::pattern_kind_op); 476 assert_eq!(rhs.as_rule(), Rule::expression); 477 let span = lhs.as_span().start_pos().span(&rhs.as_span().end_pos()); 478 let modifier = Box::new(ModifierNode { 479 name: lhs.as_str(), 480 name_span: lhs.as_span(), 481 body: parse_expression_node(rhs.into_inner())?, 482 }); 483 let expr = ExpressionKind::Modifier(modifier); 484 Ok(ExpressionNode::new(expr, span)) 485 } 486 r => panic!("unexpected revset parse rule: {r:?}"), 487 } 488} 489 490fn parse_expression_node(pairs: Pairs<Rule>) -> Result<ExpressionNode, RevsetParseError> { 491 fn not_prefix_op( 492 op: &Pair<Rule>, 493 similar_op: impl Into<String>, 494 description: impl Into<String>, 495 ) -> RevsetParseError { 496 RevsetParseError::with_span( 497 RevsetParseErrorKind::NotPrefixOperator { 498 op: op.as_str().to_owned(), 499 similar_op: similar_op.into(), 500 description: description.into(), 501 }, 502 op.as_span(), 503 ) 504 } 505 506 fn not_postfix_op( 507 op: &Pair<Rule>, 508 similar_op: impl Into<String>, 509 description: impl Into<String>, 510 ) -> RevsetParseError { 511 RevsetParseError::with_span( 512 RevsetParseErrorKind::NotPostfixOperator { 513 op: op.as_str().to_owned(), 514 similar_op: similar_op.into(), 515 description: description.into(), 516 }, 517 op.as_span(), 518 ) 519 } 520 521 fn not_infix_op( 522 op: &Pair<Rule>, 523 similar_op: impl Into<String>, 524 description: impl Into<String>, 525 ) -> RevsetParseError { 526 RevsetParseError::with_span( 527 RevsetParseErrorKind::NotInfixOperator { 528 op: op.as_str().to_owned(), 529 similar_op: similar_op.into(), 530 description: description.into(), 531 }, 532 op.as_span(), 533 ) 534 } 535 536 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| { 537 PrattParser::new() 538 .op(Op::infix(Rule::union_op, Assoc::Left) 539 | Op::infix(Rule::compat_add_op, Assoc::Left)) 540 .op(Op::infix(Rule::intersection_op, Assoc::Left) 541 | Op::infix(Rule::difference_op, Assoc::Left) 542 | Op::infix(Rule::compat_sub_op, Assoc::Left)) 543 .op(Op::prefix(Rule::negate_op)) 544 // Ranges can't be nested without parentheses. Associativity doesn't matter. 545 .op(Op::infix(Rule::dag_range_op, Assoc::Left) 546 | Op::infix(Rule::compat_dag_range_op, Assoc::Left) 547 | Op::infix(Rule::range_op, Assoc::Left)) 548 .op(Op::prefix(Rule::dag_range_pre_op) 549 | Op::prefix(Rule::compat_dag_range_pre_op) 550 | Op::prefix(Rule::range_pre_op)) 551 .op(Op::postfix(Rule::dag_range_post_op) 552 | Op::postfix(Rule::compat_dag_range_post_op) 553 | Op::postfix(Rule::range_post_op)) 554 // Neighbors 555 .op(Op::postfix(Rule::parents_op) 556 | Op::postfix(Rule::children_op) 557 | Op::postfix(Rule::compat_parents_op)) 558 }); 559 PRATT 560 .map_primary(|primary| { 561 let expr = match primary.as_rule() { 562 Rule::primary => return parse_primary_node(primary), 563 Rule::dag_range_all_op => ExpressionKind::DagRangeAll, 564 Rule::range_all_op => ExpressionKind::RangeAll, 565 r => panic!("unexpected primary rule {r:?}"), 566 }; 567 Ok(ExpressionNode::new(expr, primary.as_span())) 568 }) 569 .map_prefix(|op, rhs| { 570 let op_kind = match op.as_rule() { 571 Rule::negate_op => UnaryOp::Negate, 572 Rule::dag_range_pre_op => UnaryOp::DagRangePre, 573 Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?, 574 Rule::range_pre_op => UnaryOp::RangePre, 575 r => panic!("unexpected prefix operator rule {r:?}"), 576 }; 577 let rhs = Box::new(rhs?); 578 let span = op.as_span().start_pos().span(&rhs.span.end_pos()); 579 let expr = ExpressionKind::Unary(op_kind, rhs); 580 Ok(ExpressionNode::new(expr, span)) 581 }) 582 .map_postfix(|lhs, op| { 583 let op_kind = match op.as_rule() { 584 Rule::dag_range_post_op => UnaryOp::DagRangePost, 585 Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?, 586 Rule::range_post_op => UnaryOp::RangePost, 587 Rule::parents_op => UnaryOp::Parents, 588 Rule::children_op => UnaryOp::Children, 589 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?, 590 r => panic!("unexpected postfix operator rule {r:?}"), 591 }; 592 let lhs = Box::new(lhs?); 593 let span = lhs.span.start_pos().span(&op.as_span().end_pos()); 594 let expr = ExpressionKind::Unary(op_kind, lhs); 595 Ok(ExpressionNode::new(expr, span)) 596 }) 597 .map_infix(|lhs, op, rhs| { 598 let op_kind = match op.as_rule() { 599 Rule::union_op => return Ok(union_nodes(lhs?, rhs?)), 600 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?, 601 Rule::intersection_op => BinaryOp::Intersection, 602 Rule::difference_op => BinaryOp::Difference, 603 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?, 604 Rule::dag_range_op => BinaryOp::DagRange, 605 Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?, 606 Rule::range_op => BinaryOp::Range, 607 r => panic!("unexpected infix operator rule {r:?}"), 608 }; 609 let lhs = Box::new(lhs?); 610 let rhs = Box::new(rhs?); 611 let span = lhs.span.start_pos().span(&rhs.span.end_pos()); 612 let expr = ExpressionKind::Binary(op_kind, lhs, rhs); 613 Ok(ExpressionNode::new(expr, span)) 614 }) 615 .parse(pairs) 616} 617 618fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> { 619 let span = pair.as_span(); 620 let mut pairs = pair.into_inner(); 621 let first = pairs.next().unwrap(); 622 let expr = match first.as_rule() { 623 Rule::expression => return parse_expression_node(first.into_inner()), 624 Rule::function => { 625 let function = Box::new(FUNCTION_CALL_PARSER.parse( 626 first, 627 |pair| Ok(pair.as_str()), 628 |pair| parse_expression_node(pair.into_inner()), 629 )?); 630 ExpressionKind::FunctionCall(function) 631 } 632 Rule::string_pattern => { 633 let (lhs, op, rhs) = first.into_inner().collect_tuple().unwrap(); 634 assert_eq!(lhs.as_rule(), Rule::strict_identifier); 635 assert_eq!(op.as_rule(), Rule::pattern_kind_op); 636 let kind = lhs.as_str(); 637 let value = parse_as_string_literal(rhs); 638 ExpressionKind::StringPattern { kind, value } 639 } 640 // Identifier without "@" may be substituted by aliases. Primary expression including "@" 641 // is considered an indecomposable unit, and no alias substitution would be made. 642 Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()), 643 Rule::identifier | Rule::string_literal | Rule::raw_string_literal => { 644 let name = parse_as_string_literal(first); 645 match pairs.next() { 646 None => ExpressionKind::String(name), 647 Some(op) => { 648 assert_eq!(op.as_rule(), Rule::at_op); 649 match pairs.next() { 650 // postfix "<workspace_id>@" 651 None => ExpressionKind::AtWorkspace(name), 652 // infix "<name>@<remote>" 653 Some(second) => { 654 let remote = parse_as_string_literal(second); 655 ExpressionKind::RemoteSymbol { name, remote } 656 } 657 } 658 } 659 } 660 } 661 // nullary "@" 662 Rule::at_op => ExpressionKind::AtCurrentWorkspace, 663 r => panic!("unexpected revset parse rule: {r:?}"), 664 }; 665 Ok(ExpressionNode::new(expr, span)) 666} 667 668/// Parses part of compound symbol to string. 669fn parse_as_string_literal(pair: Pair<Rule>) -> String { 670 match pair.as_rule() { 671 Rule::identifier => pair.as_str().to_owned(), 672 Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()), 673 Rule::raw_string_literal => { 674 let (content,) = pair.into_inner().collect_tuple().unwrap(); 675 assert_eq!(content.as_rule(), Rule::raw_string_content); 676 content.as_str().to_owned() 677 } 678 _ => { 679 panic!("unexpected string literal rule: {:?}", pair.as_str()); 680 } 681 } 682} 683 684/// Checks if the text is a valid identifier 685pub fn is_identifier(text: &str) -> bool { 686 match RevsetParser::parse(Rule::identifier, text) { 687 Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(), 688 Err(_) => false, 689 } 690} 691 692pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>; 693 694#[derive(Clone, Debug, Default)] 695pub struct RevsetAliasParser; 696 697impl AliasDeclarationParser for RevsetAliasParser { 698 type Error = RevsetParseError; 699 700 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> { 701 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?; 702 let first = pairs.next().unwrap(); 703 match first.as_rule() { 704 Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())), 705 Rule::function_alias_declaration => { 706 let (name_pair, params_pair) = first.into_inner().collect_tuple().unwrap(); 707 assert_eq!(name_pair.as_rule(), Rule::function_name); 708 assert_eq!(params_pair.as_rule(), Rule::formal_parameters); 709 let name = name_pair.as_str().to_owned(); 710 let params_span = params_pair.as_span(); 711 let params = params_pair 712 .into_inner() 713 .map(|pair| match pair.as_rule() { 714 Rule::strict_identifier => pair.as_str().to_owned(), 715 r => panic!("unexpected formal parameter rule {r:?}"), 716 }) 717 .collect_vec(); 718 if params.iter().all_unique() { 719 Ok(AliasDeclaration::Function(name, params)) 720 } else { 721 Err(RevsetParseError::with_span( 722 RevsetParseErrorKind::RedefinedFunctionParameter, 723 params_span, 724 )) 725 } 726 } 727 r => panic!("unexpected alias declaration rule {r:?}"), 728 } 729 } 730} 731 732impl AliasDefinitionParser for RevsetAliasParser { 733 type Output<'i> = ExpressionKind<'i>; 734 type Error = RevsetParseError; 735 736 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> { 737 parse_program(source) 738 } 739} 740 741/// Applies the given functions to the top-level expression body node with an 742/// optional modifier. Alias expansion nodes are unwrapped accordingly. 743pub(super) fn expect_program_with<B, M>( 744 diagnostics: &mut RevsetDiagnostics, 745 node: &ExpressionNode, 746 parse_body: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<B, RevsetParseError>, 747 parse_modifier: impl FnOnce( 748 &mut RevsetDiagnostics, 749 &str, 750 pest::Span<'_>, 751 ) -> Result<M, RevsetParseError>, 752) -> Result<(B, Option<M>), RevsetParseError> { 753 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind { 754 ExpressionKind::Modifier(modifier) => { 755 let parsed_modifier = parse_modifier(diagnostics, modifier.name, modifier.name_span)?; 756 let parsed_body = parse_body(diagnostics, &modifier.body)?; 757 Ok((parsed_body, Some(parsed_modifier))) 758 } 759 _ => Ok((parse_body(diagnostics, node)?, None)), 760 }) 761} 762 763pub(super) fn expect_pattern_with<T, E: Into<Box<dyn error::Error + Send + Sync>>>( 764 diagnostics: &mut RevsetDiagnostics, 765 type_name: &str, 766 node: &ExpressionNode, 767 parse_pattern: impl FnOnce(&mut RevsetDiagnostics, &str, Option<&str>) -> Result<T, E>, 768) -> Result<T, RevsetParseError> { 769 let wrap_error = |err: E| { 770 RevsetParseError::expression(format!("Invalid {type_name}"), node.span).with_source(err) 771 }; 772 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind { 773 ExpressionKind::Identifier(name) => { 774 parse_pattern(diagnostics, name, None).map_err(wrap_error) 775 } 776 ExpressionKind::String(name) => parse_pattern(diagnostics, name, None).map_err(wrap_error), 777 ExpressionKind::StringPattern { kind, value } => { 778 parse_pattern(diagnostics, value, Some(kind)).map_err(wrap_error) 779 } 780 _ => Err(RevsetParseError::expression( 781 format!("Expected expression of {type_name}"), 782 node.span, 783 )), 784 }) 785} 786 787pub fn expect_literal<T: FromStr>( 788 diagnostics: &mut RevsetDiagnostics, 789 type_name: &str, 790 node: &ExpressionNode, 791) -> Result<T, RevsetParseError> { 792 let make_error = || { 793 RevsetParseError::expression( 794 format!("Expected expression of type {type_name}"), 795 node.span, 796 ) 797 }; 798 expect_expression_with(diagnostics, node, |_diagnostics, node| match &node.kind { 799 ExpressionKind::Identifier(name) => name.parse().map_err(|_| make_error()), 800 ExpressionKind::String(name) => name.parse().map_err(|_| make_error()), 801 _ => Err(make_error()), 802 }) 803} 804 805/// Applies the give function to the innermost `node` by unwrapping alias 806/// expansion nodes. 807pub(super) fn expect_expression_with<T>( 808 diagnostics: &mut RevsetDiagnostics, 809 node: &ExpressionNode, 810 f: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<T, RevsetParseError>, 811) -> Result<T, RevsetParseError> { 812 if let ExpressionKind::AliasExpanded(id, subst) = &node.kind { 813 let mut inner_diagnostics = RevsetDiagnostics::new(); 814 let expression = expect_expression_with(&mut inner_diagnostics, subst, f) 815 .map_err(|e| e.within_alias_expansion(*id, node.span))?; 816 diagnostics.extend_with(inner_diagnostics, |diag| { 817 diag.within_alias_expansion(*id, node.span) 818 }); 819 Ok(expression) 820 } else { 821 f(diagnostics, node) 822 } 823} 824 825#[cfg(test)] 826mod tests { 827 use assert_matches::assert_matches; 828 829 use super::*; 830 use crate::dsl_util::KeywordArgument; 831 832 #[derive(Debug)] 833 struct WithRevsetAliasesMap(RevsetAliasesMap); 834 835 impl WithRevsetAliasesMap { 836 fn parse<'i>(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> { 837 let node = parse_program(text)?; 838 dsl_util::expand_aliases(node, &self.0) 839 } 840 841 fn parse_normalized<'i>(&'i self, text: &'i str) -> ExpressionNode<'i> { 842 normalize_tree(self.parse(text).unwrap()) 843 } 844 } 845 846 fn with_aliases( 847 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>, 848 ) -> WithRevsetAliasesMap { 849 let mut aliases_map = RevsetAliasesMap::new(); 850 for (decl, defn) in aliases { 851 aliases_map.insert(decl, defn).unwrap(); 852 } 853 WithRevsetAliasesMap(aliases_map) 854 } 855 856 fn parse_into_kind(text: &str) -> Result<ExpressionKind, RevsetParseErrorKind> { 857 parse_program(text) 858 .map(|node| node.kind) 859 .map_err(|err| err.kind) 860 } 861 862 fn parse_normalized(text: &str) -> ExpressionNode { 863 normalize_tree(parse_program(text).unwrap()) 864 } 865 866 /// Drops auxiliary data from parsed tree so it can be compared with other. 867 fn normalize_tree(node: ExpressionNode) -> ExpressionNode { 868 fn empty_span() -> pest::Span<'static> { 869 pest::Span::new("", 0, 0).unwrap() 870 } 871 872 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> { 873 nodes.into_iter().map(normalize_tree).collect() 874 } 875 876 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode { 877 FunctionCallNode { 878 name: function.name, 879 name_span: empty_span(), 880 args: normalize_list(function.args), 881 keyword_args: function 882 .keyword_args 883 .into_iter() 884 .map(|arg| KeywordArgument { 885 name: arg.name, 886 name_span: empty_span(), 887 value: normalize_tree(arg.value), 888 }) 889 .collect(), 890 args_span: empty_span(), 891 } 892 } 893 894 let normalized_kind = match node.kind { 895 ExpressionKind::Identifier(_) 896 | ExpressionKind::String(_) 897 | ExpressionKind::StringPattern { .. } 898 | ExpressionKind::RemoteSymbol { .. } 899 | ExpressionKind::AtWorkspace(_) 900 | ExpressionKind::AtCurrentWorkspace 901 | ExpressionKind::DagRangeAll 902 | ExpressionKind::RangeAll => node.kind, 903 ExpressionKind::Unary(op, arg) => { 904 let arg = Box::new(normalize_tree(*arg)); 905 ExpressionKind::Unary(op, arg) 906 } 907 ExpressionKind::Binary(op, lhs, rhs) => { 908 let lhs = Box::new(normalize_tree(*lhs)); 909 let rhs = Box::new(normalize_tree(*rhs)); 910 ExpressionKind::Binary(op, lhs, rhs) 911 } 912 ExpressionKind::UnionAll(nodes) => { 913 let nodes = normalize_list(nodes); 914 ExpressionKind::UnionAll(nodes) 915 } 916 ExpressionKind::FunctionCall(function) => { 917 let function = Box::new(normalize_function_call(*function)); 918 ExpressionKind::FunctionCall(function) 919 } 920 ExpressionKind::Modifier(modifier) => { 921 let modifier = Box::new(ModifierNode { 922 name: modifier.name, 923 name_span: empty_span(), 924 body: normalize_tree(modifier.body), 925 }); 926 ExpressionKind::Modifier(modifier) 927 } 928 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind, 929 }; 930 ExpressionNode { 931 kind: normalized_kind, 932 span: empty_span(), 933 } 934 } 935 936 #[test] 937 fn test_parse_tree_eq() { 938 assert_eq!( 939 parse_normalized(r#" foo( x ) | ~bar:"baz" "#), 940 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#) 941 ); 942 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#)); 943 } 944 945 #[test] 946 fn test_parse_revset() { 947 // Parse a quoted symbol 948 assert_eq!( 949 parse_into_kind("\"foo\""), 950 Ok(ExpressionKind::String("foo".to_owned())) 951 ); 952 assert_eq!( 953 parse_into_kind("'foo'"), 954 Ok(ExpressionKind::String("foo".to_owned())) 955 ); 956 // Parse the "parents" operator 957 assert_matches!( 958 parse_into_kind("foo-"), 959 Ok(ExpressionKind::Unary(UnaryOp::Parents, _)) 960 ); 961 // Parse the "children" operator 962 assert_matches!( 963 parse_into_kind("foo+"), 964 Ok(ExpressionKind::Unary(UnaryOp::Children, _)) 965 ); 966 // Parse the "ancestors" operator 967 assert_matches!( 968 parse_into_kind("::foo"), 969 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _)) 970 ); 971 // Parse the "descendants" operator 972 assert_matches!( 973 parse_into_kind("foo::"), 974 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _)) 975 ); 976 // Parse the "dag range" operator 977 assert_matches!( 978 parse_into_kind("foo::bar"), 979 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _)) 980 ); 981 // Parse the nullary "dag range" operator 982 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll)); 983 // Parse the "range" prefix operator 984 assert_matches!( 985 parse_into_kind("..foo"), 986 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _)) 987 ); 988 assert_matches!( 989 parse_into_kind("foo.."), 990 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _)) 991 ); 992 assert_matches!( 993 parse_into_kind("foo..bar"), 994 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _)) 995 ); 996 // Parse the nullary "range" operator 997 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll)); 998 // Parse the "negate" operator 999 assert_matches!( 1000 parse_into_kind("~ foo"), 1001 Ok(ExpressionKind::Unary(UnaryOp::Negate, _)) 1002 ); 1003 assert_eq!( 1004 parse_normalized("~ ~~ foo"), 1005 parse_normalized("~(~(~(foo)))"), 1006 ); 1007 // Parse the "intersection" operator 1008 assert_matches!( 1009 parse_into_kind("foo & bar"), 1010 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _)) 1011 ); 1012 // Parse the "union" operator 1013 assert_matches!( 1014 parse_into_kind("foo | bar"), 1015 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2 1016 ); 1017 assert_matches!( 1018 parse_into_kind("foo | bar | baz"), 1019 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3 1020 ); 1021 // Parse the "difference" operator 1022 assert_matches!( 1023 parse_into_kind("foo ~ bar"), 1024 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _)) 1025 ); 1026 // Parentheses are allowed before suffix operators 1027 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-")); 1028 // Space is allowed around expressions 1029 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo")); 1030 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo")); 1031 // Space is not allowed around prefix operators 1032 assert_eq!( 1033 parse_into_kind(" :: foo "), 1034 Err(RevsetParseErrorKind::SyntaxError) 1035 ); 1036 // Incomplete parse 1037 assert_eq!( 1038 parse_into_kind("foo | -"), 1039 Err(RevsetParseErrorKind::SyntaxError) 1040 ); 1041 // Space is allowed around infix operators and function arguments 1042 assert_eq!( 1043 parse_normalized( 1044 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ", 1045 ), 1046 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"), 1047 ); 1048 // Space is allowed around keyword arguments 1049 assert_eq!( 1050 parse_normalized("remote_bookmarks( remote = foo )"), 1051 parse_normalized("remote_bookmarks(remote=foo)"), 1052 ); 1053 1054 // Trailing comma isn't allowed for empty argument 1055 assert!(parse_into_kind("bookmarks(,)").is_err()); 1056 // Trailing comma is allowed for the last argument 1057 assert_eq!( 1058 parse_normalized("bookmarks(a,)"), 1059 parse_normalized("bookmarks(a)") 1060 ); 1061 assert_eq!( 1062 parse_normalized("bookmarks(a , )"), 1063 parse_normalized("bookmarks(a)") 1064 ); 1065 assert!(parse_into_kind("bookmarks(,a)").is_err()); 1066 assert!(parse_into_kind("bookmarks(a,,)").is_err()); 1067 assert!(parse_into_kind("bookmarks(a , , )").is_err()); 1068 assert_eq!( 1069 parse_normalized("file(a,b,)"), 1070 parse_normalized("file(a, b)") 1071 ); 1072 assert!(parse_into_kind("file(a,,b)").is_err()); 1073 assert_eq!( 1074 parse_normalized("remote_bookmarks(a,remote=b , )"), 1075 parse_normalized("remote_bookmarks(a, remote=b)"), 1076 ); 1077 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err()); 1078 } 1079 1080 #[test] 1081 fn test_parse_revset_with_modifier() { 1082 // all: is a program modifier, but all:: isn't 1083 assert_eq!( 1084 parse_into_kind("all:"), 1085 Err(RevsetParseErrorKind::SyntaxError) 1086 ); 1087 assert_matches!( 1088 parse_into_kind("all:foo"), 1089 Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all" 1090 ); 1091 assert_matches!( 1092 parse_into_kind("all::"), 1093 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _)) 1094 ); 1095 assert_matches!( 1096 parse_into_kind("all::foo"), 1097 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _)) 1098 ); 1099 1100 // all::: could be parsed as all:(::), but rejected for simplicity 1101 assert_eq!( 1102 parse_into_kind("all:::"), 1103 Err(RevsetParseErrorKind::SyntaxError) 1104 ); 1105 assert_eq!( 1106 parse_into_kind("all:::foo"), 1107 Err(RevsetParseErrorKind::SyntaxError) 1108 ); 1109 1110 assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo")); 1111 assert_eq!( 1112 parse_normalized("all:all::foo"), 1113 parse_normalized("all:(all::foo)"), 1114 ); 1115 assert_eq!( 1116 parse_normalized("all:all | foo"), 1117 parse_normalized("all:(all | foo)"), 1118 ); 1119 1120 assert_eq!( 1121 parse_normalized("all: ::foo"), 1122 parse_normalized("all:(::foo)"), 1123 ); 1124 assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo")); 1125 assert_eq!( 1126 parse_into_kind("(all:foo)"), 1127 Ok(ExpressionKind::StringPattern { 1128 kind: "all", 1129 value: "foo".to_owned() 1130 }) 1131 ); 1132 assert_matches!( 1133 parse_into_kind("all :foo"), 1134 Err(RevsetParseErrorKind::SyntaxError) 1135 ); 1136 assert_eq!( 1137 parse_normalized("all:all:all"), 1138 parse_normalized("all:(all:all)"), 1139 ); 1140 } 1141 1142 #[test] 1143 fn test_parse_whitespace() { 1144 let ascii_whitespaces: String = ('\x00'..='\x7f') 1145 .filter(char::is_ascii_whitespace) 1146 .collect(); 1147 assert_eq!( 1148 parse_normalized(&format!("{ascii_whitespaces}all()")), 1149 parse_normalized("all()"), 1150 ); 1151 } 1152 1153 #[test] 1154 fn test_parse_identifier() { 1155 // Integer is a symbol 1156 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0"))); 1157 // Tag/bookmark name separated by / 1158 assert_eq!( 1159 parse_into_kind("foo_bar/baz"), 1160 Ok(ExpressionKind::Identifier("foo_bar/baz")) 1161 ); 1162 1163 // Internal '.', '-', and '+' are allowed 1164 assert_eq!( 1165 parse_into_kind("foo.bar-v1+7"), 1166 Ok(ExpressionKind::Identifier("foo.bar-v1+7")) 1167 ); 1168 assert_eq!( 1169 parse_normalized("foo.bar-v1+7-"), 1170 parse_normalized("(foo.bar-v1+7)-") 1171 ); 1172 // '.' is not allowed at the beginning or end 1173 assert_eq!( 1174 parse_into_kind(".foo"), 1175 Err(RevsetParseErrorKind::SyntaxError) 1176 ); 1177 assert_eq!( 1178 parse_into_kind("foo."), 1179 Err(RevsetParseErrorKind::SyntaxError) 1180 ); 1181 // Multiple '.', '-', '+' are not allowed 1182 assert_eq!( 1183 parse_into_kind("foo.+bar"), 1184 Err(RevsetParseErrorKind::SyntaxError) 1185 ); 1186 assert_eq!( 1187 parse_into_kind("foo--bar"), 1188 Err(RevsetParseErrorKind::SyntaxError) 1189 ); 1190 assert_eq!( 1191 parse_into_kind("foo+-bar"), 1192 Err(RevsetParseErrorKind::SyntaxError) 1193 ); 1194 1195 // Parse a parenthesized symbol 1196 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo")); 1197 1198 // Non-ASCII tag/bookmark name 1199 assert_eq!( 1200 parse_into_kind("柔術+jj"), 1201 Ok(ExpressionKind::Identifier("柔術+jj")) 1202 ); 1203 } 1204 1205 #[test] 1206 fn test_parse_string_literal() { 1207 // "\<char>" escapes 1208 assert_eq!( 1209 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#), 1210 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned())) 1211 ); 1212 1213 // Invalid "\<char>" escape 1214 assert_eq!( 1215 parse_into_kind(r#" "\y" "#), 1216 Err(RevsetParseErrorKind::SyntaxError) 1217 ); 1218 1219 // Single-quoted raw string 1220 assert_eq!( 1221 parse_into_kind(r#" '' "#), 1222 Ok(ExpressionKind::String("".to_owned())) 1223 ); 1224 assert_eq!( 1225 parse_into_kind(r#" 'a\n' "#), 1226 Ok(ExpressionKind::String(r"a\n".to_owned())) 1227 ); 1228 assert_eq!( 1229 parse_into_kind(r#" '\' "#), 1230 Ok(ExpressionKind::String(r"\".to_owned())) 1231 ); 1232 assert_eq!( 1233 parse_into_kind(r#" '"' "#), 1234 Ok(ExpressionKind::String(r#"""#.to_owned())) 1235 ); 1236 1237 // Hex bytes 1238 assert_eq!( 1239 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#), 1240 Ok(ExpressionKind::String("aeiou".to_owned())) 1241 ); 1242 assert_eq!( 1243 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#), 1244 Ok(ExpressionKind::String("àèìðù".to_owned())) 1245 ); 1246 assert_eq!( 1247 parse_into_kind(r#""\x""#), 1248 Err(RevsetParseErrorKind::SyntaxError) 1249 ); 1250 assert_eq!( 1251 parse_into_kind(r#""\xf""#), 1252 Err(RevsetParseErrorKind::SyntaxError) 1253 ); 1254 assert_eq!( 1255 parse_into_kind(r#""\xgg""#), 1256 Err(RevsetParseErrorKind::SyntaxError) 1257 ); 1258 } 1259 1260 #[test] 1261 fn test_parse_string_pattern() { 1262 assert_eq!( 1263 parse_into_kind(r#"(substring:"foo")"#), 1264 Ok(ExpressionKind::StringPattern { 1265 kind: "substring", 1266 value: "foo".to_owned() 1267 }) 1268 ); 1269 assert_eq!( 1270 parse_into_kind(r#"("exact:foo")"#), 1271 Ok(ExpressionKind::String("exact:foo".to_owned())) 1272 ); 1273 assert_eq!( 1274 parse_normalized(r#"(exact:"foo" )"#), 1275 parse_normalized(r#"(exact:"foo")"#), 1276 ); 1277 assert_eq!( 1278 parse_into_kind(r#"(exact:'\')"#), 1279 Ok(ExpressionKind::StringPattern { 1280 kind: "exact", 1281 value: r"\".to_owned() 1282 }) 1283 ); 1284 assert_matches!( 1285 parse_into_kind(r#"(exact:("foo" ))"#), 1286 Err(RevsetParseErrorKind::NotInfixOperator { .. }) 1287 ); 1288 } 1289 1290 #[test] 1291 fn parse_at_workspace_and_remote_symbol() { 1292 // Parse "@" (the current working copy) 1293 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace)); 1294 assert_eq!( 1295 parse_into_kind("main@"), 1296 Ok(ExpressionKind::AtWorkspace("main".to_owned())) 1297 ); 1298 assert_eq!( 1299 parse_into_kind("main@origin"), 1300 Ok(ExpressionKind::RemoteSymbol { 1301 name: "main".to_owned(), 1302 remote: "origin".to_owned() 1303 }) 1304 ); 1305 1306 // Quoted component in @ expression 1307 assert_eq!( 1308 parse_into_kind(r#""foo bar"@"#), 1309 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned())) 1310 ); 1311 assert_eq!( 1312 parse_into_kind(r#""foo bar"@origin"#), 1313 Ok(ExpressionKind::RemoteSymbol { 1314 name: "foo bar".to_owned(), 1315 remote: "origin".to_owned() 1316 }) 1317 ); 1318 assert_eq!( 1319 parse_into_kind(r#"main@"foo bar""#), 1320 Ok(ExpressionKind::RemoteSymbol { 1321 name: "main".to_owned(), 1322 remote: "foo bar".to_owned() 1323 }) 1324 ); 1325 assert_eq!( 1326 parse_into_kind(r#"'foo bar'@'bar baz'"#), 1327 Ok(ExpressionKind::RemoteSymbol { 1328 name: "foo bar".to_owned(), 1329 remote: "bar baz".to_owned() 1330 }) 1331 ); 1332 1333 // Quoted "@" is not interpreted as a working copy or remote symbol 1334 assert_eq!( 1335 parse_into_kind(r#""@""#), 1336 Ok(ExpressionKind::String("@".to_owned())) 1337 ); 1338 assert_eq!( 1339 parse_into_kind(r#""main@""#), 1340 Ok(ExpressionKind::String("main@".to_owned())) 1341 ); 1342 assert_eq!( 1343 parse_into_kind(r#""main@origin""#), 1344 Ok(ExpressionKind::String("main@origin".to_owned())) 1345 ); 1346 1347 // Non-ASCII name 1348 assert_eq!( 1349 parse_into_kind("@"), 1350 Ok(ExpressionKind::AtWorkspace("".to_owned())) 1351 ); 1352 assert_eq!( 1353 parse_into_kind("@"), 1354 Ok(ExpressionKind::RemoteSymbol { 1355 name: "".to_owned(), 1356 remote: "".to_owned() 1357 }) 1358 ); 1359 } 1360 1361 #[test] 1362 fn test_parse_revset_alias_symbol_decl() { 1363 let mut aliases_map = RevsetAliasesMap::new(); 1364 // Working copy or remote symbol cannot be used as an alias name. 1365 assert!(aliases_map.insert("@", "none()").is_err()); 1366 assert!(aliases_map.insert("a@", "none()").is_err()); 1367 assert!(aliases_map.insert("a@b", "none()").is_err()); 1368 // Non-ASCII character isn't allowed in alias symbol. This rule can be 1369 // relaxed if needed. 1370 assert!(aliases_map.insert("", "none()").is_err()); 1371 } 1372 1373 #[test] 1374 fn test_parse_revset_alias_func_decl() { 1375 let mut aliases_map = RevsetAliasesMap::new(); 1376 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err()); 1377 aliases_map.insert("func()", r#""is function 0""#).unwrap(); 1378 aliases_map 1379 .insert("func(a, b)", r#""is function 2""#) 1380 .unwrap(); 1381 aliases_map.insert("func(a)", r#""is function a""#).unwrap(); 1382 aliases_map.insert("func(b)", r#""is function b""#).unwrap(); 1383 1384 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap(); 1385 assert_eq!(id, AliasId::Function("func", &[])); 1386 assert!(params.is_empty()); 1387 assert_eq!(defn, r#""is function 0""#); 1388 1389 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap(); 1390 assert_eq!(id, AliasId::Function("func", &["b".to_owned()])); 1391 assert_eq!(params, ["b"]); 1392 assert_eq!(defn, r#""is function b""#); 1393 1394 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap(); 1395 assert_eq!( 1396 id, 1397 AliasId::Function("func", &["a".to_owned(), "b".to_owned()]) 1398 ); 1399 assert_eq!(params, ["a", "b"]); 1400 assert_eq!(defn, r#""is function 2""#); 1401 1402 assert!(aliases_map.get_function("func", 3).is_none()); 1403 } 1404 1405 #[test] 1406 fn test_parse_revset_alias_formal_parameter() { 1407 let mut aliases_map = RevsetAliasesMap::new(); 1408 // Working copy or remote symbol cannot be used as an parameter name. 1409 assert!(aliases_map.insert("f(@)", "none()").is_err()); 1410 assert!(aliases_map.insert("f(a@)", "none()").is_err()); 1411 assert!(aliases_map.insert("f(a@b)", "none()").is_err()); 1412 // Trailing comma isn't allowed for empty parameter 1413 assert!(aliases_map.insert("f(,)", "none()").is_err()); 1414 // Trailing comma is allowed for the last parameter 1415 assert!(aliases_map.insert("g(a,)", "none()").is_ok()); 1416 assert!(aliases_map.insert("h(a , )", "none()").is_ok()); 1417 assert!(aliases_map.insert("i(,a)", "none()").is_err()); 1418 assert!(aliases_map.insert("j(a,,)", "none()").is_err()); 1419 assert!(aliases_map.insert("k(a , , )", "none()").is_err()); 1420 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok()); 1421 assert!(aliases_map.insert("m(a,,b)", "none()").is_err()); 1422 } 1423 1424 #[test] 1425 fn test_parse_revset_compat_operator() { 1426 assert_eq!( 1427 parse_into_kind(":foo"), 1428 Err(RevsetParseErrorKind::NotPrefixOperator { 1429 op: ":".to_owned(), 1430 similar_op: "::".to_owned(), 1431 description: "ancestors".to_owned(), 1432 }) 1433 ); 1434 assert_eq!( 1435 parse_into_kind("foo^"), 1436 Err(RevsetParseErrorKind::NotPostfixOperator { 1437 op: "^".to_owned(), 1438 similar_op: "-".to_owned(), 1439 description: "parents".to_owned(), 1440 }) 1441 ); 1442 assert_eq!( 1443 parse_into_kind("foo + bar"), 1444 Err(RevsetParseErrorKind::NotInfixOperator { 1445 op: "+".to_owned(), 1446 similar_op: "|".to_owned(), 1447 description: "union".to_owned(), 1448 }) 1449 ); 1450 assert_eq!( 1451 parse_into_kind("foo - bar"), 1452 Err(RevsetParseErrorKind::NotInfixOperator { 1453 op: "-".to_owned(), 1454 similar_op: "~".to_owned(), 1455 description: "difference".to_owned(), 1456 }) 1457 ); 1458 } 1459 1460 #[test] 1461 fn test_parse_revset_operator_combinations() { 1462 // Parse repeated "parents" operator 1463 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-")); 1464 // Parse repeated "children" operator 1465 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+")); 1466 // Set operator associativity/precedence 1467 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y")); 1468 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)")); 1469 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)")); 1470 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))")); 1471 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)")); 1472 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z")); 1473 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z")); 1474 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)")); 1475 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)")); 1476 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)")); 1477 // Parse repeated "ancestors"/"descendants"/"dag range"/"range" operators 1478 assert_eq!( 1479 parse_into_kind("::foo::"), 1480 Err(RevsetParseErrorKind::SyntaxError) 1481 ); 1482 assert_eq!( 1483 parse_into_kind(":::foo"), 1484 Err(RevsetParseErrorKind::SyntaxError) 1485 ); 1486 assert_eq!( 1487 parse_into_kind("::::foo"), 1488 Err(RevsetParseErrorKind::SyntaxError) 1489 ); 1490 assert_eq!( 1491 parse_into_kind("foo:::"), 1492 Err(RevsetParseErrorKind::SyntaxError) 1493 ); 1494 assert_eq!( 1495 parse_into_kind("foo::::"), 1496 Err(RevsetParseErrorKind::SyntaxError) 1497 ); 1498 assert_eq!( 1499 parse_into_kind("foo:::bar"), 1500 Err(RevsetParseErrorKind::SyntaxError) 1501 ); 1502 assert_eq!( 1503 parse_into_kind("foo::::bar"), 1504 Err(RevsetParseErrorKind::SyntaxError) 1505 ); 1506 assert_eq!( 1507 parse_into_kind("::foo::bar"), 1508 Err(RevsetParseErrorKind::SyntaxError) 1509 ); 1510 assert_eq!( 1511 parse_into_kind("foo::bar::"), 1512 Err(RevsetParseErrorKind::SyntaxError) 1513 ); 1514 assert_eq!( 1515 parse_into_kind("::::"), 1516 Err(RevsetParseErrorKind::SyntaxError) 1517 ); 1518 assert_eq!( 1519 parse_into_kind("....foo"), 1520 Err(RevsetParseErrorKind::SyntaxError) 1521 ); 1522 assert_eq!( 1523 parse_into_kind("foo...."), 1524 Err(RevsetParseErrorKind::SyntaxError) 1525 ); 1526 assert_eq!( 1527 parse_into_kind("foo.....bar"), 1528 Err(RevsetParseErrorKind::SyntaxError) 1529 ); 1530 assert_eq!( 1531 parse_into_kind("..foo..bar"), 1532 Err(RevsetParseErrorKind::SyntaxError) 1533 ); 1534 assert_eq!( 1535 parse_into_kind("foo..bar.."), 1536 Err(RevsetParseErrorKind::SyntaxError) 1537 ); 1538 assert_eq!( 1539 parse_into_kind("...."), 1540 Err(RevsetParseErrorKind::SyntaxError) 1541 ); 1542 assert_eq!( 1543 parse_into_kind("::.."), 1544 Err(RevsetParseErrorKind::SyntaxError) 1545 ); 1546 // Parse combinations of "parents"/"children" operators and the range operators. 1547 // The former bind more strongly. 1548 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+")); 1549 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::")); 1550 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)")); 1551 assert_eq!( 1552 parse_into_kind("::-"), 1553 Err(RevsetParseErrorKind::SyntaxError) 1554 ); 1555 assert_eq!( 1556 parse_into_kind("..+"), 1557 Err(RevsetParseErrorKind::SyntaxError) 1558 ); 1559 } 1560 1561 #[test] 1562 fn test_parse_revset_function() { 1563 assert_matches!( 1564 parse_into_kind("parents(foo)"), 1565 Ok(ExpressionKind::FunctionCall(_)) 1566 ); 1567 assert_eq!( 1568 parse_normalized("parents((foo))"), 1569 parse_normalized("parents(foo)"), 1570 ); 1571 assert_eq!( 1572 parse_into_kind("parents(foo"), 1573 Err(RevsetParseErrorKind::SyntaxError) 1574 ); 1575 } 1576 1577 #[test] 1578 fn test_expand_symbol_alias() { 1579 assert_eq!( 1580 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"), 1581 parse_normalized("(a&b)|c") 1582 ); 1583 assert_eq!( 1584 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"), 1585 parse_normalized("(a|b)::heads(a|b)") 1586 ); 1587 1588 // Not string substitution 'a&b|c', but tree substitution. 1589 assert_eq!( 1590 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"), 1591 parse_normalized("a&(b|c)") 1592 ); 1593 1594 // String literal should not be substituted with alias. 1595 assert_eq!( 1596 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#), 1597 parse_normalized("a|'A'|'A'") 1598 ); 1599 1600 // Part of string pattern cannot be substituted. 1601 assert_eq!( 1602 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"), 1603 parse_normalized("author(exact:A)") 1604 ); 1605 1606 // Part of @ symbol cannot be substituted. 1607 assert_eq!( 1608 with_aliases([("A", "a")]).parse_normalized("A@"), 1609 parse_normalized("A@") 1610 ); 1611 assert_eq!( 1612 with_aliases([("A", "a")]).parse_normalized("A@b"), 1613 parse_normalized("A@b") 1614 ); 1615 assert_eq!( 1616 with_aliases([("B", "b")]).parse_normalized("a@B"), 1617 parse_normalized("a@B") 1618 ); 1619 1620 // Modifier cannot be substituted. 1621 assert_eq!( 1622 with_aliases([("all", "ALL")]).parse_normalized("all:all"), 1623 parse_normalized("all:ALL") 1624 ); 1625 1626 // Top-level alias can be substituted to modifier expression. 1627 assert_eq!( 1628 with_aliases([("A", "all:a")]).parse_normalized("A"), 1629 parse_normalized("all:a") 1630 ); 1631 1632 // Multi-level substitution. 1633 assert_eq!( 1634 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"), 1635 parse_normalized("b|c") 1636 ); 1637 1638 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind. 1639 assert_eq!( 1640 with_aliases([("A", "A")]).parse("A").unwrap_err().kind, 1641 RevsetParseErrorKind::InAliasExpansion("A".to_owned()) 1642 ); 1643 assert_eq!( 1644 with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")]) 1645 .parse("A") 1646 .unwrap_err() 1647 .kind, 1648 RevsetParseErrorKind::InAliasExpansion("A".to_owned()) 1649 ); 1650 1651 // Error in alias definition. 1652 assert_eq!( 1653 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind, 1654 RevsetParseErrorKind::InAliasExpansion("A".to_owned()) 1655 ); 1656 } 1657 1658 #[test] 1659 fn test_expand_function_alias() { 1660 assert_eq!( 1661 with_aliases([("F( )", "a")]).parse_normalized("F()"), 1662 parse_normalized("a") 1663 ); 1664 assert_eq!( 1665 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"), 1666 parse_normalized("a") 1667 ); 1668 assert_eq!( 1669 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"), 1670 parse_normalized("a|b") 1671 ); 1672 1673 // Not recursion because functions are overloaded by arity. 1674 assert_eq!( 1675 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"), 1676 parse_normalized("a|b") 1677 ); 1678 1679 // Arguments should be resolved in the current scope. 1680 assert_eq!( 1681 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"), 1682 parse_normalized("(a::y)|(b::x)") 1683 ); 1684 // F(a) -> G(a)&y -> (x|a)&y 1685 assert_eq!( 1686 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"), 1687 parse_normalized("(x|a)&y") 1688 ); 1689 // F(G(a)) -> F(x|a) -> G(x|a)&y -> (x|(x|a))&y 1690 assert_eq!( 1691 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"), 1692 parse_normalized("(x|(x|a))&y") 1693 ); 1694 1695 // Function parameter should precede the symbol alias. 1696 assert_eq!( 1697 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"), 1698 parse_normalized("a|x") 1699 ); 1700 1701 // Function parameter shouldn't be expanded in symbol alias. 1702 assert_eq!( 1703 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"), 1704 parse_normalized("a|x") 1705 ); 1706 1707 // String literal should not be substituted with function parameter. 1708 assert_eq!( 1709 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"), 1710 parse_normalized("a|'x'") 1711 ); 1712 1713 // Modifier expression body as parameter. 1714 assert_eq!( 1715 with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"), 1716 parse_normalized("all:(a|b)") 1717 ); 1718 1719 // Function and symbol aliases reside in separate namespaces. 1720 assert_eq!( 1721 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"), 1722 parse_normalized("a") 1723 ); 1724 1725 // Invalid number of arguments. 1726 assert_eq!( 1727 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind, 1728 RevsetParseErrorKind::InvalidFunctionArguments { 1729 name: "F".to_owned(), 1730 message: "Expected 0 arguments".to_owned() 1731 } 1732 ); 1733 assert_eq!( 1734 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind, 1735 RevsetParseErrorKind::InvalidFunctionArguments { 1736 name: "F".to_owned(), 1737 message: "Expected 1 arguments".to_owned() 1738 } 1739 ); 1740 assert_eq!( 1741 with_aliases([("F(x,y)", "x|y")]) 1742 .parse("F(a,b,c)") 1743 .unwrap_err() 1744 .kind, 1745 RevsetParseErrorKind::InvalidFunctionArguments { 1746 name: "F".to_owned(), 1747 message: "Expected 2 arguments".to_owned() 1748 } 1749 ); 1750 assert_eq!( 1751 with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")]) 1752 .parse("F()") 1753 .unwrap_err() 1754 .kind, 1755 RevsetParseErrorKind::InvalidFunctionArguments { 1756 name: "F".to_owned(), 1757 message: "Expected 1 to 2 arguments".to_owned() 1758 } 1759 ); 1760 assert_eq!( 1761 with_aliases([("F()", "x"), ("F(x,y)", "x|y")]) 1762 .parse("F(a)") 1763 .unwrap_err() 1764 .kind, 1765 RevsetParseErrorKind::InvalidFunctionArguments { 1766 name: "F".to_owned(), 1767 message: "Expected 0, 2 arguments".to_owned() 1768 } 1769 ); 1770 1771 // Keyword argument isn't supported for now. 1772 assert_eq!( 1773 with_aliases([("F(x)", "x")]) 1774 .parse("F(x=y)") 1775 .unwrap_err() 1776 .kind, 1777 RevsetParseErrorKind::InvalidFunctionArguments { 1778 name: "F".to_owned(), 1779 message: "Unexpected keyword arguments".to_owned() 1780 } 1781 ); 1782 1783 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind. 1784 assert_eq!( 1785 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")]) 1786 .parse("F(a)") 1787 .unwrap_err() 1788 .kind, 1789 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned()) 1790 ); 1791 assert_eq!( 1792 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")]) 1793 .parse("F(a)") 1794 .unwrap_err() 1795 .kind, 1796 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned()) 1797 ); 1798 } 1799}