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