dsl_util: add trait that constructs ExpressionKind of basic AST node types

This isn't fancy, but we'll need some generic way to return either original
or substituted expression node. I think this is the simplest abstraction.
This commit is contained in:
Yuya Nishihara 2024-05-18 12:07:42 +09:00
parent b0913342b1
commit cf6357459d
2 changed files with 31 additions and 6 deletions

View file

@ -17,8 +17,8 @@ use std::{error, mem};
use itertools::Itertools as _;
use jj_lib::dsl_util::{
self, collect_similar, AliasDeclaration, AliasDeclarationParser, AliasId, AliasesMap,
InvalidArguments, StringLiteralParser,
self, collect_similar, AliasDeclaration, AliasDeclarationParser, AliasExpandableExpression,
AliasId, AliasesMap, InvalidArguments, StringLiteralParser,
};
use once_cell::sync::Lazy;
use pest::iterators::{Pair, Pairs};
@ -262,6 +262,20 @@ pub enum ExpressionKind<'i> {
AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
}
impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
fn identifier(name: &'i str) -> Self {
ExpressionKind::Identifier(name)
}
fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
ExpressionKind::FunctionCall(function)
}
fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
ExpressionKind::AliasExpanded(id, subst)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UnaryOp {
/// `!`
@ -547,7 +561,7 @@ pub fn expand_aliases<'i>(
// Parsed defn could be cached if needed.
parse_template(defn)
.and_then(|node| expand_node(node, expanding_state))
.map(|node| ExpressionKind::AliasExpanded(id, Box::new(node)))
.map(|node| ExpressionKind::alias_expanded(id, Box::new(node)))
.map_err(|e| e.within_alias_expansion(id, span))
}
@ -581,12 +595,13 @@ pub fn expand_aliases<'i>(
let kind = match kind {
ExpressionKind::Identifier(name) => {
if let Some(subst) = state.locals.get(name) {
ExpressionKind::AliasExpanded(AliasId::Parameter(name), Box::new(subst.clone()))
let id = AliasId::Parameter(name);
ExpressionKind::alias_expanded(id, Box::new(subst.clone()))
} else if let Some((id, defn)) = state.aliases_map.get_symbol(name) {
let locals = HashMap::new(); // Don't spill out the current scope
expand_defn(id, defn, &locals, span, state)?
} else {
kind
ExpressionKind::identifier(name)
}
}
ExpressionKind::Boolean(_) | ExpressionKind::Integer(_) | ExpressionKind::String(_) => {
@ -619,7 +634,7 @@ pub fn expand_aliases<'i>(
expand_defn(id, defn, &locals, span, state)?
} else {
let function = Box::new(expand_function_call(*function, state)?);
ExpressionKind::FunctionCall(function)
ExpressionKind::function_call(function)
}
}
ExpressionKind::MethodCall(method) => {

View file

@ -266,6 +266,16 @@ pub trait AliasDeclarationParser {
fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error>;
}
/// Expression item that supports alias substitution.
pub trait AliasExpandableExpression<'i>: Sized {
/// Wraps identifier.
fn identifier(name: &'i str) -> Self;
/// Wraps function call.
fn function_call(function: Box<FunctionCallNode<'i, Self>>) -> Self;
/// Wraps substituted expression.
fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i, Self>>) -> Self;
}
/// Collects similar names from the `candidates` list.
pub fn collect_similar<I>(name: &str, candidates: I) -> Vec<String>
where