1use super::framework::*;
9
10pub use SubstDetails as SD;
11pub use TemplateElement as TE;
12
13#[derive(Debug, Default)]
14pub struct Template<O: SubstParseContext> {
16 pub elements: Vec<TemplateElement<O>>,
18}
19
20#[derive(Debug)]
21pub struct TopTemplate {
22 content: Template<TokenAccumulator>,
23}
24impl_deref!(TopTemplate, content, Template<TokenAccumulator>);
25
26#[derive(Debug)]
37pub struct Argument<O: SubstParseContext = TokenAccumulator>(pub Template<O>);
38
39#[derive(Debug)]
40pub struct TemplateWithWhens<O: SubstParseContext> {
41 pub elements: Vec<TemplateElement<O>>,
42}
43
44#[derive(Debug)]
45pub enum TemplateElement<O: SubstParseContext> {
46 Ident(Ident, O::NotInConcat),
47 LitStr(syn::LitStr),
48 Literal(syn::Lit, AllowTokens<O>),
50 Punct(Punct, AllowTokens<O>),
51 Group {
52 delim_span: Span,
54 delimiter: Delimiter,
55 template: Template<O>,
56 allow_tokens: AllowTokens<O>,
57 },
58 Subst(Subst<O>),
60 Repeat(RepeatedTemplate<O>),
61}
62
63#[derive(Debug)]
64pub struct RepeatedTemplate<O: SubstParseContext> {
65 pub span: Span,
66 pub template: Template<O>,
67 #[allow(clippy::vec_box)]
68 pub whens: Vec<Box<Subst<BooleanContext>>>,
69 pub over: RepeatOver,
70}
71
72#[derive(Debug)]
73pub struct Subst<O: SubstParseContext> {
74 pub kw_span: Span,
75 pub sd: SubstDetails<O>,
77}
78
79pub type Condition = Subst<BooleanContext>;
85
86#[allow(non_camel_case_types)] #[derive(Debug)]
104pub enum SubstDetails<O: SubstParseContext> {
105 tname(O::NotInBool),
107 ttype(O::NotInBool),
108 tdeftype(O::NotInBool),
109 vname(O::NotInBool),
110 fname(O::NotInBool),
111 ftype(O::NotInBool),
112 fpatname(O::NotInBool),
113 Vis(SubstVis, AllowTokens<O>), tdefkwd(O::NotInBool),
115 vindex(O::NotInBool, beta::Enabled),
116 findex(O::NotInBool, beta::Enabled),
117
118 Xmeta(meta::SubstMeta<O>),
120 tattrs(RawAttr, AllowTokens<O>, O::NotInBool),
121 vattrs(RawAttr, AllowTokens<O>, O::NotInBool),
122 fattrs(RawAttr, AllowTokens<O>, O::NotInBool),
123
124 tgens(AllowTokens<O>),
126 tdefgens(AllowTokens<O>, O::NotInBool),
127 tgnames(AllowTokens<O>, O::NotInBool),
128 twheres(AllowTokens<O>, O::NotInBool),
129
130 vpat(SubstVPat, AllowTokens<O>, O::NotInBool),
131 vtype(SubstVType, AllowTokens<O>, O::NotInBool),
132
133 tdefvariants(Template<TokenAccumulator>, AllowTokens<O>, O::NotInBool),
134 fdefine(Option<Argument>, AllowTokens<O>, O::NotInBool),
135 vdefbody(
136 Argument<O>,
137 Template<TokenAccumulator>,
138 AllowTokens<O>,
139 O::NotInBool,
140 ),
141
142 paste(Template<paste::Items>, O::NotInBool),
144 paste_spanned(
145 Argument,
146 Argument<paste::Items>,
147 O::NotInBool,
148 beta::Enabled,
149 ),
150 ChangeCase(
151 Template<paste::Items>,
152 paste::ChangeCase,
153 paste::ChangeCaseOkIn<O>,
154 ),
155 concat(
156 Template<concat::Accumulator>,
157 O::NotInBool,
158 O::NotInPaste,
159 beta::Enabled,
160 ),
161
162 when(Box<Condition>, O::NotInBool),
164 define(Definition<DefinitionBody>, O::NotInBool),
165 defcond(Definition<DefCondBody>, O::NotInBool),
166 UserDefined(DefinitionName),
167
168 False(O::BoolOnly),
170 True(O::BoolOnly),
171 not(Box<Condition>, O::BoolOnly),
172 any(Punctuated<Condition, token::Comma>, O::BoolOnly),
173 all(Punctuated<Condition, token::Comma>, O::BoolOnly),
174 is_struct(O::BoolOnly),
175 is_enum(O::BoolOnly),
176 is_union(O::BoolOnly),
177 v_is_unit(O::BoolOnly),
178 v_is_tuple(O::BoolOnly),
179 v_is_named(O::BoolOnly),
180 is_empty(O::BoolOnly, Template<TokenAccumulator>),
181 approx_equal(O::BoolOnly, [Argument; 2]),
182
183 For(RepeatedTemplate<O>, O::NotInBool),
185 If(SubstIf<O>, O::NotInBool),
187 select1(SubstIf<O>, O::NotInBool),
188
189 ignore(Template<O>, O::NotInBool),
190 error(ExplicitError, O::NotInBool),
191 require_beta(beta::Enabled, O::NotInBool),
192 dbg(DbgDumpRequest<O>),
193 dbg_all_keywords(O::NotInBool),
194
195 Crate(AllowTokens<O>, O::NotInBool),
196}
197
198#[derive(Debug)]
199pub struct Definition<B> {
200 pub name: DefinitionName,
201 pub body_span: Span,
202 pub body: B,
203}
204
205#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
206pub struct DefinitionName(syn::Ident);
207impl_to_tokens!(DefinitionName, 0);
208impl_display!(DefinitionName, 0);
209
210#[derive(Debug)]
211pub enum DefinitionBody {
212 Normal(Argument),
213 Paste(Argument<paste::Items>),
214 Concat(Argument<concat::Accumulator>),
215}
216
217pub type DefCondBody = Box<Condition>;
218
219#[derive(Debug)]
220pub struct ExplicitError {
221 pub message: Argument<concat::Accumulator>,
222 pub span: Option<(Argument, beta::Enabled)>,
223}
224
225#[derive(Debug)]
226pub struct SubstIf<O: SubstParseContext> {
227 pub tests: Vec<(Condition, Template<O>)>,
232 pub otherwise: Option<Box<Template<O>>>,
234 pub kw_span: Span,
235}
236
237#[derive(Debug)]
239pub enum SubstVis {
240 T,
241 F,
242 FD,
243}
244
245#[derive(Debug)]
246pub struct SubstVType {
247 pub self_: Option<Argument>,
248 pub vname: Option<Argument>,
249}
250
251#[derive(Debug)]
252pub struct SubstVPat {
253 pub vtype: SubstVType,
254 pub fprefix: Option<Argument<paste::Items>>,
255}
256
257#[derive(Debug, Clone)]
258pub enum RawAttr {
259 Default,
260 Include {
261 entries: Punctuated<RawAttrEntry, token::Comma>,
262 },
263 Exclude {
264 exclusions: Punctuated<syn::Path, token::Comma>,
265 },
266}
267
268#[derive(Debug, Clone)]
269pub struct RawAttrEntry {
270 pub path: syn::Path,
271}
272
273#[derive(Debug)]
274pub struct DbgDumpRequest<O: SubstParseContext> {
275 pub note: Option<String>,
276 pub content_parsed: Box<O::DbgContent>,
277
278 pub content_string: (),
299}
300
301pub struct InvalidDefinitionName;
303
304impl TryFrom<syn::Ident> for DefinitionName {
305 type Error = InvalidDefinitionName;
306 fn try_from(ident: syn::Ident) -> Result<Self, InvalidDefinitionName> {
307 let s = ident.to_string();
316 let c = s.chars().next().expect("identifer was empty string!");
317 if c.is_lowercase() {
318 Err(InvalidDefinitionName)
319 } else {
320 Ok(DefinitionName(ident))
321 }
322 }
323}
324
325impl Parse for DefinitionName {
326 fn parse(input: ParseStream) -> syn::Result<Self> {
327 let ident = input.call(Ident::parse_any)?;
328 let span = ident.span();
329 Ok(ident.try_into().map_err(|InvalidDefinitionName| {
330 span.error(
331 "invalid name for definition - may not start with lowercase",
332 )
333 })?)
334 }
335}
336impl Parse for Definition<DefinitionBody> {
337 fn parse(input: ParseStream) -> syn::Result<Self> {
338 let name = input.parse()?;
339 let body_span = input.span();
340 let mut body: Argument<_> = input.parse()?;
341
342 struct PushedBack;
344
345 let body = match (|| {
347 let Template { elements } = &mut body.0;
348 if elements.len() != 1 {
349 return Err(PushedBack);
350 }
351 let first = elements.pop().expect("just checked length");
352 let (kw_span, sd) = match first {
354 TE::Subst(Subst { kw_span, sd }) => (kw_span, sd),
355 _ => {
356 elements.push(first);
357 return Err(PushedBack);
358 }
359 };
360
361 fn mk_special_body<IO: ExpansionOutput>(
362 kw_span: Span,
363 db_constructor: impl FnOnce(Argument<IO>) -> DefinitionBody,
364 new_sd: SubstDetails<IO>,
365 ) -> DefinitionBody {
366 db_constructor(Argument(Template {
367 elements: vec![TE::Subst(Subst {
368 kw_span,
369 sd: new_sd,
370 })],
371 }))
372 }
373
374 let db = match sd {
375 SD::paste(items, not_in_bool) => mk_special_body(
376 kw_span,
377 DefinitionBody::Paste,
378 SD::paste(items, not_in_bool),
379 ),
380 SD::concat(items, not_in_bool, not_in_paste, beta) => {
381 mk_special_body(
382 kw_span,
383 DefinitionBody::Concat,
384 SD::concat(items, not_in_bool, not_in_paste, beta),
385 )
386 }
387 other => {
388 let reconstruct = Subst { kw_span, sd: other };
389 elements.push(TE::Subst(reconstruct));
390 return Err(PushedBack);
391 }
392 };
393
394 Ok(db)
395 })() {
396 Ok(special) => special,
397 Err(PushedBack) => DefinitionBody::Normal(body),
398 };
399
400 Ok(Definition {
401 name,
402 body_span,
403 body,
404 })
405 }
406}
407impl Parse for Definition<DefCondBody> {
408 fn parse(input: ParseStream) -> syn::Result<Self> {
409 let name = input.parse()?;
410 let body_span = input.span();
411 let body = Box::new(input.parse()?);
412 Ok(Definition {
413 name,
414 body_span,
415 body,
416 })
417 }
418}
419
420impl<O: SubstParseContext> Spanned for Subst<O> {
421 fn span(&self) -> Span {
422 self.kw_span
423 }
424}
425
426impl TopTemplate {
427 pub fn parse(
428 input: ParseStream,
429 beta_enabled: Option<beta::Enabled>,
430 ) -> syn::Result<Self> {
431 let beta_enabled = beta_enabled.ok_or(error_generator!(
432 "beta derive-deftly feature used, without `beta_deftly` template option"
433 ));
434
435 let content = beta::with_maybe_enabled(
436 beta_enabled,
438 || input.parse(),
439 )?;
440 Ok(TopTemplate { content })
441 }
442}
443
444impl<O: SubstParseContext> Parse for Template<O> {
445 fn parse(input: ParseStream) -> syn::Result<Self> {
446 Template::parse_special(input, &mut O::SpecialParseContext::default())
447 }
448}
449
450impl<O: SubstParseContext> Template<O> {
451 pub fn parse_special<S: SpecialParseContext>(
452 input: ParseStream,
453 special: &mut S,
454 ) -> syn::Result<Self> {
455 TemplateWithWhens::parse_special(input, special)?.try_into()
456 }
457}
458
459impl<O: SubstParseContext> TemplateWithWhens<O> {
460 fn parse_special<S: SpecialParseContext>(
461 input: ParseStream,
462 mut special: &mut S,
463 ) -> syn::Result<Self> {
464 let mut good = vec![];
466 let mut errors = ErrorAccumulator::default();
467 while !input.is_empty() {
468 let special = &mut special;
469 match errors.handle_in(|| {
470 special.before_element_hook(input)
471 }) {
472 Some(None) => {},
473 None | Some(Some(SpecialInstructions::EndOfTemplate)) => break,
475 }
476 errors.handle_in(|| {
477 let elem = input.parse()?;
478 good.push(elem);
479 Ok(special)
480 });
481 }
482 errors.finish_with(TemplateWithWhens { elements: good })
483 }
484}
485
486impl<O: SubstParseContext> Parse for Argument<O> {
487 fn parse(input: ParseStream) -> syn::Result<Self> {
488 let la = input.lookahead1();
489 if la.peek(token::Brace) {
490 let inner;
491 let _brace = braced!(inner in input);
492 Template::parse(&inner)
493 } else if la.peek(Ident::peek_any)
494 || la.peek(Token![$])
495 || la.peek(syn::Lit)
496 {
497 let element = input.parse()?;
498 TemplateWithWhens {
499 elements: vec![element],
500 }
501 .try_into()
502 } else {
503 Err(la.error())
504 }
505 .map(Argument)
506 }
507}
508
509impl<O: SubstParseContext> Deref for Argument<O> {
510 type Target = Template<O>;
511 fn deref(&self) -> &Template<O> {
512 &self.0
513 }
514}
515
516impl Argument<TokenAccumulator> {
517 pub fn span_from_arg(&self, gctx: GeneralContext) -> syn::Result<Span> {
518 let mut span_tokens = TokenAccumulator::new();
519 self.expand(gctx, &mut span_tokens);
520 let span = span_tokens.tokens()?.span();
521 Ok(span)
522 }
523}
524
525#[derive(Debug, strum::EnumDiscriminants)]
532pub enum OrigDollarHandled {
533 NotFound,
535 Found(Span),
538}
539
540impl OrigDollarHandled {
541 pub fn discriminant(&self) -> OrigDollarHandledDiscriminants {
543 self.into()
544 }
545}
546
547pub fn deescape_orig_dollar(
553 input: ParseStream,
554) -> syn::Result<OrigDollarHandled> {
555 input.step(|cursor| {
556 let (found, rest) = (|| {
557 let (ident, rest) = cursor.ident()?;
558 (ident == "orig_dollar").then(|| ())?;
559 Some((OrigDollarHandled::Found(ident.span()), rest))
560 })()
561 .unwrap_or((OrigDollarHandled::NotFound, *cursor));
562 Ok((found, rest))
563 })
564}
565
566impl<O: SubstParseContext> Parse for TemplateElement<O> {
567 fn parse(input: ParseStream) -> syn::Result<Self> {
568 let input_span = input.span();
569 let allow_tokens = || O::allow_tokens(&input_span);
570 let not_in_concat = || O::not_in_concat(&input_span);
571
572 let backtracked = input.fork();
573
574 Ok(match input.parse()? {
575 TT::Group(group) => {
576 let delim_span = group.span_open();
577 let delimiter = group.delimiter();
578 let t_parser = |input: ParseStream| Template::parse(input);
579 let template = t_parser.parse2(group.stream())?;
580 TE::Group {
581 allow_tokens: allow_tokens()?,
582 delim_span,
583 delimiter,
584 template,
585 }
586 }
587 TT::Ident(tt) => TE::Ident(tt, not_in_concat()?),
588 tt @ TT::Literal(..) => match syn::parse2(tt.into())? {
589 syn::Lit::Str(s) => TE::LitStr(s),
590 other => TE::Literal(other, allow_tokens()?),
591 },
592 TT::Punct(tok) if tok.as_char() == '#' => {
593 if let Ok(attr) = syn::Attribute::parse_inner(&backtracked) {
594 if let Some(attr) = attr.first() {
595 return Err(attr.error(
596 "inner attributes are reserved syntax, anywhere in derive-deftly templates"
597 ));
598 }
599 }
600 TE::Punct(tok, allow_tokens()?)
601 }
602 TT::Punct(tok) if tok.as_char() != '$' => {
603 TE::Punct(tok, allow_tokens()?)
604 }
605 TT::Punct(_dollar) => {
606 let deescaped = deescape_orig_dollar(input)?;
607 let la = input.lookahead1();
608 if la.peek(Token![$]) {
609 let dollar: Punct = input.parse()?;
611 match deescaped {
612 OrigDollarHandled::NotFound => {},
613 OrigDollarHandled::Found(_) => {
614 match deescape_orig_dollar(input)? {
615 OrigDollarHandled::Found(_) => {},
616 OrigDollarHandled::NotFound => {
617 return Err(dollar.error(
618 "found `$orig_dollar $` not followed by another orig_dollar!"
619 ))
620 },
621 }
622 },
623 }
624 TE::Punct(dollar, allow_tokens()?)
625 } else if la.peek(token::Paren) {
626 RepeatedTemplate::parse_in_parens(input)?
627 } else {
628 TE::Subst(Subst::parse_after_dollar(la, input, deescaped)?)
629 }
630 }
631 })
632 }
633}
634
635pub trait ParseUsingSubkeywords: Sized + ParseOneSubkeyword {
644 fn parse(input: ParseStream, kw_span: Span) -> syn::Result<Self> {
648 let mut out = Self::new_default(kw_span)?;
649 while !input.is_empty() {
650 let subkw: IdentAny = input.parse()?;
651 let _: Token![=] = input.parse()?;
652 out.process_one_keyword(&subkw, input).unwrap_or_else(|| {
653 Err(subkw.error("unknown $vpat/$vconstr argument sub-keyword"))
654 })?;
655 }
656 Ok(out)
657 }
658
659 fn new_default(kw_span: Span) -> syn::Result<Self>;
667}
668
669pub trait ParseOneSubkeyword: Sized {
670 fn process_one_keyword(
677 &mut self,
678 kw: &syn::Ident,
679 input: ParseStream,
680 ) -> Option<syn::Result<()>>;
681}
682
683fn subkw_parse_store<KO>(
693 subkw: &syn::Ident,
694 input: ParseStream,
695 dest: &mut Option<Argument<KO>>,
696) -> syn::Result<()>
697where
698 KO: SubstParseContext,
699{
700 if let Some(_) = &dest {
701 return Err(
703 subkw.error("same argument sub-keyword specified more than once")
704 );
705 }
706 *dest = Some(input.parse()?);
707 Ok(())
708}
709
710macro_rules! impl_parse_one_subkeyword { {
723 $ty:ident $( < $O:ident > )?:
724 $( ( $($spec:tt)+ ) ),* $(,)?
725} => {
726 impl $(<$O: SubstParseContext>)?
727 ParseOneSubkeyword for $ty $(<$O>)? {
728 fn process_one_keyword(&mut self, got: &syn::Ident, ps: ParseStream)
729 -> Option<syn::Result<()>> {
730 $( impl_parse_one_subkeyword!{ @ (self, got, ps) @ $($spec)+ } )*
731 None
732 }
733 }
734}; { @ $bind:tt @ $exp:ident } => {
737 impl_parse_one_subkeyword! { @@ $bind @ stringify!($exp), . $exp }
738}; { @ $bind:tt @ $exp:literal: . $($field:tt)+ } => {
739 impl_parse_one_subkeyword! { @@ $bind @ $exp, . $($field)+ }
740}; { @ ($self:expr, $got:expr, $ps:expr) @ .. $($substruct:tt)+ } => {
741 if let Some(r) = $self.$($substruct)+.process_one_keyword($got, $ps) {
742 return Some(r);
743 }
744}; { @@ ($self:expr, $got:expr, $ps:expr) @ $exp:expr, .$($field:tt)+ } => {
746 if $got == $exp {
747 return Some(subkw_parse_store($got, $ps, &mut $self.$($field)+));
748 }
749} }
750
751impl_parse_one_subkeyword! {
752 SubstVType:
753 ("self": .self_),
754 (vname),
755}
756
757impl_parse_one_subkeyword! {
758 SubstVPat:
759 (..vtype),
760 (fprefix),
761}
762
763impl ParseUsingSubkeywords for SubstVType {
764 fn new_default(_tspan: Span) -> syn::Result<Self> {
765 Ok(SubstVType {
766 self_: None,
767 vname: None,
768 })
769 }
770}
771impl ParseUsingSubkeywords for SubstVPat {
772 fn new_default(tspan: Span) -> syn::Result<Self> {
773 Ok(SubstVPat {
774 vtype: SubstVType::new_default(tspan)?,
775 fprefix: None,
776 })
777 }
778}
779
780impl<O: SubstParseContext> Subst<O> {
781 pub fn parse_entire(input: ParseStream) -> syn::Result<Self> {
783 let _dollar: Token![$] = input.parse()?;
784 let deescaped = deescape_orig_dollar(input)?;
785 let la = input.lookahead1();
786 Self::parse_after_dollar(la, input, deescaped)
787 }
788
789 fn parse_after_dollar(
794 la: Lookahead1,
795 input: ParseStream,
796 _deescaped: OrigDollarHandled,
797 ) -> syn::Result<Self> {
798 if la.peek(token::Brace) {
799 let exp;
800 struct Only<O: SubstParseContext>(Subst<O>);
801 impl<O: SubstParseContext> Parse for Only<O> {
802 fn parse(input: ParseStream) -> syn::Result<Self> {
803 let subst = input.parse()?;
804 let unwanted: Option<TT> = input.parse()?;
805 if let Some(unwanted) = unwanted {
806 return Err(unwanted.error(
807 "unexpected arguments to expansion keyword",
808 ));
809 }
810 Ok(Only(subst))
811 }
812 }
813 let _brace = braced!(exp in input);
814 let exp = exp.parse()?;
815 let Only(exp) = exp;
816 Ok(exp)
817 } else if la.peek(syn::Ident::peek_any) {
818 let exp: TokenTree = input.parse()?; let exp = syn::parse2(exp.to_token_stream())?;
820 Ok(exp)
821 } else if la.peek(Token![<]) {
822 let angle: Token![<] = input.parse()?;
823 let state = paste::AngleBrackets::default();
824 let mut special = Some(state);
825 let template = Template::parse_special(input, &mut special)?;
826 let state = special.unwrap();
827 state.finish(angle.span())?;
828 Ok(Subst {
829 kw_span: angle.span(),
830 sd: SD::paste(template, O::not_in_bool(&angle)?),
831 })
832 } else {
833 return Err(la.error());
834 }
835 }
836}
837
838impl<O: SubstParseContext> Parse for Subst<O> {
840 fn parse<'i>(input: ParseStream<'i>) -> syn::Result<Self> {
841 let kw: IdentAny = input.parse()?;
842 let from_sd = |sd| {
843 Ok(Subst {
844 sd,
845 kw_span: kw.span(),
846 })
847 };
848
849 #[cfg(feature = "bizarre")]
851 let kw = {
852 let s = kw.to_string();
853 let s = s
854 .strip_suffix("_bizarre")
855 .ok_or_else(|| kw.error("bizarre mode but not _bizarre"))?;
856 IdentAny(syn::Ident::new(s, kw.span()))
857 };
858
859 macro_rules! keyword { { $($args:tt)* } => {
874 keyword_general! { kw from_sd SD; $($args)* }
875 } }
876
877 let allow_tokens = || O::allow_tokens(&kw);
878 let not_in_paste = || O::not_in_paste(&kw);
879 let not_in_bool = || O::not_in_bool(&kw);
880 let bool_only = || O::bool_only(&kw);
881 let beta = || beta::Enabled::new_for_syntax(kw.span());
882
883 let parse_if = |input| SubstIf::parse(input, kw.span());
884
885 let in_parens = |input: ParseStream<'i>| {
886 let inner;
887 let _paren = parenthesized!(inner in input);
888 Ok(inner)
889 };
890
891 let parse_def_body = |input: ParseStream<'i>, m| {
892 if input.is_empty() {
893 return Err(kw.error(m));
894 }
895 Template::parse(input)
896 };
897
898 let parse_meta =
899 |input, scope| meta::SubstMeta::parse(input, kw.span(), scope);
900
901 keyword! { tname(not_in_bool()?) }
902 keyword! { ttype(not_in_bool()?) }
903 keyword! { tdeftype(not_in_bool()?) }
904 keyword! { vname(not_in_bool()?) }
905 keyword! { fname(not_in_bool()?) }
906 keyword! { ftype(not_in_bool()?) }
907 keyword! { fpatname(not_in_bool()?) }
908 keyword! { vindex(not_in_bool()?, beta()?) } keyword! { findex(not_in_bool()?, beta()?) } keyword! { tdefkwd(not_in_bool()?) }
911
912 keyword! { "tvis": Vis(SubstVis::T, allow_tokens()?) }
913 keyword! { "fvis": Vis(SubstVis::F, allow_tokens()?) }
914 keyword! { "fdefvis": Vis(SubstVis::FD, allow_tokens()?) }
915
916 keyword! { is_struct(bool_only()?) }
917 keyword! { is_enum(bool_only()?) }
918 keyword! { is_union(bool_only()?) }
919 keyword! { v_is_unit(bool_only()?) }
920 keyword! { v_is_tuple(bool_only()?) }
921 keyword! { v_is_named(bool_only()?) }
922
923 keyword! { tgens(allow_tokens()?) }
924 keyword! { tdefgens(allow_tokens()?, not_in_bool()?) }
925 keyword! { tgnames(allow_tokens()?, not_in_bool()?) }
926 keyword! { twheres(allow_tokens()?, not_in_bool()?) }
927
928 use meta::Scope as MS;
929 keyword! { "tmeta": Xmeta(parse_meta(input, MS::T)?) }
930 keyword! { "vmeta": Xmeta(parse_meta(input, MS::V)?) }
931 keyword! { "fmeta": Xmeta(parse_meta(input, MS::F)?) }
932
933 keyword! { tattrs(input.parse()?, allow_tokens()?, not_in_bool()?) }
934 keyword! { vattrs(input.parse()?, allow_tokens()?, not_in_bool()?) }
935 keyword! { fattrs(input.parse()?, allow_tokens()?, not_in_bool()?) }
936
937 keyword! { vtype(
938 SubstVType::parse(input, kw.span())?,
939 allow_tokens()?, not_in_bool()?,
940 ) }
941 keyword! { vpat(
942 SubstVPat::parse(input, kw.span())?,
943 allow_tokens()?, not_in_bool()?,
944 ) }
945
946 keyword! { tdefvariants(
947 parse_def_body(
948 input,
949 "tdefvariants needs to contain the variant definitions",
950 )?,
951 allow_tokens()?, not_in_bool()?,
952 ) }
953 keyword! { fdefine(
954 (!input.is_empty()).then(|| input.parse()).transpose()?,
955 allow_tokens()?, not_in_bool()?
956 ) }
957 keyword! { vdefbody(
958 input.parse()?,
959 parse_def_body(
960 input,
961 "vdefbody needs to contain the body definition",
962 )?,
963 allow_tokens()?, not_in_bool()?,
964 ) }
965 keyword! { is_empty(bool_only()?, {
966 let content;
967 let _ = parenthesized!(content in input);
968 content.parse()?
969 }) }
970 keyword! { approx_equal(bool_only()?, {
971 let args =
972 Punctuated::<_, Token![,]>::parse_separated_nonempty(
973 &in_parens(input)?,
974 )?;
975 if args.len() != 2 {
976 return Err(kw.error(
977 "approx_equal() requires two comma-separated arguments"
978 ))
979 }
980 let mut args = args.into_iter();
981 let mut arg = || args.next().unwrap();
983 [ arg(), arg() ]
984 }) }
985
986 keyword! { paste(Template::parse(input)?, not_in_bool()?) }
987 keyword! { paste_spanned(
988 input.parse()?,
989 input.parse()?,
990 not_in_bool()?,
991 beta()?,
992 ) }
993
994 keyword! { concat(
995 Template::parse(input)?,
996 not_in_bool()?,
997 not_in_paste()?,
998 beta()?,
999 ) }
1000
1001 keyword! { when(input.parse()?, not_in_bool()?) }
1002 keyword! { define(input.parse()?, not_in_bool()?) }
1003 keyword! { defcond(input.parse()?, not_in_bool()?) }
1004
1005 keyword! { "false": False(bool_only()?) }
1006 keyword! { "true": True(bool_only()?) }
1007 keyword! { "if": If(parse_if(input)?, not_in_bool()?) }
1008 keyword! { select1(parse_if(input)?, not_in_bool()?) }
1009 keyword! { ignore(input.parse()?, not_in_bool()?) }
1010 keyword! { error(
1011 ExplicitError::parse(input, kw.span())?,
1012 not_in_bool()?,
1013 ) }
1014 keyword! { require_beta(beta()?, not_in_bool()?) }
1015 keyword! { dbg(input.parse()?) }
1016 keyword! { dbg_all_keywords(not_in_bool()?) }
1017 keyword! { "crate": Crate(allow_tokens()?, not_in_bool()?) }
1018 keyword! { "_dd_intern_crate": Crate(allow_tokens()?, not_in_bool()?) }
1019
1020 keyword! { "for": For(
1021 RepeatedTemplate::parse_for(input)?,
1022 not_in_bool()?,
1023 )}
1024
1025 let any_all_contents = |input: ParseStream<'i>| {
1026 Punctuated::parse_terminated(&in_parens(input)?)
1027 };
1028 keyword! { any(any_all_contents(input)?, bool_only()?) }
1029 keyword! { all(any_all_contents(input)?, bool_only()?) }
1030 keyword! { not(in_parens(input)?.parse()?, bool_only()?) }
1031
1032 if let Ok(case) = kw.to_string().parse() {
1033 let ok = paste::ChangeCaseOkIn::new_checked(case, kw.span())?;
1034
1035 return from_sd(SD::ChangeCase(Template::parse(input)?, case, ok));
1036 }
1037
1038 if let Ok(user_defined) = kw.clone().try_into() {
1039 return from_sd(SD::UserDefined(user_defined));
1040 }
1041
1042 Err(kw.error("unknown derive-deftly keyword"))
1043 }
1044}
1045
1046impl<O: SubstParseContext> Parse for DbgDumpRequest<O> {
1047 fn parse(input: ParseStream) -> syn::Result<Self> {
1048 O::parse_maybe_within_parens(input, |input| {
1049 let note = if input.peek(syn::LitStr) {
1050 let note: syn::LitStr = input.parse()?;
1051 O::parse_maybe_comma(input)?;
1052 Some(note.value())
1053 } else {
1054 None
1055 };
1056
1057 let content_buf;
1058 let content = if O::IS_BOOL {
1059 input
1060 } else {
1061 let _ = braced!(content_buf in input);
1062 &content_buf
1063 };
1064 let content_string = ();
1066 let content_parsed = content.parse()?;
1067 Ok(DbgDumpRequest {
1068 note,
1069 content_string,
1070 content_parsed,
1071 })
1072 })
1073 }
1074}
1075
1076impl<O: SubstParseContext> DbgDumpRequest<O> {
1077 pub fn display_heading<'s>(
1078 &'s self,
1079 ctx: GeneralContext<'s>,
1080 ) -> impl Display + 's {
1081 struct Adapter<'a, 'c, O: SubstParseContext>(
1082 &'a DbgDumpRequest<O>,
1083 GeneralContext<'c>,
1084 );
1085
1086 impl<O> Display for Adapter<'_, '_, O>
1087 where
1088 O: SubstParseContext,
1089 {
1090 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1091 let Adapter(ddr, ctx) = self;
1092 if let Some(note) = &ddr.note {
1093 write!(f, "{:?} ", ¬e)?;
1094 }
1095 write!(f, "{}", ctx.display_for_dbg())
1096 }
1097 }
1098
1099 Adapter(self, ctx)
1100 }
1101}
1102
1103#[derive(Default, Debug)]
1104struct ExplicitErrorNamedArgs {
1105 message: Option<Argument<concat::Accumulator>>,
1106 span: Option<Argument<TokenAccumulator>>,
1107}
1108impl_parse_one_subkeyword! {
1109 ExplicitErrorNamedArgs:
1110 (message),
1111 (span),
1112}
1113impl ParseUsingSubkeywords for ExplicitErrorNamedArgs {
1114 fn new_default(_: Span) -> syn::Result<Self> {
1115 Ok(Self::default())
1116 }
1117}
1118
1119impl ExplicitError {
1120 fn parse(input: ParseStream, kw_span: Span) -> syn::Result<Self> {
1121 let la = input.lookahead1();
1122
1123 if la.peek(syn::LitStr) {
1124 let message: syn::LitStr = input.parse()?;
1125 if message.suffix() != "" {
1126 return Err(message.error("suffix forbidden on error string"));
1127 }
1128 let message = Argument(Template {
1129 elements: vec![TE::LitStr(message)],
1130 });
1131 Ok(ExplicitError {
1132 message,
1133 span: None,
1134 })
1135 } else if la.peek(Ident::peek_any) {
1136 let beta_ok = beta::Enabled::new_for_syntax(input.span())?;
1137 let parsed = ParseUsingSubkeywords::parse(input, kw_span)?;
1138 let ExplicitErrorNamedArgs { message, span } = parsed;
1139
1140 let message = message.ok_or_else(|| {
1141 kw_span.error("${error} needs `message=` argument")
1142 })?;
1143 let span = span.map(|span| (span, beta_ok));
1144
1145 Ok(ExplicitError { message, span })
1146 } else {
1147 Err(la.error())
1148 }
1149 }
1150}
1151
1152impl<O: SubstParseContext> SubstIf<O> {
1153 fn parse(input: ParseStream, kw_span: Span) -> syn::Result<Self> {
1154 let mut tests = Vec::new();
1155 let mut otherwise = None;
1156
1157 loop {
1158 let condition = input.parse()?;
1159 let content;
1160 let _br = braced![ content in input ];
1161 let consequence = Template::parse(&content)?;
1162 tests.push((condition, consequence));
1163
1164 if input.is_empty() {
1167 break;
1169 }
1170
1171 let lookahead1 = input.lookahead1();
1172 if lookahead1.peek(syn::Ident) {
1173 continue;
1176 } else if lookahead1.peek(Token![else]) {
1177 } else {
1179 return Err(lookahead1.error());
1180 }
1181
1182 let _else: Token![else] = input.parse()?;
1183
1184 let lookahead = input.lookahead1();
1185 if lookahead.peek(Token![if]) {
1186 let _if: Token![if] = input.parse()?;
1187 continue;
1189 } else if lookahead.peek(token::Brace) {
1190 let content;
1191 let _br = braced![ content in input ];
1192 otherwise = Some(Template::parse(&content)?.into());
1193 break;
1194 } else {
1198 return Err(lookahead.error());
1199 }
1200 }
1201
1202 Ok(SubstIf {
1203 kw_span,
1204 tests,
1205 otherwise,
1206 })
1207 }
1208}
1209
1210impl SubstVis {
1211 pub fn syn_vis<'c>(
1212 &self,
1213 ctx: &'c Context<'c>,
1214 tspan: Span,
1215 ) -> syn::Result<&'c syn::Visibility> {
1216 let field_decl_vis =
1217 || Ok::<_, syn::Error>(&ctx.field(&tspan)?.field.vis);
1218 Ok(match self {
1219 SubstVis::T => &ctx.top.vis,
1220 SubstVis::FD => field_decl_vis()?,
1221 SubstVis::F => {
1222 let field = field_decl_vis()?;
1225 match ctx.top.data {
1226 syn::Data::Struct(_) | syn::Data::Union(_) => field,
1227 syn::Data::Enum(_) => &ctx.top.vis,
1228 }
1229 }
1230 })
1231 }
1232}
1233
1234impl RawAttrEntry {
1235 fn simple(self, _negated: &Token![!]) -> syn::Result<syn::Path> {
1236 Ok(self.path)
1237 }
1238}
1239
1240impl Parse for RawAttr {
1241 fn parse(input: ParseStream) -> syn::Result<Self> {
1242 if input.is_empty() {
1243 return Ok(RawAttr::Default);
1244 }
1245
1246 let la = input.lookahead1();
1247 let negated;
1248 if la.peek(Token![!]) {
1249 negated = Some(input.parse()?);
1250 } else if la.peek(Token![=]) {
1251 let _: Token![=] = input.parse()?;
1252 negated = None;
1253 } else {
1254 negated = None;
1255 }
1256
1257 let entries: Punctuated<RawAttrEntry, _> =
1258 input.call(Punctuated::parse_terminated)?;
1259
1260 if let Some(negated) = &negated {
1261 let exclusions = entries
1262 .into_iter()
1263 .map(|ent| ent.simple(negated))
1264 .try_collect()?;
1265 Ok(RawAttr::Exclude { exclusions })
1266 } else {
1267 Ok(RawAttr::Include { entries })
1268 }
1269 }
1270}
1271
1272impl Parse for RawAttrEntry {
1273 fn parse(input: ParseStream) -> syn::Result<Self> {
1274 let path = input.parse()?;
1275 Ok(RawAttrEntry { path })
1276 }
1277}
1278
1279macro_rules! te_extract_when { { $te:expr } => {
1286 match $te {
1287 TE::Subst(Subst { kw_span, sd: SD::when(bc, _) }) => {
1288 Left((kw_span, bc))
1289 }
1290 other => Right(other),
1291 }
1292} }
1293
1294impl<O: SubstParseContext> RepeatedTemplate<O> {
1295 fn parse_in_parens(input: ParseStream) -> syn::Result<TemplateElement<O>> {
1296 let template;
1297 let paren = parenthesized!(template in input);
1298 let rt = RepeatedTemplate::parse(&template, paren.span, None)?;
1299 Ok(TE::Repeat(rt))
1300 }
1301
1302 fn parse_for(input: ParseStream) -> syn::Result<RepeatedTemplate<O>> {
1303 let over: Ident = input.parse()?;
1304 let over = if over == "fields" {
1305 RepeatOver::Fields
1306 } else if over == "variants" {
1307 RepeatOver::Variants
1308 } else {
1309 return Err(
1310 over.error("$for must be followed by 'fields' or 'variants'")
1311 );
1312 };
1313 let template;
1314 let brace = braced!(template in input);
1315 RepeatedTemplate::parse(&template, brace.span, Some(over))
1316 }
1317
1318 fn parse(
1319 input: ParseStream,
1320 span: DelimSpan,
1321 over: Option<RepeatOver>,
1322 ) -> Result<RepeatedTemplate<O>, syn::Error> {
1323 use TemplateWithWhens as TWW;
1324
1325 let TWW { elements } = TWW::parse_special::<O::SpecialParseContext>(
1326 input,
1327 &mut Default::default(),
1328 )?;
1329
1330 let mut elements = VecDeque::from(elements);
1332 let mut whens = vec![];
1333
1334 while let Some(()) = {
1335 match elements.pop_front().map(|e| te_extract_when!(e)) {
1336 Some(Left((_kw_span, bc))) => {
1337 whens.push(bc);
1338 Some(())
1339 }
1340 Some(Right(other)) => {
1341 elements.push_front(other);
1342 None
1343 }
1344 None => None,
1345 }
1346 } {}
1347
1348 let elements = Vec::from(elements);
1349 let template = TemplateWithWhens { elements };
1350 let template = Template::try_from(template)?;
1351
1352 let over = match over {
1353 Some(over) => Ok(over),
1354 None => {
1355 let mut visitor = RepeatAnalysisVisitor::default();
1356 template.analyse_repeat(&mut visitor)?;
1357 visitor.finish(span)
1358 }
1359 };
1360
1361 match over {
1362 Ok(over) => Ok(RepeatedTemplate {
1363 span: span.open(),
1364 over,
1365 template,
1366 whens,
1367 }),
1368 Err(errs) => Err(errs),
1369 }
1370 }
1371}
1372
1373impl<O> TryFrom<TemplateWithWhens<O>> for Template<O>
1374where
1375 O: SubstParseContext,
1376{
1377 type Error = syn::Error;
1378
1379 fn try_from(unchecked: TemplateWithWhens<O>) -> syn::Result<Template<O>> {
1380 let TemplateWithWhens { elements } = unchecked;
1381 for e in &elements {
1382 if let Left((kw_span, _)) = te_extract_when!(e) {
1383 return Err(kw_span.error(
1384 "${when } must be at the top-level of a repetition, before other content"
1385 ));
1386 }
1387 }
1388 Ok(Template { elements })
1389 }
1390}
1391
1392pub fn preprocess_attrs(
1393 attrs: &[syn::Attribute],
1394) -> syn::Result<meta::PreprocessedMetas> {
1395 attrs
1396 .iter()
1397 .filter_map(|attr| {
1398 match attr.style {
1400 syn::AttrStyle::Outer => {}
1401 syn::AttrStyle::Inner(_) => return None,
1402 };
1403 if attr.path().leading_colon.is_some() {
1404 return None;
1405 }
1406 let segment = Itertools::exactly_one(
1407 attr.path().segments.iter(),
1410 )
1411 .ok()?;
1412 if segment.ident != "deftly" {
1413 return None;
1414 }
1415 Some(attr)
1416 })
1417 .map(|attr| {
1418 attr.call_in_parens(meta::PreprocessedValueList::parse_inner)
1419 })
1420 .collect()
1421}
1422
1423pub fn preprocess_fields(
1424 fields: &syn::Fields,
1425) -> syn::Result<Vec<PreprocessedField>> {
1426 let fields = match fields {
1427 syn::Fields::Named(f) => &f.named,
1428 syn::Fields::Unnamed(f) => &f.unnamed,
1429 syn::Fields::Unit => return Ok(vec![]),
1430 };
1431 fields
1432 .into_iter()
1433 .map(|field| {
1434 let pmetas = preprocess_attrs(&field.attrs)?;
1435 Ok(PreprocessedField { pmetas })
1436 })
1437 .collect()
1438}