use CompleteFunction;
use CompleteImpl;
use Data;
use Enum;
use Execution;
use Field;
use Program;
use Struct;
use StructStruct;
use Tracker;
use TupleStruct;
use Type;
use TypeNode;
use UnitStruct;
use WipFunction;
use WipImpl;
use proc_macro2::{self, TokenStream};
use syn;
pub fn derive<TokenStream>(input: TokenStream, run: fn(Execution)) -> TokenStream
where
TokenStream: Into<proc_macro2::TokenStream> + From<proc_macro2::TokenStream>,
{
let input = input.into();
let output = derive2(input, run);
output.into()
}
fn derive2(input: TokenStream, run: fn(Execution)) -> TokenStream {
let input = syn::parse2(input).unwrap();
let ty = syn_to_type(input);
let tracker = Tracker::new();
run(Execution {
ty: &ty,
tracker: &tracker,
});
let program = tracker_to_program(tracker);
let tokens = program.compile();
tokens.into()
}
fn syn_to_type(input: syn::DeriveInput) -> Type {
Type(TypeNode::DataStructure {
name: input.ident.to_string(),
data: match input.data {
syn::Data::Struct(data) => {
match data.fields {
syn::Fields::Named(fields) => {
Data::Struct(Struct::Struct(StructStruct {
fields: fields
.named
.into_iter()
.map(|field| {
Field {
name: field.ident.unwrap().to_string(),
element: Type::unit().0,
}
})
.collect(),
}))
}
syn::Fields::Unnamed(fields) => {
Data::Struct(Struct::Tuple(TupleStruct {
fields: fields
.unnamed
.into_iter()
.enumerate()
.map(|(i, field)| {
Field {
name: i.to_string(),
element: Type::unit().0,
}
})
.collect(),
}))
}
syn::Fields::Unit => Data::Struct(Struct::Unit(UnitStruct { private: () })),
}
}
syn::Data::Enum(data) => {
Data::Enum(Enum {
variants: Vec::new(),
})
}
syn::Data::Union(_) => unimplemented!("union"),
},
})
}
fn tracker_to_program(tracker: Tracker) -> Program {
Program {
crates: tracker.crates.borrow().clone(),
impls: tracker
.impls
.borrow()
.iter()
.map(|imp| {
let imp: WipImpl = imp.borrow().clone();
CompleteImpl {
of: imp.of,
ty: imp.ty,
functions: imp.functions
.into_iter()
.map(|function| {
let function: WipFunction = function.borrow().clone();
let values = function.values.borrow().clone();
let invokes = function.invokes.borrow().clone();
CompleteFunction {
self_ty: function.self_ty,
f: function.f,
values,
invokes,
ret: function.ret,
}
})
.collect(),
}
})
.collect(),
}
}