1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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(),
                                        // FIXME convert syn field type
                                        element: Type::unit().0,
                                    }
                                })
                                .collect(),
                        }))
                    }
                    syn::Fields::Unnamed(fields) => {
                        Data::Struct(Struct::Tuple(TupleStruct {
                            fields: fields
                                .unnamed
                                .into_iter()
                                .enumerate()
                                .map(|(i, field)| {
                                    Field {
                                        // FIXME store field index
                                        name: i.to_string(),
                                        // FIXME convert syn field type
                                        element: Type::unit().0,
                                    }
                                })
                                .collect(),
                        }))
                    }
                    syn::Fields::Unit => Data::Struct(Struct::Unit(UnitStruct { private: () })),
                }
            }
            syn::Data::Enum(data) => {
                // FIXME convert enum variants
                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(),
    }
}