1#![allow(clippy::missing_docs_in_private_items, reason = "Only AST definitions")]
14#![allow(clippy::allow_attributes, reason = "Foreign code")]
15#![allow(clippy::allow_attributes_without_reason, reason = "Foreign code")]
16
17use std::fmt;
18
19use syn::ext::IdentExt;
20use syn::parse::{Parse, ParseStream, Result};
21use syn::punctuated::Punctuated;
22use syn::spanned::Spanned;
23use syn::token::{Bracket, Paren};
24use syn::{Ident, Lit, Token};
25
26use chandeliers_san::sp::{Sp, Span, SpanEnd};
27
28macro_rules! span_end_on_field {
41 ($ty:ident . $field:ident $( or $alt:ident )?) => {
42 impl SpanEnd for $ty {
43 fn span_end(&self) -> Option<Span> {
44 self.$field.span_end()
45 $( .or_else(|| self.$alt.span_end()) )?
46 }
47 }
48 };
49}
50
51macro_rules! span_end_by_match {
71 ( $ty:ident . $( $variant:ident $(( $($field:tt),* ))? => $($select:ident)? ; )* ) => {
72 impl SpanEnd for $ty {
73 fn span_end(&self) -> Option<Span> {
74 match self {
75 $( Self::$variant $(($($field),*))? => None$(.or($select.span_end()))?, )*
76 }
77 }
78 }
79 }
80}
81
82macro_rules! span_end_from_spanned {
85 ( $($ty:tt)* ) => {
86 impl SpanEnd for $($ty)* {
87 fn span_end(&self) -> Option<Span> {
88 Some(Span::from(self.span()))
89 }
90 }
91 }
92}
93
94trait Hint {
97 fn hint(s: ParseStream) -> bool;
98}
99
100pub mod kw {
102 use syn::custom_keyword;
103
104 custom_keyword!(int);
106 custom_keyword!(bool);
108 custom_keyword!(float);
109
110 custom_keyword!(assert);
111
112 custom_keyword!(node);
113 custom_keyword!(returns);
114 custom_keyword!(var);
115 custom_keyword!(tel);
116
117 custom_keyword!(fby);
118 custom_keyword!(and);
119 custom_keyword!(pre);
120 custom_keyword!(or);
121 custom_keyword!(not);
122 custom_keyword!(then);
123
124 custom_keyword!(when);
125 custom_keyword!(whenot);
126 custom_keyword!(merge);
127}
128
129span_end_from_spanned!(kw::int);
130span_end_from_spanned!(kw::bool);
131span_end_from_spanned!(kw::float);
132span_end_from_spanned!(kw::tel);
133
134pub mod punct {
136 use syn::custom_punctuation;
137
138 custom_punctuation!(Neq, <>);
139}
140
141pub struct LusIdent {
149 pub inner: Ident,
150}
151
152impl Parse for LusIdent {
153 fn parse(input: ParseStream) -> Result<Self> {
170 let ahead = input.fork();
171 match ahead.call(Ident::parse_any) {
172 Ok(inner) => {
173 match inner.to_string().as_str() {
174 "true" | "false" | "fby" | "if" | "then" | "else" | "or" | "and" | "not"
175 | "pre" | "node" | "const" | "extern" | "returns" | "var" | "let" | "tel"
176 | "assert" | "when" | "whenot" | "merge" => Err(syn::Error::new(
177 inner.span(),
178 "expected identifier, found keyword reserved by Lustre",
179 )),
180 "crate" | "self" | "Self" | "super" | "move" | "static" => {
181 Err(syn::Error::new(
182 inner.span(),
183 "expected identifier, found keyword reserved by Rust",
184 ))
185 }
186 _ => {
190 let _ = input.call(Ident::parse_any).unwrap_or_else(|e| {
191 chandeliers_err::abort!("{input} cannot be parsed as `Ident`: {e}")
192 });
193 Ok(Self { inner })
194 }
195 }
196 }
197 Err(e) => Err(e),
198 }
199 }
200}
201
202impl LusIdent {
203 fn peek(input: ParseStream) -> bool {
204 let ahead = input.fork();
205 Self::parse(&ahead).is_ok()
206 }
207}
208
209impl fmt::Display for LusIdent {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "{}", self.inner)
212 }
213}
214
215span_end_on_field!(LusIdent.inner);
216
217pub mod ty {
218 use super::{kw, LusIdent, Sp, Span, SpanEnd};
219
220 #[derive(syn_derive::Parse)]
222 pub enum Base {
223 #[parse(peek = kw::int)]
224 Int(kw::int),
225 #[parse(peek = kw::bool)]
226 Bool(kw::bool),
227 #[parse(peek = kw::float)]
228 Float(kw::float),
229 #[parse(peek_func = LusIdent::peek)]
230 Other(Sp<LusIdent>),
231 }
232 span_end_by_match! {
233 Base.
234 Int(i) => i;
235 Bool(b) => b;
236 Float(f) => f;
237 Other(t) => t;
238 }
239
240 #[derive(syn_derive::Parse)]
241 pub struct When {
242 _when: kw::when,
243 pub clock: Sp<LusIdent>,
244 }
245 span_end_on_field!(When.clock);
246
247 #[derive(syn_derive::Parse)]
248 pub struct Whenot {
249 _whenot: kw::whenot,
250 pub clock: Sp<LusIdent>,
251 }
252 span_end_on_field!(Whenot.clock);
253
254 #[derive(syn_derive::Parse)]
255 pub enum Clock {
256 #[parse(peek = kw::when)]
257 When(Sp<When>),
258 #[parse(peek = kw::whenot)]
259 Whenot(Sp<Whenot>),
260 None,
261 }
262 span_end_by_match! {
263 Clock.
264 When(c) => c;
265 Whenot(c) => c;
266 None =>;
267 }
268
269 #[derive(syn_derive::Parse)]
270 pub struct Type {
271 pub base: Sp<Base>,
272 pub clock: Sp<Clock>,
273 }
274 span_end_on_field!(Type.base);
275}
276
277#[derive(syn_derive::Parse)]
285pub struct Decls {
286 #[parse(Punctuated::parse_separated_nonempty)]
287 pub ids: Punctuated<Sp<LusIdent>, Token![,]>,
288}
289span_end_on_field!(Decls.ids);
290
291#[derive(syn_derive::Parse)]
299pub struct ArgsTy {
300 pub args: Sp<Decls>,
301 _colon: Token![:],
302 pub ty: Sp<ty::Type>,
303}
304span_end_on_field!(ArgsTy.ty);
305
306#[derive(Default)]
313pub struct ArgsTys {
314 pub items: Punctuated<Sp<ArgsTy>, Token![;]>,
315}
316span_end_on_field!(ArgsTys.items);
317impl ArgsTys {
318 fn parse_terminated(input: ParseStream) -> Result<Sp<Self>> {
319 let mut span = input.span();
320 let items = Punctuated::parse_terminated(input)?;
321 span = span.join(input.span()).unwrap_or_else(|| {
322 chandeliers_err::abort!("Malformed span between {span:?} and {input:?}")
323 });
324 Ok(Sp {
325 t: Self { items },
326 span: Span::from(span),
327 })
328 }
329
330 fn parse_separated_trailing_until_let(input: ParseStream) -> Result<Sp<Self>> {
331 let mut span = input.span();
332 let items =
333 punctuated_parse_separated_trailing_until::<Sp<ArgsTy>, Token![;], Token![let]>(input)?;
334 span = span.join(input.span()).unwrap_or_else(|| {
335 chandeliers_err::abort!("Malformed span between {span:?} and {input:?}")
336 });
337
338 Ok(Sp {
339 t: Self { items },
340 span: Span::from(span),
341 })
342 }
343}
344
345#[derive(syn_derive::Parse)]
360pub enum TargetExpr {
361 #[parse(peek = Paren)]
362 Tuple(Sp<TargetExprTuple>),
363 Var(Sp<LusIdent>),
364}
365span_end_by_match! {
366 TargetExpr.
367 Tuple(t) => t;
368 Var(v) => v;
369}
370
371#[derive(syn_derive::Parse)]
379pub struct TargetExprTuple {
380 #[syn(parenthesized)]
381 _paren: Paren,
382 #[syn(in = _paren)]
383 #[parse(Punctuated::parse_terminated)]
384 pub fields: Punctuated<Sp<TargetExpr>, Token![,]>,
385}
386span_end_on_field!(TargetExprTuple.fields);
387
388pub fn punctuated_parse_separated_nonempty_costly<T, P>(
391 input: ParseStream,
392) -> Result<Punctuated<T, P>>
393where
394 T: Parse,
395 P: Parse,
396{
397 let mut punctuated = Punctuated::new();
398
399 loop {
400 let value: T = input.parse()?;
401 punctuated.push_value(value);
402 if P::parse(&input.fork()).is_err() {
403 break;
404 }
405 let punct: P = input.parse()?;
406 punctuated.push_punct(punct);
407 }
408
409 Ok(punctuated)
410}
411
412pub fn punctuated_parse_separated_trailing_until<T, P, E>(
415 input: ParseStream,
416) -> Result<Punctuated<T, P>>
417where
418 T: Parse,
419 P: syn::token::Token + Parse,
420 E: syn::token::Token + Parse,
421{
422 let mut punctuated = Punctuated::new();
423
424 loop {
425 if E::peek(input.cursor()) {
426 break;
427 }
428 let value = T::parse(input)?;
429 punctuated.push_value(value);
430 let punct = input.parse()?;
431 punctuated.push_punct(punct);
432 }
433
434 Ok(punctuated)
435}
436
437pub mod op {
438 use super::{kw, punct, ParseStream, Token};
439
440 pub use kw::and as And;
441 pub use kw::fby as Fby;
442 pub use kw::or as Or;
443 pub type Arrow = Token![->];
444
445 #[derive(syn_derive::Parse)]
447 pub enum Mul {
448 #[expect(
449 clippy::enum_variant_names,
450 reason = "Same abbreviation of different things"
451 )]
452 #[parse(peek = Token![*])]
453 Mul(Token![*]),
454 #[parse(peek = Token![/])]
455 Div(Token![/]),
456 #[parse(peek = Token![%])]
457 Rem(Token![%]),
458 }
459
460 fn exactly_token_neg(s: ParseStream) -> bool {
462 s.peek(Token![-]) && !s.peek2(Token![>])
463 }
464
465 #[derive(syn_derive::Parse)]
467 pub enum Add {
468 #[parse(peek = Token![+])]
469 Add(Token![+]),
470 #[parse(peek_func = exactly_token_neg)]
471 Sub(Token![-]),
472 }
473
474 #[derive(syn_derive::Parse)]
479 pub enum Cmp {
480 #[parse(peek = punct::Neq)]
481 Ne(punct::Neq),
482 #[parse(peek = Token![<=])]
483 Le(Token![<=]),
484 #[parse(peek = Token![>=])]
485 Ge(Token![>=]),
486 #[parse(peek = Token![<])]
487 Lt(Token![<]),
488 #[parse(peek = Token![>])]
489 Gt(Token![>]),
490 #[parse(peek = Token![=])]
491 Eq(Token![=]),
492 }
493
494 #[derive(syn_derive::Parse)]
496 pub enum Clock {
497 #[parse(peek = kw::when)]
498 When(kw::when),
499 #[parse(peek = kw::whenot)]
500 Whenot(kw::whenot),
501 }
502}
503
504pub mod expr {
506 use super::punctuated_parse_separated_nonempty_costly;
524 use super::{kw, op, Hint, LusIdent};
525 use super::{Parse, ParseStream, Punctuated, Token};
526 use super::{Result, Sp, Span, SpanEnd};
527
528 #[derive(syn_derive::Parse)]
538 pub struct Lit {
539 pub lit: Sp<syn::Lit>,
540 }
541 span_end_on_field!(Lit.lit);
542 impl Hint for Lit {
543 fn hint(s: ParseStream) -> bool {
544 s.peek(syn::Lit)
545 }
546 }
547
548 #[derive(syn_derive::Parse)]
567 pub enum Atomic {
568 #[parse(peek_func = Paren::hint)]
569 Paren(Sp<Paren>),
570 #[parse(peek_func = Lit::hint)]
571 Lit(Sp<Lit>),
572 #[parse(peek_func = Var::hint)]
573 Var(Sp<Var>),
574 }
575 span_end_by_match! {
576 Atomic.
577 Paren(p) => p;
578 Lit(l) => l;
579 Var(v) => v;
580 }
581
582 #[derive(syn_derive::Parse)]
601 pub enum Positive {
602 #[parse(peek_func = Call::hint)]
603 Call(Sp<Call>),
604 #[parse(peek_func = If::hint)]
605 If(Sp<If>),
606 #[parse(peek_func = Merge::hint)]
607 Merge(Sp<Merge>),
608 #[parse(peek_func = Pre::hint)]
609 Pre(Sp<Pre>),
610 #[parse(peek_func = Neg::hint)]
611 Neg(Sp<Neg>),
612 #[parse(peek_func = Not::hint)]
613 Not(Sp<Not>),
614 Atomic(Sp<Atomic>),
615 }
616 span_end_by_match! {
617 Positive.
618 If(i) => i;
619 Merge(m) => m;
620 Call(c) => c;
621 Pre(p) => p;
622 Neg(n) => n;
623 Not(n) => n;
624 Atomic(a) => a;
625 }
626
627 #[derive(syn_derive::Parse)]
632 pub struct Var {
633 pub name: Sp<LusIdent>,
634 }
635 span_end_on_field!(Var.name);
636 impl Hint for Var {
637 fn hint(s: ParseStream) -> bool {
638 LusIdent::peek(s)
639 }
640 }
641
642 #[derive(syn_derive::Parse)]
654 pub struct Call {
655 pub fun: Sp<LusIdent>,
656 pub args: Sp<Paren>,
657 }
658 span_end_on_field!(Call.args);
659 impl Hint for Call {
660 fn hint(s: ParseStream) -> bool {
661 fn is_parenthesized(s: ParseStream) -> Result<syn::token::Paren> {
662 s.parse::<LusIdent>()?;
663 let _content;
664 let p = syn::parenthesized!(_content in s);
665 Ok(p)
666 }
667 is_parenthesized(s).is_ok()
668 }
669 }
670
671 #[derive(syn_derive::Parse)]
679 pub struct Paren {
680 #[syn(parenthesized)]
681 pub paren: syn::token::Paren,
682 #[syn(in = paren)]
683 #[parse(Punctuated::parse_terminated)]
684 pub inner: Punctuated<Sp<Box<Expr>>, Token![,]>,
685 }
686 span_end_on_field!(Paren.paren);
687 impl Hint for Paren {
688 fn hint(s: ParseStream) -> bool {
689 fn is_parenthesized(s: ParseStream) -> Result<syn::token::Paren> {
690 let _content;
691 let p = syn::parenthesized!(_content in s);
692 Ok(p)
693 }
694 is_parenthesized(s).is_ok()
695 }
696 }
697
698 #[derive(syn_derive::Parse)]
706 pub struct Pre {
707 pub _pre: kw::pre,
708 pub inner: Sp<Box<Positive>>,
709 }
710 span_end_on_field!(Pre.inner);
711 impl Hint for Pre {
712 fn hint(s: ParseStream) -> bool {
713 s.peek(kw::pre)
714 }
715 }
716
717 #[derive(syn_derive::Parse)]
725 pub struct Neg {
726 pub _neg: Token![-],
727 pub inner: Sp<Box<Positive>>,
728 }
729 span_end_on_field!(Neg.inner);
730 impl Hint for Neg {
731 fn hint(s: ParseStream) -> bool {
732 s.peek(Token![-])
733 }
734 }
735
736 #[derive(syn_derive::Parse)]
744 pub struct Not {
745 pub _not: kw::not,
746 pub inner: Sp<Box<Positive>>,
747 }
748 span_end_on_field!(Not.inner);
749 impl Hint for Not {
750 fn hint(s: ParseStream) -> bool {
751 s.peek(kw::not)
752 }
753 }
754
755 #[derive(syn_derive::Parse)]
757 pub struct Clock {
758 #[parse(punctuated_parse_separated_nonempty_costly)]
759 pub items: Punctuated<Sp<Positive>, op::Clock>,
760 }
761 span_end_on_field!(Clock.items);
762
763 #[derive(syn_derive::Parse)]
765 pub struct Mul {
766 #[parse(punctuated_parse_separated_nonempty_costly)]
767 pub items: Punctuated<Sp<Clock>, op::Mul>,
768 }
769 span_end_on_field!(Mul.items);
770
771 #[derive(syn_derive::Parse)]
773 pub struct Add {
774 #[parse(punctuated_parse_separated_nonempty_costly)]
775 pub items: Punctuated<Sp<Mul>, op::Add>,
776 }
777 span_end_on_field!(Add.items);
778
779 #[derive(syn_derive::Parse)]
781 pub struct Then {
782 #[parse(punctuated_parse_separated_nonempty_costly)]
783 pub items: Punctuated<Sp<Add>, op::Arrow>,
784 }
785 span_end_on_field!(Then.items);
786
787 #[derive(syn_derive::Parse)]
789 pub struct Fby {
790 #[parse(punctuated_parse_separated_nonempty_costly)]
791 pub items: Punctuated<Sp<Then>, op::Fby>,
792 }
793 span_end_on_field!(Fby.items);
794
795 #[derive(syn_derive::Parse)]
797 pub struct Cmp {
798 #[parse(punctuated_parse_separated_nonempty_costly)]
799 pub items: Punctuated<Sp<Fby>, op::Cmp>,
800 }
801 span_end_on_field!(Cmp.items);
802
803 #[derive(syn_derive::Parse)]
805 pub struct And {
806 #[parse(Punctuated::parse_separated_nonempty)]
807 pub items: Punctuated<Sp<Cmp>, op::And>,
808 }
809 span_end_on_field!(And.items);
810
811 #[derive(syn_derive::Parse)]
813 pub struct Or {
814 #[parse(Punctuated::parse_separated_nonempty)]
815 pub items: Punctuated<Sp<And>, op::Or>,
816 }
817 span_end_on_field!(Or.items);
818
819 #[derive(syn_derive::Parse)]
831 pub struct If {
832 pub _if: Token![if],
833 pub cond: Sp<Expr>,
834 pub _then: kw::then,
835 pub yes: Sp<Expr>,
836 pub _else: Token![else],
837 pub no: Sp<Expr>,
838 }
839 impl Hint for If {
840 fn hint(s: ParseStream) -> bool {
841 s.peek(Token![if])
842 }
843 }
844 span_end_on_field!(If.no);
845
846 #[derive(syn_derive::Parse)]
856 pub struct Merge {
857 pub _merge: kw::merge,
858 pub clk: Sp<Box<Atomic>>,
859 pub on: Sp<Box<Atomic>>,
860 pub off: Sp<Box<Atomic>>,
861 }
862 impl Hint for Merge {
863 fn hint(s: ParseStream) -> bool {
864 s.peek(kw::merge)
865 }
866 }
867 span_end_on_field!(Merge.off);
868
869 pub struct Expr {
871 pub inner: Sp<Or>,
873 }
874 span_end_on_field!(Expr.inner);
875
876 impl Parse for Expr {
877 fn parse(input: ParseStream) -> Result<Self> {
878 let inner: Sp<Or> = input.parse()?;
879 Ok(Self { inner })
880 }
881 }
882}
883
884pub use expr::Expr;
885
886#[derive(syn_derive::Parse)]
895pub struct Def {
896 pub target: Sp<TargetExpr>,
897 _equal: Token![=],
898 pub source: Sp<expr::Expr>,
899}
900span_end_on_field!(Def.source);
901
902#[derive(syn_derive::Parse)]
910pub struct Assertion {
911 _assert: kw::assert,
912 pub expr: Sp<expr::Expr>,
913}
914span_end_on_field!(Assertion.expr);
915
916#[derive(syn_derive::Parse)]
926pub enum Statement {
927 #[parse(peek = kw::assert)]
928 Assert(Sp<Assertion>),
929 Def(Sp<Def>),
930}
931span_end_by_match! {
932 Statement.
933 Assert(a) => a;
934 Def(d) => d;
935}
936
937#[derive(syn_derive::Parse)]
945pub struct VarsDecl {
946 _var: kw::var,
947 #[parse(ArgsTys::parse_separated_trailing_until_let)]
948 pub decls: Sp<ArgsTys>,
949}
950span_end_on_field!(VarsDecl.decls);
951
952#[derive(syn_derive::Parse)]
954pub enum OptionalVarsDecl {
955 #[parse(peek = kw::var)]
956 Decls(Sp<VarsDecl>),
957 None,
958}
959span_end_by_match! {
960 OptionalVarsDecl.
961 Decls(d) => d;
962 None =>;
963}
964
965#[derive(syn_derive::Parse)]
987pub struct Node {
988 _node: kw::node,
989
990 pub name: Sp<LusIdent>,
991
992 #[syn(parenthesized)]
993 pub _inputs_paren: Paren,
994 #[syn(in = _inputs_paren)]
995 #[parse(ArgsTys::parse_terminated)]
996 pub inputs: Sp<ArgsTys>,
997
998 _returns: kw::returns,
999
1000 #[syn(parenthesized)]
1001 pub _outputs_paren: Paren,
1002 #[syn(in = _outputs_paren)]
1003 #[parse(ArgsTys::parse_terminated)]
1004 pub outputs: Sp<ArgsTys>,
1005
1006 _decl_semi: Token![;],
1007
1008 pub locals: Sp<OptionalVarsDecl>,
1009
1010 _kwlet: Token![let],
1011
1012 #[parse(punctuated_parse_separated_trailing_until::<Sp<Statement>, Token![;], kw::tel>)]
1013 pub defs: Punctuated<Sp<Statement>, Token![;]>,
1014
1015 kwtel: kw::tel,
1016}
1017span_end_on_field!(Node.kwtel);
1018
1019#[derive(syn_derive::Parse)]
1031pub struct Const {
1032 _const: Token![const],
1033 pub name: Sp<LusIdent>,
1034 _colon: Token![:],
1035 pub ty: Sp<ty::Base>,
1036 _equal: Token![=],
1037 pub value: Sp<Expr>,
1038}
1039span_end_on_field!(Const.value);
1040
1041#[derive(syn_derive::Parse)]
1054pub struct ExtNode {
1055 _extern: Token![extern],
1056 _node: kw::node,
1057 pub name: Sp<LusIdent>,
1058
1059 #[syn(parenthesized)]
1060 pub _inputs_paren: Paren,
1061 #[syn(in = _inputs_paren)]
1062 #[parse(ArgsTys::parse_terminated)]
1063 pub inputs: Sp<ArgsTys>,
1064
1065 _returns: kw::returns,
1066
1067 #[syn(parenthesized)]
1068 pub _outputs_paren: Paren,
1069 #[syn(in = _outputs_paren)]
1070 #[parse(ArgsTys::parse_terminated)]
1071 pub outputs: Sp<ArgsTys>,
1072}
1073span_end_on_field!(ExtNode.outputs);
1074
1075#[derive(syn_derive::Parse)]
1086pub struct ExtConst {
1087 _extern: Token![extern],
1088 _const: Token![const],
1089 pub name: Sp<LusIdent>,
1090 _colon: Token![:],
1091 pub ty: Sp<ty::Type>,
1092}
1093span_end_on_field!(ExtConst.ty);
1094
1095#[derive(syn_derive::Parse)]
1096#[parse(prefix = <Token![extern]>::parse)]
1097pub enum Extern {
1098 #[parse(peek = Token![const])]
1099 Const(Sp<ExtConst>),
1100 Node(Sp<ExtNode>),
1101}
1102span_end_by_match! {
1103 Extern.
1104 Const(c) => c;
1105 Node(n) => n;
1106}
1107
1108#[derive(syn_derive::Parse)]
1109pub enum AttrArg {
1110 #[parse(peek_func = LusIdent::peek)]
1111 LusIdent(Sp<LusIdent>),
1112 #[parse(peek = Lit)]
1113 Lit(Sp<Lit>),
1114}
1115span_end_by_match! {
1116 AttrArg.
1117 LusIdent(i) => i;
1118 Lit(l) => l;
1119}
1120
1121#[derive(syn_derive::Parse)]
1122pub struct AttrTargets {
1123 #[syn(parenthesized)]
1124 paren: Paren,
1125 #[syn(in = paren)]
1126 #[parse(Punctuated::parse_terminated)]
1127 targets: Punctuated<syn::Lit, Token![,]>,
1128}
1129span_end_on_field!(AttrTargets.paren);
1130impl Hint for AttrTargets {
1131 fn hint(s: ParseStream) -> bool {
1132 fn is_parenthesized(s: ParseStream) -> Result<Paren> {
1133 let _content;
1134 let p = syn::parenthesized!(_content in s);
1135 Ok(p)
1136 }
1137 is_parenthesized(s).is_ok()
1138 }
1139}
1140
1141#[derive(syn_derive::Parse)]
1142pub enum OptionAttrTargets {
1143 #[parse(peek_func = AttrTargets::hint)]
1144 Targets(AttrTargets),
1145 None,
1146}
1147span_end_by_match! {
1148 OptionAttrTargets.
1149 Targets(p) => p;
1150 None =>;
1151}
1152
1153#[derive(syn_derive::Parse)]
1154pub struct AttrParams {
1155 #[syn(bracketed)]
1156 brack: Bracket,
1157 #[syn(in = brack)]
1158 #[parse(Punctuated::parse_terminated)]
1159 params: Punctuated<Sp<LusIdent>, Token![,]>,
1160}
1161span_end_on_field!(AttrParams.brack);
1162impl Hint for AttrParams {
1163 fn hint(s: ParseStream) -> bool {
1164 fn is_bracketed(s: ParseStream) -> Result<Bracket> {
1165 let _content;
1166 let p = syn::bracketed!(_content in s);
1167 Ok(p)
1168 }
1169 is_bracketed(s).is_ok()
1170 }
1171}
1172
1173#[derive(syn_derive::Parse)]
1174pub enum OptionAttrParams {
1175 #[parse(peek_func = AttrParams::hint)]
1176 Params(AttrParams),
1177 None,
1178}
1179span_end_by_match! {
1180 OptionAttrParams.
1181 Params(p) => p;
1182 None =>;
1183}
1184
1185impl OptionAttrParams {
1186 pub fn flatten(self) -> Vec<Sp<String>> {
1187 match self {
1188 Self::None => vec![],
1189 Self::Params(ps) => ps
1190 .params
1191 .into_iter()
1192 .map(|i| i.map(|_, t| t.inner.to_string()))
1193 .collect(),
1194 }
1195 }
1196}
1197impl OptionAttrTargets {
1198 pub fn flatten(self) -> Vec<syn::Lit> {
1199 match self {
1200 Self::None => vec![],
1201 Self::Targets(ts) => ts.targets.into_iter().collect(),
1202 }
1203 }
1204}
1205
1206#[derive(syn_derive::Parse)]
1207pub struct AttrDef {
1208 pub action: Sp<LusIdent>,
1209 pub params: Sp<OptionAttrParams>,
1210 pub targets: Sp<OptionAttrTargets>,
1211}
1212span_end_on_field!(AttrDef.action);
1213
1214#[derive(syn_derive::Parse)]
1215pub struct Attribute {
1216 _marker: Token![#],
1217 #[syn(bracketed)]
1218 brack: Bracket,
1219 #[syn(in = brack)]
1220 pub attr: Sp<AttrDef>,
1221}
1222span_end_on_field!(Attribute.brack);
1223
1224#[derive(syn_derive::Parse)]
1225pub enum Decl {
1226 #[parse(peek = Token![extern])]
1227 Extern(Sp<Box<Extern>>),
1228 #[parse(peek = Token![const])]
1229 Const(Sp<Const>),
1230 Node(Sp<Node>),
1231}
1232span_end_by_match! {
1233 Decl.
1234 Extern(e) => e;
1235 Const(c) => c;
1236 Node(n) => n;
1237}
1238
1239#[derive(syn_derive::Parse)]
1240pub enum AttrDecl {
1241 #[parse(peek = Token![#])]
1242 Tagged(Sp<Box<Attribute>>, Sp<Box<AttrDecl>>),
1243 Node(Sp<Decl>),
1244}
1245span_end_by_match! {
1246 AttrDecl.
1247 Tagged(_, d) => d;
1248 Node(n) => n;
1249}
1250
1251#[derive(syn_derive::Parse)]
1253pub struct Prog {
1254 #[parse(Punctuated::parse_terminated)]
1255 pub(crate) decls: Punctuated<Sp<AttrDecl>, Token![;]>,
1256}
1257span_end_on_field!(Prog.decls);