// Copyright 2020 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::collections::HashMap;use std::num::ParseIntError;use std::{error, fmt}; use itertools::Itertools as _;use pest::iterators::{Pair, Pairs};use pest::Parser;use pest_derive::Parser;use thiserror::Error; #[derive(Parser)]#[grammar = "template.pest"]struct TemplateParser; pub type TemplateParseResult<T> = Result<T, TemplateParseError>; #[derive(Clone, Debug)]pub struct TemplateParseError { kind: TemplateParseErrorKind, pest_error: Box<pest::error::Error<Rule>>, origin: Option<Box<TemplateParseError>>,} #[derive(Clone, Debug, Eq, Error, PartialEq)]pub enum TemplateParseErrorKind { #[error("Syntax error")] SyntaxError, #[error("Invalid integer literal: {0}")] ParseIntError(#[source] ParseIntError), #[error(r#"Keyword "{0}" doesn't exist"#)] NoSuchKeyword(String), #[error(r#"Function "{0}" doesn't exist"#)] NoSuchFunction(String), #[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)] NoSuchMethod { type_name: String, name: String }, #[error(r#"Function "{name}": {message}"#)] InvalidArguments { name: String, message: String }, #[error("Redefinition of function parameter")] RedefinedFunctionParameter, #[error("{0}")] UnexpectedExpression(String), #[error(r#"Alias "{0}" cannot be expanded"#)] BadAliasExpansion(String), #[error(r#"Alias "{0}" expanded recursively"#)] RecursiveAlias(String),} impl TemplateParseError { pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self { let pest_error = Box::new(pest::error::Error::new_from_span( pest::error::ErrorVariant::CustomError { message: kind.to_string(), }, span, )); TemplateParseError { kind, pest_error, origin: None, } } pub fn with_span_and_origin( kind: TemplateParseErrorKind, span: pest::Span<'_>, origin: Self, ) -> Self { let pest_error = Box::new(pest::error::Error::new_from_span( pest::error::ErrorVariant::CustomError { message: kind.to_string(), }, span, )); TemplateParseError { kind, pest_error, origin: Some(Box::new(origin)), } } pub fn no_such_keyword(name: impl Into<String>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span(TemplateParseErrorKind::NoSuchKeyword(name.into()), span) } pub fn no_such_function(function: &FunctionCallNode) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::NoSuchFunction(function.name.to_owned()), function.name_span, ) } pub fn no_such_method(type_name: impl Into<String>, function: &FunctionCallNode) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::NoSuchMethod { type_name: type_name.into(), name: function.name.to_owned(), }, function.name_span, ) } pub fn invalid_arguments(function: &FunctionCallNode, message: impl Into<String>) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::InvalidArguments { name: function.name.to_owned(), message: message.into(), }, function.args_span, ) } pub fn expected_type(type_name: &str, span: pest::Span<'_>) -> Self { let message = format!(r#"Expected expression of type "{type_name}""#); TemplateParseError::unexpected_expression(message, span) } pub fn unexpected_expression(message: impl Into<String>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::UnexpectedExpression(message.into()), span, ) } pub fn within_alias_expansion(self, id: TemplateAliasId<'_>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span_and_origin( TemplateParseErrorKind::BadAliasExpansion(id.to_string()), span, self, ) } /// Original parsing error which typically occurred in an alias expression. pub fn origin(&self) -> Option<&Self> { self.origin.as_deref() }} impl From<pest::error::Error<Rule>> for TemplateParseError { fn from(err: pest::error::Error<Rule>) -> Self { TemplateParseError { kind: TemplateParseErrorKind::SyntaxError, pest_error: Box::new(err), origin: None, } }} impl fmt::Display for TemplateParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.pest_error.fmt(f) }} impl error::Error for TemplateParseError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { if let Some(e) = self.origin() { return Some(e as &dyn error::Error); } match &self.kind { // SyntaxError is a wrapper for pest::error::Error. TemplateParseErrorKind::SyntaxError => Some(&self.pest_error as &dyn error::Error), // Otherwise the kind represents this error. e => e.source(), } }} /// AST node without type or name checking.#[derive(Clone, Debug, PartialEq)]pub struct ExpressionNode<'i> { pub kind: ExpressionKind<'i>, pub span: pest::Span<'i>,} impl<'i> ExpressionNode<'i> { fn new(kind: ExpressionKind<'i>, span: pest::Span<'i>) -> Self { ExpressionNode { kind, span } }} #[derive(Clone, Debug, PartialEq)]pub enum ExpressionKind<'i> { Identifier(&'i str), Boolean(bool), Integer(i64), String(String), Concat(Vec<ExpressionNode<'i>>), FunctionCall(FunctionCallNode<'i>), MethodCall(MethodCallNode<'i>), Lambda(LambdaNode<'i>), /// Identity node to preserve the span in the source template text. AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>),} #[derive(Clone, Debug, PartialEq)]pub struct FunctionCallNode<'i> { pub name: &'i str, pub name_span: pest::Span<'i>, pub args: Vec<ExpressionNode<'i>>, pub args_span: pest::Span<'i>,} #[derive(Clone, Debug, PartialEq)]pub struct MethodCallNode<'i> { pub object: Box<ExpressionNode<'i>>, pub function: FunctionCallNode<'i>,} #[derive(Clone, Debug, PartialEq)]pub struct LambdaNode<'i> { pub params: Vec<&'i str>, pub params_span: pest::Span<'i>, pub body: Box<ExpressionNode<'i>>,} fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind { assert_eq!(pair.as_rule(), Rule::identifier); match pair.as_str() { "false" => ExpressionKind::Boolean(false), "true" => ExpressionKind::Boolean(true), name => ExpressionKind::Identifier(name), }} fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> { let span = pair.as_span(); if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) { Ok(name) } else { Err(TemplateParseError::unexpected_expression( "Expected identifier", span, )) }} fn parse_string_literal(pair: Pair<Rule>) -> String { assert_eq!(pair.as_rule(), Rule::literal); let mut result = String::new(); for part in pair.into_inner() { match part.as_rule() { Rule::raw_literal => { result.push_str(part.as_str()); } Rule::escape => match &part.as_str()[1..] { "\"" => result.push('"'), "\\" => result.push('\\'), "t" => result.push('\t'), "r" => result.push('\r'), "n" => result.push('\n'), "0" => result.push('\0'), char => panic!("invalid escape: \\{char:?}"), }, _ => panic!("unexpected part of string: {part:?}"), } } result} fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&str>> { assert_eq!(params_pair.as_rule(), Rule::formal_parameters); let params_span = params_pair.as_span(); let params: Vec<_> = params_pair .into_inner() .map(parse_identifier_name) .try_collect()?; if params.iter().all_unique() { Ok(params) } else { Err(TemplateParseError::with_span( TemplateParseErrorKind::RedefinedFunctionParameter, params_span, )) }} fn parse_function_call_node(pair: Pair<Rule>) -> TemplateParseResult<FunctionCallNode> { assert_eq!(pair.as_rule(), Rule::function); let mut inner = pair.into_inner(); let name_pair = inner.next().unwrap(); let name_span = name_pair.as_span(); let args_pair = inner.next().unwrap(); let args_span = args_pair.as_span(); assert_eq!(args_pair.as_rule(), Rule::function_arguments); let name = parse_identifier_name(name_pair)?; let args = args_pair .into_inner() .map(parse_template_node) .try_collect()?; Ok(FunctionCallNode { name, name_span, args, args_span, })} fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> { assert_eq!(pair.as_rule(), Rule::lambda); let mut inner = pair.into_inner(); let params_pair = inner.next().unwrap(); let params_span = params_pair.as_span(); let body_pair = inner.next().unwrap(); let params = parse_formal_parameters(params_pair)?; let body = parse_template_node(body_pair)?; Ok(LambdaNode { params, params_span, body: Box::new(body), })} fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { assert_eq!(pair.as_rule(), Rule::term); let mut inner = pair.into_inner(); let expr = inner.next().unwrap(); let span = expr.as_span(); let primary = match expr.as_rule() { Rule::literal => { let text = parse_string_literal(expr); ExpressionNode::new(ExpressionKind::String(text), span) } Rule::integer_literal => { let value = expr.as_str().parse().map_err(|err| { TemplateParseError::with_span(TemplateParseErrorKind::ParseIntError(err), span) })?; ExpressionNode::new(ExpressionKind::Integer(value), span) } Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span), Rule::function => { let function = parse_function_call_node(expr)?; ExpressionNode::new(ExpressionKind::FunctionCall(function), span) } Rule::lambda => { let lambda = parse_lambda_node(expr)?; ExpressionNode::new(ExpressionKind::Lambda(lambda), span) } Rule::template => parse_template_node(expr)?, other => panic!("unexpected term: {other:?}"), }; inner.try_fold(primary, |object, chain| { assert_eq!(chain.as_rule(), Rule::function); let span = object.span.start_pos().span(&chain.as_span().end_pos()); let method = MethodCallNode { object: Box::new(object), function: parse_function_call_node(chain)?, }; Ok(ExpressionNode::new( ExpressionKind::MethodCall(method), span, )) })} fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { assert_eq!(pair.as_rule(), Rule::template); let span = pair.as_span(); let inner = pair.into_inner(); let mut nodes: Vec<_> = inner.map(parse_term_node).try_collect()?; if nodes.len() == 1 { Ok(nodes.pop().unwrap()) } else { Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span)) }} /// Parses text into AST nodes. No type/name checking is made at this stage.pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode> { let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?; let first_pair = pairs.next().unwrap(); if first_pair.as_rule() == Rule::EOI { let span = first_pair.as_span(); Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span)) } else { parse_template_node(first_pair) }} #[derive(Clone, Debug, Default)]pub struct TemplateAliasesMap { symbol_aliases: HashMap<String, String>, function_aliases: HashMap<String, (Vec<String>, String)>,} impl TemplateAliasesMap { pub fn new() -> Self { Self::default() } /// Adds new substitution rule `decl = defn`. /// /// Returns error if `decl` is invalid. The `defn` part isn't checked. A bad /// `defn` will be reported when the alias is substituted. pub fn insert( &mut self, decl: impl AsRef<str>, defn: impl Into<String>, ) -> TemplateParseResult<()> { match TemplateAliasDeclaration::parse(decl.as_ref())? { TemplateAliasDeclaration::Symbol(name) => { self.symbol_aliases.insert(name, defn.into()); } TemplateAliasDeclaration::Function(name, params) => { self.function_aliases.insert(name, (params, defn.into())); } } Ok(()) } fn get_symbol(&self, name: &str) -> Option<(TemplateAliasId<'_>, &str)> { self.symbol_aliases .get_key_value(name) .map(|(name, defn)| (TemplateAliasId::Symbol(name), defn.as_ref())) } fn get_function(&self, name: &str) -> Option<(TemplateAliasId<'_>, &[String], &str)> { self.function_aliases .get_key_value(name) .map(|(name, (params, defn))| { ( TemplateAliasId::Function(name), params.as_ref(), defn.as_ref(), ) }) }} /// Parsed declaration part of alias rule.#[derive(Clone, Debug)]enum TemplateAliasDeclaration { Symbol(String), Function(String, Vec<String>),} impl TemplateAliasDeclaration { fn parse(source: &str) -> TemplateParseResult<Self> { let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?; let first = pairs.next().unwrap(); match first.as_rule() { Rule::identifier => { let name = parse_identifier_name(first)?.to_owned(); Ok(TemplateAliasDeclaration::Symbol(name)) } Rule::function_alias_declaration => { let mut inner = first.into_inner(); let name_pair = inner.next().unwrap(); let params_pair = inner.next().unwrap(); let name = parse_identifier_name(name_pair)?.to_owned(); let params = parse_formal_parameters(params_pair)? .into_iter() .map(|s| s.to_owned()) .collect(); Ok(TemplateAliasDeclaration::Function(name, params)) } r => panic!("unexpected alias declaration rule {r:?}"), } }} /// Borrowed reference to identify alias expression.#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub enum TemplateAliasId<'a> { Symbol(&'a str), Function(&'a str),} impl fmt::Display for TemplateAliasId<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TemplateAliasId::Symbol(name) => write!(f, "{name}"), TemplateAliasId::Function(name) => write!(f, "{name}()"), } }} /// Expand aliases recursively.pub fn expand_aliases<'i>( node: ExpressionNode<'i>, aliases_map: &'i TemplateAliasesMap,) -> TemplateParseResult<ExpressionNode<'i>> { #[derive(Clone, Copy, Debug)] struct State<'a, 'i> { aliases_map: &'i TemplateAliasesMap, aliases_expanding: &'a [TemplateAliasId<'a>], locals: &'a HashMap<&'a str, ExpressionNode<'i>>,Lines 1–500 of 1217. Load more
// Copyright 2020 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::collections::HashMap; use std::num::ParseIntError; use std::{error, fmt}; use itertools::Itertools as _; use pest::iterators::{Pair, Pairs}; use pest::Parser; use pest_derive::Parser; use thiserror::Error; #[derive(Parser)] #[grammar = "template.pest"] struct TemplateParser; pub type TemplateParseResult<T> = Result<T, TemplateParseError>; #[derive(Clone, Debug)] pub struct TemplateParseError { kind: TemplateParseErrorKind, pest_error: Box<pest::error::Error<Rule>>, origin: Option<Box<TemplateParseError>>, } #[derive(Clone, Debug, Eq, Error, PartialEq)] pub enum TemplateParseErrorKind { #[error("Syntax error")] SyntaxError, #[error("Invalid integer literal: {0}")] ParseIntError(#[source] ParseIntError), #[error(r#"Keyword "{0}" doesn't exist"#)] NoSuchKeyword(String), #[error(r#"Function "{0}" doesn't exist"#)] NoSuchFunction(String), #[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)] NoSuchMethod { type_name: String, name: String }, #[error(r#"Function "{name}": {message}"#)] InvalidArguments { name: String, message: String }, #[error("Redefinition of function parameter")] RedefinedFunctionParameter, #[error("{0}")] UnexpectedExpression(String), #[error(r#"Alias "{0}" cannot be expanded"#)] BadAliasExpansion(String), #[error(r#"Alias "{0}" expanded recursively"#)] RecursiveAlias(String), } impl TemplateParseError { pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self { let pest_error = Box::new(pest::error::Error::new_from_span( pest::error::ErrorVariant::CustomError { message: kind.to_string(), }, span, )); TemplateParseError { kind, pest_error, origin: None, } } pub fn with_span_and_origin( kind: TemplateParseErrorKind, span: pest::Span<'_>, origin: Self, ) -> Self { let pest_error = Box::new(pest::error::Error::new_from_span( pest::error::ErrorVariant::CustomError { message: kind.to_string(), }, span, )); TemplateParseError { kind, pest_error, origin: Some(Box::new(origin)), } } pub fn no_such_keyword(name: impl Into<String>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span(TemplateParseErrorKind::NoSuchKeyword(name.into()), span) } pub fn no_such_function(function: &FunctionCallNode) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::NoSuchFunction(function.name.to_owned()), function.name_span, ) } pub fn no_such_method(type_name: impl Into<String>, function: &FunctionCallNode) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::NoSuchMethod { type_name: type_name.into(), name: function.name.to_owned(), }, function.name_span, ) } pub fn invalid_arguments(function: &FunctionCallNode, message: impl Into<String>) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::InvalidArguments { name: function.name.to_owned(), message: message.into(), }, function.args_span, ) } pub fn expected_type(type_name: &str, span: pest::Span<'_>) -> Self { let message = format!(r#"Expected expression of type "{type_name}""#); TemplateParseError::unexpected_expression(message, span) } pub fn unexpected_expression(message: impl Into<String>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span( TemplateParseErrorKind::UnexpectedExpression(message.into()), span, ) } pub fn within_alias_expansion(self, id: TemplateAliasId<'_>, span: pest::Span<'_>) -> Self { TemplateParseError::with_span_and_origin( TemplateParseErrorKind::BadAliasExpansion(id.to_string()), span, self, ) } /// Original parsing error which typically occurred in an alias expression. pub fn origin(&self) -> Option<&Self> { self.origin.as_deref() } } impl From<pest::error::Error<Rule>> for TemplateParseError { fn from(err: pest::error::Error<Rule>) -> Self { TemplateParseError { kind: TemplateParseErrorKind::SyntaxError, pest_error: Box::new(err), origin: None, } } } impl fmt::Display for TemplateParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.pest_error.fmt(f) } } impl error::Error for TemplateParseError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { if let Some(e) = self.origin() { return Some(e as &dyn error::Error); } match &self.kind { // SyntaxError is a wrapper for pest::error::Error. TemplateParseErrorKind::SyntaxError => Some(&self.pest_error as &dyn error::Error), // Otherwise the kind represents this error. e => e.source(), } } } /// AST node without type or name checking. #[derive(Clone, Debug, PartialEq)] pub struct ExpressionNode<'i> { pub kind: ExpressionKind<'i>, pub span: pest::Span<'i>, } impl<'i> ExpressionNode<'i> { fn new(kind: ExpressionKind<'i>, span: pest::Span<'i>) -> Self { ExpressionNode { kind, span } } } #[derive(Clone, Debug, PartialEq)] pub enum ExpressionKind<'i> { Identifier(&'i str), Boolean(bool), Integer(i64), String(String), Concat(Vec<ExpressionNode<'i>>), FunctionCall(FunctionCallNode<'i>), MethodCall(MethodCallNode<'i>), Lambda(LambdaNode<'i>), /// Identity node to preserve the span in the source template text. AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>), } #[derive(Clone, Debug, PartialEq)] pub struct FunctionCallNode<'i> { pub name: &'i str, pub name_span: pest::Span<'i>, pub args: Vec<ExpressionNode<'i>>, pub args_span: pest::Span<'i>, } #[derive(Clone, Debug, PartialEq)] pub struct MethodCallNode<'i> { pub object: Box<ExpressionNode<'i>>, pub function: FunctionCallNode<'i>, } #[derive(Clone, Debug, PartialEq)] pub struct LambdaNode<'i> { pub params: Vec<&'i str>, pub params_span: pest::Span<'i>, pub body: Box<ExpressionNode<'i>>, } fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind { assert_eq!(pair.as_rule(), Rule::identifier); match pair.as_str() { "false" => ExpressionKind::Boolean(false), "true" => ExpressionKind::Boolean(true), name => ExpressionKind::Identifier(name), } } fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> { let span = pair.as_span(); if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) { Ok(name) } else { Err(TemplateParseError::unexpected_expression( "Expected identifier", span, )) } } fn parse_string_literal(pair: Pair<Rule>) -> String { assert_eq!(pair.as_rule(), Rule::literal); let mut result = String::new(); for part in pair.into_inner() { match part.as_rule() { Rule::raw_literal => { result.push_str(part.as_str()); } Rule::escape => match &part.as_str()[1..] { "\"" => result.push('"'), "\\" => result.push('\\'), "t" => result.push('\t'), "r" => result.push('\r'), "n" => result.push('\n'), "0" => result.push('\0'), char => panic!("invalid escape: \\{char:?}"), }, _ => panic!("unexpected part of string: {part:?}"), } } result } fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&str>> { assert_eq!(params_pair.as_rule(), Rule::formal_parameters); let params_span = params_pair.as_span(); let params: Vec<_> = params_pair .into_inner() .map(parse_identifier_name) .try_collect()?; if params.iter().all_unique() { Ok(params) } else { Err(TemplateParseError::with_span( TemplateParseErrorKind::RedefinedFunctionParameter, params_span, )) } } fn parse_function_call_node(pair: Pair<Rule>) -> TemplateParseResult<FunctionCallNode> { assert_eq!(pair.as_rule(), Rule::function); let mut inner = pair.into_inner(); let name_pair = inner.next().unwrap(); let name_span = name_pair.as_span(); let args_pair = inner.next().unwrap(); let args_span = args_pair.as_span(); assert_eq!(args_pair.as_rule(), Rule::function_arguments); let name = parse_identifier_name(name_pair)?; let args = args_pair .into_inner() .map(parse_template_node) .try_collect()?; Ok(FunctionCallNode { name, name_span, args, args_span, }) } fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> { assert_eq!(pair.as_rule(), Rule::lambda); let mut inner = pair.into_inner(); let params_pair = inner.next().unwrap(); let params_span = params_pair.as_span(); let body_pair = inner.next().unwrap(); let params = parse_formal_parameters(params_pair)?; let body = parse_template_node(body_pair)?; Ok(LambdaNode { params, params_span, body: Box::new(body), }) } fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { assert_eq!(pair.as_rule(), Rule::term); let mut inner = pair.into_inner(); let expr = inner.next().unwrap(); let span = expr.as_span(); let primary = match expr.as_rule() { Rule::literal => { let text = parse_string_literal(expr); ExpressionNode::new(ExpressionKind::String(text), span) } Rule::integer_literal => { let value = expr.as_str().parse().map_err(|err| { TemplateParseError::with_span(TemplateParseErrorKind::ParseIntError(err), span) })?; ExpressionNode::new(ExpressionKind::Integer(value), span) } Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span), Rule::function => { let function = parse_function_call_node(expr)?; ExpressionNode::new(ExpressionKind::FunctionCall(function), span) } Rule::lambda => { let lambda = parse_lambda_node(expr)?; ExpressionNode::new(ExpressionKind::Lambda(lambda), span) } Rule::template => parse_template_node(expr)?, other => panic!("unexpected term: {other:?}"), }; inner.try_fold(primary, |object, chain| { assert_eq!(chain.as_rule(), Rule::function); let span = object.span.start_pos().span(&chain.as_span().end_pos()); let method = MethodCallNode { object: Box::new(object), function: parse_function_call_node(chain)?, }; Ok(ExpressionNode::new( ExpressionKind::MethodCall(method), span, )) }) } fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> { assert_eq!(pair.as_rule(), Rule::template); let span = pair.as_span(); let inner = pair.into_inner(); let mut nodes: Vec<_> = inner.map(parse_term_node).try_collect()?; if nodes.len() == 1 { Ok(nodes.pop().unwrap()) } else { Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span)) } } /// Parses text into AST nodes. No type/name checking is made at this stage. pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode> { let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?; let first_pair = pairs.next().unwrap(); if first_pair.as_rule() == Rule::EOI { let span = first_pair.as_span(); Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span)) } else { parse_template_node(first_pair) } } #[derive(Clone, Debug, Default)] pub struct TemplateAliasesMap { symbol_aliases: HashMap<String, String>, function_aliases: HashMap<String, (Vec<String>, String)>, } impl TemplateAliasesMap { pub fn new() -> Self { Self::default() } /// Adds new substitution rule `decl = defn`. /// /// Returns error if `decl` is invalid. The `defn` part isn't checked. A bad /// `defn` will be reported when the alias is substituted. pub fn insert( &mut self, decl: impl AsRef<str>, defn: impl Into<String>, ) -> TemplateParseResult<()> { match TemplateAliasDeclaration::parse(decl.as_ref())? { TemplateAliasDeclaration::Symbol(name) => { self.symbol_aliases.insert(name, defn.into()); } TemplateAliasDeclaration::Function(name, params) => { self.function_aliases.insert(name, (params, defn.into())); } } Ok(()) } fn get_symbol(&self, name: &str) -> Option<(TemplateAliasId<'_>, &str)> { self.symbol_aliases .get_key_value(name) .map(|(name, defn)| (TemplateAliasId::Symbol(name), defn.as_ref())) } fn get_function(&self, name: &str) -> Option<(TemplateAliasId<'_>, &[String], &str)> { self.function_aliases .get_key_value(name) .map(|(name, (params, defn))| { ( TemplateAliasId::Function(name), params.as_ref(), defn.as_ref(), ) }) } } /// Parsed declaration part of alias rule. #[derive(Clone, Debug)] enum TemplateAliasDeclaration { Symbol(String), Function(String, Vec<String>), } impl TemplateAliasDeclaration { fn parse(source: &str) -> TemplateParseResult<Self> { let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?; let first = pairs.next().unwrap(); match first.as_rule() { Rule::identifier => { let name = parse_identifier_name(first)?.to_owned(); Ok(TemplateAliasDeclaration::Symbol(name)) } Rule::function_alias_declaration => { let mut inner = first.into_inner(); let name_pair = inner.next().unwrap(); let params_pair = inner.next().unwrap(); let name = parse_identifier_name(name_pair)?.to_owned(); let params = parse_formal_parameters(params_pair)? .into_iter() .map(|s| s.to_owned()) .collect(); Ok(TemplateAliasDeclaration::Function(name, params)) } r => panic!("unexpected alias declaration rule {r:?}"), } } } /// Borrowed reference to identify alias expression. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TemplateAliasId<'a> { Symbol(&'a str), Function(&'a str), } impl fmt::Display for TemplateAliasId<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TemplateAliasId::Symbol(name) => write!(f, "{name}"), TemplateAliasId::Function(name) => write!(f, "{name}()"), } } } /// Expand aliases recursively. pub fn expand_aliases<'i>( node: ExpressionNode<'i>, aliases_map: &'i TemplateAliasesMap, ) -> TemplateParseResult<ExpressionNode<'i>> { #[derive(Clone, Copy, Debug)] struct State<'a, 'i> { aliases_map: &'i TemplateAliasesMap, aliases_expanding: &'a [TemplateAliasId<'a>], locals: &'a HashMap<&'a str, ExpressionNode<'i>>,