naga/front/wgsl/parse/
directive.rs

1//! WGSL directives. The focal point of this API is [`DirectiveKind`].
2//!
3//! See also <https://www.w3.org/TR/WGSL/#directives>.
4
5pub mod enable_extension;
6pub(crate) mod language_extension;
7
8use alloc::boxed::Box;
9
10/// A parsed sentinel word indicating the type of directive to be parsed next.
11#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
12#[cfg_attr(test, derive(strum::EnumIter))]
13pub(crate) enum DirectiveKind {
14    /// A [`crate::diagnostic_filter`].
15    Diagnostic,
16    /// An [`enable_extension`].
17    Enable,
18    /// A [`language_extension`].
19    Requires,
20}
21
22impl DirectiveKind {
23    const DIAGNOSTIC: &'static str = "diagnostic";
24    const ENABLE: &'static str = "enable";
25    const REQUIRES: &'static str = "requires";
26
27    /// Convert from a sentinel word in WGSL into its associated [`DirectiveKind`], if possible.
28    pub fn from_ident(s: &str) -> Option<Self> {
29        Some(match s {
30            Self::DIAGNOSTIC => Self::Diagnostic,
31            Self::ENABLE => Self::Enable,
32            Self::REQUIRES => Self::Requires,
33            _ => return None,
34        })
35    }
36}
37
38impl crate::diagnostic_filter::Severity {
39    #[cfg(feature = "wgsl-in")]
40    pub(crate) fn report_wgsl_parse_diag<'a>(
41        self,
42        err: Box<crate::front::wgsl::error::Error<'a>>,
43        source: &str,
44    ) -> crate::front::wgsl::Result<'a, ()> {
45        self.report_diag(err, |e, level| {
46            let e = e.as_parse_error(source);
47            log::log!(level, "{}", e.emit_to_string(source));
48        })
49    }
50}
51
52#[cfg(test)]
53mod test {
54    use alloc::format;
55
56    use strum::IntoEnumIterator;
57
58    use super::DirectiveKind;
59    use crate::front::wgsl::assert_parse_err;
60
61    #[test]
62    fn directive_after_global_decl() {
63        for unsupported_shader in DirectiveKind::iter() {
64            let directive;
65            let expected_msg;
66            match unsupported_shader {
67                DirectiveKind::Diagnostic => {
68                    directive = "diagnostic(off,derivative_uniformity)";
69                    expected_msg = "\
70error: expected global declaration, but found a global directive
71  ┌─ wgsl:2:1
72732 │ diagnostic(off,derivative_uniformity);
74  │ ^^^^^^^^^^ written after first global declaration
7576  = note: global directives are only allowed before global declarations; maybe hoist this closer to the top of the shader module?
77
78";
79                }
80                DirectiveKind::Enable => {
81                    directive = "enable f16";
82                    expected_msg = "\
83error: expected global declaration, but found a global directive
84  ┌─ wgsl:2:1
85862 │ enable f16;
87  │ ^^^^^^ written after first global declaration
8889  = note: global directives are only allowed before global declarations; maybe hoist this closer to the top of the shader module?
90
91";
92                }
93                DirectiveKind::Requires => {
94                    directive = "requires readonly_and_readwrite_storage_textures";
95                    expected_msg = "\
96error: expected global declaration, but found a global directive
97  ┌─ wgsl:2:1
98992 │ requires readonly_and_readwrite_storage_textures;
100  │ ^^^^^^^^ written after first global declaration
101102  = note: global directives are only allowed before global declarations; maybe hoist this closer to the top of the shader module?
103
104";
105                }
106            }
107
108            let shader = format!(
109                "\
110@group(0) @binding(0) var<storage> thing: i32;
111{directive};
112"
113            );
114            assert_parse_err(&shader, expected_msg);
115        }
116    }
117}