helixir_macros/
lib.rs

1extern crate proc_macro;
2extern crate quote;
3extern crate syn;
4
5use proc_macro::TokenStream;
6use quote::quote;
7use std::path::Path;
8use syn::{parse_macro_input, ItemFn};
9
10struct Answer {
11    lesson_number: u32,
12    queries: Option<String>,
13    hql_src: Option<String>,
14}
15
16#[proc_macro_attribute]
17pub fn parse_answers(_attr: TokenStream, item: TokenStream) -> TokenStream {
18    let main_fn = parse_macro_input!(item as ItemFn);
19    let visibility = main_fn.vis;
20    let signature = main_fn.sig;
21    let body = main_fn.block;
22    let mut answers = Vec::new();
23
24    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
25    let project_root = Path::new(&manifest_dir);
26
27    // read from ../lesson_answers/lesson_<lesson_number>.rs
28    for lesson_number in 1..=24 {
29        let query_answer_path =
30            project_root.join(format!("query_answers/lesson{}.json", lesson_number));
31        let hql_answer_path =
32            project_root.join(format!("lesson_answers/lesson{}_queries.hx", lesson_number));
33
34        let lesson_answers = std::fs::read_to_string(&query_answer_path).ok();
35        let lesson_queries = std::fs::read_to_string(&hql_answer_path).ok();
36
37        answers.push(Answer {
38            lesson_number,
39            queries: lesson_answers,
40            hql_src: lesson_queries,
41        });
42    }
43
44    let lessons = answers.iter().map(
45        |Answer {
46             lesson_number,
47             queries,
48             hql_src,
49         }| {
50            let queries_value = queries.clone().unwrap_or(String::new());
51            let hql_src_value = hql_src.clone().unwrap_or(String::new());
52            quote! {
53                (#lesson_number, Lesson {
54                    query_answer: #queries_value.to_string(),
55                    hql_answer: #hql_src_value.to_string(),
56                })
57            }
58        },
59    );
60
61    let expanded = quote! {
62        use std::collections::HashMap;
63        pub struct Lesson {
64            pub query_answer: String,
65            pub hql_answer: String,
66        }
67        #visibility #signature {
68            let lessons = HashMap::from([
69                #(#lessons),*
70            ]);
71            #body
72        }
73    };
74
75    TokenStream::from(expanded)
76}