1use std::{fs::File, io::Read, path::Path};
2
3use grass_ir::GrassIR;
4use ir_expand::ExpansionContext;
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::quote;
8use syn::{parse_macro_input, LitStr};
9
10mod ir_expand;
11
12fn grass_impl(ir: &str, span: Span) -> TokenStream {
13 let ir: GrassIR = match serde_json::from_str(ir) {
14 Err(e) => {
15 return syn::Error::new(span, format!("Unable to parse Grass IR {}", e.to_string()))
16 .to_compile_error()
17 .into()
18 }
19 Ok(ir) => ir,
20 };
21
22 let mut ctx = ExpansionContext::new(span);
23
24 let result = match ir_expand::expand_grass_ir(&ir, &mut ctx) {
25 Ok(_code) => {
26 let code = ctx.to_token_stream();
27 quote! {
28 #code;
29 }
30 }
31 Err(err) => err.into_compile_error(),
32 };
33
34 result.into()
35}
36
37#[proc_macro]
38pub fn import_grass_ir_from_file(input: TokenStream) -> TokenStream {
39 let ir_lit = parse_macro_input!(input as LitStr);
40 let ir_lit_val = ir_lit.value();
41 let ir_path_rel: &Path = ir_lit_val.as_ref();
42
43 let manifest_path_str = env!("CARGO_MANIFEST_DIR");
44 let manifest_path: &Path = manifest_path_str.as_ref();
45
46 let ir_path = if ir_path_rel.is_relative() {
47 let mut pb = manifest_path.to_path_buf();
48 pb.push(ir_path_rel);
49 pb
50 } else {
51 ir_path_rel.to_path_buf()
52 };
53
54 let ir_str = match File::open(&ir_path) {
55 Err(e) => {
56 return syn::Error::new(
57 ir_lit.span(),
58 format!(
59 "Unable to open file \"{}\": {}",
60 ir_path.to_string_lossy(),
61 e
62 ),
63 )
64 .to_compile_error()
65 .into()
66 }
67 Ok(mut fp) => {
68 let mut buf = String::new();
69 if let Err(e) = fp.read_to_string(&mut buf) {
70 return syn::Error::new(
71 ir_lit.span(),
72 format!(
73 "Unable to read file \"{}\": {}",
74 ir_path.to_string_lossy(),
75 e
76 ),
77 )
78 .to_compile_error()
79 .into();
80 }
81 buf
82 }
83 };
84 grass_impl(ir_str.as_str(), ir_lit.span())
85}
86
87#[proc_macro]
88pub fn import_grass_ir(input: TokenStream) -> TokenStream {
89 let ir_lit = parse_macro_input!(input as LitStr);
90 grass_impl(ir_lit.value().as_str(), ir_lit.span())
91}