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