just playing with tangled
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}