derive_deftly_macros/
repeat.rs

1//! Handling of repetition, and also useful methods on context
2
3use super::framework::*;
4
5pub const NESTING_LIMIT: u16 = 100;
6
7pub use RepeatOver as RO;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Display)]
10#[strum(serialize_all = "snake_case")]
11pub enum RepeatOver {
12    Variants,
13    Fields,
14}
15
16#[derive(Debug, Clone)]
17struct RepeatOverInference {
18    over: RepeatOver,
19    span: Span,
20}
21
22#[derive(Default, Debug, Clone)]
23pub struct RepeatAnalysisVisitor {
24    over: Option<RepeatOverInference>,
25}
26
27pub trait AnalyseRepeat {
28    fn analyse_repeat(
29        &self,
30        visitor: &mut RepeatAnalysisVisitor,
31    ) -> syn::Result<()>;
32}
33
34/// What would `${fname}` expand to?  As type from [`syn`].
35///
36/// Implements [`quote::IdentFragment`] and [`ToTokens`].
37#[derive(Debug, Eq, PartialEq)]
38pub enum Fname<'r> {
39    Name(&'r syn::Ident),
40    Index(syn::Index),
41}
42
43impl RepeatAnalysisVisitor {
44    fn set_over(&mut self, over: RepeatOverInference) -> syn::Result<()> {
45        match &self.over {
46            None => self.over = Some(over),
47            Some(already) => {
48                if already.over != over.over {
49                    let mut e1 = already.span.error(format_args!(
50 "inconsistent repetition depth: firstly, {} inferred here",
51                            already.over,
52                        ));
53                    let e2 = over.span.error(format_args!(
54 "inconsistent repetition depth: secondly, {} inferred here",
55                            over.over,
56                        ));
57                    e1.combine(e2);
58                    return Err(e1);
59                }
60            }
61        }
62        Ok(())
63    }
64
65    pub fn finish(self, start: DelimSpan) -> Result<RepeatOver, syn::Error> {
66        Ok(self
67            .over
68            .ok_or_else(|| {
69                start.error(
70            "no contained expansion field determined what to repeat here"
71        )
72            })?
73            .over)
74    }
75}
76
77impl<O: SubstParseContext> AnalyseRepeat for SubstIf<O> {
78    fn analyse_repeat(
79        &self,
80        visitor: &mut RepeatAnalysisVisitor,
81    ) -> syn::Result<()> {
82        for (cond, _) in &self.tests {
83            cond.analyse_repeat(visitor)?;
84            // We don't analyse the consequents.  We would have to scan
85            // them all unconditionally, which is rather strange.  It might
86            // even cause trouble: the template author might have used
87            // conditions (including for example `is_enum` to try to select an
88            // expansion appropriate for the context.
89            //
90            // It seems less confusing to avoid this, and require the
91            // template author to use `${for ...}`.
92        }
93        if let Some(consequence) = &self.otherwise {
94            consequence.analyse_repeat(visitor)?;
95        }
96        Ok(())
97    }
98}
99
100impl<O: SubstParseContext> AnalyseRepeat for Template<O> {
101    /// Analyses a template section to be repeated
102    fn analyse_repeat(
103        &self,
104        visitor: &mut RepeatAnalysisVisitor,
105    ) -> syn::Result<()> {
106        for element in &self.elements {
107            element.analyse_repeat(visitor)?;
108        }
109        Ok(())
110    }
111}
112
113impl<O: SubstParseContext> AnalyseRepeat for TemplateElement<O> {
114    fn analyse_repeat(
115        &self,
116        visitor: &mut RepeatAnalysisVisitor,
117    ) -> syn::Result<()> {
118        match self {
119            TE::Ident(..) => {}
120            TE::Literal(..) => {}
121            TE::LitStr(_) => {}
122            TE::Punct(..) => {}
123            TE::Repeat(_) => {}
124            TE::Group { template, .. } => template.analyse_repeat(visitor)?,
125            TE::Subst(exp) => exp.analyse_repeat(visitor)?,
126        }
127        Ok(())
128    }
129}
130
131impl<O: SubstParseContext> AnalyseRepeat for Subst<O> {
132    fn analyse_repeat(
133        &self,
134        visitor: &mut RepeatAnalysisVisitor,
135    ) -> syn::Result<()> {
136        macro_rules! recurse { { $v:expr } => { {
137            $v.analyse_repeat(visitor)?;
138            None
139        } } }
140
141        let over = match &self.sd {
142            SD::tname(..) => None,
143            SD::vname(..) => Some(RO::Variants),
144            SD::fname(..) => Some(RO::Fields),
145            SD::ttype(..) => None,
146            SD::tdeftype(..) => None,
147            SD::ftype(..) => Some(RO::Fields),
148            SD::fpatname(_) => Some(RO::Fields),
149            SD::vindex(..) => Some(RO::Variants),
150            SD::findex(..) => Some(RO::Fields),
151            SD::Vis(SubstVis::T, ..) => None,
152            SD::Vis(SubstVis::F, ..) => Some(RO::Fields),
153            SD::Vis(SubstVis::FD, ..) => Some(RO::Fields),
154            SD::Xmeta(sm) => sm.repeat_over(),
155            SD::tattrs(..) => None,
156            SD::vattrs(..) => Some(RO::Variants),
157            SD::fattrs(..) => Some(RO::Fields),
158            SD::tgens(..) => None,
159            SD::tdefgens(..) => None,
160            SD::tgnames(..) => None,
161            SD::twheres(..) => None,
162            SD::vpat(..) => Some(RO::Variants),
163            SD::vtype(..) => Some(RO::Variants),
164            SD::tdefkwd(..) => None,
165            SD::is_struct(..) => None,
166            SD::is_enum(..) => None,
167            SD::is_union(..) => None,
168            SD::v_is_unit(..) => Some(RO::Variants),
169            SD::v_is_tuple(..) => Some(RO::Variants),
170            SD::v_is_named(..) => Some(RO::Variants),
171            SD::tdefvariants(..) => None,
172            SD::fdefine(..) => Some(RO::Fields),
173            SD::vdefbody(..) => Some(RO::Variants),
174            SD::paste(body, ..) => recurse!(body),
175            SD::paste_spanned(span, content, ..) => {
176                span.analyse_repeat(visitor)?;
177                content.analyse_repeat(visitor)?;
178                None
179            }
180            SD::ChangeCase(body, ..) => recurse!(body),
181            SD::concat(body, ..) => recurse!(body),
182            SD::when(..) => None, // out-of-place when, ignore it
183            SD::define(..) => None,
184            SD::defcond(..) => None,
185            SD::UserDefined(..) => None,
186            SD::is_empty(_, content) => recurse!(content),
187            SD::approx_equal(_, ab) => {
188                for x in ab {
189                    x.analyse_repeat(visitor)?;
190                }
191                None
192            }
193            SD::not(cond, _) => recurse!(cond),
194            SD::If(conds, ..) | SD::select1(conds, ..) => recurse!(conds),
195            SD::any(conds, _) | SD::all(conds, _) => {
196                for c in conds.iter() {
197                    c.analyse_repeat(visitor)?;
198                }
199                None
200            }
201            // Has a RepeatOver, but does not imply anything about its context.
202            SD::For(..) => None,
203            SD::False(..) | SD::True(..) => None, // condition: ignore.
204            SD::error(ee, _) => {
205                ee.message.analyse_repeat(visitor)?;
206                if let Some((span, _)) = &ee.span {
207                    span.analyse_repeat(visitor)?;
208                }
209                None
210            }
211            SD::require_beta(..) => None,
212            SD::ignore(content, _) => recurse!(content),
213            SD::dbg(ddr) => recurse!(ddr.content_parsed),
214            SD::dbg_all_keywords(..) => None,
215            SD::Crate(..) => None,
216        };
217        if let Some(over) = over {
218            let over = RepeatOverInference {
219                over,
220                span: self.kw_span,
221            };
222            visitor.set_over(over)?;
223        }
224        Ok(())
225    }
226}
227
228/// Implemented for [`WithinVariant`] and [`WithinField`]
229///
230/// For combining code that applies similarly for different repeat levels.
231pub trait WithinRepeatLevel<'w>: 'w {
232    fn level_display_name() -> &'static str;
233
234    fn current(ctx: &'w Context) -> Option<&'w Self>;
235
236    /// Iterate over all the things at this level
237    ///
238    /// If it needs a current container of the next level up (eg, a
239    /// field needing a variant) and there is none current, iterates
240    /// over containing things too.
241    fn for_each<'c, F, E>(ctx: &'c Context<'c>, call: F) -> Result<(), E>
242    where
243        'c: 'w,
244        F: FnMut(&Context, &Self) -> Result<(), E>;
245
246    fn missing_repeat_level_special_error(
247        _ctx: &'w Context,
248        _span: Span,
249    ) -> Option<syn::Error> {
250        None
251    }
252}
253
254impl<'w> WithinRepeatLevel<'w> for WithinVariant<'w> {
255    fn level_display_name() -> &'static str {
256        "variant"
257    }
258
259    fn current(ctx: &'w Context) -> Option<&'w WithinVariant<'w>> {
260        ctx.variant
261    }
262
263    fn for_each<'c, F, E>(ctx: &'c Context<'c>, mut call: F) -> Result<(), E>
264    where
265        'c: 'w,
266        F: FnMut(&Context, &WithinVariant<'w>) -> Result<(), E>,
267    {
268        let mut within_variant =
269            |index, variant, ppv: &'c PreprocessedVariant| {
270                let fields = &ppv.fields;
271                let pmetas = &ppv.pmetas;
272                let pfields = &ppv.pfields;
273                let wv = WithinVariant {
274                    variant,
275                    fields,
276                    pmetas,
277                    pfields,
278                    index,
279                };
280                let wv = &wv;
281                let ctx = Context {
282                    variant: Some(wv),
283                    ..*ctx
284                };
285                call(&ctx, wv)
286            };
287        match &ctx.top.data {
288            syn::Data::Enum(syn::DataEnum { variants, .. }) => {
289                for (index, (variant, pvariant)) in
290                    izip!(variants, ctx.pvariants).enumerate()
291                {
292                    let index = index.try_into().expect(">=2^32 variants!");
293                    within_variant(index, Some(variant), pvariant)?;
294                }
295            }
296            syn::Data::Struct(_) | syn::Data::Union(_) => {
297                within_variant(0, None, &ctx.pvariants[0])?;
298            }
299        }
300        Ok(())
301    }
302}
303
304impl<'w> WithinRepeatLevel<'w> for WithinField<'w> {
305    fn level_display_name() -> &'static str {
306        "field"
307    }
308
309    fn current(ctx: &'w Context) -> Option<&'w WithinField<'w>> {
310        ctx.field
311    }
312
313    fn for_each<'c, F, E>(ctx: &'c Context<'c>, mut call: F) -> Result<(), E>
314    where
315        'c: 'w,
316        F: FnMut(&Context, &WithinField<'w>) -> Result<(), E>,
317    {
318        ctx.for_with_within(|ctx, variant: &WithinVariant| {
319            for (index, (field, pfield)) in
320                izip!(variant.fields, variant.pfields,).enumerate()
321            {
322                // Ideally WithinField would contain a within_variant field
323                // but the genercity of the lifetimes is hard to express.
324                // I haven't found a version that compiles, unless we
325                // *copy* the WithinVariant for each field.
326                let index = index.try_into().expect(">=2^32 fields!");
327                let wf = WithinField {
328                    field,
329                    index,
330                    pfield,
331                };
332                let wf = &wf;
333                let ctx = Context {
334                    field: Some(wf),
335                    ..*ctx
336                };
337                call(&ctx, wf)?;
338            }
339            Ok(())
340        })
341    }
342
343    fn missing_repeat_level_special_error(
344        ctx: &'w Context,
345        span: Span,
346    ) -> Option<syn::Error> {
347        if let Some(wv) = &ctx.variant {
348            return Some(span.error(
349                if wv.variant.is_some() {
350                    // Definitely within a variant repeat group.
351                    "must be within a field, so within a field repeat group; but, is only within a variant repeat group"
352                } else {
353                    // We have a WithinVariant but not a syn::Variant.
354                    // The driver isn't an enum.  We can't tell if we're
355                    // lexically within a variant repeat group.
356                    "must be within a field, so within a field repeat group"
357                }
358            ));
359        }
360        None
361    }
362}
363
364impl<'c> Context<'c> {
365    /// Returns an [`ErrorLoc`] for the current part of the driver
366    pub fn error_loc(&self) -> ErrorLoc<'static> {
367        if let Some(field) = &self.field {
368            (field.field.span(), "in this field")
369        } else if let Some(variant) =
370            &self.variant.and_then(|variant| variant.variant.as_ref())
371        {
372            (variant.span(), "in this variant")
373        } else {
374            (self.top.span(), "in this data structure")
375        }
376    }
377
378    /// Obtains the relevant `Within`(s), and calls `call` for each one
379    ///
380    /// If there is a current `W`, simply calls `call`.
381    /// Otherwise, iterates over all of them and calls `call` for each one.
382    pub fn for_with_within<'w, W, F, E>(&'c self, mut call: F) -> Result<(), E>
383    where
384        'c: 'w,
385        W: WithinRepeatLevel<'w>,
386        F: FnMut(&Context, &W) -> Result<(), E>,
387    {
388        let ctx = self;
389        if let Some(w) = W::current(ctx) {
390            call(ctx, w)?;
391        } else {
392            W::for_each(ctx, call)?;
393        }
394        Ok(())
395    }
396
397    /// Obtains the current `Within` of type `W`
398    ///
399    /// Demands that there actually is a current container `W`.
400    /// If we aren't, calls it an error.
401    fn within_level<W>(&'c self, why: &dyn Spanned) -> syn::Result<&'c W>
402    where
403        W: WithinRepeatLevel<'c>,
404    {
405        W::current(self).ok_or_else(|| {
406            let span = why.span();
407            W::missing_repeat_level_special_error(self, span).unwrap_or_else(
408                || {
409                    span.error(format_args!(
410                        "must be within a {} (so, in a repeat group)",
411                        W::level_display_name(),
412                    ))
413                },
414            )
415        })
416    }
417
418    /// Obtains the current field (or calls it an error)
419    pub fn field(&self, why: &dyn Spanned) -> syn::Result<&WithinField<'_>> {
420        self.within_level(why)
421    }
422    /// Obtains the current variant (or calls it an error)
423    pub fn variant(
424        &self,
425        why: &dyn Spanned,
426    ) -> syn::Result<&WithinVariant<'_>> {
427        self.within_level(why)
428    }
429    /// Obtains the current variant as a `syn::Variant`
430    pub fn syn_variant(
431        &self,
432        why: &dyn Spanned,
433    ) -> syn::Result<&syn::Variant> {
434        let r = self.variant(why)?.variant.as_ref().ok_or_else(|| {
435            why.span().error("expansion only valid in enums")
436        })?;
437        Ok(r)
438    }
439}
440
441//---------- Fname ----------
442
443impl<'w> WithinField<'w> {
444    /// What would `${fname}` expand to?
445    pub fn fname(&self, tspan: Span) -> Fname<'_> {
446        if let Some(fname) = &self.field.ident {
447            // todo is this the right span to emit?
448            Fname::Name(fname)
449        } else {
450            Fname::Index(syn::Index {
451                index: self.index,
452                span: tspan,
453            })
454        }
455    }
456}
457
458impl IdentFrag for Fname<'_> {
459    type BadIdent = IdentFragInfallible;
460    fn frag_to_tokens(
461        &self,
462        out: &mut TokenStream,
463    ) -> Result<(), IdentFragInfallible> {
464        Ok(self.to_tokens(out))
465    }
466    fn fragment(&self) -> String {
467        self.to_string()
468    }
469}
470impl Display for Fname<'_> {
471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472        match self {
473            Fname::Name(v) => quote::IdentFragment::fmt(v, f),
474            Fname::Index(v) => quote::IdentFragment::fmt(v, f),
475        }
476    }
477}
478impl ToTokens for Fname<'_> {
479    fn to_tokens(&self, out: &mut TokenStream) {
480        match self {
481            Fname::Name(v) => v.to_tokens(out),
482            Fname::Index(v) => v.to_tokens(out),
483        }
484    }
485}
486
487//---------- useful impl ----------
488
489impl<'w> WithinVariant<'w> {
490    pub fn is_struct_toplevel_as_variant(&self) -> bool {
491        self.variant.is_none()
492    }
493}
494
495//---------- definitions (user-defined keywords) ----------
496
497impl<'c> GeneralContext<'c> {
498    pub fn find_definition<B>(
499        &'c self,
500        call: &'c DefinitionName,
501    ) -> syn::Result<Option<(&'c Definition<B>, GeneralContextBuf<'c>)>>
502    where
503        Definitions<'c>: AsRef<[&'c Definition<B>]>,
504        B: 'static,
505    {
506        let def = match self.defs().defs.find_raw(call) {
507            Some(y) => y,
508            None => return Ok(None),
509        };
510
511        let defs = self.defs().find_definition_deeper(&def.name, call)?;
512        let mut self_ = self.clone_buf();
513        *self_.as_mut() = defs;
514        Ok(Some((def, self_)))
515    }
516}
517
518impl<'c> DefinitionsContext<'c> {
519    /// Internal function for use by `find_definition`
520    pub fn find_definition_deeper(
521        &'c self,
522        def: &'c DefinitionName,
523        call: &'c DefinitionName,
524    ) -> syn::Result<DefinitionsContext<'c>> {
525        let nesting_depth = self.nesting_depth + 1;
526        let stack_entry = (self, call);
527        if nesting_depth > NESTING_LIMIT {
528            // We report the definition site of the innermost reference:
529            let mut errs = def.error(format_args!(
530 "probably-recursive user-defined expansion/condition (more than {} deep)",
531                NESTING_LIMIT
532            ));
533            // And the unique reference sites from the call stack
534            let calls = {
535                let mut ascend = Some(stack_entry);
536                iter::from_fn(|| {
537                    let (ctx, call) = ascend?;
538                    ascend = ctx.nesting_parent;
539                    Some((call, ctx.nesting_depth))
540                })
541                .collect_vec()
542            };
543
544            // Collect and reverse because we preferentially want
545            // to display less deep entries (earlier ones), which are
546            // furthest away in the stack chain.
547
548            let calls = calls
549                .iter()
550                .rev()
551                .unique_by(
552                    // De-dup by pointer identity on the name as found
553                    // at the call site.  These are all references
554                    // nodes in our template AST, so this is correct.
555                    |(call, _)| *call as *const DefinitionName,
556                )
557                .collect_vec();
558
559            // We report the deepest errors first, since they're
560            // definitely implicated in the cycle and more interesting.
561            // (So this involves collecting and reversing again.)
562            for (call, depth) in calls.iter().rev() {
563                errs.combine(call.error(format_args!(
564             "reference involved in too-deep expansion/condition, depth {}",
565                    depth,
566                )));
567            }
568            return Err(errs);
569        }
570        Ok(DefinitionsContext {
571            nesting_depth,
572            nesting_parent: Some(stack_entry),
573            ..*self
574        })
575    }
576}
577
578pub struct DefinitionsIter<'c, B>(
579    Option<&'c Definitions<'c>>,
580    PhantomData<&'c B>,
581);
582
583impl<'c, B> Iterator for DefinitionsIter<'c, B>
584where
585    Definitions<'c>: AsRef<[&'c Definition<B>]>,
586{
587    type Item = &'c [&'c Definition<B>];
588    fn next(&mut self) -> Option<Self::Item> {
589        let here = self.0?;
590        let r = here.as_ref();
591        self.0 = here.earlier;
592        Some(r)
593    }
594}
595
596impl<'c> Definitions<'c> {
597    pub fn iter<B>(&'c self) -> DefinitionsIter<'c, B>
598    where
599        Definitions<'c>: AsRef<[&'c Definition<B>]>,
600    {
601        DefinitionsIter(Some(self), PhantomData)
602    }
603
604    /// Find the definition of `name` as a `B`, without recursion checking
605    ///
606    /// The caller is responsible for preventing unbounded recursion.
607    pub fn find_raw<B>(
608        &'c self,
609        name: &DefinitionName,
610    ) -> Option<&'c Definition<B>>
611    where
612        Definitions<'c>: AsRef<[&'c Definition<B>]>,
613        B: 'static,
614    {
615        self.iter()
616            .map(|l| l.iter().rev())
617            .flatten()
618            .find(|def| &def.name == name)
619            .cloned()
620    }
621}
622
623impl<'c> AsRef<[&'c Definition<DefinitionBody>]> for Definitions<'c> {
624    fn as_ref(&self) -> &[&'c Definition<DefinitionBody>] {
625        self.here
626    }
627}
628impl<'c> AsRef<[&'c Definition<DefCondBody>]> for Definitions<'c> {
629    fn as_ref(&self) -> &[&'c Definition<DefCondBody>] {
630        self.conds
631    }
632}