templater: move boxing to ExpressionKind variants to make the enum smaller

I'm trying to extract generic alias substitution functions, and some of them
will take ExpressionKind or Box<FunctionCallNode> by value, then return it or
substituted value of the same type. The cost of moving values wouldn't matter
in practice, but I think it's better to keep the value types small.

Now ExpressionKind is 4-word long.
This commit is contained in:
Yuya Nishihara 2024-05-16 22:38:27 +09:00
parent fe9daac483
commit e87b49ccc1

View file

@ -261,9 +261,9 @@ pub enum ExpressionKind<'i> {
Unary(UnaryOp, Box<ExpressionNode<'i>>), Unary(UnaryOp, Box<ExpressionNode<'i>>),
Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>), Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
Concat(Vec<ExpressionNode<'i>>), Concat(Vec<ExpressionNode<'i>>),
FunctionCall(FunctionCallNode<'i>), FunctionCall(Box<FunctionCallNode<'i>>),
MethodCall(MethodCallNode<'i>), MethodCall(Box<MethodCallNode<'i>>),
Lambda(LambdaNode<'i>), Lambda(Box<LambdaNode<'i>>),
/// Identity node to preserve the span in the source template text. /// Identity node to preserve the span in the source template text.
AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>), AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>),
} }
@ -294,7 +294,7 @@ pub struct FunctionCallNode<'i> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct MethodCallNode<'i> { pub struct MethodCallNode<'i> {
pub object: Box<ExpressionNode<'i>>, pub object: ExpressionNode<'i>,
pub function: FunctionCallNode<'i>, pub function: FunctionCallNode<'i>,
} }
@ -302,7 +302,7 @@ pub struct MethodCallNode<'i> {
pub struct LambdaNode<'i> { pub struct LambdaNode<'i> {
pub params: Vec<&'i str>, pub params: Vec<&'i str>,
pub params_span: pest::Span<'i>, pub params_span: pest::Span<'i>,
pub body: Box<ExpressionNode<'i>>, pub body: ExpressionNode<'i>,
} }
fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind { fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind {
@ -372,7 +372,7 @@ fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> {
Ok(LambdaNode { Ok(LambdaNode {
params, params,
params_span, params_span,
body: Box::new(body), body,
}) })
} }
@ -400,11 +400,11 @@ fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
} }
Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span), Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),
Rule::function => { Rule::function => {
let function = parse_function_call_node(expr)?; let function = Box::new(parse_function_call_node(expr)?);
ExpressionNode::new(ExpressionKind::FunctionCall(function), span) ExpressionNode::new(ExpressionKind::FunctionCall(function), span)
} }
Rule::lambda => { Rule::lambda => {
let lambda = parse_lambda_node(expr)?; let lambda = Box::new(parse_lambda_node(expr)?);
ExpressionNode::new(ExpressionKind::Lambda(lambda), span) ExpressionNode::new(ExpressionKind::Lambda(lambda), span)
} }
Rule::template => parse_template_node(expr)?, Rule::template => parse_template_node(expr)?,
@ -413,10 +413,10 @@ fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
inner.try_fold(primary, |object, chain| { inner.try_fold(primary, |object, chain| {
assert_eq!(chain.as_rule(), Rule::function); assert_eq!(chain.as_rule(), Rule::function);
let span = object.span.start_pos().span(&chain.as_span().end_pos()); let span = object.span.start_pos().span(&chain.as_span().end_pos());
let method = MethodCallNode { let method = Box::new(MethodCallNode {
object: Box::new(object), object,
function: parse_function_call_node(chain)?, function: parse_function_call_node(chain)?,
}; });
Ok(ExpressionNode::new( Ok(ExpressionNode::new(
ExpressionKind::MethodCall(method), ExpressionKind::MethodCall(method),
span, span,
@ -703,24 +703,26 @@ pub fn expand_aliases<'i>(
let locals = params.iter().map(|s| s.as_str()).zip(args).collect(); let locals = params.iter().map(|s| s.as_str()).zip(args).collect();
expand_defn(id, defn, &locals, node.span, state) expand_defn(id, defn, &locals, node.span, state)
} else { } else {
node.kind = let function = Box::new(expand_function_call(*function, state)?);
ExpressionKind::FunctionCall(expand_function_call(function, state)?); node.kind = ExpressionKind::FunctionCall(function);
Ok(node) Ok(node)
} }
} }
ExpressionKind::MethodCall(method) => { ExpressionKind::MethodCall(method) => {
node.kind = ExpressionKind::MethodCall(MethodCallNode { let method = Box::new(MethodCallNode {
object: Box::new(expand_node(*method.object, state)?), object: expand_node(method.object, state)?,
function: expand_function_call(method.function, state)?, function: expand_function_call(method.function, state)?,
}); });
node.kind = ExpressionKind::MethodCall(method);
Ok(node) Ok(node)
} }
ExpressionKind::Lambda(lambda) => { ExpressionKind::Lambda(lambda) => {
node.kind = ExpressionKind::Lambda(LambdaNode { let lambda = Box::new(LambdaNode {
params: lambda.params, params: lambda.params,
params_span: lambda.params_span, params_span: lambda.params_span,
body: Box::new(expand_node(*lambda.body, state)?), body: expand_node(lambda.body, state)?,
}); });
node.kind = ExpressionKind::Lambda(lambda);
Ok(node) Ok(node)
} }
ExpressionKind::AliasExpanded(id, subst) => { ExpressionKind::AliasExpanded(id, subst) => {
@ -973,20 +975,23 @@ mod tests {
} }
ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)), ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)),
ExpressionKind::FunctionCall(function) => { ExpressionKind::FunctionCall(function) => {
ExpressionKind::FunctionCall(normalize_function_call(function)) let function = Box::new(normalize_function_call(*function));
ExpressionKind::FunctionCall(function)
} }
ExpressionKind::MethodCall(method) => { ExpressionKind::MethodCall(method) => {
let object = Box::new(normalize_tree(*method.object)); let method = Box::new(MethodCallNode {
let function = normalize_function_call(method.function); object: normalize_tree(method.object),
ExpressionKind::MethodCall(MethodCallNode { object, function }) function: normalize_function_call(method.function),
});
ExpressionKind::MethodCall(method)
} }
ExpressionKind::Lambda(lambda) => { ExpressionKind::Lambda(lambda) => {
let body = Box::new(normalize_tree(*lambda.body)); let lambda = Box::new(LambdaNode {
ExpressionKind::Lambda(LambdaNode {
params: lambda.params, params: lambda.params,
params_span: empty_span(), params_span: empty_span(),
body, body: normalize_tree(lambda.body),
}) });
ExpressionKind::Lambda(lambda)
} }
ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind, ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
}; };
@ -1099,7 +1104,7 @@ mod tests {
#[test] #[test]
fn test_lambda_syntax() { fn test_lambda_syntax() {
fn unwrap_lambda(node: ExpressionNode<'_>) -> LambdaNode<'_> { fn unwrap_lambda(node: ExpressionNode<'_>) -> Box<LambdaNode<'_>> {
match node.kind { match node.kind {
ExpressionKind::Lambda(lambda) => lambda, ExpressionKind::Lambda(lambda) => lambda,
_ => panic!("unexpected expression: {node:?}"), _ => panic!("unexpected expression: {node:?}"),