Skip to main content

hippo_macro/
lib.rs

1//
2// Hippo
3// (C) 2021 Brave Monday
4//
5
6extern 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/// Preprocess and embed an asset in conformance to the [`Preprocessed`](hippo::Preprocessed)
22/// trait.
23#[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}