extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{Item, parse_quote, Fields};
use crate::{numeric_type::NumericType, recurrence::RecurrencyConstraint};
use super::synthesis::{synthesize, Synthesis};
pub struct Invocation {
pub config: Config,
pub item: Item,
pub recurrency_constraint: RecurrencyConstraint
}
pub enum CgeType {
Module(syn::Path),
File(String),
Direct(String)
}
pub struct Config {
pub cge: CgeType,
pub numeric_type: NumericType
}
pub fn core(invocation: Invocation) -> TokenStream {
if let CgeType::Module(p) = invocation.config.cge {
let invocation_ident = match invocation.recurrency_constraint {
RecurrencyConstraint::DontCare => quote!(network),
RecurrencyConstraint::Required => quote!(recurrent),
RecurrencyConstraint::Forbidden => quote!(nonrecurrent),
};
let numeric_token = invocation.config.numeric_type.token();
let item = invocation.item;
return quote! {
#p!(
#invocation_ident,
#item,
numeric_type = #numeric_token
);
}.into()
}
let Synthesis {
recurrency_count,
documentation,
persistence_field,
associated_constants,
persistence_methods,
evaluate_function
} = synthesize(&invocation);
match invocation.recurrency_constraint {
RecurrencyConstraint::DontCare => {},
RecurrencyConstraint::Required => if recurrency_count == 0 { panic!("Network is not recurrent (it was demanded)."); },
RecurrencyConstraint::Forbidden => if recurrency_count != 0 { panic!("Network is recurrent (it was forbidden)."); }
}
let name = match invocation.item {
syn::Item::Struct(ref s) => {
if recurrency_count != 0 {
match &s.fields {
Fields::Named(f) if f.named.len() != 0 => panic!("Your network is recurrent. Only unit structs (no fields) support recurrency at this time."),
Fields::Unnamed(f) if f.unnamed.len() != 0 => panic!("Your network is recurrent. Only unit structs (no fields) support recurrency at this time."),
_ => {}
}
}
s.ident.clone()
},
syn::Item::Enum(ref e) => {
if recurrency_count != 0 {
panic!("Your network is recurrent. Enums cannot always store recurrent state, so are not supported as targets of recurrent networks (for now).");
}
e.ident.clone()
},
_ => panic!("Unsupported language construct (`struct` and `enum` only).")
};
let item = if let Item::Struct(mut s) = invocation.item.clone() {
s.fields = Fields::Named(parse_quote!({ #persistence_field }));
Item::Struct(s)
} else {
invocation.item
};
quote! {
#documentation
#[derive(Clone, Copy, Default)]
#item
impl #name {
#associated_constants
#persistence_methods
#evaluate_function
}
}.into()
}