just playing with tangled
at diffedit3 1465 lines 52 kB view raw
1// Copyright 2020 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 15use std::collections::HashMap; 16use std::{error, fmt, mem}; 17 18use itertools::Itertools as _; 19use jj_lib::dsl_util::{collect_similar, StringLiteralParser}; 20use once_cell::sync::Lazy; 21use pest::iterators::{Pair, Pairs}; 22use pest::pratt_parser::{Assoc, Op, PrattParser}; 23use pest::Parser; 24use pest_derive::Parser; 25use thiserror::Error; 26 27#[derive(Parser)] 28#[grammar = "template.pest"] 29struct TemplateParser; 30 31const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser { 32 content_rule: Rule::string_content, 33 escape_rule: Rule::string_escape, 34}; 35 36impl Rule { 37 fn to_symbol(self) -> Option<&'static str> { 38 match self { 39 Rule::EOI => None, 40 Rule::whitespace => None, 41 Rule::string_escape => None, 42 Rule::string_content_char => None, 43 Rule::string_content => None, 44 Rule::string_literal => None, 45 Rule::raw_string_content => None, 46 Rule::raw_string_literal => None, 47 Rule::integer_literal => None, 48 Rule::identifier => None, 49 Rule::concat_op => Some("++"), 50 Rule::logical_or_op => Some("||"), 51 Rule::logical_and_op => Some("&&"), 52 Rule::logical_not_op => Some("!"), 53 Rule::negate_op => Some("-"), 54 Rule::prefix_ops => None, 55 Rule::infix_ops => None, 56 Rule::function => None, 57 Rule::function_arguments => None, 58 Rule::lambda => None, 59 Rule::formal_parameters => None, 60 Rule::primary => None, 61 Rule::term => None, 62 Rule::expression => None, 63 Rule::template => None, 64 Rule::program => None, 65 Rule::function_alias_declaration => None, 66 Rule::alias_declaration => None, 67 } 68 } 69} 70 71pub type TemplateParseResult<T> = Result<T, TemplateParseError>; 72 73#[derive(Debug, Error)] 74#[error("{pest_error}")] 75pub struct TemplateParseError { 76 kind: TemplateParseErrorKind, 77 pest_error: Box<pest::error::Error<Rule>>, 78 source: Option<Box<dyn error::Error + Send + Sync>>, 79} 80 81#[derive(Clone, Debug, Eq, Error, PartialEq)] 82pub enum TemplateParseErrorKind { 83 #[error("Syntax error")] 84 SyntaxError, 85 #[error(r#"Keyword "{name}" doesn't exist"#)] 86 NoSuchKeyword { 87 name: String, 88 candidates: Vec<String>, 89 }, 90 #[error(r#"Function "{name}" doesn't exist"#)] 91 NoSuchFunction { 92 name: String, 93 candidates: Vec<String>, 94 }, 95 #[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)] 96 NoSuchMethod { 97 type_name: String, 98 name: String, 99 candidates: Vec<String>, 100 }, 101 #[error(r#"Function "{name}": {message}"#)] 102 InvalidArguments { name: String, message: String }, 103 #[error("Redefinition of function parameter")] 104 RedefinedFunctionParameter, 105 #[error("{0}")] 106 Expression(String), 107 #[error(r#"Alias "{0}" cannot be expanded"#)] 108 BadAliasExpansion(String), 109 #[error(r#"Alias "{0}" expanded recursively"#)] 110 RecursiveAlias(String), 111} 112 113impl TemplateParseError { 114 pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self { 115 let message = kind.to_string(); 116 let pest_error = Box::new(pest::error::Error::new_from_span( 117 pest::error::ErrorVariant::CustomError { message }, 118 span, 119 )); 120 TemplateParseError { 121 kind, 122 pest_error, 123 source: None, 124 } 125 } 126 127 pub fn with_source(mut self, source: impl Into<Box<dyn error::Error + Send + Sync>>) -> Self { 128 self.source = Some(source.into()); 129 self 130 } 131 132 // TODO: migrate all callers to table-based lookup_method() 133 pub(crate) fn no_such_method( 134 type_name: impl Into<String>, 135 function: &FunctionCallNode, 136 ) -> Self { 137 TemplateParseError::with_span( 138 TemplateParseErrorKind::NoSuchMethod { 139 type_name: type_name.into(), 140 name: function.name.to_owned(), 141 candidates: vec![], 142 }, 143 function.name_span, 144 ) 145 } 146 147 pub fn invalid_arguments(function: &FunctionCallNode, message: impl Into<String>) -> Self { 148 TemplateParseError::with_span( 149 TemplateParseErrorKind::InvalidArguments { 150 name: function.name.to_owned(), 151 message: message.into(), 152 }, 153 function.args_span, 154 ) 155 } 156 157 pub fn expected_type(expected: &str, actual: &str, span: pest::Span<'_>) -> Self { 158 let message = 159 format!(r#"Expected expression of type "{expected}", but actual type is "{actual}""#); 160 TemplateParseError::expression(message, span) 161 } 162 163 /// Some other expression error. 164 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self { 165 TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span) 166 } 167 168 pub fn within_alias_expansion(self, id: TemplateAliasId<'_>, span: pest::Span<'_>) -> Self { 169 TemplateParseError::with_span( 170 TemplateParseErrorKind::BadAliasExpansion(id.to_string()), 171 span, 172 ) 173 .with_source(self) 174 } 175 176 /// If this is a `NoSuchKeyword` error, expands the candidates list with the 177 /// given `other_keywords`. 178 pub fn extend_keyword_candidates<I>(mut self, other_keywords: I) -> Self 179 where 180 I: IntoIterator, 181 I::Item: AsRef<str>, 182 { 183 if let TemplateParseErrorKind::NoSuchKeyword { name, candidates } = &mut self.kind { 184 let other_candidates = collect_similar(name, other_keywords); 185 *candidates = itertools::merge(mem::take(candidates), other_candidates) 186 .dedup() 187 .collect(); 188 } 189 self 190 } 191 192 /// If this is a `NoSuchFunction` error, expands the candidates list with 193 /// the given `other_functions`. 194 pub fn extend_function_candidates<I>(mut self, other_functions: I) -> Self 195 where 196 I: IntoIterator, 197 I::Item: AsRef<str>, 198 { 199 if let TemplateParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind { 200 let other_candidates = collect_similar(name, other_functions); 201 *candidates = itertools::merge(mem::take(candidates), other_candidates) 202 .dedup() 203 .collect(); 204 } 205 self 206 } 207 208 /// Expands keyword/function candidates with the given aliases. 209 pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self { 210 self.extend_keyword_candidates(aliases_map.symbol_aliases.keys()) 211 .extend_function_candidates(aliases_map.function_aliases.keys()) 212 } 213 214 pub fn kind(&self) -> &TemplateParseErrorKind { 215 &self.kind 216 } 217 218 /// Original parsing error which typically occurred in an alias expression. 219 pub fn origin(&self) -> Option<&Self> { 220 self.source.as_ref().and_then(|e| e.downcast_ref()) 221 } 222} 223 224impl From<pest::error::Error<Rule>> for TemplateParseError { 225 fn from(err: pest::error::Error<Rule>) -> Self { 226 TemplateParseError { 227 kind: TemplateParseErrorKind::SyntaxError, 228 pest_error: Box::new(rename_rules_in_pest_error(err)), 229 source: None, 230 } 231 } 232} 233 234fn rename_rules_in_pest_error(err: pest::error::Error<Rule>) -> pest::error::Error<Rule> { 235 err.renamed_rules(|rule| { 236 rule.to_symbol() 237 .map(|sym| format!("`{sym}`")) 238 .unwrap_or_else(|| format!("<{rule:?}>")) 239 }) 240} 241 242/// AST node without type or name checking. 243#[derive(Clone, Debug, PartialEq)] 244pub struct ExpressionNode<'i> { 245 pub kind: ExpressionKind<'i>, 246 pub span: pest::Span<'i>, 247} 248 249impl<'i> ExpressionNode<'i> { 250 fn new(kind: ExpressionKind<'i>, span: pest::Span<'i>) -> Self { 251 ExpressionNode { kind, span } 252 } 253} 254 255#[derive(Clone, Debug, PartialEq)] 256pub enum ExpressionKind<'i> { 257 Identifier(&'i str), 258 Boolean(bool), 259 Integer(i64), 260 String(String), 261 Unary(UnaryOp, Box<ExpressionNode<'i>>), 262 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>), 263 Concat(Vec<ExpressionNode<'i>>), 264 FunctionCall(FunctionCallNode<'i>), 265 MethodCall(MethodCallNode<'i>), 266 Lambda(LambdaNode<'i>), 267 /// Identity node to preserve the span in the source template text. 268 AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>), 269} 270 271#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 272pub enum UnaryOp { 273 /// `!` 274 LogicalNot, 275 /// `-` 276 Negate, 277} 278 279#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 280pub enum BinaryOp { 281 /// `||` 282 LogicalOr, 283 /// `&&` 284 LogicalAnd, 285} 286 287#[derive(Clone, Debug, PartialEq)] 288pub struct FunctionCallNode<'i> { 289 pub name: &'i str, 290 pub name_span: pest::Span<'i>, 291 pub args: Vec<ExpressionNode<'i>>, 292 pub args_span: pest::Span<'i>, 293} 294 295#[derive(Clone, Debug, PartialEq)] 296pub struct MethodCallNode<'i> { 297 pub object: Box<ExpressionNode<'i>>, 298 pub function: FunctionCallNode<'i>, 299} 300 301#[derive(Clone, Debug, PartialEq)] 302pub struct LambdaNode<'i> { 303 pub params: Vec<&'i str>, 304 pub params_span: pest::Span<'i>, 305 pub body: Box<ExpressionNode<'i>>, 306} 307 308fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind { 309 assert_eq!(pair.as_rule(), Rule::identifier); 310 match pair.as_str() { 311 "false" => ExpressionKind::Boolean(false), 312 "true" => ExpressionKind::Boolean(true), 313 name => ExpressionKind::Identifier(name), 314 } 315} 316 317fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> { 318 let span = pair.as_span(); 319 if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) { 320 Ok(name) 321 } else { 322 Err(TemplateParseError::expression("Expected identifier", span)) 323 } 324} 325 326fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&str>> { 327 assert_eq!(params_pair.as_rule(), Rule::formal_parameters); 328 let params_span = params_pair.as_span(); 329 let params: Vec<_> = params_pair 330 .into_inner() 331 .map(parse_identifier_name) 332 .try_collect()?; 333 if params.iter().all_unique() { 334 Ok(params) 335 } else { 336 Err(TemplateParseError::with_span( 337 TemplateParseErrorKind::RedefinedFunctionParameter, 338 params_span, 339 )) 340 } 341} 342 343fn parse_function_call_node(pair: Pair<Rule>) -> TemplateParseResult<FunctionCallNode> { 344 assert_eq!(pair.as_rule(), Rule::function); 345 let mut inner = pair.into_inner(); 346 let name_pair = inner.next().unwrap(); 347 let name_span = name_pair.as_span(); 348 let args_pair = inner.next().unwrap(); 349 let args_span = args_pair.as_span(); 350 assert_eq!(args_pair.as_rule(), Rule::function_arguments); 351 let name = parse_identifier_name(name_pair)?; 352 let args = args_pair 353 .into_inner() 354 .map(parse_template_node) 355 .try_collect()?; 356 Ok(FunctionCallNode { 357 name, 358 name_span, 359 args, 360 args_span, 361 }) 362} 363 364fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> { 365 assert_eq!(pair.as_rule(), Rule::lambda); 366 let mut inner = pair.into_inner(); 367 let params_pair = inner.next().unwrap(); 368 let params_span = params_pair.as_span(); 369 let body_pair = inner.next().unwrap(); 370 let params = parse_formal_parameters(params_pair)?; 371 let body = parse_template_node(body_pair)?; 372 Ok(LambdaNode { 373 params, 374 params_span, 375 body: Box::new(body), 376 }) 377} 378 379fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { 380 assert_eq!(pair.as_rule(), Rule::term); 381 let mut inner = pair.into_inner(); 382 let expr = inner.next().unwrap(); 383 let span = expr.as_span(); 384 let primary = match expr.as_rule() { 385 Rule::string_literal => { 386 let text = STRING_LITERAL_PARSER.parse(expr.into_inner()); 387 ExpressionNode::new(ExpressionKind::String(text), span) 388 } 389 Rule::raw_string_literal => { 390 let (content,) = expr.into_inner().collect_tuple().unwrap(); 391 assert_eq!(content.as_rule(), Rule::raw_string_content); 392 let text = content.as_str().to_owned(); 393 ExpressionNode::new(ExpressionKind::String(text), span) 394 } 395 Rule::integer_literal => { 396 let value = expr.as_str().parse().map_err(|err| { 397 TemplateParseError::expression("Invalid integer literal", span).with_source(err) 398 })?; 399 ExpressionNode::new(ExpressionKind::Integer(value), span) 400 } 401 Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span), 402 Rule::function => { 403 let function = parse_function_call_node(expr)?; 404 ExpressionNode::new(ExpressionKind::FunctionCall(function), span) 405 } 406 Rule::lambda => { 407 let lambda = parse_lambda_node(expr)?; 408 ExpressionNode::new(ExpressionKind::Lambda(lambda), span) 409 } 410 Rule::template => parse_template_node(expr)?, 411 other => panic!("unexpected term: {other:?}"), 412 }; 413 inner.try_fold(primary, |object, chain| { 414 assert_eq!(chain.as_rule(), Rule::function); 415 let span = object.span.start_pos().span(&chain.as_span().end_pos()); 416 let method = MethodCallNode { 417 object: Box::new(object), 418 function: parse_function_call_node(chain)?, 419 }; 420 Ok(ExpressionNode::new( 421 ExpressionKind::MethodCall(method), 422 span, 423 )) 424 }) 425} 426 427fn parse_expression_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { 428 assert_eq!(pair.as_rule(), Rule::expression); 429 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| { 430 PrattParser::new() 431 .op(Op::infix(Rule::logical_or_op, Assoc::Left)) 432 .op(Op::infix(Rule::logical_and_op, Assoc::Left)) 433 .op(Op::prefix(Rule::logical_not_op) | Op::prefix(Rule::negate_op)) 434 }); 435 PRATT 436 .map_primary(parse_term_node) 437 .map_prefix(|op, rhs| { 438 let op_kind = match op.as_rule() { 439 Rule::logical_not_op => UnaryOp::LogicalNot, 440 Rule::negate_op => UnaryOp::Negate, 441 r => panic!("unexpected prefix operator rule {r:?}"), 442 }; 443 let rhs = Box::new(rhs?); 444 let span = op.as_span().start_pos().span(&rhs.span.end_pos()); 445 let expr = ExpressionKind::Unary(op_kind, rhs); 446 Ok(ExpressionNode::new(expr, span)) 447 }) 448 .map_infix(|lhs, op, rhs| { 449 let op_kind = match op.as_rule() { 450 Rule::logical_or_op => BinaryOp::LogicalOr, 451 Rule::logical_and_op => BinaryOp::LogicalAnd, 452 r => panic!("unexpected infix operator rule {r:?}"), 453 }; 454 let lhs = Box::new(lhs?); 455 let rhs = Box::new(rhs?); 456 let span = lhs.span.start_pos().span(&rhs.span.end_pos()); 457 let expr = ExpressionKind::Binary(op_kind, lhs, rhs); 458 Ok(ExpressionNode::new(expr, span)) 459 }) 460 .parse(pair.into_inner()) 461} 462 463fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { 464 assert_eq!(pair.as_rule(), Rule::template); 465 let span = pair.as_span(); 466 let inner = pair.into_inner(); 467 let mut nodes: Vec<_> = inner 468 .filter_map(|pair| match pair.as_rule() { 469 Rule::concat_op => None, 470 Rule::expression => Some(parse_expression_node(pair)), 471 r => panic!("unexpected template item rule {r:?}"), 472 }) 473 .try_collect()?; 474 if nodes.len() == 1 { 475 Ok(nodes.pop().unwrap()) 476 } else { 477 Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span)) 478 } 479} 480 481/// Parses text into AST nodes. No type/name checking is made at this stage. 482pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode> { 483 let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?; 484 let first_pair = pairs.next().unwrap(); 485 if first_pair.as_rule() == Rule::EOI { 486 let span = first_pair.as_span(); 487 Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span)) 488 } else { 489 parse_template_node(first_pair) 490 } 491} 492 493#[derive(Clone, Debug, Default)] 494pub struct TemplateAliasesMap { 495 symbol_aliases: HashMap<String, String>, 496 function_aliases: HashMap<String, (Vec<String>, String)>, 497} 498 499impl TemplateAliasesMap { 500 pub fn new() -> Self { 501 Self::default() 502 } 503 504 pub fn symbol_names(&self) -> impl Iterator<Item = &str> { 505 self.symbol_aliases.keys().map(|s| s.as_str()) 506 } 507 508 /// Adds new substitution rule `decl = defn`. 509 /// 510 /// Returns error if `decl` is invalid. The `defn` part isn't checked. A bad 511 /// `defn` will be reported when the alias is substituted. 512 pub fn insert( 513 &mut self, 514 decl: impl AsRef<str>, 515 defn: impl Into<String>, 516 ) -> TemplateParseResult<()> { 517 match TemplateAliasDeclaration::parse(decl.as_ref())? { 518 TemplateAliasDeclaration::Symbol(name) => { 519 self.symbol_aliases.insert(name, defn.into()); 520 } 521 TemplateAliasDeclaration::Function(name, params) => { 522 self.function_aliases.insert(name, (params, defn.into())); 523 } 524 } 525 Ok(()) 526 } 527 528 fn get_symbol(&self, name: &str) -> Option<(TemplateAliasId<'_>, &str)> { 529 self.symbol_aliases 530 .get_key_value(name) 531 .map(|(name, defn)| (TemplateAliasId::Symbol(name), defn.as_ref())) 532 } 533 534 fn get_function(&self, name: &str) -> Option<(TemplateAliasId<'_>, &[String], &str)> { 535 self.function_aliases 536 .get_key_value(name) 537 .map(|(name, (params, defn))| { 538 ( 539 TemplateAliasId::Function(name), 540 params.as_ref(), 541 defn.as_ref(), 542 ) 543 }) 544 } 545} 546 547/// Parsed declaration part of alias rule. 548#[derive(Clone, Debug)] 549enum TemplateAliasDeclaration { 550 Symbol(String), 551 Function(String, Vec<String>), 552} 553 554impl TemplateAliasDeclaration { 555 fn parse(source: &str) -> TemplateParseResult<Self> { 556 let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?; 557 let first = pairs.next().unwrap(); 558 match first.as_rule() { 559 Rule::identifier => { 560 let name = parse_identifier_name(first)?.to_owned(); 561 Ok(TemplateAliasDeclaration::Symbol(name)) 562 } 563 Rule::function_alias_declaration => { 564 let mut inner = first.into_inner(); 565 let name_pair = inner.next().unwrap(); 566 let params_pair = inner.next().unwrap(); 567 let name = parse_identifier_name(name_pair)?.to_owned(); 568 let params = parse_formal_parameters(params_pair)? 569 .into_iter() 570 .map(|s| s.to_owned()) 571 .collect(); 572 Ok(TemplateAliasDeclaration::Function(name, params)) 573 } 574 r => panic!("unexpected alias declaration rule {r:?}"), 575 } 576 } 577} 578 579/// Borrowed reference to identify alias expression. 580#[derive(Clone, Copy, Debug, Eq, PartialEq)] 581pub enum TemplateAliasId<'a> { 582 Symbol(&'a str), 583 Function(&'a str), 584} 585 586impl fmt::Display for TemplateAliasId<'_> { 587 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 588 match self { 589 TemplateAliasId::Symbol(name) => write!(f, "{name}"), 590 TemplateAliasId::Function(name) => write!(f, "{name}()"), 591 } 592 } 593} 594 595/// Expand aliases recursively. 596pub fn expand_aliases<'i>( 597 node: ExpressionNode<'i>, 598 aliases_map: &'i TemplateAliasesMap, 599) -> TemplateParseResult<ExpressionNode<'i>> { 600 #[derive(Clone, Copy, Debug)] 601 struct State<'a, 'i> { 602 aliases_map: &'i TemplateAliasesMap, 603 aliases_expanding: &'a [TemplateAliasId<'a>], 604 locals: &'a HashMap<&'a str, ExpressionNode<'i>>, 605 } 606 607 fn expand_defn<'i>( 608 id: TemplateAliasId<'i>, 609 defn: &'i str, 610 locals: &HashMap<&str, ExpressionNode<'i>>, 611 span: pest::Span<'i>, 612 state: State<'_, 'i>, 613 ) -> TemplateParseResult<ExpressionNode<'i>> { 614 // The stack should be short, so let's simply do linear search and duplicate. 615 if state.aliases_expanding.contains(&id) { 616 return Err(TemplateParseError::with_span( 617 TemplateParseErrorKind::RecursiveAlias(id.to_string()), 618 span, 619 )); 620 } 621 let mut aliases_expanding = state.aliases_expanding.to_vec(); 622 aliases_expanding.push(id); 623 let expanding_state = State { 624 aliases_map: state.aliases_map, 625 aliases_expanding: &aliases_expanding, 626 locals, 627 }; 628 // Parsed defn could be cached if needed. 629 parse_template(defn) 630 .and_then(|node| expand_node(node, expanding_state)) 631 .map(|node| { 632 ExpressionNode::new(ExpressionKind::AliasExpanded(id, Box::new(node)), span) 633 }) 634 .map_err(|e| e.within_alias_expansion(id, span)) 635 } 636 637 fn expand_list<'i>( 638 nodes: Vec<ExpressionNode<'i>>, 639 state: State<'_, 'i>, 640 ) -> TemplateParseResult<Vec<ExpressionNode<'i>>> { 641 nodes 642 .into_iter() 643 .map(|node| expand_node(node, state)) 644 .try_collect() 645 } 646 647 fn expand_function_call<'i>( 648 function: FunctionCallNode<'i>, 649 state: State<'_, 'i>, 650 ) -> TemplateParseResult<FunctionCallNode<'i>> { 651 Ok(FunctionCallNode { 652 name: function.name, 653 name_span: function.name_span, 654 args: expand_list(function.args, state)?, 655 args_span: function.args_span, 656 }) 657 } 658 659 fn expand_node<'i>( 660 mut node: ExpressionNode<'i>, 661 state: State<'_, 'i>, 662 ) -> TemplateParseResult<ExpressionNode<'i>> { 663 match node.kind { 664 ExpressionKind::Identifier(name) => { 665 if let Some(node) = state.locals.get(name) { 666 Ok(node.clone()) 667 } else if let Some((id, defn)) = state.aliases_map.get_symbol(name) { 668 let locals = HashMap::new(); // Don't spill out the current scope 669 expand_defn(id, defn, &locals, node.span, state) 670 } else { 671 Ok(node) 672 } 673 } 674 ExpressionKind::Boolean(_) | ExpressionKind::Integer(_) | ExpressionKind::String(_) => { 675 Ok(node) 676 } 677 ExpressionKind::Unary(op, arg) => { 678 let arg = Box::new(expand_node(*arg, state)?); 679 node.kind = ExpressionKind::Unary(op, arg); 680 Ok(node) 681 } 682 ExpressionKind::Binary(op, lhs, rhs) => { 683 let lhs = Box::new(expand_node(*lhs, state)?); 684 let rhs = Box::new(expand_node(*rhs, state)?); 685 node.kind = ExpressionKind::Binary(op, lhs, rhs); 686 Ok(node) 687 } 688 ExpressionKind::Concat(nodes) => { 689 node.kind = ExpressionKind::Concat(expand_list(nodes, state)?); 690 Ok(node) 691 } 692 ExpressionKind::FunctionCall(function) => { 693 if let Some((id, params, defn)) = state.aliases_map.get_function(function.name) { 694 if function.args.len() != params.len() { 695 return Err(TemplateParseError::invalid_arguments( 696 &function, 697 format!("Expected {} arguments", params.len()), 698 )); 699 } 700 // Resolve arguments in the current scope, and pass them in to the alias 701 // expansion scope. 702 let args = expand_list(function.args, state)?; 703 let locals = params.iter().map(|s| s.as_str()).zip(args).collect(); 704 expand_defn(id, defn, &locals, node.span, state) 705 } else { 706 node.kind = 707 ExpressionKind::FunctionCall(expand_function_call(function, state)?); 708 Ok(node) 709 } 710 } 711 ExpressionKind::MethodCall(method) => { 712 node.kind = ExpressionKind::MethodCall(MethodCallNode { 713 object: Box::new(expand_node(*method.object, state)?), 714 function: expand_function_call(method.function, state)?, 715 }); 716 Ok(node) 717 } 718 ExpressionKind::Lambda(lambda) => { 719 node.kind = ExpressionKind::Lambda(LambdaNode { 720 params: lambda.params, 721 params_span: lambda.params_span, 722 body: Box::new(expand_node(*lambda.body, state)?), 723 }); 724 Ok(node) 725 } 726 ExpressionKind::AliasExpanded(id, subst) => { 727 // Just in case the original tree contained AliasExpanded node. 728 let subst = Box::new(expand_node(*subst, state)?); 729 node.kind = ExpressionKind::AliasExpanded(id, subst); 730 Ok(node) 731 } 732 } 733 } 734 735 let state = State { 736 aliases_map, 737 aliases_expanding: &[], 738 locals: &HashMap::new(), 739 }; 740 expand_node(node, state) 741} 742 743/// Parses text into AST nodes, and expands aliases. 744/// 745/// No type/name checking is made at this stage. 746pub fn parse<'i>( 747 template_text: &'i str, 748 aliases_map: &'i TemplateAliasesMap, 749) -> TemplateParseResult<ExpressionNode<'i>> { 750 let node = parse_template(template_text)?; 751 expand_aliases(node, aliases_map) 752} 753 754pub fn expect_no_arguments(function: &FunctionCallNode) -> TemplateParseResult<()> { 755 if function.args.is_empty() { 756 Ok(()) 757 } else { 758 Err(TemplateParseError::invalid_arguments( 759 function, 760 "Expected 0 arguments", 761 )) 762 } 763} 764 765/// Extracts exactly N required arguments. 766pub fn expect_exact_arguments<'a, 'i, const N: usize>( 767 function: &'a FunctionCallNode<'i>, 768) -> TemplateParseResult<&'a [ExpressionNode<'i>; N]> { 769 function.args.as_slice().try_into().map_err(|_| { 770 TemplateParseError::invalid_arguments(function, format!("Expected {N} arguments")) 771 }) 772} 773 774/// Extracts N required arguments and remainders. 775pub fn expect_some_arguments<'a, 'i, const N: usize>( 776 function: &'a FunctionCallNode<'i>, 777) -> TemplateParseResult<(&'a [ExpressionNode<'i>; N], &'a [ExpressionNode<'i>])> { 778 if function.args.len() >= N { 779 let (required, rest) = function.args.split_at(N); 780 Ok((required.try_into().unwrap(), rest)) 781 } else { 782 Err(TemplateParseError::invalid_arguments( 783 function, 784 format!("Expected at least {N} arguments"), 785 )) 786 } 787} 788 789/// Extracts N required arguments and M optional arguments. 790pub fn expect_arguments<'a, 'i, const N: usize, const M: usize>( 791 function: &'a FunctionCallNode<'i>, 792) -> TemplateParseResult<( 793 &'a [ExpressionNode<'i>; N], 794 [Option<&'a ExpressionNode<'i>>; M], 795)> { 796 let count_range = N..=(N + M); 797 if count_range.contains(&function.args.len()) { 798 let (required, rest) = function.args.split_at(N); 799 let mut optional = rest.iter().map(Some).collect_vec(); 800 optional.resize(M, None); 801 Ok((required.try_into().unwrap(), optional.try_into().unwrap())) 802 } else { 803 Err(TemplateParseError::invalid_arguments( 804 function, 805 format!("Expected {min} to {max} arguments", min = N, max = N + M), 806 )) 807 } 808} 809 810/// Applies the given function if the `node` is a string literal. 811pub fn expect_string_literal_with<'a, 'i, T>( 812 node: &'a ExpressionNode<'i>, 813 f: impl FnOnce(&'a str, pest::Span<'i>) -> TemplateParseResult<T>, 814) -> TemplateParseResult<T> { 815 match &node.kind { 816 ExpressionKind::String(s) => f(s, node.span), 817 ExpressionKind::Identifier(_) 818 | ExpressionKind::Boolean(_) 819 | ExpressionKind::Integer(_) 820 | ExpressionKind::Unary(..) 821 | ExpressionKind::Binary(..) 822 | ExpressionKind::Concat(_) 823 | ExpressionKind::FunctionCall(_) 824 | ExpressionKind::MethodCall(_) 825 | ExpressionKind::Lambda(_) => Err(TemplateParseError::expression( 826 "Expected string literal", 827 node.span, 828 )), 829 ExpressionKind::AliasExpanded(id, subst) => expect_string_literal_with(subst, f) 830 .map_err(|e| e.within_alias_expansion(*id, node.span)), 831 } 832} 833 834/// Applies the given function if the `node` is a lambda. 835pub fn expect_lambda_with<'a, 'i, T>( 836 node: &'a ExpressionNode<'i>, 837 f: impl FnOnce(&'a LambdaNode<'i>, pest::Span<'i>) -> TemplateParseResult<T>, 838) -> TemplateParseResult<T> { 839 match &node.kind { 840 ExpressionKind::Lambda(lambda) => f(lambda, node.span), 841 ExpressionKind::Identifier(_) 842 | ExpressionKind::Boolean(_) 843 | ExpressionKind::Integer(_) 844 | ExpressionKind::String(_) 845 | ExpressionKind::Unary(..) 846 | ExpressionKind::Binary(..) 847 | ExpressionKind::Concat(_) 848 | ExpressionKind::FunctionCall(_) 849 | ExpressionKind::MethodCall(_) => Err(TemplateParseError::expression( 850 "Expected lambda expression", 851 node.span, 852 )), 853 ExpressionKind::AliasExpanded(id, subst) => { 854 expect_lambda_with(subst, f).map_err(|e| e.within_alias_expansion(*id, node.span)) 855 } 856 } 857} 858 859/// Looks up `table` by the given function name. 860pub fn lookup_function<'a, V>( 861 table: &'a HashMap<&str, V>, 862 function: &FunctionCallNode, 863) -> TemplateParseResult<&'a V> { 864 if let Some(value) = table.get(function.name) { 865 Ok(value) 866 } else { 867 let candidates = collect_similar(function.name, table.keys()); 868 Err(TemplateParseError::with_span( 869 TemplateParseErrorKind::NoSuchFunction { 870 name: function.name.to_owned(), 871 candidates, 872 }, 873 function.name_span, 874 )) 875 } 876} 877 878/// Looks up `table` by the given method name. 879pub fn lookup_method<'a, V>( 880 type_name: impl Into<String>, 881 table: &'a HashMap<&str, V>, 882 function: &FunctionCallNode, 883) -> TemplateParseResult<&'a V> { 884 if let Some(value) = table.get(function.name) { 885 Ok(value) 886 } else { 887 let candidates = collect_similar(function.name, table.keys()); 888 Err(TemplateParseError::with_span( 889 TemplateParseErrorKind::NoSuchMethod { 890 type_name: type_name.into(), 891 name: function.name.to_owned(), 892 candidates, 893 }, 894 function.name_span, 895 )) 896 } 897} 898 899#[cfg(test)] 900mod tests { 901 use assert_matches::assert_matches; 902 903 use super::*; 904 905 #[derive(Debug)] 906 struct WithTemplateAliasesMap(TemplateAliasesMap); 907 908 impl WithTemplateAliasesMap { 909 fn parse<'i>(&'i self, template_text: &'i str) -> TemplateParseResult<ExpressionNode<'i>> { 910 parse(template_text, &self.0) 911 } 912 913 fn parse_normalized<'i>( 914 &'i self, 915 template_text: &'i str, 916 ) -> TemplateParseResult<ExpressionNode<'i>> { 917 self.parse(template_text).map(normalize_tree) 918 } 919 } 920 921 fn with_aliases( 922 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>, 923 ) -> WithTemplateAliasesMap { 924 let mut aliases_map = TemplateAliasesMap::new(); 925 for (decl, defn) in aliases { 926 aliases_map.insert(decl, defn).unwrap(); 927 } 928 WithTemplateAliasesMap(aliases_map) 929 } 930 931 fn parse_into_kind(template_text: &str) -> Result<ExpressionKind, TemplateParseErrorKind> { 932 parse_template(template_text) 933 .map(|node| node.kind) 934 .map_err(|err| err.kind) 935 } 936 937 fn parse_normalized(template_text: &str) -> TemplateParseResult<ExpressionNode> { 938 parse_template(template_text).map(normalize_tree) 939 } 940 941 /// Drops auxiliary data of AST so it can be compared with other node. 942 fn normalize_tree(node: ExpressionNode) -> ExpressionNode { 943 fn empty_span() -> pest::Span<'static> { 944 pest::Span::new("", 0, 0).unwrap() 945 } 946 947 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> { 948 nodes.into_iter().map(normalize_tree).collect() 949 } 950 951 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode { 952 FunctionCallNode { 953 name: function.name, 954 name_span: empty_span(), 955 args: normalize_list(function.args), 956 args_span: empty_span(), 957 } 958 } 959 960 let normalized_kind = match node.kind { 961 ExpressionKind::Identifier(_) 962 | ExpressionKind::Boolean(_) 963 | ExpressionKind::Integer(_) 964 | ExpressionKind::String(_) => node.kind, 965 ExpressionKind::Unary(op, arg) => { 966 let arg = Box::new(normalize_tree(*arg)); 967 ExpressionKind::Unary(op, arg) 968 } 969 ExpressionKind::Binary(op, lhs, rhs) => { 970 let lhs = Box::new(normalize_tree(*lhs)); 971 let rhs = Box::new(normalize_tree(*rhs)); 972 ExpressionKind::Binary(op, lhs, rhs) 973 } 974 ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)), 975 ExpressionKind::FunctionCall(function) => { 976 ExpressionKind::FunctionCall(normalize_function_call(function)) 977 } 978 ExpressionKind::MethodCall(method) => { 979 let object = Box::new(normalize_tree(*method.object)); 980 let function = normalize_function_call(method.function); 981 ExpressionKind::MethodCall(MethodCallNode { object, function }) 982 } 983 ExpressionKind::Lambda(lambda) => { 984 let body = Box::new(normalize_tree(*lambda.body)); 985 ExpressionKind::Lambda(LambdaNode { 986 params: lambda.params, 987 params_span: empty_span(), 988 body, 989 }) 990 } 991 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind, 992 }; 993 ExpressionNode { 994 kind: normalized_kind, 995 span: empty_span(), 996 } 997 } 998 999 #[test] 1000 fn test_parse_tree_eq() { 1001 assert_eq!( 1002 normalize_tree(parse_template(r#" commit_id.short(1 ) ++ description"#).unwrap()), 1003 normalize_tree(parse_template(r#"commit_id.short( 1 )++(description)"#).unwrap()), 1004 ); 1005 assert_ne!( 1006 normalize_tree(parse_template(r#" "ab" "#).unwrap()), 1007 normalize_tree(parse_template(r#" "a" ++ "b" "#).unwrap()), 1008 ); 1009 assert_ne!( 1010 normalize_tree(parse_template(r#" "foo" ++ "0" "#).unwrap()), 1011 normalize_tree(parse_template(r#" "foo" ++ 0 "#).unwrap()), 1012 ); 1013 } 1014 1015 #[test] 1016 fn test_parse_whitespace() { 1017 let ascii_whitespaces: String = ('\x00'..='\x7f') 1018 .filter(char::is_ascii_whitespace) 1019 .collect(); 1020 assert_eq!( 1021 parse_normalized(&format!("{ascii_whitespaces}f()")).unwrap(), 1022 parse_normalized("f()").unwrap(), 1023 ); 1024 } 1025 1026 #[test] 1027 fn test_parse_operator_syntax() { 1028 // Operator precedence 1029 assert_eq!( 1030 parse_normalized("!!x").unwrap(), 1031 parse_normalized("!(!x)").unwrap(), 1032 ); 1033 assert_eq!( 1034 parse_normalized("!x.f() || !g()").unwrap(), 1035 parse_normalized("(!(x.f())) || (!(g()))").unwrap(), 1036 ); 1037 assert_eq!( 1038 parse_normalized("x.f() || y || z").unwrap(), 1039 parse_normalized("((x.f()) || y) || z").unwrap(), 1040 ); 1041 assert_eq!( 1042 parse_normalized("x || y && z.h()").unwrap(), 1043 parse_normalized("x || (y && (z.h()))").unwrap(), 1044 ); 1045 1046 // Logical operator bounds more tightly than concatenation. This might 1047 // not be so intuitive, but should be harmless. 1048 assert_eq!( 1049 parse_normalized(r"x && y ++ z").unwrap(), 1050 parse_normalized(r"(x && y) ++ z").unwrap(), 1051 ); 1052 assert_eq!( 1053 parse_normalized(r"x ++ y || z").unwrap(), 1054 parse_normalized(r"x ++ (y || z)").unwrap(), 1055 ); 1056 1057 // Expression span 1058 assert_eq!(parse_template(" ! x ").unwrap().span.as_str(), "! x"); 1059 assert_eq!(parse_template(" x ||y ").unwrap().span.as_str(), "x ||y"); 1060 } 1061 1062 #[test] 1063 fn test_function_call_syntax() { 1064 // Trailing comma isn't allowed for empty argument 1065 assert!(parse_template(r#" "".first_line() "#).is_ok()); 1066 assert!(parse_template(r#" "".first_line(,) "#).is_err()); 1067 1068 // Trailing comma is allowed for the last argument 1069 assert!(parse_template(r#" "".contains("") "#).is_ok()); 1070 assert!(parse_template(r#" "".contains("",) "#).is_ok()); 1071 assert!(parse_template(r#" "".contains("" , ) "#).is_ok()); 1072 assert!(parse_template(r#" "".contains(,"") "#).is_err()); 1073 assert!(parse_template(r#" "".contains("",,) "#).is_err()); 1074 assert!(parse_template(r#" "".contains("" , , ) "#).is_err()); 1075 assert!(parse_template(r#" label("","") "#).is_ok()); 1076 assert!(parse_template(r#" label("","",) "#).is_ok()); 1077 assert!(parse_template(r#" label("",,"") "#).is_err()); 1078 1079 // Boolean literal cannot be used as a function name 1080 assert!(parse_template("false()").is_err()); 1081 // Function arguments can be any expression 1082 assert!(parse_template("f(false)").is_ok()); 1083 } 1084 1085 #[test] 1086 fn test_method_call_syntax() { 1087 assert_eq!( 1088 parse_normalized("x.f().g()").unwrap(), 1089 parse_normalized("(x.f()).g()").unwrap(), 1090 ); 1091 1092 // Expression span 1093 assert_eq!(parse_template(" x.f() ").unwrap().span.as_str(), "x.f()"); 1094 assert_eq!( 1095 parse_template(" x.f().g() ").unwrap().span.as_str(), 1096 "x.f().g()", 1097 ); 1098 } 1099 1100 #[test] 1101 fn test_lambda_syntax() { 1102 fn unwrap_lambda(node: ExpressionNode<'_>) -> LambdaNode<'_> { 1103 match node.kind { 1104 ExpressionKind::Lambda(lambda) => lambda, 1105 _ => panic!("unexpected expression: {node:?}"), 1106 } 1107 } 1108 1109 let lambda = unwrap_lambda(parse_template("|| a").unwrap()); 1110 assert_eq!(lambda.params.len(), 0); 1111 assert_eq!(lambda.body.kind, ExpressionKind::Identifier("a")); 1112 let lambda = unwrap_lambda(parse_template("|foo| a").unwrap()); 1113 assert_eq!(lambda.params.len(), 1); 1114 let lambda = unwrap_lambda(parse_template("|foo, b| a").unwrap()); 1115 assert_eq!(lambda.params.len(), 2); 1116 1117 // No body 1118 assert!(parse_template("||").is_err()); 1119 1120 // Binding 1121 assert_eq!( 1122 parse_normalized("|| x ++ y").unwrap(), 1123 parse_normalized("|| (x ++ y)").unwrap(), 1124 ); 1125 assert_eq!( 1126 parse_normalized("f( || x, || y)").unwrap(), 1127 parse_normalized("f((|| x), (|| y))").unwrap(), 1128 ); 1129 assert_eq!( 1130 parse_normalized("|| x ++ || y").unwrap(), 1131 parse_normalized("|| (x ++ (|| y))").unwrap(), 1132 ); 1133 1134 // Lambda vs logical operator: weird, but this is type error anyway 1135 assert_eq!( 1136 parse_normalized("x||||y").unwrap(), 1137 parse_normalized("x || (|| y)").unwrap(), 1138 ); 1139 assert_eq!( 1140 parse_normalized("||||x").unwrap(), 1141 parse_normalized("|| (|| x)").unwrap(), 1142 ); 1143 1144 // Trailing comma 1145 assert!(parse_template("|,| a").is_err()); 1146 assert!(parse_template("|x,| a").is_ok()); 1147 assert!(parse_template("|x , | a").is_ok()); 1148 assert!(parse_template("|,x| a").is_err()); 1149 assert!(parse_template("| x,y,| a").is_ok()); 1150 assert!(parse_template("|x,,y| a").is_err()); 1151 1152 // Formal parameter can't be redefined 1153 assert_eq!( 1154 parse_template("|x, x| a").unwrap_err().kind, 1155 TemplateParseErrorKind::RedefinedFunctionParameter 1156 ); 1157 1158 // Boolean literal cannot be used as a parameter name 1159 assert!(parse_template("|false| a").is_err()); 1160 } 1161 1162 #[test] 1163 fn test_keyword_literal() { 1164 assert_eq!(parse_into_kind("false"), Ok(ExpressionKind::Boolean(false))); 1165 assert_eq!(parse_into_kind("(true)"), Ok(ExpressionKind::Boolean(true))); 1166 // Keyword literals are case sensitive 1167 assert_eq!( 1168 parse_into_kind("False"), 1169 Ok(ExpressionKind::Identifier("False")), 1170 ); 1171 assert_eq!( 1172 parse_into_kind("tRue"), 1173 Ok(ExpressionKind::Identifier("tRue")), 1174 ); 1175 } 1176 1177 #[test] 1178 fn test_string_literal() { 1179 // "\<char>" escapes 1180 assert_eq!( 1181 parse_into_kind(r#" "\t\r\n\"\\\0" "#), 1182 Ok(ExpressionKind::String("\t\r\n\"\\\0".to_owned())), 1183 ); 1184 1185 // Invalid "\<char>" escape 1186 assert_eq!( 1187 parse_into_kind(r#" "\y" "#), 1188 Err(TemplateParseErrorKind::SyntaxError), 1189 ); 1190 1191 // Single-quoted raw string 1192 assert_eq!( 1193 parse_into_kind(r#" '' "#), 1194 Ok(ExpressionKind::String("".to_owned())), 1195 ); 1196 assert_eq!( 1197 parse_into_kind(r#" 'a\n' "#), 1198 Ok(ExpressionKind::String(r"a\n".to_owned())), 1199 ); 1200 assert_eq!( 1201 parse_into_kind(r#" '\' "#), 1202 Ok(ExpressionKind::String(r"\".to_owned())), 1203 ); 1204 assert_eq!( 1205 parse_into_kind(r#" '"' "#), 1206 Ok(ExpressionKind::String(r#"""#.to_owned())), 1207 ); 1208 } 1209 1210 #[test] 1211 fn test_integer_literal() { 1212 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Integer(0))); 1213 assert_eq!(parse_into_kind("(42)"), Ok(ExpressionKind::Integer(42))); 1214 assert_eq!( 1215 parse_into_kind("00"), 1216 Err(TemplateParseErrorKind::SyntaxError), 1217 ); 1218 1219 assert_eq!( 1220 parse_into_kind(&format!("{}", i64::MAX)), 1221 Ok(ExpressionKind::Integer(i64::MAX)), 1222 ); 1223 assert_matches!( 1224 parse_into_kind(&format!("{}", (i64::MAX as u64) + 1)), 1225 Err(TemplateParseErrorKind::Expression(_)) 1226 ); 1227 } 1228 1229 #[test] 1230 fn test_parse_alias_decl() { 1231 let mut aliases_map = TemplateAliasesMap::new(); 1232 aliases_map.insert("sym", r#""is symbol""#).unwrap(); 1233 aliases_map.insert("func(a)", r#""is function""#).unwrap(); 1234 1235 let (id, defn) = aliases_map.get_symbol("sym").unwrap(); 1236 assert_eq!(id, TemplateAliasId::Symbol("sym")); 1237 assert_eq!(defn, r#""is symbol""#); 1238 1239 let (id, params, defn) = aliases_map.get_function("func").unwrap(); 1240 assert_eq!(id, TemplateAliasId::Function("func")); 1241 assert_eq!(params, ["a"]); 1242 assert_eq!(defn, r#""is function""#); 1243 1244 // Formal parameter 'a' can't be redefined 1245 assert_eq!( 1246 aliases_map.insert("f(a, a)", r#""""#).unwrap_err().kind, 1247 TemplateParseErrorKind::RedefinedFunctionParameter 1248 ); 1249 1250 // Boolean literal cannot be used as a symbol, function, or parameter name 1251 assert!(aliases_map.insert("false", r#"""#).is_err()); 1252 assert!(aliases_map.insert("true()", r#"""#).is_err()); 1253 assert!(aliases_map.insert("f(false)", r#"""#).is_err()); 1254 1255 // Trailing comma isn't allowed for empty parameter 1256 assert!(aliases_map.insert("f(,)", r#"""#).is_err()); 1257 // Trailing comma is allowed for the last parameter 1258 assert!(aliases_map.insert("g(a,)", r#"""#).is_ok()); 1259 assert!(aliases_map.insert("h(a , )", r#"""#).is_ok()); 1260 assert!(aliases_map.insert("i(,a)", r#"""#).is_err()); 1261 assert!(aliases_map.insert("j(a,,)", r#"""#).is_err()); 1262 assert!(aliases_map.insert("k(a , , )", r#"""#).is_err()); 1263 assert!(aliases_map.insert("l(a,b,)", r#"""#).is_ok()); 1264 assert!(aliases_map.insert("m(a,,b)", r#"""#).is_err()); 1265 } 1266 1267 #[test] 1268 fn test_expand_symbol_alias() { 1269 assert_eq!( 1270 with_aliases([("AB", "a ++ b")]) 1271 .parse_normalized("AB ++ c") 1272 .unwrap(), 1273 parse_normalized("(a ++ b) ++ c").unwrap(), 1274 ); 1275 assert_eq!( 1276 with_aliases([("AB", "a ++ b")]) 1277 .parse_normalized("if(AB, label(c, AB))") 1278 .unwrap(), 1279 parse_normalized("if((a ++ b), label(c, (a ++ b)))").unwrap(), 1280 ); 1281 1282 // Multi-level substitution. 1283 assert_eq!( 1284 with_aliases([("A", "BC"), ("BC", "b ++ C"), ("C", "c")]) 1285 .parse_normalized("A") 1286 .unwrap(), 1287 parse_normalized("b ++ c").unwrap(), 1288 ); 1289 1290 // Operator expression can be expanded in concatenation. 1291 assert_eq!( 1292 with_aliases([("AB", "a || b")]) 1293 .parse_normalized("AB ++ c") 1294 .unwrap(), 1295 parse_normalized("(a || b) ++ c").unwrap(), 1296 ); 1297 1298 // Operands should be expanded. 1299 assert_eq!( 1300 with_aliases([("A", "a"), ("B", "b")]) 1301 .parse_normalized("A || !B") 1302 .unwrap(), 1303 parse_normalized("a || !b").unwrap(), 1304 ); 1305 1306 // Method receiver and arguments should be expanded. 1307 assert_eq!( 1308 with_aliases([("A", "a")]) 1309 .parse_normalized("A.f()") 1310 .unwrap(), 1311 parse_normalized("a.f()").unwrap(), 1312 ); 1313 assert_eq!( 1314 with_aliases([("A", "a"), ("B", "b")]) 1315 .parse_normalized("x.f(A, B)") 1316 .unwrap(), 1317 parse_normalized("x.f(a, b)").unwrap(), 1318 ); 1319 1320 // Lambda expression body should be expanded. 1321 assert_eq!( 1322 with_aliases([("A", "a")]).parse_normalized("|| A").unwrap(), 1323 parse_normalized("|| a").unwrap(), 1324 ); 1325 // No matter if 'A' is a formal parameter. Alias substitution isn't scoped. 1326 // If we don't like this behavior, maybe we can turn off alias substitution 1327 // for lambda parameters. 1328 assert_eq!( 1329 with_aliases([("A", "a ++ b")]) 1330 .parse_normalized("|A| A") 1331 .unwrap(), 1332 parse_normalized("|A| (a ++ b)").unwrap(), 1333 ); 1334 1335 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind. 1336 assert_eq!( 1337 with_aliases([("A", "A")]).parse("A").unwrap_err().kind, 1338 TemplateParseErrorKind::BadAliasExpansion("A".to_owned()), 1339 ); 1340 assert_eq!( 1341 with_aliases([("A", "B"), ("B", "b ++ C"), ("C", "c ++ B")]) 1342 .parse("A") 1343 .unwrap_err() 1344 .kind, 1345 TemplateParseErrorKind::BadAliasExpansion("A".to_owned()), 1346 ); 1347 1348 // Error in alias definition. 1349 assert_eq!( 1350 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind, 1351 TemplateParseErrorKind::BadAliasExpansion("A".to_owned()), 1352 ); 1353 } 1354 1355 #[test] 1356 fn test_expand_function_alias() { 1357 assert_eq!( 1358 with_aliases([("F( )", "a")]) 1359 .parse_normalized("F()") 1360 .unwrap(), 1361 parse_normalized("a").unwrap(), 1362 ); 1363 assert_eq!( 1364 with_aliases([("F( x )", "x")]) 1365 .parse_normalized("F(a)") 1366 .unwrap(), 1367 parse_normalized("a").unwrap(), 1368 ); 1369 assert_eq!( 1370 with_aliases([("F( x, y )", "x ++ y")]) 1371 .parse_normalized("F(a, b)") 1372 .unwrap(), 1373 parse_normalized("a ++ b").unwrap(), 1374 ); 1375 1376 // Arguments should be resolved in the current scope. 1377 assert_eq!( 1378 with_aliases([("F(x,y)", "if(x, y)")]) 1379 .parse_normalized("F(a ++ y, b ++ x)") 1380 .unwrap(), 1381 parse_normalized("if((a ++ y), (b ++ x))").unwrap(), 1382 ); 1383 // F(a) -> if(G(a), y) -> if((x ++ a), y) 1384 assert_eq!( 1385 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]) 1386 .parse_normalized("F(a)") 1387 .unwrap(), 1388 parse_normalized("if((x ++ a), y)").unwrap(), 1389 ); 1390 // F(G(a)) -> F(x ++ a) -> if(G(x ++ a), y) -> if((x ++ (x ++ a)), y) 1391 assert_eq!( 1392 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]) 1393 .parse_normalized("F(G(a))") 1394 .unwrap(), 1395 parse_normalized("if((x ++ (x ++ a)), y)").unwrap(), 1396 ); 1397 1398 // Function parameter should precede the symbol alias. 1399 assert_eq!( 1400 with_aliases([("F(X)", "X"), ("X", "x")]) 1401 .parse_normalized("F(a) ++ X") 1402 .unwrap(), 1403 parse_normalized("a ++ x").unwrap(), 1404 ); 1405 1406 // Function parameter shouldn't be expanded in symbol alias. 1407 assert_eq!( 1408 with_aliases([("F(x)", "x ++ A"), ("A", "x")]) 1409 .parse_normalized("F(a)") 1410 .unwrap(), 1411 parse_normalized("a ++ x").unwrap(), 1412 ); 1413 1414 // Function and symbol aliases reside in separate namespaces. 1415 assert_eq!( 1416 with_aliases([("A()", "A"), ("A", "a")]) 1417 .parse_normalized("A()") 1418 .unwrap(), 1419 parse_normalized("a").unwrap(), 1420 ); 1421 1422 // Method call shouldn't be substituted by function alias. 1423 assert_eq!( 1424 with_aliases([("F()", "f()")]) 1425 .parse_normalized("x.F()") 1426 .unwrap(), 1427 parse_normalized("x.F()").unwrap(), 1428 ); 1429 1430 // Formal parameter shouldn't be substituted by alias parameter, but 1431 // the expression should be substituted. 1432 assert_eq!( 1433 with_aliases([("F(x)", "|x| x")]) 1434 .parse_normalized("F(a ++ b)") 1435 .unwrap(), 1436 parse_normalized("|x| (a ++ b)").unwrap(), 1437 ); 1438 1439 // Invalid number of arguments. 1440 assert_matches!( 1441 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind, 1442 TemplateParseErrorKind::InvalidArguments { .. } 1443 ); 1444 assert_matches!( 1445 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind, 1446 TemplateParseErrorKind::InvalidArguments { .. } 1447 ); 1448 assert_matches!( 1449 with_aliases([("F(x,y)", "x ++ y")]) 1450 .parse("F(a,b,c)") 1451 .unwrap_err() 1452 .kind, 1453 TemplateParseErrorKind::InvalidArguments { .. } 1454 ); 1455 1456 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind. 1457 assert_eq!( 1458 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")]) 1459 .parse("F(a)") 1460 .unwrap_err() 1461 .kind, 1462 TemplateParseErrorKind::BadAliasExpansion("F()".to_owned()), 1463 ); 1464 } 1465}