grass_macro/
lib.rs

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}