chandeliers_syn/
ast.rs

1//! Parsing output of a Lustre program.
2//!
3//! This AST is targeted for ease of parsing and quality of error messages,
4//! not for traversal.
5//! See `translate.rs` for how we can transform this AST into one that is
6//! more easy to use.
7//!
8//! A Lustre program is a sequence of declarations, that are either
9//! constants or nodes.
10//! A node has inputs, outputs, and a body constituted of definitions of
11//! outputs from inputs.
12
13#![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
28/// Impl `SpanEnd` for structs.
29///
30/// Example:
31/// ```skip
32/// #[derive(syn_derive::Parse)]
33/// struct Addition {
34///     lhs: Ident,
35///     plus: Token![+],
36///     rhs: Ident,
37/// }
38/// span_end_on_field!(Addition.rhs);
39/// ```
40macro_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
51/// Impl `SpanEnd` for enums.
52///
53/// Example:
54/// ```skip
55/// #[derive(syn_derive::Parse)]
56/// enum Operator {
57///     #[parse(peek = Token![+])]
58///     Plus(Token![+]),
59///     #[parse(peek = Token![-])]
60///     Minus(Token![-]),
61///     Times(Token![*]),
62/// }
63/// span_end_by_match! {
64///     Operator.
65///         Plus(o) => o;
66///         Minus(o) => o;
67///         Times(o) => o;
68/// }
69/// ```
70macro_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
82/// Trivial implementation of `SpanEnd` for types that already have a
83/// `span` method.
84macro_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
94/// `peek`-like implementation for types that do not implement `syn`'s
95/// `Token` but are nevertheless still trivially peekable.
96trait Hint {
97    fn hint(s: ParseStream) -> bool;
98}
99
100/// Reserved keywords defined by Lustre.
101pub mod kw {
102    use syn::custom_keyword;
103
104    // We might eventually accept an arbitrary Ident as type.
105    custom_keyword!(int);
106    // Warning: this locally overrides the builtin `bool`
107    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
134/// Extra punctuation defined by Lustre.
135pub mod punct {
136    use syn::custom_punctuation;
137
138    custom_punctuation!(Neq, <>);
139}
140
141/// A valid Lustre identifier.
142///
143/// The identifiers accepted here are not comparable with those accepted by
144/// Rust, because some keywords are reserved by Lustre that do not exist in
145/// Rust, and some Rust keywords can't even be used as raw identifiers.
146///
147/// See the `Parse` implementation for details.
148pub struct LusIdent {
149    pub inner: Ident,
150}
151
152impl Parse for LusIdent {
153    /// Attempts to read an identifier from a stream.
154    ///
155    /// Valid identifiers *exclude*
156    /// - Keywords that both Lustre and Rust agree are reserved
157    ///     * literals: `true`, `false`
158    ///     * control flow: `if`, `else`
159    ///     * declarations: `let`, `const`, `extern`
160    /// - Lustre-only reserved keywords
161    ///     * temporal operators: `pre`, `fby`
162    ///     * boolean operators: `or`, `and`, `not`
163    ///     * control flow: `then`, `assert`
164    ///     * declarations: `node`, `returns`, `var`, `tel`
165    /// - Rust keywords that cannot be raw identifiers
166    ///     * path keywords: `crate`, `self`, `Self`, `super`
167    ///     * `move`
168    ///     * `static`
169    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                    // NOTE: "int", "float" and "bool" are also keywords, but they are not
187                    // reserved. Because the grammar is not ambiguous we can always tell if "float"
188                    // refers to the type or the builtin.
189                    _ => {
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    /// A scalar type: `int`, `bool`, `float`.
221    #[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./*clock or*/ base);
275}
276
277/// A comma-separated list of idents.
278///
279/// ```lus
280/// var x, y, z : int; a, b, c : float;
281///     ^^^^^^^
282///                    ^^^^^^^
283/// ```
284#[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/// Variables and one type that applies to them all.
292///
293/// ```lus
294/// var x, y, z : int; a, b, c : float;
295///     ^^^^^^^^^^^^^
296///                    ^^^^^^^^^^^^^^^
297/// ```
298#[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/// Declarations of variables and their types.
307///
308/// ```lus
309/// var x, y, z : int; a, b, c : float;
310///     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
311/// ```
312#[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/// Assignment expression.
346///
347/// ```lus
348/// x
349/// ^Var
350///
351/// (x, y, z)
352/// ^^^^^^^^^Tuple
353///
354/// (x, (y, z), w)
355///  ^Var       ^Var
356///     ^^^^^^Tuple
357/// ^^^^^^^^^^^^^^Tuple
358/// ```
359#[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/// Parenthesized tuple of variables.
372///
373/// ```lus
374/// (x, (y, z), w)
375///      ^^^^fields
376///  ^^^^^^^^^^^^fields
377/// ```
378#[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
388/// Implement a version of `Punctuated::parse_separated_nonempty` but
389/// for punctuation that is not trivially peekable.
390pub 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
412/// Implement a version of `Punctuated::parse_terminated` but that requires
413/// trailing punctuation and stops upon seeing a terminator of type `E`.
414pub 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    /// Multiplicative operators: `*`, `/`, `%`, all with the same precedence.
446    #[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    /// Do not confuse an actual `-` with the beginning of a `->`.
461    fn exactly_token_neg(s: ParseStream) -> bool {
462        s.peek(Token![-]) && !s.peek2(Token![>])
463    }
464
465    /// Additive operators: `+`, `-`, all with the same precedence.
466    #[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    /// Comparison operators: `<=`, `>=`, `<`, `>`, `=`, `<>`.
475    ///
476    /// NOTE: these operators are associative at the parsing level,
477    /// but the translator will ensure that they are exactly binary.
478    #[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    /// Clock operators: `when` and `whenot`.
495    #[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
504/// Parsing expressions.
505pub mod expr {
506    //! Expressions by order of decreasing precedence
507    //!    [ _ or _ ] (<-)
508    //!    [ _ and _ ] (<-)
509    //!    [ _ <= _ ], [ _ >= _ ], [ _ < _ ], [ _ > _ ] [ _ = _ ] (==)
510    //!    [ _ fby _ ] (<-)
511    //!    [ _ -> _ ] (<-)
512    //!    [ _ + _ ], [ _ - _ ] (->)
513    //!    [ _ * _ ], [ _ / _ ], [ _ % _ ] (->)
514    //!
515    //! Atomics:
516    //!    [ pre _ ]
517    //!    [ - _ ]
518    //!    [ ( _, ... ) ]
519    //!    [ f( _, ... ) ]
520    //!    [ v ]
521    //!    [ not _ ]
522
523    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    /// A literal.
529    ///
530    /// ```lus
531    /// 1.0
532    /// ^^^lit
533    ///
534    /// 2
535    /// ^lit
536    /// ```
537    #[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    /// An expression that is atomically parseable.
549    ///
550    /// It must not have any associativity, must always consume
551    /// at least one token immediately, and its end must be unambiguous.
552    ///
553    /// ```lus
554    /// (a + b, c)
555    /// ^^^^^^^^^^Paren
556    ///
557    /// f(x, y)
558    /// ^^^^^^^Call
559    ///
560    /// 1.0
561    /// ^^^Lit
562    ///
563    /// y
564    /// ^Var
565    /// ```
566    #[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    /// An expression that consumes at least one token immediately.
583    ///
584    /// ```skip
585    /// pre x
586    /// ^^^^^Pre
587    ///
588    /// -x
589    /// ^^Neg
590    ///
591    /// not x
592    /// ^^^^^Not
593    ///
594    /// if b then y else n
595    /// ^^^^^^^^^^^^^^^^^^If
596    ///
597    /// merge b on off
598    /// ^^^^^^^^^^^^^^Merge
599    /// ```
600    #[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    /// A variable.
628    ///
629    /// It can have any name accepted under the rules defined by `LusIdent`
630    /// (i.e. everything except Lustre keywords and some Rust keywords)
631    #[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    /// A function call
643    ///
644    /// ```lus
645    /// foo(x, y, z)
646    /// ^^^fun
647    ///    ^^^^^^^^^args
648    /// ```
649    ///
650    /// Notice how the arguments are a `Paren` and not a
651    /// `Punctuated<Expr, Token![,]>`: this is to accomodate some identifications
652    /// between `foo(())` and `foo()` at the translation level.
653    #[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    /// An expression between parentheses.
672    ///
673    /// ```lus
674    /// (x, y, z)
675    /// ^_paren
676    ///  ^^^^^^^inner
677    /// ```
678    #[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    /// The temporal operator `pre`.
699    ///
700    /// ```lus
701    /// pre x
702    /// ^^^_pre
703    ///     ^inner
704    /// ```
705    #[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    /// A unary negation.
718    ///
719    /// ```lus
720    /// -x
721    /// ^_neg
722    ///  ^inner
723    /// ```
724    #[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    /// A unary boolean negation.
737    ///
738    /// ```lus
739    /// not b
740    /// ^^^_not
741    ///     ^inner
742    /// ```
743    #[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    /// A clocked expression as a `Clock`-separated list of atomic expressions.
756    #[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    /// A multiplicative expression as a `Mul`-separated list of clocked expressions.
764    #[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    /// An additive expression as an `Add`-separated list of multiplicative expressions.
772    #[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    /// A "Then" temporal expression as a `->`-separated list of additive expressions.
780    #[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    /// A "Fby" temporal expression as a `fby`-separated list of then expressions.
788    #[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    /// A comparison expression as a `Cmp`-separated list of temporal expressions.
796    #[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    /// A conjunction as an `and`-separated list of comparisons.
804    #[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    /// A disjunction as an `or`-separated list of conjunctions.
812    #[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    /// A conditional expression.
820    ///
821    /// ```lus
822    /// if c then y else n
823    /// ^^_if
824    ///    ^cond
825    ///      ^^^^_then
826    ///           ^yes
827    ///             ^^^^_else
828    ///                  ^no
829    /// ```
830    #[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    /// A merge of two clocks.
847    ///
848    /// ```lus
849    /// merge b on off
850    /// ^^^^^_merge
851    ///       ^clk
852    ///         ^^on
853    ///            ^^^off
854    /// ```
855    #[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    /// Any expression.
870    pub struct Expr {
871        /// `or` has the lowest precedence.
872        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/// An assignment statement.
887///
888/// ```lus
889/// (x, y, z) = foo(a, b);
890/// ^^^^^^^^^target
891///           ^_equal
892///             ^^^^^^^^^source
893/// ```
894#[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/// An assertion.
903///
904/// ```lus
905/// assert b;
906/// ^^^^^^_assert
907///        ^expr
908/// ```
909#[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/// A statement in the body of a node.
917///
918/// ```lus
919/// assert b;
920/// ^^^^^^^^Assert
921///
922/// x = 1;
923/// ^^^^^Def
924/// ```
925#[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/// Declaration of local variables
938///
939/// ```lus
940/// var x, y : int;
941/// ^^^_var
942///     ^^^^^^^^^^^decls
943/// ```
944#[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/// Maybe local variables, or maybe empty.
953#[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/// A Lustre node.
966///
967/// ```lus
968/// node foo(i : int) returns (o : int);
969/// ^^^^_node
970///      ^^^name
971///         ^^^^^^^^^inputs
972///                   ^^^^^^^_returns
973///                           ^^^^^^^^^outputs
974///                                    ^_decl_semi
975/// var n : int;
976/// ^^^^^^^^^^^^locals
977///
978/// let
979/// ^^^_kwlet
980///     o = i;
981///     n = i;
982///     ^^^^^^defs
983/// tel
984/// ^^^_kwtel
985/// ```
986#[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/// Definition of a global constant.
1020///
1021/// ```lus
1022/// const x : int = 5;
1023/// ^^^^^_const
1024///       ^name
1025///         ^_colon
1026///           ^^^ty
1027///               ^_equal
1028///                 ^value
1029/// ```
1030#[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/// A Lustre node that the compiler should trust is defined elsewhere.
1042///
1043/// ```lus
1044/// extern node foo(i : int) returns (o : int);
1045/// ^^^^^^_extern
1046///        ^^^^_node
1047///             ^^^name
1048///                ^^^^^^^^^inputs
1049///                          ^^^^^^^_returns
1050///                                  ^^^^^^^^^outputs
1051///                                           ^_decl_semi
1052/// ```
1053#[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/// A global constant that the compiler should trust already exists.
1076///
1077/// ```lus
1078/// extern const x : int;
1079/// ^^^^^^_extern
1080///        ^^^^^_const
1081///              ^name
1082///                ^_colon
1083///                  ^^^ty
1084/// ```
1085#[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/// A Lustre program.
1252#[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);