wgsl_parse/
syntax.rs

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