sim-macros 0.1.1

Proc-macro surface for authored SIM libraries.
Documentation
//! Native macro ABI dispatch generation.

use crate::parse::ParsedMacro;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use syn::LitStr;

pub(crate) fn native_macro_call_dispatch(macros: &[ParsedMacro]) -> TokenStream2 {
    let arms = macros.iter().map(macro_dispatch_arm);
    let result_adapter = if macros.is_empty() {
        TokenStream2::new()
    } else {
        quote! {
            trait NativeMacroResult {
                fn into_native_macro_result(self) -> ::sim::kernel::Result<::sim::kernel::Expr>;
            }

            impl NativeMacroResult for ::sim::kernel::Expr {
                fn into_native_macro_result(self) -> ::sim::kernel::Result<::sim::kernel::Expr> {
                    Ok(self)
                }
            }

            impl NativeMacroResult for ::sim::kernel::Result<::sim::kernel::Expr> {
                fn into_native_macro_result(self) -> ::sim::kernel::Result<::sim::kernel::Expr> {
                    self
                }
            }
        }
    };

    quote! {
        #result_adapter

        fn native_macro_call(
            function: &str,
            expr: &::sim::kernel::Expr,
        ) -> ::sim::kernel::Result<Option<::sim::kernel::Expr>> {
            match function {
                #(#arms,)*
                _ => Ok(None),
            }
        }
    }
}

fn macro_dispatch_arm(mac: &ParsedMacro) -> TokenStream2 {
    let op_lit = LitStr::new(&format!("{}/expand", mac.symbol), Span::call_site());
    let expand_ident = &mac.expand_ident;
    quote! {
        #op_lit => {
            let expanded = NativeMacroResult::into_native_macro_result(
                super::#expand_ident(expr.clone()),
            )?;
            Ok(Some(expanded))
        }
    }
}