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}
206
207pub type GlobalDeclarationNode = Spanned<GlobalDeclaration>;
208
209#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
210#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
211#[derive(Clone, Debug, PartialEq)]
212pub struct Declaration {
213    pub attributes: Attributes,
214    pub kind: DeclarationKind,
215    pub ident: Ident,
216    pub ty: Option<TypeExpression>,
217    pub initializer: Option<ExpressionNode>,
218}
219
220#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
221#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
222#[derive(Clone, Copy, Debug, PartialEq, Eq, IsVariant)]
223pub enum DeclarationKind {
224    Const,
225    Override,
226    Let,
227    Var(Option<(AddressSpace, Option<AccessMode>)>), // "None" corresponds to handle space if it is a module-scope declaration, otherwise function space.
228}
229
230#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232#[derive(Clone, Debug, PartialEq)]
233pub struct TypeAlias {
234    #[cfg(feature = "attributes")]
235    pub attributes: Attributes,
236    pub ident: Ident,
237    pub ty: TypeExpression,
238}
239
240#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
241#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
242#[derive(Clone, Debug, PartialEq)]
243pub struct Struct {
244    #[cfg(feature = "attributes")]
245    pub attributes: Attributes,
246    pub ident: Ident,
247    pub members: Vec<StructMemberNode>,
248}
249
250#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
251#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
252#[derive(Clone, Debug, PartialEq)]
253pub struct StructMember {
254    pub attributes: Attributes,
255    pub ident: Ident,
256    pub ty: TypeExpression,
257}
258
259pub type StructMemberNode = Spanned<StructMember>;
260
261#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
262#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
263#[derive(Clone, Debug, PartialEq)]
264pub struct Function {
265    pub attributes: Attributes,
266    pub ident: Ident,
267    pub parameters: Vec<FormalParameter>,
268    pub return_attributes: Attributes,
269    pub return_type: Option<TypeExpression>,
270    pub body: CompoundStatement,
271}
272
273#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
274#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
275#[derive(Clone, Debug, PartialEq)]
276pub struct FormalParameter {
277    pub attributes: Attributes,
278    pub ident: Ident,
279    pub ty: TypeExpression,
280}
281
282#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284#[derive(Clone, Debug, PartialEq)]
285pub struct ConstAssert {
286    #[cfg(feature = "attributes")]
287    pub attributes: Attributes,
288    pub expression: ExpressionNode,
289}
290
291#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
292#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
293#[derive(Clone, Debug, PartialEq)]
294pub struct DiagnosticAttribute {
295    pub severity: DiagnosticSeverity,
296    pub rule: String,
297}
298
299#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
300#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
301#[derive(Clone, Debug, PartialEq)]
302pub struct InterpolateAttribute {
303    pub ty: InterpolationType,
304    pub sampling: Option<InterpolationSampling>,
305}
306
307#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
308#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
309#[derive(Clone, Debug, PartialEq)]
310pub struct WorkgroupSizeAttribute {
311    pub x: ExpressionNode,
312    pub y: Option<ExpressionNode>,
313    pub z: Option<ExpressionNode>,
314}
315
316#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
317#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
318#[derive(Clone, Debug, PartialEq)]
319pub struct CustomAttribute {
320    pub name: String,
321    pub arguments: Option<Vec<ExpressionNode>>,
322}
323
324#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
326#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
327pub enum Attribute {
328    Align(ExpressionNode),
329    Binding(ExpressionNode),
330    BlendSrc(ExpressionNode),
331    #[from]
332    Builtin(BuiltinValue),
333    Const,
334    #[from]
335    Diagnostic(DiagnosticAttribute),
336    Group(ExpressionNode),
337    Id(ExpressionNode),
338    #[from]
339    Interpolate(InterpolateAttribute),
340    Invariant,
341    Location(ExpressionNode),
342    MustUse,
343    Size(ExpressionNode),
344    #[from]
345    WorkgroupSize(WorkgroupSizeAttribute),
346    Vertex,
347    Fragment,
348    Compute,
349    #[cfg(feature = "naga-ext")]
350    Task,
351    #[cfg(feature = "naga-ext")]
352    Payload(ExpressionNode),
353    #[cfg(feature = "naga-ext")]
354    Mesh(ExpressionNode),
355    #[cfg(feature = "imports")]
356    Publish,
357    #[cfg(feature = "condcomp")]
358    If(ExpressionNode),
359    #[cfg(feature = "condcomp")]
360    Elif(ExpressionNode),
361    #[cfg(feature = "condcomp")]
362    Else,
363    #[cfg(feature = "generics")]
364    #[from]
365    Type(TypeConstraint),
366    #[cfg(feature = "naga-ext")]
367    EarlyDepthTest(Option<ConservativeDepth>),
368    #[from]
369    Custom(CustomAttribute),
370}
371
372impl Attribute {
373    pub fn is_entry_point(&self) -> bool {
374        match self {
375            Attribute::Vertex | Attribute::Fragment | Attribute::Compute => true,
376            #[cfg(feature = "naga-ext")]
377            Attribute::Task | Attribute::Mesh(_) => true,
378            _ => false,
379        }
380    }
381}
382
383pub type AttributeNode = Spanned<Attribute>;
384
385#[cfg(feature = "generics")]
386#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
387#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
388#[derive(Clone, Debug, PartialEq, From)]
389pub struct TypeConstraint {
390    pub ident: Ident,
391    pub variants: Vec<TypeExpression>,
392}
393
394pub type Attributes = Vec<AttributeNode>;
395
396#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
397#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
398#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
399pub enum Expression {
400    Literal(LiteralExpression),
401    Parenthesized(ParenthesizedExpression),
402    NamedComponent(NamedComponentExpression),
403    Indexing(IndexingExpression),
404    Unary(UnaryExpression),
405    Binary(BinaryExpression),
406    FunctionCall(FunctionCallExpression),
407    TypeOrIdentifier(TypeExpression),
408}
409
410pub type ExpressionNode = Spanned<Expression>;
411
412#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
413#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
414#[derive(Clone, Copy, Debug, PartialEq, From, IsVariant, Unwrap)]
415pub enum LiteralExpression {
416    Bool(bool),
417    AbstractInt(i64),
418    AbstractFloat(f64),
419    I32(i32),
420    U32(u32),
421    F32(f32),
422    #[from(skip)]
423    F16(f32),
424    #[cfg(feature = "naga-ext")]
425    #[from(skip)]
426    I64(i64),
427    #[cfg(feature = "naga-ext")]
428    #[from(skip)]
429    U64(u64),
430    #[cfg(feature = "naga-ext")]
431    #[from(skip)]
432    F64(f64),
433}
434
435#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
436#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
437#[derive(Clone, Debug, PartialEq)]
438pub struct ParenthesizedExpression {
439    pub expression: ExpressionNode,
440}
441
442#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
444#[derive(Clone, Debug, PartialEq)]
445pub struct NamedComponentExpression {
446    pub base: ExpressionNode,
447    pub component: Ident,
448}
449
450#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
452#[derive(Clone, Debug, PartialEq)]
453pub struct IndexingExpression {
454    pub base: ExpressionNode,
455    pub index: ExpressionNode,
456}
457
458#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
459#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
460#[derive(Clone, Debug, PartialEq)]
461pub struct UnaryExpression {
462    pub operator: UnaryOperator,
463    pub operand: ExpressionNode,
464}
465
466#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
467#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
468#[derive(Clone, Debug, PartialEq)]
469pub struct BinaryExpression {
470    pub operator: BinaryOperator,
471    pub left: ExpressionNode,
472    pub right: ExpressionNode,
473}
474
475#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
477#[derive(Clone, Debug, PartialEq)]
478pub struct FunctionCall {
479    pub ty: TypeExpression,
480    pub arguments: Vec<ExpressionNode>,
481}
482
483pub type FunctionCallExpression = FunctionCall;
484
485#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
487#[derive(Clone, Debug, PartialEq)]
488pub struct TypeExpression {
489    #[cfg(feature = "imports")]
490    pub path: Option<ModulePath>,
491    pub ident: Ident,
492    pub template_args: TemplateArgs,
493}
494
495#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
496#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
497#[derive(Clone, Debug, PartialEq)]
498pub struct TemplateArg {
499    pub expression: ExpressionNode,
500}
501pub type TemplateArgs = Option<Vec<TemplateArg>>;
502
503#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
504#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
505#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
506pub enum Statement {
507    Void,
508    Compound(CompoundStatement),
509    Assignment(AssignmentStatement),
510    Increment(IncrementStatement),
511    Decrement(DecrementStatement),
512    If(IfStatement),
513    Switch(SwitchStatement),
514    Loop(LoopStatement),
515    For(ForStatement),
516    While(WhileStatement),
517    Break(BreakStatement),
518    Continue(ContinueStatement),
519    Return(ReturnStatement),
520    Discard(DiscardStatement),
521    FunctionCall(FunctionCallStatement),
522    ConstAssert(ConstAssertStatement),
523    Declaration(DeclarationStatement),
524}
525
526pub type StatementNode = Spanned<Statement>;
527
528#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
529#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
530#[derive(Clone, Debug, PartialEq, Default)]
531pub struct CompoundStatement {
532    pub attributes: Attributes,
533    pub statements: Vec<StatementNode>,
534}
535
536#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
537#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
538#[derive(Clone, Debug, PartialEq)]
539pub struct AssignmentStatement {
540    #[cfg(feature = "attributes")]
541    pub attributes: Attributes,
542    pub operator: AssignmentOperator,
543    pub lhs: ExpressionNode,
544    pub rhs: ExpressionNode,
545}
546
547#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
548#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
549#[derive(Clone, Debug, PartialEq)]
550pub struct IncrementStatement {
551    #[cfg(feature = "attributes")]
552    pub attributes: Attributes,
553    pub expression: ExpressionNode,
554}
555
556#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
557#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
558#[derive(Clone, Debug, PartialEq)]
559pub struct DecrementStatement {
560    #[cfg(feature = "attributes")]
561    pub attributes: Attributes,
562    pub expression: ExpressionNode,
563}
564
565#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
566#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
567#[derive(Clone, Debug, PartialEq)]
568pub struct IfStatement {
569    pub attributes: Attributes,
570    pub if_clause: IfClause,
571    pub else_if_clauses: Vec<ElseIfClause>,
572    pub else_clause: Option<ElseClause>,
573}
574
575#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
577#[derive(Clone, Debug, PartialEq)]
578pub struct IfClause {
579    pub expression: ExpressionNode,
580    pub body: CompoundStatement,
581}
582
583#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
584#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
585#[derive(Clone, Debug, PartialEq)]
586pub struct ElseIfClause {
587    #[cfg(feature = "attributes")]
588    pub attributes: Attributes,
589    pub expression: ExpressionNode,
590    pub body: CompoundStatement,
591}
592
593#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
595#[derive(Clone, Debug, PartialEq)]
596pub struct ElseClause {
597    #[cfg(feature = "attributes")]
598    pub attributes: Attributes,
599    pub body: CompoundStatement,
600}
601
602#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
603#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
604#[derive(Clone, Debug, PartialEq)]
605pub struct SwitchStatement {
606    pub attributes: Attributes,
607    pub expression: ExpressionNode,
608    pub body_attributes: Attributes,
609    pub clauses: Vec<SwitchClause>,
610}
611
612#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
613#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
614#[derive(Clone, Debug, PartialEq)]
615pub struct SwitchClause {
616    #[cfg(feature = "attributes")]
617    pub attributes: Attributes,
618    pub case_selectors: Vec<CaseSelector>,
619    pub body: CompoundStatement,
620}
621
622#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
623#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
624#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
625pub enum CaseSelector {
626    Default,
627    Expression(ExpressionNode),
628}
629
630#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
631#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
632#[derive(Clone, Debug, PartialEq)]
633pub struct LoopStatement {
634    pub attributes: Attributes,
635    pub body: CompoundStatement,
636    // a ContinuingStatement can only appear inside a LoopStatement body, therefore it is
637    // not part of the StatementNode enum. it appears here instead, but consider it part of
638    // body as the last statement of the CompoundStatement.
639    pub continuing: Option<ContinuingStatement>,
640}
641
642#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
643#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
644#[derive(Clone, Debug, PartialEq)]
645pub struct ContinuingStatement {
646    #[cfg(feature = "attributes")]
647    pub attributes: Attributes,
648    pub body: CompoundStatement,
649    // a BreakIfStatement can only appear inside a ContinuingStatement body, therefore it
650    // not part of the StatementNode enum. it appears here instead, but consider it part of
651    // body as the last statement of the CompoundStatement.
652    pub break_if: Option<BreakIfStatement>,
653}
654
655#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
656#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
657#[derive(Clone, Debug, PartialEq)]
658pub struct BreakIfStatement {
659    #[cfg(feature = "attributes")]
660    pub attributes: Attributes,
661    pub 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 ForStatement {
668    pub attributes: Attributes,
669    pub initializer: Option<StatementNode>,
670    pub condition: Option<ExpressionNode>,
671    pub update: Option<StatementNode>,
672    pub body: CompoundStatement,
673}
674
675#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
676#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
677#[derive(Clone, Debug, PartialEq)]
678pub struct WhileStatement {
679    pub attributes: Attributes,
680    pub condition: ExpressionNode,
681    pub body: CompoundStatement,
682}
683
684#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
685#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
686#[derive(Clone, Debug, PartialEq)]
687pub struct BreakStatement {
688    #[cfg(feature = "attributes")]
689    pub attributes: Attributes,
690}
691
692#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
693#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
694#[derive(Clone, Debug, PartialEq)]
695pub struct ContinueStatement {
696    #[cfg(feature = "attributes")]
697    pub attributes: Attributes,
698}
699
700#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
701#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
702#[derive(Clone, Debug, PartialEq)]
703pub struct ReturnStatement {
704    #[cfg(feature = "attributes")]
705    pub attributes: Attributes,
706    pub expression: Option<ExpressionNode>,
707}
708
709#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
710#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
711#[derive(Clone, Debug, PartialEq)]
712pub struct DiscardStatement {
713    #[cfg(feature = "attributes")]
714    pub attributes: Attributes,
715}
716
717#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
718#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
719#[derive(Clone, Debug, PartialEq)]
720pub struct FunctionCallStatement {
721    #[cfg(feature = "attributes")]
722    pub attributes: Attributes,
723    pub call: FunctionCall,
724}
725
726pub type ConstAssertStatement = ConstAssert;
727
728pub type DeclarationStatement = Declaration;