1use super::framework::*;
7
8impl<O> Expand<O> for SubstIf<O>
9where
10 Template<O>: ExpandInfallible<O>,
11 O: ExpansionOutput,
12{
13 fn expand<'c>(
14 &self,
15 ctx: GeneralContext<'c>,
16 out: &mut O,
17 ) -> syn::Result<()> {
18 for (condition, consequence) in &self.tests {
19 if condition.eval_bool(ctx)? {
21 consequence.expand(ctx, out);
23 return Ok(());
24 }
25 }
26 if let Some(consequence) = &self.otherwise {
27 consequence.expand(ctx, out);
29 }
30 Ok(())
31 }
32}
33
34impl<O> SubstIf<O>
35where
36 Template<O>: ExpandInfallible<O>,
37 O: ExpansionOutput,
38{
39 fn expand_select1<'c>(
40 &self,
41 ctx: GeneralContext<'c>,
42 out: &mut O,
43 ) -> syn::Result<()> {
44 let mut found: Result<Option<(Span, &Template<O>)>, Vec<ErrorLoc>> =
45 Ok(None);
46
47 for (condition, consequence) in &self.tests {
48 if !condition.eval_bool(ctx)? {
49 continue;
50 }
51 let cspan = condition.span();
52 let error_loc = |span| (span, "true condition");
53 match &mut found {
54 Ok(None) => found = Ok(Some((cspan, consequence))),
55 Ok(Some((span1, _))) => {
56 found = Err(ctx.prepend_error_loc(&[
57 error_loc(*span1),
58 error_loc(cspan),
59 ]))
60 }
61 Err(several) => several.push(error_loc(cspan)),
62 }
63 }
64 let found = found
65 .map_err(|several| several.error("multiple conditions matched"))?
66 .map(|(_cspan, consequence)| consequence)
67 .or(self.otherwise.as_deref())
68 .ok_or_else(|| {
69 ctx.prepend_error_loc(
70 &[(self.kw_span, "select1 expansion")], )
72 .error("no conditions matched, and no else clause")
73 })?;
74 found.expand(ctx, out);
75 Ok(())
76 }
77}
78
79impl SubstVType {
80 fn expand(
81 &self,
82 ctx: &Context,
83 out: &mut TokenAccumulator,
84 kw_span: Span,
85 self_def: SubstDetails<TokenAccumulator>,
86 ) -> syn::Result<()> {
87 let expand_spec_or_sd =
88 |out: &mut _,
89 spec: &Option<Argument<TokenAccumulator>>,
90 sd: SubstDetails<TokenAccumulator>| {
91 if let Some(spec) = spec {
92 spec.expand(ctx.as_general(), out);
93 Ok(())
94 } else {
95 sd.expand(ctx.as_general(), out, kw_span)
96 }
97 };
98
99 if !ctx.is_enum() {
100 return expand_spec_or_sd(out, &self.self_, self_def);
101 }
102 let mut self_ty = TokenAccumulator::new();
117 expand_spec_or_sd(&mut self_ty, &self.self_, self_def)?;
118 let self_ty = self_ty.tokens()?;
119 let mut self_ty: syn::Path =
120 syn::parse2(self_ty).map_err(|mut e| {
121 e.combine(kw_span.error(
122 "error re-parsing self type path for this expansion",
123 ));
124 e
125 })?;
126
127 let mut generics = mem::take(
128 &mut self_ty
129 .segments
130 .last_mut()
131 .ok_or_else(|| {
132 kw_span.error(
133 "self type path for this expansion is empty path!",
134 )
135 })?
136 .arguments,
137 );
138
139 out.append(self_ty);
140 out.append(Token);
141 expand_spec_or_sd(out, &self.vname, SD::vname(Default::default()))?;
142 let gen_content = match &mut generics {
143 syn::PathArguments::AngleBracketed(content) => Some(content),
144 syn::PathArguments::None => None,
145 syn::PathArguments::Parenthesized(..) => {
146 return Err([
147 (generics.span(), "generics"),
148 (kw_span, "template keyword"),
149 ]
150 .error("self type has parenthesised generics, not supported"))
151 }
152 };
153 if let Some(gen_content) = gen_content {
154 gen_content
156 .colon2_token
157 .get_or_insert_with(|| Token);
158 out.append(&generics);
159 }
160 Ok(())
161 }
162}
163
164impl SubstVPat {
165 fn expand(
168 &self,
169 ctx: &Context,
170 out: &mut TokenAccumulator,
171 kw_span: Span,
172 ) -> syn::Result<()> {
173 let self_def = SD::tname(Default::default());
174 SubstVType::expand(&self.vtype, ctx, out, kw_span, self_def)?;
175
176 let in_braces = braced_group(kw_span, |mut out| {
177 WithinField::for_each(ctx, |ctx, field| {
178 SD::fname::<TokenAccumulator>(()).expand(
179 ctx.as_general(),
180 &mut out,
181 kw_span,
182 )?;
183 out.append_tokens(&((), ()), Token)?;
184
185 let mut paste = paste::Items::new(kw_span);
189 if let Some(fprefix) = &self.fprefix {
190 fprefix.expand(ctx.as_general(), &mut paste);
191 } else {
192 paste.append_fixed_string("f_");
193 }
194 paste.append_identfrag_toks(&field.fname(kw_span))?;
195 paste.assemble(out, None)?;
196 out.append(Token);
197
198 Ok::<_, syn::Error>(())
199 })
200 })?;
201 out.append(in_braces);
202 Ok(())
203 }
204}
205
206impl<O> ExpandInfallible<O> for Template<O>
207where
208 TemplateElement<O>: Expand<O>,
209 O: ExpansionOutput,
210{
211 fn expand<'c>(&self, ctx_in: GeneralContext<'c>, out: &mut O) {
212 Self::expand_iter(&self.elements, ctx_in, out)
213 }
214}
215
216impl<'s, O> Template<O>
217where
218 TemplateElement<O>: Expand<O>,
219 O: ExpansionOutput + 's,
220{
221 pub fn expand_iter<'c>(
222 elements: impl IntoIterator<Item = &'s TemplateElement<O>>,
223 ctx_in: GeneralContext<'c>,
224 out: &mut O,
225 ) {
226 let mut ctx_buf;
227 let mut definitions_here = vec![];
228 let mut defconds_here = vec![];
229 let mut ctx = ctx_in;
230
231 for element in elements {
232 macro_rules! handle_definition { {
233 $variant:ident, $store:expr
234 } => {
235 if let TE::Subst(Subst {
236 sd: SD::$variant(def, _),
237 ..
238 }) = element
239 {
240 $store.push(def);
243 ctx_buf = ctx_in.clone_buf();
244 ctx_buf.as_mut().defs = Definitions {
245 earlier: Some(&ctx_in.defs().defs),
246 here: &definitions_here,
247 conds: &defconds_here,
248 };
249 ctx = ctx_buf.as_ref();
250 continue;
251 }
252
253 } }
254
255 handle_definition!(define, definitions_here);
256 handle_definition!(defcond, defconds_here);
257
258 let () = element
259 .expand(ctx, out)
260 .unwrap_or_else(|err| out.record_error(err));
261 }
262 }
263}
264
265impl Expand<TokenAccumulator> for TemplateElement<TokenAccumulator> {
266 fn expand<'c>(
267 &self,
268 ctx: GeneralContext<'c>,
269 out: &mut TokenAccumulator,
270 ) -> syn::Result<()> {
271 match self {
272 TE::Ident(tt, ..) => out.append(tt.clone()),
273 TE::Literal(tt, ..) => out.append(tt.clone()),
274 TE::LitStr(tt) => out.append(tt.clone()),
275 TE::Punct(tt, _) => out.append(tt.clone()),
276 TE::Group {
277 delim_span,
278 delimiter,
279 template,
280 allow_tokens: _,
281 } => {
282 let mut content = TokenAccumulator::new();
283 template.expand(ctx, &mut content);
284 let group = group_new_with_span(
285 *delimiter,
286 *delim_span,
287 content.tokens()?,
288 );
289 out.append(TT::Group(group));
290 }
291 TE::Subst(exp) => {
292 exp.expand(ctx, out)?;
293 }
294 TE::Repeat(repeated_template) => {
295 repeated_template.expand(ctx, out);
296 }
297 }
298 Ok(())
299 }
300}
301
302impl<O> Expand<O> for Subst<O>
303where
304 O: ExpansionOutput,
305 TemplateElement<O>: Expand<O>,
306{
307 fn expand<'c>(
308 &self,
309 ctx: GeneralContext<'c>,
310 out: &mut O,
311 ) -> syn::Result<()> {
312 self.sd.expand(ctx, out, self.kw_span)
313 }
314}
315
316impl<O> SubstDetails<O>
317where
318 O: ExpansionOutput,
319 TemplateElement<O>: Expand<O>,
320{
321 fn expand<'c>(
325 &self,
326 gctx: GeneralContext<'c>,
327 out: &mut O,
328 kw_span: Span,
329 ) -> syn::Result<()> {
330 let ctx = gctx.full_ctx(kw_span);
333
334 let do_meta = |sm: &meta::SubstMeta<_>, out, meta| {
335 sm.expand(ctx?, kw_span, out, meta)
336 };
337
338 let do_tgnames = |out: &mut TokenAccumulator,
344 ctx: &Context,
345 composable| {
346 for pair in ctx.top.generics.params.pairs() {
347 use syn::GenericParam as GP;
348 match pair.value() {
349 GP::Type(t) => out.append(&t.ident),
350 GP::Const(c) => out.append(&c.ident),
351 GP::Lifetime(l) => out.append(&l.lifetime),
352 }
353 out.append_maybe_punct_composable(&pair.punct(), composable);
354 }
355 };
356 let do_tgens_nodefs = |out: &mut TokenAccumulator| {
357 for pair in ctx?.top.generics.params.pairs() {
358 use syn::GenericParam as GP;
359 let out_attrs = |out: &mut TokenAccumulator, attrs: &[_]| {
360 attrs.iter().for_each(|attr| out.append(attr));
361 };
362 match pair.value() {
363 GP::Type(t) => {
364 out_attrs(out, &t.attrs);
365 out.append(&t.ident);
366 out.append(&t.colon_token);
367 out.append(&t.bounds);
368 }
369 GP::Const(c) => {
370 out_attrs(out, &c.attrs);
371 out.append(&c.const_token);
372 out.append(&c.ident);
373 out.append(&c.colon_token);
374 out.append(&c.ty);
375 }
376 GP::Lifetime(l) => out.append(&l),
377 }
378 out.with_tokens(|out| {
379 pair.punct().to_tokens_punct_composable(out);
380 });
381 }
382 Ok::<_, MissingContextError>(())
383 };
384 let do_tgens =
385 |out: &mut TokenAccumulator, ctx: &Context, composable: bool| {
386 out.append_maybe_punct_composable(
387 &ctx.top.generics.params,
388 composable,
389 );
390 };
391
392 let do_ttype = |out: &mut O, colons: Option<()>, do_some_gens| {
399 let _: &dyn Fn(&mut _, _, bool) = do_some_gens; let ctx = ctx?;
401 let gens = &ctx.top.generics;
402 let colons = gens
403 .lt_token
404 .and_then(|_| colons.map(|()| Token));
405 out.append_idpath(
406 kw_span,
407 |_| {},
408 &ctx.top.ident,
409 |out| {
410 out.append(colons);
411 out.append(gens.lt_token);
412 do_some_gens(out, ctx, false);
413 out.append(gens.gt_token);
414 },
415 Grouping::Ungrouped,
416 )
417 .unwrap_or_else(|e| e.unreachable());
418 Ok::<_, MissingContextError>(())
419 };
420
421 let do_maybe_delimited_group = |out, np, delim, content| {
422 let _: &mut O = out;
423 let _: &Template<TokenAccumulator> = content;
424 out.append_tokens_with(np, |out| {
425 if let Some(delim) = delim {
426 out.append(delimit_token_group(
427 delim,
428 kw_span,
429 |inside: &mut TokenAccumulator| {
430 Ok(content.expand(gctx, inside))
431 },
432 )?);
433 } else {
434 content.expand(gctx, out);
435 }
436 Ok(())
437 })
438 };
439
440 let do_index = |out: &mut O, index| {
441 let index = syn::Index {
442 index,
443 span: kw_span,
444 };
445 out.append_identfrag_toks(&TokenPastesAsIdent(index))
446 };
447
448 match self {
449 SD::tname(_) => out.append_identfrag_toks(&ctx?.top.ident)?,
450 SD::ttype(_) => do_ttype(out, Some(()), &do_tgnames)?,
451 SD::tdeftype(_) => do_ttype(out, None, &do_tgens)?,
452 SD::vname(_) => {
453 out.append_identfrag_toks(&ctx?.syn_variant(&kw_span)?.ident)?
454 }
455 SD::fname(_) => {
456 let fname = ctx?.field(&kw_span)?.fname(kw_span);
457 out.append_identfrag_toks(&fname)?;
458 }
459 SD::ftype(_) => {
460 let f = ctx?.field(&kw_span)?;
461 out.append_syn_type(
462 kw_span,
463 f.field.ty.clone(),
464 Grouping::Invisible,
465 );
466 }
467 SD::fpatname(_) => {
468 let f = ctx?.field(&kw_span)?;
469 let fpatname =
470 Ident::new(&format!("f_{}", f.fname(kw_span)), kw_span);
471 out.append_identfrag_toks(&fpatname)?;
472 }
473 SD::vindex(..) => do_index(out, ctx?.variant(&kw_span)?.index)?,
474 SD::findex(..) => do_index(out, ctx?.field(&kw_span)?.index)?,
475
476 SD::Xmeta(sm) => do_meta(sm, out, sm.pmetas(ctx?, kw_span)?)?,
477 SD::error(e, _) => e.throw(gctx, kw_span)?,
478
479 SD::Vis(vis, at) => {
480 out.append_tokens(at, vis.syn_vis(ctx?, kw_span)?)?
481 }
482 SD::tdefkwd(_) => {
483 fn w<O>(out: &mut O, t: impl ToTokens)
484 where
485 O: ExpansionOutput,
486 {
487 out.append_identfrag_toks(&TokenPastesAsIdent(t))
488 .unwrap_or_else(|e| e.unreachable());
489 }
490 use syn::Data::*;
491 match &ctx?.top.data {
492 Struct(d) => w(out, &d.struct_token),
493 Enum(d) => w(out, &d.enum_token),
494 Union(d) => w(out, &d.union_token),
495 };
496 }
497
498 SD::tattrs(ra, np, ..) => out.append_tokens_with(np, |out| {
499 ra.expand(ctx?, out, &ctx?.top.attrs)
500 })?,
501 SD::vattrs(ra, np, ..) => out.append_tokens_with(np, |out| {
502 let variant = ctx?.variant(&kw_span)?.variant;
503 let attrs = variant.as_ref().map(|v| &*v.attrs);
504 ra.expand(ctx?, out, attrs.unwrap_or_default())
505 })?,
506 SD::fattrs(ra, np, ..) => out.append_tokens_with(np, |out| {
507 ra.expand(ctx?, out, &ctx?.field(&kw_span)?.field.attrs)
508 })?,
509
510 SD::tgens(np, ..) => out.append_tokens_with(np, |out| {
511 do_tgens_nodefs(out)?;
512 Ok(())
513 })?,
514 SD::tdefgens(np, ..) => out.append_tokens_with(np, |out| {
515 do_tgens(out, ctx?, true);
516 Ok(())
517 })?,
518 SD::tgnames(np, ..) => out.append_tokens_with(np, |out| {
519 do_tgnames(out, ctx?, true);
520 Ok(())
521 })?,
522 SD::twheres(np, ..) => out.append_tokens_with(np, |out| {
523 if let Some(clause) = &ctx?.top.generics.where_clause {
524 out.with_tokens(|out| {
525 clause.predicates.to_tokens_punct_composable(out);
526 });
527 }
528 Ok(())
529 })?,
530
531 SD::vpat(v, np, ..) => out.append_tokens_with(np, |out| {
532 v.expand(ctx?, out, kw_span)
534 })?,
535 SD::vtype(v, np, ..) => out.append_tokens_with(np, |out| {
536 v.expand(ctx?, out, kw_span, SD::ttype(Default::default()))
537 })?,
538
539 SD::tdefvariants(content, np, ..) => {
540 let delim = if ctx?.is_enum() {
541 Some(Delimiter::Brace)
542 } else {
543 None
544 };
545 do_maybe_delimited_group(out, np, delim, content)?;
546 }
547 SD::fdefine(spec_f, np, ..) => {
548 out.append_tokens_with(np, |out| {
549 let field = ctx?.field(&kw_span)?.field;
550 if let Some(driver_f) = &field.ident {
551 if let Some(spec_f) = spec_f {
552 spec_f.expand(gctx, out);
553 } else {
554 out.append(driver_f);
555 }
556 }
557 out.append(&field.colon_token);
558 Ok(())
559 })?
560 }
561 SD::vdefbody(vname, content, np, ..) => {
562 use syn::Fields as SF;
563 let variant = ctx?.variant(&kw_span)?;
564 let struct_variant = variant.is_struct_toplevel_as_variant();
565 if !struct_variant {
566 vname.expand(gctx, out);
567 }
568 let delim = match variant.fields {
569 SF::Unit => None,
570 SF::Unnamed(..) => Some(Delimiter::Parenthesis),
571 SF::Named(..) => Some(Delimiter::Brace),
572 };
573 do_maybe_delimited_group(out, np, delim, content)?;
574 if !struct_variant {
575 out.append_tokens(np, Token)?;
577 } else if matches!(variant.fields, SF::Named(_)) {
578 } else {
580 out.append_tokens(np, Token)?;
582 }
583 }
584 SD::Crate(np, ..) => {
585 out.append_tokens(np, &ctx?.template_crate)?
586 }
587
588 SD::paste(content, ..) => {
589 paste::expand(gctx, kw_span, content, out)?;
590 }
591 SD::paste_spanned(span, content, ..) => {
592 let span = span.span_from_arg(gctx).unwrap_or_else(|e| {
593 out.record_error(e);
594 kw_span
595 });
596 paste::expand(gctx, span, content, out)?;
597 }
598 SD::ChangeCase(content, case, ..) => {
599 let mut items = paste::Items::new(kw_span);
600 content.expand(gctx, &mut items);
601 items.assemble(out, Some(*case))?;
602 }
603 SD::concat(content, _not_in_bool, not_in_paste, _) => {
604 let mut accum = concat::Accumulator::new_with_span(kw_span);
605 content.expand(gctx, &mut accum);
606 accum.finish_onto(not_in_paste, out);
607 }
608
609 SD::define(..) | SD::defcond(..) => out.write_error(
610 &kw_span,
611 "${define } and ${defcond } only allowed in a full template",
619 ),
620 SD::UserDefined(name) => name.lookup_expand(gctx, out)?,
621
622 SD::ignore(content, _) => {
623 let mut ignore = O::new_with_span(kw_span);
624 content.expand(gctx, &mut ignore);
625 let () = ignore.ignore_impl()?;
626 }
627 SD::when(..) => out.write_error(
628 &kw_span,
629 "internal error - misplaced ${when } detected too late!",
630 ),
631 SD::If(conds, ..) => conds.expand(gctx, out)?,
632 SD::select1(conds, ..) => conds.expand_select1(gctx, out)?,
633 SD::For(repeat, _) => repeat.expand(gctx, out),
634
635 SD::require_beta(..) => {}
636 SD::dbg(ddr) => ddr.expand(gctx, out, kw_span),
637 SD::dbg_all_keywords(_) => dbg_allkw::dump(ctx?),
638
639 SD::is_struct(bo)
641 | SD::is_enum(bo)
642 | SD::is_union(bo)
643 | SD::v_is_unit(bo)
644 | SD::v_is_tuple(bo)
645 | SD::v_is_named(bo)
646 | SD::is_empty(bo, _)
647 | SD::approx_equal(bo, _)
648 | SD::False(bo)
649 | SD::True(bo)
650 | SD::not(_, bo)
651 | SD::any(_, bo)
652 | SD::all(_, bo) => out.append_bool_only(bo),
653 };
654 Ok(())
655 }
656}
657
658impl<O: ExpansionOutput> DbgDumpRequest<O> {
659 fn expand<'c>(&self, ctx: GeneralContext<'c>, out: &mut O, kw_span: Span) {
660 let desc =
661 format!("derive-deftly dbg dump {}", self.display_heading(ctx),);
662
663 let mut msg = String::new();
664 let () = self.content_string;
665 writeln!(
666 msg, r#"---------- {} expansion (start) ----------"#,
668 desc,
669 )
670 .expect("write to String failed");
671
672 out.dbg_expand(kw_span, ctx, &mut msg, &self.content_parsed)
673 .expect("write dbg expansion info failed");
674
675 writeln!(
676 msg,
677 r#"
678---------- {} expansion (end) ----------"#,
679 desc
680 )
681 .expect("write to String failed");
682
683 eprint!("{}", msg);
684 }
685}
686
687impl ExplicitError {
688 pub fn throw<'c, T>(
689 &self,
690 gctx: GeneralContext<'c>,
691 kw_span: Span,
692 ) -> Result<T, syn::Error> {
693 let mut message = concat::Accumulator::new_with_span(kw_span);
694 self.message.expand(gctx, &mut message);
695 let message = message.finish_literal()?;
696
697 let explicit_loc = self
698 .span
699 .as_ref()
700 .map(|(span, _)| {
701 let span = span.span_from_arg(gctx)?;
702 let frag = (|| {
703 let ctx = gctx.full_ctx_raw().ok()?;
704 let templ = ctx.template_name?.to_token_stream();
705 Some(format!("reported by {}", templ))
706 })()
707 .unwrap_or_else(|| format!("reported by template"));
708 Ok::<_, syn::Error>((span, frag))
709 })
710 .transpose()?;
711
712 let message_loc = (message.span(), "template error message");
713 let locs = chain!(
714 explicit_loc.as_ref().map(|(s, f)| (*s, &**f)), gctx.error_loc(),
716 [message_loc],
717 )
718 .collect_vec();
719
720 Err(locs.error(message.value()))
721 }
722}
723
724impl DefinitionName {
725 fn lookup_expand<'c, O: ExpansionOutput>(
726 &self,
727 ctx: GeneralContext<'c>,
728 out: &mut O,
729 ) -> syn::Result<()> {
730 let (def, ctx) = ctx.find_definition(self)?.ok_or_else(|| {
731 self.error(format!("user-defined expansion `{}` not found", self))
732 })?;
733
734 let not_in_paste = || {
735 O::not_in_paste(self).map_err(|mut unpasteable| {
736 unpasteable.combine(def.body_span.error(
737 "user-defined expansion is not pasteable because it isn't, itself, ${paste }"
738 ));
739 unpasteable
740 })
741 };
742 let not_in_concat = || {
743 O::not_in_concat(self).map_err(|mut unconcatable| {
744 unconcatable.combine(def.body_span.error(
745"user-defined expansion is not concatenable because it isn't, itself, ${concat } or ${paste }"
746 ));
747 unconcatable
748 })
749 };
750 let ctx = ctx.as_ref();
751
752 match &def.body {
753 DefinitionBody::Paste(content) => {
754 paste::expand(ctx, def.body_span, content, out)?;
755 }
756 DefinitionBody::Concat(content) => {
757 let mut inner =
758 concat::Accumulator::new_with_span(def.body_span);
759 content.expand(ctx, &mut inner);
760 inner.finish_onto(¬_in_paste()?, out);
761 }
762 DefinitionBody::Normal(content) => {
763 let ok = (not_in_paste()?, not_in_concat()?);
764 out.append_tokens_with(&ok, |out| {
765 content.expand(ctx, out);
766 Ok(())
767 })?;
768 }
769 }
770 Ok(())
771 }
772}
773
774impl RawAttr {
775 fn expand(
776 &self,
777 ctx: &Context,
778 out: &mut TokenAccumulator,
779 attrs: &[syn::Attribute],
780 ) -> syn::Result<()> {
781 for attr in attrs {
782 match self {
783 RawAttr::Default => {
784 if ["deftly", "derive_deftly", "derive_deftly_adhoc"]
785 .iter()
786 .all(|exclude| !attr.path().is_ident(exclude))
787 {
788 out.append(attr);
789 }
790 }
791 RawAttr::Include { entries } => {
792 let ent = entries.iter().find(|ent| ent.matches(attr));
793 if let Some(ent) = ent {
794 ent.expand(ctx, out, attr)?;
795 }
796 }
797 RawAttr::Exclude { exclusions } => {
798 if !exclusions.iter().any(|excl| excl == attr.path()) {
799 out.append(attr);
800 }
801 }
802 }
803 }
804 Ok(())
805 }
806}
807
808impl RawAttrEntry {
809 fn matches(&self, attr: &syn::Attribute) -> bool {
810 &self.path == attr.path()
811 }
812
813 fn expand(
814 &self,
815 _ctx: &Context,
816 out: &mut TokenAccumulator,
817 attr: &syn::Attribute,
818 ) -> syn::Result<()> {
819 out.append(attr);
820 Ok(())
821 }
822}
823
824impl<O> ExpandInfallible<O> for RepeatedTemplate<O>
825where
826 Template<O>: ExpandInfallible<O>,
827 O: ExpansionOutput,
828{
829 fn expand<'c>(&self, ctx: GeneralContext<'c>, out: &mut O) {
830 let ctx = match ctx.full_ctx(self.span) {
831 Ok(y) => y,
832 Err(e) => {
833 out.record_error(e.into());
834 return;
835 }
836 };
837
838 #[allow(clippy::unit_arg)] match self.over {
843 RO::Variants => ctx.for_with_within(|ctx, _: &WithinVariant| {
844 Ok::<_, Void>(self.expand_inner(ctx, out))
845 }),
846 RO::Fields => ctx.for_with_within(|ctx, _: &WithinField| {
847 Ok::<_, Void>(self.expand_inner(ctx, out))
848 }),
849 }
850 .void_unwrap()
851 }
852}
853
854impl<O: ExpansionOutput> RepeatedTemplate<O> {
855 fn expand_inner(&self, ctx: &Context, out: &mut O)
857 where
858 Template<O>: ExpandInfallible<O>,
859 O: ExpansionOutput,
860 {
861 let mut ctx = ctx.clone();
862 ctx.within_loop = WithinLoop::When;
863
864 for when in &self.whens {
865 match when.eval_bool(ctx.as_general()) {
866 Ok(true) => continue,
867 Ok(false) => return,
868 Err(e) => {
869 out.record_error(e);
870 return;
871 }
872 }
873 }
874
875 ctx.within_loop = WithinLoop::Body;
876 self.template.expand(ctx.as_general(), out)
877 }
878}