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