Skip to main content

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