Documentation
mod ast;
mod generator;

use proc_macro::TokenStream;
use syn::{
    parse_macro_input, punctuated::Punctuated, spanned::Spanned, Error, Item, ItemFn, Meta, Token,
};

use crate::ast::{SdfOperatorFn, SdfOperatorKind, SdfBindgenConfig};

#[proc_macro_attribute]
pub fn sdf(args: TokenStream, input: TokenStream) -> TokenStream {
    let args = parse_macro_input!(args with Punctuated::<Meta, Token![,]>::parse_terminated);
    let input = parse_macro_input!(input as Item);

    match input {
        Item::Fn(item_fn) => sdf_operator_fn(args, item_fn),
        _ => Error::new(input.span(), "macro supports only functions")
            .into_compile_error()
            .into(),
    }
}

fn sdf_operator_fn(args: Punctuated<Meta, Token![,]>, func: ItemFn) -> TokenStream {
    let bindgen_config = match SdfBindgenConfig::from_ast(&args) {
        Ok(config) => config,
        Err(e) => return e.into_compile_error().into(),
    };

    let operator = match SdfOperatorKind::from_ast(&args) {
        Ok(kind) => kind,
        Err(e) => return e.into_compile_error().into(),
    };

    let sdf_fn = match SdfOperatorFn::from_ast(&func, operator) {
        Ok(sdf_fn) => sdf_fn,
        Err(e) => return e.into_compile_error().into(),
    };

    generator::generate_operator(&sdf_fn, &bindgen_config).into()
}