wgsl_parse/
syntax_impl.rs

1use super::syntax::*;
2use crate::span::Spanned;
3
4impl TranslationUnit {
5    /// New empty [`TranslationUnit`]
6    pub fn new() -> Self {
7        Self::default()
8    }
9
10    /// Remove all [`GlobalDeclaration::Void`] and [`Statement::Void`]
11    pub fn remove_voids(&mut self) {
12        self.global_declarations
13            .retain_mut(|decl| match decl.node() {
14                GlobalDeclaration::Void => false,
15                _ => {
16                    decl.remove_voids();
17                    true
18                }
19            })
20    }
21}
22
23#[cfg(feature = "imports")]
24impl ModulePath {
25    /// Create a new module path from components.
26    ///
27    /// Precondition: the path components must be valid WGSL identifiers.
28    pub fn new(origin: PathOrigin, components: Vec<String>) -> Self {
29        Self { origin, components }
30    }
31
32    /// Create a module path that refers to the root module, i.e. `package`.
33    ///
34    /// Technically `import package;` is not a valid import statement in WESL code.
35    /// However adding an item to the path, such as `import package::foo;` points at
36    /// declaration `foo` in the root module.
37    pub fn new_root() -> Self {
38        Self::new(PathOrigin::Absolute, vec![])
39    }
40
41    /// Create a new module path from a filesystem path.
42    ///
43    /// * Paths with a root (leading `/` on Unix) produce `package::` paths.
44    /// * Relative paths (starting with `.` or `..`) produce `self::` or `super::` paths.
45    /// * The file extension is ignored.
46    /// * The path is canonicalized and to do so it does NOT follow symlinks.
47    ///
48    /// Preconditions:
49    /// * The path must not start with a prefix, like C:\ on windows.
50    /// * The path must contain at least one named component.
51    /// * Named components must be valid module names.
52    ///   (Module names are WGSL identifiers + certain reserved names, see wesl-spec#127)
53    pub fn from_path(path: impl AsRef<std::path::Path>) -> Self {
54        use std::path::Component;
55        let path = path.as_ref().with_extension("");
56        let mut parts = path.components().peekable();
57
58        let origin = match parts.next() {
59            Some(Component::Prefix(_)) => panic!("path starts with a Windows prefix"),
60            Some(Component::RootDir) => PathOrigin::Absolute,
61            Some(Component::CurDir) => PathOrigin::Relative(0),
62            Some(Component::ParentDir) => {
63                let mut n = 1;
64                while let Some(&Component::ParentDir) = parts.peek() {
65                    n += 1;
66                    parts.next().unwrap();
67                }
68                PathOrigin::Relative(n)
69            }
70            Some(Component::Normal(name)) => {
71                PathOrigin::Package(name.to_string_lossy().to_string())
72            }
73            None => panic!("path is empty"),
74        };
75
76        let components = parts
77            .map(|part| match part {
78                Component::Normal(name) => name.to_string_lossy().to_string(),
79                _ => panic!("unexpected path component"),
80            })
81            .collect::<Vec<_>>();
82
83        Self { origin, components }
84    }
85
86    /// Create a `PathBuf` from a `ModulePath`.
87    ///
88    /// * `package::` paths are rooted (start with `/`).
89    /// * self::` or `super::` are relative (starting with `.` or `..`)`.
90    /// * There is no file extension.
91    pub fn to_path_buf(&self) -> std::path::PathBuf {
92        use std::path::PathBuf;
93        let mut fs_path = match &self.origin {
94            PathOrigin::Absolute => PathBuf::from("/"),
95            PathOrigin::Relative(0) => PathBuf::from("."),
96            PathOrigin::Relative(n) => PathBuf::from_iter((0..*n).map(|_| "..")),
97            PathOrigin::Package(name) => PathBuf::from(name),
98        };
99        fs_path.extend(&self.components);
100        fs_path
101    }
102
103    /// Append a component to the path.
104    ///
105    /// Precondition: the `item` must be a valid WGSL identifier.
106    pub fn push(&mut self, item: &str) {
107        self.components.push(item.to_string());
108    }
109
110    /// Get the first component of the module path.
111    pub fn first(&self) -> Option<&str> {
112        self.components.first().map(String::as_str)
113    }
114
115    /// Get the last component of the module path.
116    pub fn last(&self) -> Option<&str> {
117        self.components.last().map(String::as_str)
118    }
119
120    /// Append `suffix` to the module path.
121    pub fn join(mut self, suffix: impl IntoIterator<Item = String>) -> Self {
122        self.components.extend(suffix);
123        self
124    }
125
126    /// Append `suffix` to the module path.
127    ///
128    /// This function produces a `ModulePath` relative to `self`, as if `suffix` was
129    /// imported from module `self`.
130    ///
131    /// * If `suffix` is relative, it appends its components to `self`.
132    /// * If `suffix` if absolute or package, it ignores `self` components.
133    /// * If both `self` and `suffix` are package paths, then `suffix` imports from a
134    ///   sub-package. The package is renamed with a slash separating package names.
135    ///   (TODO: this is a hack)
136    pub fn join_path(&self, suffix: &Self) -> Self {
137        match suffix.origin {
138            PathOrigin::Absolute => {
139                match self.origin {
140                    PathOrigin::Absolute | PathOrigin::Relative(_) => suffix.clone(),
141                    PathOrigin::Package(_) => {
142                        // absolute import from inside a package is a package import
143                        let origin = self.origin.clone();
144                        let components = suffix.components.clone();
145                        Self { origin, components }
146                    }
147                }
148            }
149            PathOrigin::Relative(n) => {
150                let to_keep = self.components.len().saturating_sub(n);
151                let components = self
152                    .components
153                    .iter()
154                    .take(to_keep)
155                    .chain(&suffix.components)
156                    .cloned()
157                    .collect::<Vec<_>>();
158                let origin = match self.origin {
159                    PathOrigin::Absolute | PathOrigin::Package(_) => self.origin.clone(),
160                    PathOrigin::Relative(m) => PathOrigin::Relative(m + n - to_keep),
161                };
162                Self { origin, components }
163            }
164            PathOrigin::Package(ref suffix_pkg) => {
165                match &self.origin {
166                    PathOrigin::Absolute | PathOrigin::Relative(_) => suffix.clone(),
167                    PathOrigin::Package(self_pkg) => {
168                        // Importing a sub-package. This is a hack: we rename the package to
169                        // parent/child, which cannot be spelled in code.
170                        let origin = PathOrigin::Package(format!("{self_pkg}/{suffix_pkg}"));
171                        let components = suffix.components.clone();
172                        Self { origin, components }
173                    }
174                }
175            }
176        }
177    }
178
179    /// Whether the module path starts with a `prefix`.
180    pub fn starts_with(&self, prefix: &Self) -> bool {
181        self.origin == prefix.origin
182            && self.components.len() >= prefix.components.len()
183            && prefix
184                .components
185                .iter()
186                .zip(&self.components)
187                .all(|(a, b)| a == b)
188    }
189
190    /// Whether the module path points at the route module.
191    ///
192    /// See [`Self::new_root`].
193    pub fn is_root(&self) -> bool {
194        self.origin.is_absolute() && self.components.is_empty()
195    }
196}
197
198#[cfg(feature = "imports")]
199#[test]
200fn test_module_path_join() {
201    use std::str::FromStr;
202    // TODO: move this test and join_paths impl to ModulePath::join_path
203    let cases = [
204        ("package::m1", "package::foo", "package::foo"),
205        ("package::m1", "self::foo", "package::m1::foo"),
206        ("package::m1", "super::foo", "package::foo"),
207        ("pkg::m1::m2", "package::foo", "pkg::foo"),
208        ("pkg::m1::m2", "self::foo", "pkg::m1::m2::foo"),
209        ("pkg::m1::m2", "super::foo", "pkg::m1::foo"),
210        ("pkg::m1", "super::super::foo", "pkg::foo"),
211        ("super", "super::foo", "super::super::foo"),
212        ("super", "self::foo", "super::foo"),
213        ("self", "super::foo", "super::foo"),
214    ];
215
216    for (parent, child, expect) in cases {
217        let parent = ModulePath::from_str(parent).unwrap();
218        let child = ModulePath::from_str(child).unwrap();
219        let expect = ModulePath::from_str(expect).unwrap();
220        println!("testing join_paths({parent}, {child}) -> {expect}");
221        assert_eq!(parent.join_path(&child), expect);
222    }
223}
224
225#[cfg(feature = "imports")]
226#[derive(Clone, Copy, PartialEq, Eq, Debug, thiserror::Error)]
227pub enum ModulePathParseError {
228    #[error("module name cannot be empty")]
229    Empty,
230    #[error("`package` must be a prefix of the module path")]
231    MisplacedPackage,
232    #[error("`self` must be a prefix of the module path")]
233    MisplacedSelf,
234    #[error("`super` must be a prefix of the module path")]
235    MisplacedSuper,
236}
237
238#[cfg(feature = "imports")]
239impl std::str::FromStr for ModulePath {
240    type Err = ModulePathParseError;
241
242    /// Parse a WGSL string into a module path.
243    ///
244    /// Preconditions:
245    /// * The path components must be valid WESL module names.
246    fn from_str(s: &str) -> Result<Self, Self::Err> {
247        let mut parts = s.split("::").peekable();
248
249        let origin = match parts.next() {
250            Some("package") => PathOrigin::Absolute,
251            Some("self") => PathOrigin::Relative(0),
252            Some("super") => {
253                let mut n = 1;
254                while let Some(&"super") = parts.peek() {
255                    n += 1;
256                    parts.next().unwrap();
257                }
258                PathOrigin::Relative(n)
259            }
260            Some("") | None => return Err(ModulePathParseError::Empty),
261            Some(name) => PathOrigin::Package(name.to_string()),
262        };
263
264        let components = parts
265            .map(|part| match part {
266                "package" => Err(ModulePathParseError::MisplacedPackage),
267                "self" => Err(ModulePathParseError::MisplacedSelf),
268                "super" => Err(ModulePathParseError::MisplacedSuper),
269                _ => Ok(part.to_string()),
270            })
271            .collect::<Result<Vec<_>, _>>()?;
272
273        Ok(Self { origin, components })
274    }
275}
276
277#[cfg(feature = "imports")]
278#[test]
279fn test_module_path_fromstr() {
280    use std::str::FromStr;
281
282    let ok_cases = [
283        ("self", ModulePath::new(PathOrigin::Relative(0), vec![])),
284        ("super", ModulePath::new(PathOrigin::Relative(1), vec![])),
285        ("package", ModulePath::new(PathOrigin::Absolute, vec![])),
286        (
287            "a",
288            ModulePath::new(PathOrigin::Package("a".to_string()), vec![]),
289        ),
290        (
291            "super::super::a",
292            ModulePath::new(PathOrigin::Relative(2), vec!["a".to_string()]),
293        ),
294    ];
295    let err_cases = [
296        ("", ModulePathParseError::Empty),
297        ("a::super", ModulePathParseError::MisplacedSuper),
298        ("super::self", ModulePathParseError::MisplacedSelf),
299        ("self::package", ModulePathParseError::MisplacedPackage),
300    ];
301
302    for (s, m) in ok_cases {
303        assert_eq!(ModulePath::from_str(s), Ok(m))
304    }
305    for (s, e) in err_cases {
306        assert_eq!(ModulePath::from_str(s), Err(e))
307    }
308}
309
310impl GlobalDeclaration {
311    /// Remove all [`Statement::Void`]
312    pub fn remove_voids(&mut self) {
313        if let GlobalDeclaration::Function(decl) = self {
314            decl.body.remove_voids();
315        }
316    }
317}
318
319impl TypeAlias {
320    pub fn new(ident: Ident, ty: TypeExpression) -> Self {
321        Self {
322            #[cfg(feature = "attributes")]
323            attributes: Default::default(),
324            ident,
325            ty,
326        }
327    }
328}
329
330impl Struct {
331    pub fn new(ident: Ident) -> Self {
332        Self {
333            #[cfg(feature = "attributes")]
334            attributes: Default::default(),
335            ident,
336            members: Default::default(),
337        }
338    }
339}
340
341impl StructMember {
342    pub fn new(ident: Ident, ty: TypeExpression) -> Self {
343        Self {
344            attributes: Default::default(),
345            ident,
346            ty,
347        }
348    }
349}
350
351impl Function {
352    pub fn new(ident: Ident) -> Self {
353        Self {
354            attributes: Default::default(),
355            ident,
356            parameters: Default::default(),
357            return_attributes: Default::default(),
358            return_type: Default::default(),
359            body: Default::default(),
360        }
361    }
362}
363
364impl FormalParameter {
365    pub fn new(ident: Ident, ty: TypeExpression) -> Self {
366        Self {
367            attributes: Default::default(),
368            ident,
369            ty,
370        }
371    }
372}
373
374impl ConstAssert {
375    pub fn new(expression: Expression) -> Self {
376        Self {
377            #[cfg(feature = "attributes")]
378            attributes: Default::default(),
379            expression: expression.into(),
380        }
381    }
382}
383
384impl TypeExpression {
385    /// New [`TypeExpression`] with no template.
386    pub fn new(ident: Ident) -> Self {
387        Self {
388            #[cfg(feature = "imports")]
389            path: None,
390            ident,
391            template_args: None,
392        }
393    }
394}
395
396impl CompoundStatement {
397    /// Remove all [`Statement::Void`]
398    pub fn remove_voids(&mut self) {
399        self.statements.retain_mut(|stmt| match stmt.node_mut() {
400            Statement::Void => false,
401            _ => {
402                stmt.remove_voids();
403                true
404            }
405        })
406    }
407}
408
409impl Statement {
410    /// Remove all [`Statement::Void`]
411    pub fn remove_voids(&mut self) {
412        match self {
413            Statement::Compound(stmt) => {
414                stmt.remove_voids();
415            }
416            Statement::If(stmt) => {
417                stmt.if_clause.body.remove_voids();
418                for clause in &mut stmt.else_if_clauses {
419                    clause.body.remove_voids();
420                }
421                if let Some(clause) = &mut stmt.else_clause {
422                    clause.body.remove_voids();
423                }
424            }
425            Statement::Switch(stmt) => stmt
426                .clauses
427                .iter_mut()
428                .for_each(|clause| clause.body.remove_voids()),
429            Statement::Loop(stmt) => stmt.body.remove_voids(),
430            Statement::For(stmt) => stmt.body.remove_voids(),
431            Statement::While(stmt) => stmt.body.remove_voids(),
432            _ => (),
433        }
434    }
435}
436
437impl AccessMode {
438    /// Is [`Self::Read`] or [`Self::ReadWrite`]
439    pub fn is_read(&self) -> bool {
440        matches!(self, Self::Read | Self::ReadWrite)
441    }
442    /// Is [`Self::Write`] or [`Self::ReadWrite`]
443    pub fn is_write(&self) -> bool {
444        matches!(self, Self::Write | Self::ReadWrite)
445    }
446}
447
448impl From<Ident> for TypeExpression {
449    fn from(ident: Ident) -> Self {
450        Self::new(ident)
451    }
452}
453
454impl From<ExpressionNode> for ReturnStatement {
455    fn from(expression: ExpressionNode) -> Self {
456        Self {
457            #[cfg(feature = "attributes")]
458            attributes: Default::default(),
459            expression: Some(expression),
460        }
461    }
462}
463impl From<Expression> for ReturnStatement {
464    fn from(expression: Expression) -> Self {
465        Self::from(ExpressionNode::from(expression))
466    }
467}
468
469impl From<FunctionCall> for FunctionCallStatement {
470    fn from(call: FunctionCall) -> Self {
471        Self {
472            #[cfg(feature = "attributes")]
473            attributes: Default::default(),
474            call,
475        }
476    }
477}
478
479// Transitive `From` implementations.
480// They have to be implemented manually unfortunately.
481
482macro_rules! impl_transitive_from {
483    ($from:ident => $middle:ident => $into:ident) => {
484        impl From<$from> for $into {
485            fn from(value: $from) -> Self {
486                $into::from($middle::from(value))
487            }
488        }
489    };
490}
491
492impl_transitive_from!(bool => LiteralExpression => Expression);
493impl_transitive_from!(i64 => LiteralExpression => Expression);
494impl_transitive_from!(f64 => LiteralExpression => Expression);
495impl_transitive_from!(i32 => LiteralExpression => Expression);
496impl_transitive_from!(u32 => LiteralExpression => Expression);
497impl_transitive_from!(f32 => LiteralExpression => Expression);
498impl_transitive_from!(Ident => TypeExpression => Expression);
499
500impl GlobalDeclaration {
501    /// Get the name of the declaration, if it has one.
502    pub fn ident(&self) -> Option<&Ident> {
503        match self {
504            GlobalDeclaration::Void => None,
505            GlobalDeclaration::Declaration(decl) => Some(&decl.ident),
506            GlobalDeclaration::TypeAlias(decl) => Some(&decl.ident),
507            GlobalDeclaration::Struct(decl) => Some(&decl.ident),
508            GlobalDeclaration::Function(decl) => Some(&decl.ident),
509            GlobalDeclaration::ConstAssert(_) => None,
510        }
511    }
512    /// Get the name of the declaration, if it has one.
513    pub fn ident_mut(&mut self) -> Option<&mut Ident> {
514        match self {
515            GlobalDeclaration::Void => None,
516            GlobalDeclaration::Declaration(decl) => Some(&mut decl.ident),
517            GlobalDeclaration::TypeAlias(decl) => Some(&mut decl.ident),
518            GlobalDeclaration::Struct(decl) => Some(&mut decl.ident),
519            GlobalDeclaration::Function(decl) => Some(&mut decl.ident),
520            GlobalDeclaration::ConstAssert(_) => None,
521        }
522    }
523}
524
525/// A trait implemented on all types that can be prefixed by attributes.
526pub trait Decorated {
527    /// List all attributes (`@name`) of a syntax node.
528    fn attributes(&self) -> &[AttributeNode];
529    /// List all attributes (`@name`) of a syntax node.
530    fn attributes_mut(&mut self) -> &mut [AttributeNode];
531    /// Remove attributes with predicate.
532    fn contains_attribute(&self, attribute: &Attribute) -> bool {
533        self.attributes().iter().any(|v| v.node() == attribute)
534    }
535    /// Remove attributes with predicate.
536    fn retain_attributes_mut<F>(&mut self, f: F)
537    where
538        F: FnMut(&mut Attribute) -> bool;
539}
540
541impl<T: Decorated> Decorated for Spanned<T> {
542    fn attributes(&self) -> &[AttributeNode] {
543        self.node().attributes()
544    }
545
546    fn attributes_mut(&mut self) -> &mut [AttributeNode] {
547        self.node_mut().attributes_mut()
548    }
549
550    fn retain_attributes_mut<F>(&mut self, mut f: F)
551    where
552        F: FnMut(&mut Attribute) -> bool,
553    {
554        self.node_mut().retain_attributes_mut(|v| f(v))
555    }
556}
557
558macro_rules! impl_decorated_struct {
559    ($ty:ty) => {
560        impl Decorated for $ty {
561            fn attributes(&self) -> &[AttributeNode] {
562                &self.attributes
563            }
564            fn attributes_mut(&mut self) -> &mut [AttributeNode] {
565                &mut self.attributes
566            }
567            fn retain_attributes_mut<F>(&mut self, mut f: F)
568            where
569                F: FnMut(&mut Attribute) -> bool,
570            {
571                self.attributes.retain_mut(|v| f(v))
572            }
573        }
574    };
575}
576
577#[cfg(all(feature = "imports", feature = "attributes"))]
578impl_decorated_struct!(ImportStatement);
579
580#[cfg(feature = "attributes")]
581impl Decorated for GlobalDirective {
582    fn attributes(&self) -> &[AttributeNode] {
583        match self {
584            GlobalDirective::Diagnostic(directive) => &directive.attributes,
585            GlobalDirective::Enable(directive) => &directive.attributes,
586            GlobalDirective::Requires(directive) => &directive.attributes,
587        }
588    }
589
590    fn attributes_mut(&mut self) -> &mut [AttributeNode] {
591        match self {
592            GlobalDirective::Diagnostic(directive) => &mut directive.attributes,
593            GlobalDirective::Enable(directive) => &mut directive.attributes,
594            GlobalDirective::Requires(directive) => &mut directive.attributes,
595        }
596    }
597
598    fn retain_attributes_mut<F>(&mut self, mut f: F)
599    where
600        F: FnMut(&mut Attribute) -> bool,
601    {
602        match self {
603            GlobalDirective::Diagnostic(directive) => directive.attributes.retain_mut(|v| f(v)),
604            GlobalDirective::Enable(directive) => directive.attributes.retain_mut(|v| f(v)),
605            GlobalDirective::Requires(directive) => directive.attributes.retain_mut(|v| f(v)),
606        }
607    }
608}
609
610#[cfg(feature = "attributes")]
611impl_decorated_struct!(DiagnosticDirective);
612
613#[cfg(feature = "attributes")]
614impl_decorated_struct!(EnableDirective);
615
616#[cfg(feature = "attributes")]
617impl_decorated_struct!(RequiresDirective);
618
619#[cfg(feature = "attributes")]
620impl Decorated for GlobalDeclaration {
621    fn attributes(&self) -> &[AttributeNode] {
622        match self {
623            GlobalDeclaration::Void => &[],
624            GlobalDeclaration::Declaration(decl) => &decl.attributes,
625            GlobalDeclaration::TypeAlias(decl) => &decl.attributes,
626            GlobalDeclaration::Struct(decl) => &decl.attributes,
627            GlobalDeclaration::Function(decl) => &decl.attributes,
628            GlobalDeclaration::ConstAssert(decl) => &decl.attributes,
629        }
630    }
631
632    fn attributes_mut(&mut self) -> &mut [AttributeNode] {
633        match self {
634            GlobalDeclaration::Void => &mut [],
635            GlobalDeclaration::Declaration(decl) => &mut decl.attributes,
636            GlobalDeclaration::TypeAlias(decl) => &mut decl.attributes,
637            GlobalDeclaration::Struct(decl) => &mut decl.attributes,
638            GlobalDeclaration::Function(decl) => &mut decl.attributes,
639            GlobalDeclaration::ConstAssert(decl) => &mut decl.attributes,
640        }
641    }
642
643    fn retain_attributes_mut<F>(&mut self, mut f: F)
644    where
645        F: FnMut(&mut Attribute) -> bool,
646    {
647        match self {
648            GlobalDeclaration::Void => {}
649            GlobalDeclaration::Declaration(decl) => decl.attributes.retain_mut(|v| f(v)),
650            GlobalDeclaration::TypeAlias(decl) => decl.attributes.retain_mut(|v| f(v)),
651            GlobalDeclaration::Struct(decl) => decl.attributes.retain_mut(|v| f(v)),
652            GlobalDeclaration::Function(decl) => decl.attributes.retain_mut(|v| f(v)),
653            GlobalDeclaration::ConstAssert(decl) => decl.attributes.retain_mut(|v| f(v)),
654        }
655    }
656}
657
658impl_decorated_struct!(Declaration);
659
660#[cfg(feature = "attributes")]
661impl_decorated_struct!(TypeAlias);
662
663#[cfg(feature = "attributes")]
664impl_decorated_struct!(Struct);
665
666impl_decorated_struct!(StructMember);
667
668impl_decorated_struct!(Function);
669
670impl_decorated_struct!(FormalParameter);
671
672#[cfg(feature = "attributes")]
673impl_decorated_struct!(ConstAssert);
674
675#[cfg(feature = "attributes")]
676impl Decorated for Statement {
677    fn attributes(&self) -> &[AttributeNode] {
678        match self {
679            Statement::Void => &[],
680            Statement::Compound(stmt) => &stmt.attributes,
681            Statement::Assignment(stmt) => &stmt.attributes,
682            Statement::Increment(stmt) => &stmt.attributes,
683            Statement::Decrement(stmt) => &stmt.attributes,
684            Statement::If(stmt) => &stmt.attributes,
685            Statement::Switch(stmt) => &stmt.attributes,
686            Statement::Loop(stmt) => &stmt.attributes,
687            Statement::For(stmt) => &stmt.attributes,
688            Statement::While(stmt) => &stmt.attributes,
689            Statement::Break(stmt) => &stmt.attributes,
690            Statement::Continue(stmt) => &stmt.attributes,
691            Statement::Return(stmt) => &stmt.attributes,
692            Statement::Discard(stmt) => &stmt.attributes,
693            Statement::FunctionCall(stmt) => &stmt.attributes,
694            Statement::ConstAssert(stmt) => &stmt.attributes,
695            Statement::Declaration(stmt) => &stmt.attributes,
696        }
697    }
698
699    fn attributes_mut(&mut self) -> &mut [AttributeNode] {
700        match self {
701            Statement::Void => &mut [],
702            Statement::Compound(stmt) => &mut stmt.attributes,
703            Statement::Assignment(stmt) => &mut stmt.attributes,
704            Statement::Increment(stmt) => &mut stmt.attributes,
705            Statement::Decrement(stmt) => &mut stmt.attributes,
706            Statement::If(stmt) => &mut stmt.attributes,
707            Statement::Switch(stmt) => &mut stmt.attributes,
708            Statement::Loop(stmt) => &mut stmt.attributes,
709            Statement::For(stmt) => &mut stmt.attributes,
710            Statement::While(stmt) => &mut stmt.attributes,
711            Statement::Break(stmt) => &mut stmt.attributes,
712            Statement::Continue(stmt) => &mut stmt.attributes,
713            Statement::Return(stmt) => &mut stmt.attributes,
714            Statement::Discard(stmt) => &mut stmt.attributes,
715            Statement::FunctionCall(stmt) => &mut stmt.attributes,
716            Statement::ConstAssert(stmt) => &mut stmt.attributes,
717            Statement::Declaration(stmt) => &mut stmt.attributes,
718        }
719    }
720
721    fn retain_attributes_mut<F>(&mut self, mut f: F)
722    where
723        F: FnMut(&mut Attribute) -> bool,
724    {
725        match self {
726            Statement::Void => {}
727            Statement::Compound(stmt) => stmt.attributes.retain_mut(|v| f(v)),
728            Statement::Assignment(stmt) => stmt.attributes.retain_mut(|v| f(v)),
729            Statement::Increment(stmt) => stmt.attributes.retain_mut(|v| f(v)),
730            Statement::Decrement(stmt) => stmt.attributes.retain_mut(|v| f(v)),
731            Statement::If(stmt) => stmt.attributes.retain_mut(|v| f(v)),
732            Statement::Switch(stmt) => stmt.attributes.retain_mut(|v| f(v)),
733            Statement::Loop(stmt) => stmt.attributes.retain_mut(|v| f(v)),
734            Statement::For(stmt) => stmt.attributes.retain_mut(|v| f(v)),
735            Statement::While(stmt) => stmt.attributes.retain_mut(|v| f(v)),
736            Statement::Break(stmt) => stmt.attributes.retain_mut(|v| f(v)),
737            Statement::Continue(stmt) => stmt.attributes.retain_mut(|v| f(v)),
738            Statement::Return(stmt) => stmt.attributes.retain_mut(|v| f(v)),
739            Statement::Discard(stmt) => stmt.attributes.retain_mut(|v| f(v)),
740            Statement::FunctionCall(stmt) => stmt.attributes.retain_mut(|v| f(v)),
741            Statement::ConstAssert(stmt) => stmt.attributes.retain_mut(|v| f(v)),
742            Statement::Declaration(stmt) => stmt.attributes.retain_mut(|v| f(v)),
743        }
744    }
745}
746
747impl_decorated_struct!(CompoundStatement);
748
749#[cfg(feature = "attributes")]
750impl_decorated_struct!(AssignmentStatement);
751
752#[cfg(feature = "attributes")]
753impl_decorated_struct!(IncrementStatement);
754
755#[cfg(feature = "attributes")]
756impl_decorated_struct!(DecrementStatement);
757
758impl_decorated_struct!(IfStatement);
759
760#[cfg(feature = "attributes")]
761impl_decorated_struct!(ElseIfClause);
762
763#[cfg(feature = "attributes")]
764impl_decorated_struct!(ElseClause);
765
766impl_decorated_struct!(SwitchStatement);
767
768#[cfg(feature = "attributes")]
769impl_decorated_struct!(SwitchClause);
770
771impl_decorated_struct!(LoopStatement);
772
773#[cfg(feature = "attributes")]
774impl_decorated_struct!(ContinuingStatement);
775
776#[cfg(feature = "attributes")]
777impl_decorated_struct!(BreakIfStatement);
778
779impl_decorated_struct!(ForStatement);
780
781impl_decorated_struct!(WhileStatement);
782
783#[cfg(feature = "attributes")]
784impl_decorated_struct!(BreakStatement);
785
786#[cfg(feature = "attributes")]
787impl_decorated_struct!(ContinueStatement);
788
789#[cfg(feature = "attributes")]
790impl_decorated_struct!(ReturnStatement);
791
792#[cfg(feature = "attributes")]
793impl_decorated_struct!(DiscardStatement);
794
795#[cfg(feature = "attributes")]
796impl_decorated_struct!(FunctionCallStatement);