mathhook-macros 0.2.0

Procedural macros for MathHook - expr!, symbol!, symbols!, function!
Documentation
//! Procedural function!() macro implementation
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{Expr, Ident, Token};

struct FunctionCall {
    name: Ident,
    args: Vec<Expr>,
}

impl Parse for FunctionCall {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let name: Ident = input.parse()?;

        let args = if input.peek(Token![,]) {
            input.parse::<Token![,]>()?;
            let parsed_args = Punctuated::<Expr, Token![,]>::parse_separated_nonempty(input)?;
            parsed_args.into_iter().collect()
        } else if !input.is_empty() {
            return Err(syn::Error::new(
                input.span(),
                "Expected comma before arguments",
            ));
        } else {
            Vec::new()
        };

        Ok(FunctionCall { name, args })
    }
}

pub(crate) fn function_impl(input: TokenStream) -> TokenStream {
    match syn::parse::<FunctionCall>(input) {
        Ok(func) => {
            let name_str = func.name.to_string();
            let args = &func.args;

            let tokens: TokenStream2 = quote! {
                mathhook_core::Expression::function(#name_str, vec![#(#args),*])
            };

            tokens.into()
        }
        Err(err) => err.to_compile_error().into(),
    }
}