Skip to main content

wgsl_parse/
syntax.rs

1//! A syntax tree for WGSL and WESL files. The root of the tree is [`TranslationUnit`].
2//!
3//! The syntax tree closely mirrors WGSL spec syntax while allowing language extensions.
4//!
5//! ## Strictness
6//!
7//! This syntax tree is rather strict, meaning it cannot represent most syntactically
8//! incorrect programs. But it is only syntactic, meaning it doesn't perform many
9//! contextual checks: for example, certain attributes can only appear in certain places,
10//! or declarations have different constraints depending on where they appear.
11//!
12//! ## WESL Extensions
13//!
14//! WESL extensions are enabled with the `imports`, `generics`, `attributes` and `condcomp`. Read more about WESL at <https://wesl-lang.dev>.
15//!
16//! ## Design considerations
17//!
18//! The parsing is not designed to be primarily efficient, but flexible and correct.
19//! It is made with the ultimate goal to implement spec-compliant language extensions.
20
21use std::sync::{Arc, RwLock, RwLockReadGuard};
22
23use derive_more::{From, IsVariant, Unwrap};
24
25pub use crate::span::{Span, Spanned};
26
27pub use wgsl_types::syntax::*;
28
29#[cfg(feature = "tokrepr")]
30use tokrepr::TokRepr;
31
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34
35#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37#[derive(Default, Clone, Debug, PartialEq)]
38pub struct TranslationUnit {
39    #[cfg(feature = "imports")]
40    pub imports: Vec<ImportStatement>,
41    pub global_directives: Vec<GlobalDirective>,
42    pub global_declarations: Vec<GlobalDeclarationNode>,
43}
44
45/// Identifiers correspond to WGSL `ident` syntax node, except that they have several
46/// convenience features:
47/// * Can be shared by cloning (they are shared pointers)
48/// * Can be [renamed][Self::rename] (with interior mutability)
49/// * References to the same Ident can be [counted][Self::use_count]
50/// * Equality and Hash compares the reference, NOT the internal string value
51#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
52#[derive(Clone, Debug)]
53pub struct Ident(Arc<RwLock<String>>);
54
55impl Ident {
56    /// Create a new Ident
57    pub fn new(name: String) -> Ident {
58        // TODO: check that the name is a valid ident
59        Ident(Arc::new(RwLock::new(name)))
60    }
61    /// Get the name of the Ident
62    pub fn name(&self) -> RwLockReadGuard<'_, String> {
63        self.0.read().unwrap()
64    }
65    /// Rename all shared instances of the ident
66    pub fn rename(&mut self, name: String) {
67        *self.0.write().unwrap() = name;
68    }
69    /// Count shared instances of the ident
70    pub fn use_count(&self) -> usize {
71        Arc::<_>::strong_count(&self.0)
72    }
73}
74
75impl From<String> for Ident {
76    fn from(name: String) -> Self {
77        Ident::new(name)
78    }
79}
80
81/// equality for idents is based on address, NOT internal value
82impl PartialEq for Ident {
83    fn eq(&self, other: &Self) -> bool {
84        Arc::ptr_eq(&self.0, &other.0)
85    }
86}
87
88/// equality for idents is based on address, NOT internal value
89impl Eq for Ident {}
90
91/// hash for idents is based on address, NOT internal value
92impl std::hash::Hash for Ident {
93    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
94        std::ptr::hash(&*self.0, state)
95    }
96}
97
98#[cfg(feature = "imports")]
99#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[derive(Clone, Debug, PartialEq)]
102pub struct ImportStatement {
103    #[cfg(feature = "attributes")]
104    pub attributes: Attributes,
105    pub path: Option<ModulePath>,
106    pub content: ImportContent,
107}
108
109#[cfg(feature = "imports")]
110#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
111#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
112#[derive(Clone, Debug, PartialEq, Eq, Hash, IsVariant)]
113pub enum PathOrigin {
114    /// Import relative to the current package root, starting with 'package::'.
115    Absolute,
116    /// Import relative to the current module, starting with 'super::'. The usize is the number of 'super's.
117    Relative(usize),
118    /// Import from a package dependency, starting with the extern package name.
119    Package(String),
120}
121
122#[cfg(feature = "imports")]
123#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
124#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
125#[derive(Clone, Debug, PartialEq, Eq, Hash)]
126pub struct ModulePath {
127    pub origin: PathOrigin,
128    pub components: Vec<String>,
129}
130
131#[cfg(feature = "imports")]
132#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[derive(Clone, Debug, PartialEq)]
135pub struct Import {
136    pub path: Vec<String>,
137    pub content: ImportContent,
138}
139
140#[cfg(feature = "imports")]
141#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
142#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
143#[derive(Clone, Debug, PartialEq, IsVariant)]
144pub enum ImportContent {
145    Item(ImportItem),
146    Collection(Vec<Import>),
147}
148
149#[cfg(feature = "imports")]
150#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
151#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
152#[derive(Clone, Debug, PartialEq)]
153pub struct ImportItem {
154    pub ident: Ident,
155    pub rename: Option<Ident>,
156}
157
158#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
159#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
160#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
161pub enum GlobalDirective {
162    Diagnostic(DiagnosticDirective),
163    Enable(EnableDirective),
164    Requires(RequiresDirective),
165}
166
167#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
168#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
169#[derive(Clone, Debug, PartialEq)]
170pub struct DiagnosticDirective {
171    #[cfg(feature = "attributes")]
172    pub attributes: Attributes,
173    pub severity: DiagnosticSeverity,
174    pub rule_name: String,
175}
176
177#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
178#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
179#[derive(Clone, Debug, PartialEq)]
180pub struct EnableDirective {
181    #[cfg(feature = "attributes")]
182    pub attributes: Attributes,
183    pub extensions: Vec<String>,
184}
185
186#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
188#[derive(Clone, Debug, PartialEq)]
189pub struct RequiresDirective {
190    #[cfg(feature = "attributes")]
191    pub attributes: Attributes,
192    pub extensions: Vec<String>,
193}
194
195#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
198pub enum GlobalDeclaration {
199    Void,
200    Declaration(Declaration),
201    TypeAlias(TypeAlias),
202    Struct(Struct),
203    Function(Function),
204    ConstAssert(ConstAssert),
205    #[cfg(feature = "condcomp")]
206    Compound(CompoundGlobalDeclaration),
207}
208
209pub type GlobalDeclarationNode = Spanned<GlobalDeclaration>;
210
211#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
212#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
213#[derive(Clone, Debug, PartialEq)]
214pub struct Declaration {
215    pub attributes: Attributes,
216    pub kind: DeclarationKind,
217    pub ident: Ident,
218    pub ty: Option<TypeExpression>,
219    pub initializer: Option<ExpressionNode>,
220}
221
222#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
224#[derive(Clone, Copy, Debug, PartialEq, Eq, IsVariant)]
225pub enum DeclarationKind {
226    Const,
227    Override,
228    Let,
229    Var(Option<(AddressSpace, Option<AccessMode>)>), // "None" corresponds to handle space if it is a module-scope declaration, otherwise function space.
230}
231
232#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
234#[derive(Clone, Debug, PartialEq)]
235pub struct TypeAlias {
236    #[cfg(feature = "attributes")]
237    pub attributes: Attributes,
238    pub ident: Ident,
239    pub ty: TypeExpression,
240}
241
242#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244#[derive(Clone, Debug, PartialEq)]
245pub struct Struct {
246    #[cfg(feature = "attributes")]
247    pub attributes: Attributes,
248    pub ident: Ident,
249    pub members: Vec<StructMemberNode>,
250}
251
252#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
253#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
254#[derive(Clone, Debug, PartialEq)]
255pub struct StructMember {
256    pub attributes: Attributes,
257    pub ident: Ident,
258    pub ty: TypeExpression,
259}
260
261pub type StructMemberNode = Spanned<StructMember>;
262
263#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
264#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
265#[derive(Clone, Debug, PartialEq)]
266pub struct Function {
267    pub attributes: Attributes,
268    pub ident: Ident,
269    pub parameters: Vec<FormalParameter>,
270    pub return_attributes: Attributes,
271    pub return_type: Option<TypeExpression>,
272    pub body: CompoundStatement,
273}
274
275#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
277#[derive(Clone, Debug, PartialEq)]
278pub struct FormalParameter {
279    pub attributes: Attributes,
280    pub ident: Ident,
281    pub ty: TypeExpression,
282}
283
284#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
286#[derive(Clone, Debug, PartialEq)]
287pub struct ConstAssert {
288    #[cfg(feature = "attributes")]
289    pub attributes: Attributes,
290    pub expression: ExpressionNode,
291}
292
293#[cfg(feature = "condcomp")]
294#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
295#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
296#[derive(Clone, Debug, PartialEq)]
297pub struct CompoundGlobalDeclaration {
298    pub attributes: Attributes,
299    pub body: Vec<GlobalDeclarationNode>,
300}
301
302#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
304#[derive(Clone, Debug, PartialEq)]
305pub struct DiagnosticAttribute {
306    pub severity: DiagnosticSeverity,
307    pub rule: String,
308}
309
310#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
311#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
312#[derive(Clone, Debug, PartialEq)]
313pub struct InterpolateAttribute {
314    pub ty: InterpolationType,
315    pub sampling: Option<InterpolationSampling>,
316}
317
318#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
319#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
320#[derive(Clone, Debug, PartialEq)]
321pub struct WorkgroupSizeAttribute {
322    pub x: ExpressionNode,
323    pub y: Option<ExpressionNode>,
324    pub z: Option<ExpressionNode>,
325}
326
327#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
328#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
329#[derive(Clone, Debug, PartialEq)]
330pub struct CustomAttribute {
331    pub name: String,
332    pub arguments: Option<Vec<ExpressionNode>>,
333}
334
335#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
336#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
337#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
338pub enum Attribute {
339    Align(ExpressionNode),
340    Binding(ExpressionNode),
341    BlendSrc(ExpressionNode),
342    #[from]
343    Builtin(BuiltinValue),
344    Const,
345    #[from]
346    Diagnostic(DiagnosticAttribute),
347    Group(ExpressionNode),
348    Id(ExpressionNode),
349    #[from]
350    Interpolate(InterpolateAttribute),
351    Invariant,
352    Location(ExpressionNode),
353    MustUse,
354    Size(ExpressionNode),
355    #[from]
356    WorkgroupSize(WorkgroupSizeAttribute),
357    Vertex,
358    Fragment,
359    Compute,
360    #[cfg(feature = "naga-ext")]
361    Task,
362    #[cfg(feature = "naga-ext")]
363    Payload(ExpressionNode),
364    #[cfg(feature = "naga-ext")]
365    Mesh(ExpressionNode),
366    #[cfg(feature = "naga-ext")]
367    RayGeneration,
368    #[cfg(feature = "naga-ext")]
369    AnyHit,
370    #[cfg(feature = "naga-ext")]
371    ClosestHit,
372    #[cfg(feature = "naga-ext")]
373    Miss,
374    #[cfg(feature = "naga-ext")]
375    IncomingPayload(ExpressionNode),
376    #[cfg(feature = "imports")]
377    Publish,
378    #[cfg(feature = "condcomp")]
379    If(ExpressionNode),
380    #[cfg(feature = "condcomp")]
381    Elif(ExpressionNode),
382    #[cfg(feature = "condcomp")]
383    Else,
384    #[cfg(feature = "generics")]
385    #[from]
386    Type(TypeConstraint),
387    #[cfg(feature = "naga-ext")]
388    EarlyDepthTest(Option<ConservativeDepth>),
389    #[from]
390    Custom(CustomAttribute),
391}
392
393impl Attribute {
394    pub fn is_entry_point(&self) -> bool {
395        match self {
396            Attribute::Vertex | Attribute::Fragment | Attribute::Compute => true,
397            #[cfg(feature = "naga-ext")]
398            Attribute::Task | Attribute::Mesh(_) => true,
399            #[cfg(feature = "naga-ext")]
400            Attribute::RayGeneration
401            | Attribute::AnyHit
402            | Attribute::ClosestHit
403            | Attribute::Miss => true,
404            _ => false,
405        }
406    }
407
408    #[cfg(feature = "condcomp")]
409    pub fn is_condcomp(&self) -> bool {
410        matches!(
411            self,
412            Attribute::If(_) | Attribute::Elif(_) | Attribute::Else
413        )
414    }
415}
416
417pub type AttributeNode = Spanned<Attribute>;
418
419#[cfg(feature = "generics")]
420#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
421#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
422#[derive(Clone, Debug, PartialEq, From)]
423pub struct TypeConstraint {
424    pub ident: Ident,
425    pub variants: Vec<TypeExpression>,
426}
427
428pub type Attributes = Vec<AttributeNode>;
429
430#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
431#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
432#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
433pub enum Expression {
434    Literal(LiteralExpression),
435    Parenthesized(ParenthesizedExpression),
436    NamedComponent(NamedComponentExpression),
437    Indexing(IndexingExpression),
438    Unary(UnaryExpression),
439    Binary(BinaryExpression),
440    FunctionCall(FunctionCallExpression),
441    TypeOrIdentifier(TypeExpression),
442}
443
444pub type ExpressionNode = Spanned<Expression>;
445
446#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
447#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
448#[derive(Clone, Copy, Debug, PartialEq, From, IsVariant, Unwrap)]
449pub enum LiteralExpression {
450    Bool(bool),
451    AbstractInt(i64),
452    AbstractFloat(f64),
453    I32(i32),
454    U32(u32),
455    F32(f32),
456    #[from(skip)]
457    F16(f32),
458    #[cfg(feature = "naga-ext")]
459    #[from(skip)]
460    I64(i64),
461    #[cfg(feature = "naga-ext")]
462    #[from(skip)]
463    U64(u64),
464    #[cfg(feature = "naga-ext")]
465    #[from(skip)]
466    F64(f64),
467}
468
469#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
470#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
471#[derive(Clone, Debug, PartialEq)]
472pub struct ParenthesizedExpression {
473    pub expression: ExpressionNode,
474}
475
476#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
478#[derive(Clone, Debug, PartialEq)]
479pub struct NamedComponentExpression {
480    pub base: ExpressionNode,
481    pub component: Ident,
482}
483
484#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
485#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
486#[derive(Clone, Debug, PartialEq)]
487pub struct IndexingExpression {
488    pub base: ExpressionNode,
489    pub index: ExpressionNode,
490}
491
492#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
493#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
494#[derive(Clone, Debug, PartialEq)]
495pub struct UnaryExpression {
496    pub operator: UnaryOperator,
497    pub operand: ExpressionNode,
498}
499
500#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
501#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
502#[derive(Clone, Debug, PartialEq)]
503pub struct BinaryExpression {
504    pub operator: BinaryOperator,
505    pub left: ExpressionNode,
506    pub right: ExpressionNode,
507}
508
509#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
510#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
511#[derive(Clone, Debug, PartialEq)]
512pub struct FunctionCall {
513    pub ty: TypeExpression,
514    pub arguments: Vec<ExpressionNode>,
515}
516
517pub type FunctionCallExpression = FunctionCall;
518
519#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
520#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
521#[derive(Clone, Debug, PartialEq)]
522pub struct TypeExpression {
523    #[cfg(feature = "imports")]
524    pub path: Option<ModulePath>,
525    pub ident: Ident,
526    pub template_args: TemplateArgs,
527}
528
529#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
530#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
531#[derive(Clone, Debug, PartialEq)]
532pub struct TemplateArg {
533    pub expression: ExpressionNode,
534}
535pub type TemplateArgs = Option<Vec<TemplateArg>>;
536
537#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
540pub enum Statement {
541    Void,
542    Compound(CompoundStatement),
543    Assignment(AssignmentStatement),
544    Increment(IncrementStatement),
545    Decrement(DecrementStatement),
546    If(IfStatement),
547    Switch(SwitchStatement),
548    Loop(LoopStatement),
549    For(ForStatement),
550    While(WhileStatement),
551    Break(BreakStatement),
552    Continue(ContinueStatement),
553    Return(ReturnStatement),
554    Discard(DiscardStatement),
555    FunctionCall(FunctionCallStatement),
556    ConstAssert(ConstAssertStatement),
557    Declaration(DeclarationStatement),
558}
559
560pub type StatementNode = Spanned<Statement>;
561
562#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
563#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
564#[derive(Clone, Debug, PartialEq, Default)]
565pub struct CompoundStatement {
566    pub attributes: Attributes,
567    pub statements: Vec<StatementNode>,
568}
569
570#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
571#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
572#[derive(Clone, Debug, PartialEq)]
573pub struct AssignmentStatement {
574    #[cfg(feature = "attributes")]
575    pub attributes: Attributes,
576    pub operator: AssignmentOperator,
577    pub lhs: ExpressionNode,
578    pub rhs: ExpressionNode,
579}
580
581#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
582#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
583#[derive(Clone, Debug, PartialEq)]
584pub struct IncrementStatement {
585    #[cfg(feature = "attributes")]
586    pub attributes: Attributes,
587    pub expression: ExpressionNode,
588}
589
590#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
591#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
592#[derive(Clone, Debug, PartialEq)]
593pub struct DecrementStatement {
594    #[cfg(feature = "attributes")]
595    pub attributes: Attributes,
596    pub expression: ExpressionNode,
597}
598
599#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
600#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
601#[derive(Clone, Debug, PartialEq)]
602pub struct IfStatement {
603    pub attributes: Attributes,
604    pub if_clause: IfClause,
605    pub else_if_clauses: Vec<ElseIfClause>,
606    pub else_clause: Option<ElseClause>,
607}
608
609#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
610#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
611#[derive(Clone, Debug, PartialEq)]
612pub struct IfClause {
613    pub expression: ExpressionNode,
614    pub body: CompoundStatement,
615}
616
617#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
618#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
619#[derive(Clone, Debug, PartialEq)]
620pub struct ElseIfClause {
621    #[cfg(feature = "attributes")]
622    pub attributes: Attributes,
623    pub expression: ExpressionNode,
624    pub body: CompoundStatement,
625}
626
627#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
628#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
629#[derive(Clone, Debug, PartialEq)]
630pub struct ElseClause {
631    #[cfg(feature = "attributes")]
632    pub attributes: Attributes,
633    pub body: CompoundStatement,
634}
635
636#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
637#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
638#[derive(Clone, Debug, PartialEq)]
639pub struct SwitchStatement {
640    pub attributes: Attributes,
641    pub expression: ExpressionNode,
642    pub body_attributes: Attributes,
643    pub clauses: Vec<SwitchClause>,
644}
645
646#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
648#[derive(Clone, Debug, PartialEq)]
649pub struct SwitchClause {
650    #[cfg(feature = "attributes")]
651    pub attributes: Attributes,
652    pub case_selectors: Vec<CaseSelector>,
653    pub body: CompoundStatement,
654}
655
656#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
657#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
658#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
659pub enum CaseSelector {
660    Default,
661    Expression(ExpressionNode),
662}
663
664#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
666#[derive(Clone, Debug, PartialEq)]
667pub struct LoopStatement {
668    pub attributes: Attributes,
669    pub body: CompoundStatement,
670    // a ContinuingStatement can only appear inside a LoopStatement body, therefore it is
671    // not part of the StatementNode enum. it appears here instead, but consider it part of
672    // body as the last statement of the CompoundStatement.
673    pub continuing: Option<ContinuingStatement>,
674}
675
676#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
677#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
678#[derive(Clone, Debug, PartialEq)]
679pub struct ContinuingStatement {
680    #[cfg(feature = "attributes")]
681    pub attributes: Attributes,
682    pub body: CompoundStatement,
683    // a BreakIfStatement can only appear inside a ContinuingStatement body, therefore it
684    // not part of the StatementNode enum. it appears here instead, but consider it part of
685    // body as the last statement of the CompoundStatement.
686    pub break_if: Option<BreakIfStatement>,
687}
688
689#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
690#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
691#[derive(Clone, Debug, PartialEq)]
692pub struct BreakIfStatement {
693    #[cfg(feature = "attributes")]
694    pub attributes: Attributes,
695    pub expression: ExpressionNode,
696}
697
698#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
699#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
700#[derive(Clone, Debug, PartialEq)]
701pub struct ForStatement {
702    pub attributes: Attributes,
703    pub initializer: Option<StatementNode>,
704    pub condition: Option<ExpressionNode>,
705    pub update: Option<StatementNode>,
706    pub body: CompoundStatement,
707}
708
709#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
710#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
711#[derive(Clone, Debug, PartialEq)]
712pub struct WhileStatement {
713    pub attributes: Attributes,
714    pub condition: ExpressionNode,
715    pub body: CompoundStatement,
716}
717
718#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
719#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
720#[derive(Clone, Debug, PartialEq)]
721pub struct BreakStatement {
722    #[cfg(feature = "attributes")]
723    pub attributes: Attributes,
724}
725
726#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
727#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
728#[derive(Clone, Debug, PartialEq)]
729pub struct ContinueStatement {
730    #[cfg(feature = "attributes")]
731    pub attributes: Attributes,
732}
733
734#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
735#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
736#[derive(Clone, Debug, PartialEq)]
737pub struct ReturnStatement {
738    #[cfg(feature = "attributes")]
739    pub attributes: Attributes,
740    pub expression: Option<ExpressionNode>,
741}
742
743#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
744#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
745#[derive(Clone, Debug, PartialEq)]
746pub struct DiscardStatement {
747    #[cfg(feature = "attributes")]
748    pub attributes: Attributes,
749}
750
751#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
752#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
753#[derive(Clone, Debug, PartialEq)]
754pub struct FunctionCallStatement {
755    #[cfg(feature = "attributes")]
756    pub attributes: Attributes,
757    pub call: FunctionCall,
758}
759
760pub type ConstAssertStatement = ConstAssert;
761
762pub type DeclarationStatement = Declaration;