use syn::{
parenthesized,
parse::{Parse, ParseStream},
punctuated::Punctuated,
Block, Expr, Ident, Path, Stmt, Token,
};
pub mod param_names {
pub const PROLOGUE: &str = "prologue";
pub const ON_ENTER: &str = "on_enter";
pub const ON_EXIT: &str = "on_exit";
pub const DECORATOR: &str = "decorator";
pub const ALL_PARAMS: &[&str] = &[PROLOGUE, ON_ENTER, ON_EXIT, DECORATOR];
}
#[derive(Clone)]
pub enum FunctionSpec {
Simple(Path),
WithArgs(Path, Punctuated<Expr, Token![,]>),
}
impl Parse for FunctionSpec {
fn parse(input: ParseStream) -> syn::Result<Self> {
let path: Path = input.parse()?;
if input.peek(syn::token::Paren) {
let content;
parenthesized!(content in input);
Ok(FunctionSpec::WithArgs(
path,
Punctuated::<Expr, Token![,]>::parse_terminated(&content)?,
))
} else {
Ok(FunctionSpec::Simple(path))
}
}
}
pub struct AxinArgs {
pub args: Punctuated<AxinArg, Token![,]>,
}
pub enum AxinArg {
Prologue { stmts: Vec<Stmt> },
OnEnter { func: FunctionSpec },
OnExit { func: FunctionSpec },
Decorator { func: FunctionSpec },
}
impl Parse for AxinArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let args = Punctuated::parse_terminated(input)?;
Ok(AxinArgs { args })
}
}
impl Parse for AxinArg {
fn parse(input: ParseStream) -> syn::Result<Self> {
let name: Ident = input.parse()?;
let content;
parenthesized!(content in input);
match name.to_string().as_str() {
param_names::PROLOGUE => Ok(AxinArg::Prologue {
stmts: content.call(Block::parse_within)?,
}),
param_names::ON_ENTER | param_names::ON_EXIT | param_names::DECORATOR => {
let func: FunctionSpec = content.parse()?;
match name.to_string().as_str() {
param_names::ON_ENTER => Ok(AxinArg::OnEnter { func }),
param_names::ON_EXIT => Ok(AxinArg::OnExit { func }),
param_names::DECORATOR => Ok(AxinArg::Decorator { func }),
_ => unreachable!(),
}
}
_ => {
let name_str = name.to_string();
let supported_params = param_names::ALL_PARAMS.join(", ");
Err(syn::Error::new_spanned(
name,
format!(
"Unsupported parameter: '{}'. Supported parameters are: {}",
name_str, supported_params
),
))
}
}
}
}