extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::visit_mut::VisitMut;

mod error;
mod parser;
mod permission;
mod rewriter;
mod rules;

use parser::parse_permissions;
use rewriter::CapabilityRewriter;

#[proc_macro_attribute]
pub fn capability(attr: TokenStream, item: TokenStream) -> TokenStream {
    let permissions = parse_permissions(attr);

    let mut function = syn::parse_macro_input!(item as syn::ItemFn);

    let mut rewriter = CapabilityRewriter { permissions, errors: Vec::new() };

    rewriter.visit_block_mut(&mut function.block);

    let compile_errors = rewriter.errors.iter().map(syn::Error::to_compile_error);

    TokenStream::from(quote! {
        #(#compile_errors)*
        #function
    })
}
