Skip to main content

statum_macros/
lib.rs

1#![feature(proc_macro_span)]
2moddef::moddef!(
3    flat (pub) mod {
4    },
5    flat (pub(crate)) mod {
6        state,
7        machine,
8        transition,
9        validators
10    }
11);
12
13use crate::{
14    MachinePath, StateModulePath, ensure_machine_loaded, ensure_state_enum_loaded, get_machine,
15};
16use macro_registry::callsite::current_module_path;
17use proc_macro::TokenStream;
18use syn::{ItemEnum, ItemImpl, ItemStruct, parse_macro_input};
19
20#[proc_macro_attribute]
21pub fn state(_attr: TokenStream, item: TokenStream) -> TokenStream {
22    let input = parse_macro_input!(item as ItemEnum);
23
24    // Validate the enum before proceeding
25    if let Some(error) = validate_state_enum(&input) {
26        return error.into();
27    }
28
29    let enum_info = match EnumInfo::from_item_enum(&input) {
30        Ok(info) => info,
31        Err(err) => return err.to_compile_error().into(),
32    };
33
34    // Store metadata in `state_enum_map`
35    store_state_enum(&enum_info);
36
37    // Generate structs and implementations dynamically
38    let expanded = generate_state_impls(&enum_info.module_path);
39
40    TokenStream::from(expanded)
41}
42
43#[proc_macro_attribute]
44pub fn machine(_attr: TokenStream, item: TokenStream) -> TokenStream {
45    let input = parse_macro_input!(item as ItemStruct);
46
47    let machine_info = MachineInfo::from_item_struct(&input);
48
49    // Validate the struct before proceeding
50    if let Some(error) = validate_machine_struct(&input, &machine_info) {
51        return error.into();
52    }
53
54    // Store metadata in `machine_map`
55    store_machine_struct(&machine_info);
56
57    // Generate any required structs or implementations dynamically
58    let expanded = generate_machine_impls(&machine_info);
59
60    TokenStream::from(expanded)
61}
62
63#[proc_macro_attribute]
64pub fn transition(
65    _attr: proc_macro::TokenStream,
66    item: proc_macro::TokenStream,
67) -> proc_macro::TokenStream {
68    let input = parse_macro_input!(item as ItemImpl);
69
70    // -- Step 1: Parse
71    let tr_impl = parse_transition_impl(&input);
72
73    let module_path = current_module_path();
74
75    let state_path: StateModulePath = module_path.clone().into();
76    let machine_path: MachinePath = module_path.clone().into();
77    let _ = ensure_state_enum_loaded(&state_path);
78    let _ = ensure_machine_loaded(&machine_path);
79
80    let machine_info_owned = get_machine(&machine_path);
81    let machine_info = machine_info_owned
82        .as_ref()
83        .expect("Machine not found, even though we validated above");
84
85    if let Some(err) = validate_transition_functions(&tr_impl.functions, machine_info) {
86        return err.into();
87    }
88
89    // -- Step 3: Generate new code
90    let expanded = generate_transition_impl(&input, &tr_impl, machine_info, &module_path);
91
92    // Combine expanded code with the original `impl` if needed
93    // or simply return the expanded code
94    expanded.into()
95}
96
97#[proc_macro_attribute]
98pub fn validators(attr: TokenStream, item: TokenStream) -> TokenStream {
99    let module_path = current_module_path();
100    parse_validators(attr, item, &module_path)
101}