derive_deftly_macros/
accum.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! `derive_deftly_engine!()`, parsing accumulations

use super::framework::*;
use adviseable::*;

/// `derive_deftly_engine! accumulated form, accumulated information
///
/// We don't reify the whole input;
/// instead, we accumulate directly in the `Parse` impl.
#[derive(Debug)]
pub struct EngineFinalInput {
    driver: syn::DeriveInput,
    accum: Accumulated,
}

#[derive(Debug)]
pub struct Accumulated {
    metas: meta::CheckUsed<meta::Accum>,
}

impl EngineFinalInput {
    pub fn parse_adviseable_remainder(
        driver: syn::DeriveInput,
        input: ParseStream,
    ) -> AdviseableResult<Self> {
        let _empty_next_brackets_contents;
        let _ = bracketed!(_empty_next_brackets_contents in input);

        let accum;
        let _ = bracketed!(accum in input);
        let accum = accum.parse()?;

        let _: TokenStream = input.parse()?;

        Ok(AOk(EngineFinalInput { driver, accum }))
    }
}

impl Parse for Accumulated {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        use meta::CheckUsed as mCU;

        let mut metas = mCU::Check(meta::Accum::default());

        struct Ignore;

        while !input.is_empty() {
            let kind: syn::Ident = input.parse()?;
            match if kind == "_meta_used" {
                if let mCU::Check(m) = &mut metas {
                    match input.parse()? {
                        mCU::Check(y) => m.used.push(y),
                        mCU::Unchecked => metas = mCU::Unchecked,
                    }
                    continue;
                } else {
                    Ignore
                }
            } else if kind == "_meta_recog" {
                if let mCU::Check(m) = &mut metas {
                    let content;
                    let _brackets = bracketed!(content in input);
                    let input = content;
                    while !input.is_empty() {
                        use meta::Usage as mU;
                        let allow = match input.parse()? {
                            Some::<Token![?]>(_) => mU::BoolOnly,
                            None => mU::Value,
                        };
                        let desig = input.parse()?;
                        m.recog.update(desig, allow);
                    }
                    continue;
                } else {
                    Ignore
                }
            } else if kind == "error" {
                metas = mCU::Unchecked;
                Ignore
            } else if kind.to_string().starts_with('_') {
                Ignore
            } else {
                return Err(
                    kind.error("unrecognised mandatory accumulation kind")
                );
            } {
                Ignore => {
                    let _: TokenTree = input.parse()?;
                }
            }
        }
        Ok(Accumulated { metas })
    }
}

impl EngineFinalInput {
    pub fn process(self) -> syn::Result<TokenStream> {
        let r = Context::call(
            &self.driver,
            &dummy_path(), // template_crate, not used by our f
            None,          // template_name
            |ctx| {
                if let mCU::Check(m) = &self.accum.metas {
                    for group in &m.used {
                        adviseable_parse2_call(
                            group.content.clone(),
                            |input| {
                                ctx.decode_update_metas_used(input)?;
                                Ok(AOk(()))
                            },
                        )?
                    }
                }

                let mut errors = ErrorAccumulator::default();

                if let mCU::Check(m) = &self.accum.metas {
                    ctx.check_metas_used(&mut errors, &m.recog);
                }
                errors.finish()
            },
        );

        let mut out = TokenStream::new();

        match r {
            Ok(()) => {}
            Err(e) => e.into_compile_error().to_tokens(&mut out),
        }

        Ok(out)
    }
}