1extern crate proc_macro;
7
8mod codegen;
9mod meta;
10
11use proc_macro as pm1;
12use proc_macro2 as pm2;
13
14use proc_macro_error::{abort_call_site, proc_macro_error};
15
16use hippo_shared::{Configuration, OutputFormat};
17
18use codegen::{emit, Container};
19use meta::Meta;
20
21#[proc_macro_derive(Preprocess, attributes(hippo))]
24#[proc_macro_error]
25pub fn preprocess(ast: pm1::TokenStream) -> pm1::TokenStream {
26 let ast = syn::parse_macro_input!(ast as syn::DeriveInput);
27 let meta = Meta::new(&ast);
28
29 let name = &meta.preprocessor;
30 let inputs = &meta.inputs;
31
32 let cfg_path = Configuration::locate().unwrap_or_else(
33 || abort_call_site!("Hippo configuration file could not be located")
34 );
35
36 let cfg = Configuration::load(&cfg_path).unwrap_or_else(
37 |e| abort_call_site!("Hippo configuration contains one or more errors: {}", e)
38 );
39
40 let pp = cfg.preprocessors.get(name).unwrap_or_else(
41 || abort_call_site!("preprocessor `{}` not found in configuration", name)
42 );
43
44 let inputs = pp.rewrite_arguments(inputs);
45
46 let out = pp.execute(&inputs).unwrap_or_else(
47 |e| abort_call_site!("preprocessor command resulted in an error: {}", e)
48 );
49
50 let output: pm2::TokenStream = {
51 match pp.format {
52 OutputFormat::Bytes => emit(
53 ast,
54 &inputs,
55 Container::Bytes(out.stdout.into())
56 ),
57 OutputFormat::Utf8 => emit(
58 ast,
59 &inputs,
60 Container::Utf8(String::from_utf8_lossy(&out.stdout).to_string())
61 )
62 }
63 };
64
65 pm1::TokenStream::from(output)
66}