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'.
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 = "imports")]
350    Publish,
351    #[cfg(feature = "condcomp")]
352    If(ExpressionNode),
353    #[cfg(feature = "condcomp")]
354    Elif(ExpressionNode),
355    #[cfg(feature = "condcomp")]
356    Else,
357    #[cfg(feature = "generics")]
358    #[from]
359    Type(TypeConstraint),
360    #[cfg(feature = "naga-ext")]
361    EarlyDepthTest(Option<ConservativeDepth>),
362    #[from]
363    Custom(CustomAttribute),
364}
365
366pub type AttributeNode = Spanned<Attribute>;
367
368#[cfg(feature = "generics")]
369#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
370#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
371#[derive(Clone, Debug, PartialEq, From)]
372pub struct TypeConstraint {
373    pub ident: Ident,
374    pub variants: Vec<TypeExpression>,
375}
376
377pub type Attributes = Vec<AttributeNode>;
378
379#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
381#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
382pub enum Expression {
383    Literal(LiteralExpression),
384    Parenthesized(ParenthesizedExpression),
385    NamedComponent(NamedComponentExpression),
386    Indexing(IndexingExpression),
387    Unary(UnaryExpression),
388    Binary(BinaryExpression),
389    FunctionCall(FunctionCallExpression),
390    TypeOrIdentifier(TypeExpression),
391}
392
393pub type ExpressionNode = Spanned<Expression>;
394
395#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
397#[derive(Clone, Copy, Debug, PartialEq, From, IsVariant, Unwrap)]
398pub enum LiteralExpression {
399    Bool(bool),
400    AbstractInt(i64),
401    AbstractFloat(f64),
402    I32(i32),
403    U32(u32),
404    F32(f32),
405    #[from(skip)]
406    F16(f32),
407    #[cfg(feature = "naga-ext")]
408    #[from(skip)]
409    I64(i64),
410    #[cfg(feature = "naga-ext")]
411    #[from(skip)]
412    U64(u64),
413    #[cfg(feature = "naga-ext")]
414    #[from(skip)]
415    F64(f64),
416}
417
418#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
419#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
420#[derive(Clone, Debug, PartialEq)]
421pub struct ParenthesizedExpression {
422    pub expression: ExpressionNode,
423}
424
425#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
426#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
427#[derive(Clone, Debug, PartialEq)]
428pub struct NamedComponentExpression {
429    pub base: ExpressionNode,
430    pub component: Ident,
431}
432
433#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
434#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
435#[derive(Clone, Debug, PartialEq)]
436pub struct IndexingExpression {
437    pub base: ExpressionNode,
438    pub index: ExpressionNode,
439}
440
441#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
442#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
443#[derive(Clone, Debug, PartialEq)]
444pub struct UnaryExpression {
445    pub operator: UnaryOperator,
446    pub operand: ExpressionNode,
447}
448
449#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
450#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
451#[derive(Clone, Debug, PartialEq)]
452pub struct BinaryExpression {
453    pub operator: BinaryOperator,
454    pub left: ExpressionNode,
455    pub right: 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 FunctionCall {
462    pub ty: TypeExpression,
463    pub arguments: Vec<ExpressionNode>,
464}
465
466pub type FunctionCallExpression = FunctionCall;
467
468#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
469#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
470#[derive(Clone, Debug, PartialEq)]
471pub struct TypeExpression {
472    #[cfg(feature = "imports")]
473    pub path: Option<ModulePath>,
474    pub ident: Ident,
475    pub template_args: TemplateArgs,
476}
477
478#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
479#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
480#[derive(Clone, Debug, PartialEq)]
481pub struct TemplateArg {
482    pub expression: ExpressionNode,
483}
484pub type TemplateArgs = Option<Vec<TemplateArg>>;
485
486#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
487#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
488#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
489pub enum Statement {
490    Void,
491    Compound(CompoundStatement),
492    Assignment(AssignmentStatement),
493    Increment(IncrementStatement),
494    Decrement(DecrementStatement),
495    If(IfStatement),
496    Switch(SwitchStatement),
497    Loop(LoopStatement),
498    For(ForStatement),
499    While(WhileStatement),
500    Break(BreakStatement),
501    Continue(ContinueStatement),
502    Return(ReturnStatement),
503    Discard(DiscardStatement),
504    FunctionCall(FunctionCallStatement),
505    ConstAssert(ConstAssertStatement),
506    Declaration(DeclarationStatement),
507}
508
509pub type StatementNode = Spanned<Statement>;
510
511#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
512#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
513#[derive(Clone, Debug, PartialEq, Default)]
514pub struct CompoundStatement {
515    pub attributes: Attributes,
516    pub statements: Vec<StatementNode>,
517}
518
519#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
520#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
521#[derive(Clone, Debug, PartialEq)]
522pub struct AssignmentStatement {
523    #[cfg(feature = "attributes")]
524    pub attributes: Attributes,
525    pub operator: AssignmentOperator,
526    pub lhs: ExpressionNode,
527    pub rhs: ExpressionNode,
528}
529
530#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
532#[derive(Clone, Debug, PartialEq)]
533pub struct IncrementStatement {
534    #[cfg(feature = "attributes")]
535    pub attributes: Attributes,
536    pub expression: ExpressionNode,
537}
538
539#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
540#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
541#[derive(Clone, Debug, PartialEq)]
542pub struct DecrementStatement {
543    #[cfg(feature = "attributes")]
544    pub attributes: Attributes,
545    pub expression: ExpressionNode,
546}
547
548#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
549#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
550#[derive(Clone, Debug, PartialEq)]
551pub struct IfStatement {
552    pub attributes: Attributes,
553    pub if_clause: IfClause,
554    pub else_if_clauses: Vec<ElseIfClause>,
555    pub else_clause: Option<ElseClause>,
556}
557
558#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
559#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
560#[derive(Clone, Debug, PartialEq)]
561pub struct IfClause {
562    pub expression: ExpressionNode,
563    pub body: CompoundStatement,
564}
565
566#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
567#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
568#[derive(Clone, Debug, PartialEq)]
569pub struct ElseIfClause {
570    #[cfg(feature = "attributes")]
571    pub attributes: Attributes,
572    pub expression: ExpressionNode,
573    pub body: CompoundStatement,
574}
575
576#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
577#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
578#[derive(Clone, Debug, PartialEq)]
579pub struct ElseClause {
580    #[cfg(feature = "attributes")]
581    pub attributes: Attributes,
582    pub body: CompoundStatement,
583}
584
585#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
587#[derive(Clone, Debug, PartialEq)]
588pub struct SwitchStatement {
589    pub attributes: Attributes,
590    pub expression: ExpressionNode,
591    pub body_attributes: Attributes,
592    pub clauses: Vec<SwitchClause>,
593}
594
595#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
597#[derive(Clone, Debug, PartialEq)]
598pub struct SwitchClause {
599    #[cfg(feature = "attributes")]
600    pub attributes: Attributes,
601    pub case_selectors: Vec<CaseSelector>,
602    pub body: CompoundStatement,
603}
604
605#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
606#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
607#[derive(Clone, Debug, PartialEq, From, IsVariant, Unwrap)]
608pub enum CaseSelector {
609    Default,
610    Expression(ExpressionNode),
611}
612
613#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
614#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
615#[derive(Clone, Debug, PartialEq)]
616pub struct LoopStatement {
617    pub attributes: Attributes,
618    pub body: CompoundStatement,
619    // a ContinuingStatement can only appear inside a LoopStatement body, therefore it is
620    // not part of the StatementNode enum. it appears here instead, but consider it part of
621    // body as the last statement of the CompoundStatement.
622    pub continuing: Option<ContinuingStatement>,
623}
624
625#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
626#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
627#[derive(Clone, Debug, PartialEq)]
628pub struct ContinuingStatement {
629    #[cfg(feature = "attributes")]
630    pub attributes: Attributes,
631    pub body: CompoundStatement,
632    // a BreakIfStatement can only appear inside a ContinuingStatement body, therefore it
633    // not part of the StatementNode enum. it appears here instead, but consider it part of
634    // body as the last statement of the CompoundStatement.
635    pub break_if: Option<BreakIfStatement>,
636}
637
638#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
639#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
640#[derive(Clone, Debug, PartialEq)]
641pub struct BreakIfStatement {
642    #[cfg(feature = "attributes")]
643    pub attributes: Attributes,
644    pub expression: ExpressionNode,
645}
646
647#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
648#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
649#[derive(Clone, Debug, PartialEq)]
650pub struct ForStatement {
651    pub attributes: Attributes,
652    pub initializer: Option<StatementNode>,
653    pub condition: Option<ExpressionNode>,
654    pub update: Option<StatementNode>,
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 WhileStatement {
662    pub attributes: Attributes,
663    pub condition: ExpressionNode,
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 BreakStatement {
671    #[cfg(feature = "attributes")]
672    pub attributes: Attributes,
673}
674
675#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
676#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
677#[derive(Clone, Debug, PartialEq)]
678pub struct ContinueStatement {
679    #[cfg(feature = "attributes")]
680    pub attributes: Attributes,
681}
682
683#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
684#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
685#[derive(Clone, Debug, PartialEq)]
686pub struct ReturnStatement {
687    #[cfg(feature = "attributes")]
688    pub attributes: Attributes,
689    pub expression: Option<ExpressionNode>,
690}
691
692#[cfg_attr(feature = "tokrepr", derive(TokRepr))]
693#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
694#[derive(Clone, Debug, PartialEq)]
695pub struct DiscardStatement {
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 FunctionCallStatement {
704    #[cfg(feature = "attributes")]
705    pub attributes: Attributes,
706    pub call: FunctionCall,
707}
708
709pub type ConstAssertStatement = ConstAssert;
710
711pub type DeclarationStatement = Declaration;