Skip to content

Commit

Permalink
[naga] Add naga::common::wgsl shared by WGSL front and backends. (#…
Browse files Browse the repository at this point in the history
…6628)

Create a new module, `naga::common`, to hold code that can be
shared between front and back ends for a given language.

Create a new module, `naga::common::wgsl`, and populate it with some
code that we expect to be useful by both the WGSL front and back ends,
once the back end generates diagnostic filters.

Move some WGSL front end tests into `naga::front::wgsl::tests`.
  • Loading branch information
jimblandy authored Dec 2, 2024
1 parent cf793f7 commit 26124c7
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 209 deletions.
3 changes: 3 additions & 0 deletions naga/src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Code common to the front and backends for specific languages.

pub mod wgsl;
69 changes: 69 additions & 0 deletions naga/src/common/wgsl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Code shared between the WGSL front and back ends.

use std::fmt::{self, Display, Formatter};

use crate::diagnostic_filter::{
FilterableTriggeringRule, Severity, StandardFilterableTriggeringRule,
};

impl Severity {
const ERROR: &'static str = "error";
const WARNING: &'static str = "warning";
const INFO: &'static str = "info";
const OFF: &'static str = "off";

/// Convert from a sentinel word in WGSL into its associated [`Severity`], if possible.
pub fn from_wgsl_ident(s: &str) -> Option<Self> {
Some(match s {
Self::ERROR => Self::Error,
Self::WARNING => Self::Warning,
Self::INFO => Self::Info,
Self::OFF => Self::Off,
_ => return None,
})
}
}

struct DisplayFilterableTriggeringRule<'a>(&'a FilterableTriggeringRule);

impl Display for DisplayFilterableTriggeringRule<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let &Self(inner) = self;
match *inner {
FilterableTriggeringRule::Standard(rule) => write!(f, "{}", rule.to_wgsl_ident()),
FilterableTriggeringRule::Unknown(ref rule) => write!(f, "{rule}"),
FilterableTriggeringRule::User(ref rules) => {
let &[ref seg1, ref seg2] = rules.as_ref();
write!(f, "{seg1}.{seg2}")
}
}
}
}

impl FilterableTriggeringRule {
/// [`Display`] this rule's identifiers in WGSL.
pub const fn display_wgsl_ident(&self) -> impl Display + '_ {
DisplayFilterableTriggeringRule(self)
}
}

impl StandardFilterableTriggeringRule {
const DERIVATIVE_UNIFORMITY: &'static str = "derivative_uniformity";

/// Convert from a sentinel word in WGSL into its associated
/// [`StandardFilterableTriggeringRule`], if possible.
pub fn from_wgsl_ident(s: &str) -> Option<Self> {
Some(match s {
Self::DERIVATIVE_UNIFORMITY => Self::DerivativeUniformity,
_ => return None,
})
}

/// Maps this [`StandardFilterableTriggeringRule`] into the sentinel word associated with it in
/// WGSL.
pub const fn to_wgsl_ident(self) -> &'static str {
match self {
Self::DerivativeUniformity => Self::DERIVATIVE_UNIFORMITY,
}
}
}
208 changes: 0 additions & 208 deletions naga/src/front/wgsl/diagnostic_filter.rs
Original file line number Diff line number Diff line change
@@ -1,208 +0,0 @@
use std::fmt::{self, Display, Formatter};

use crate::diagnostic_filter::{
FilterableTriggeringRule, Severity, StandardFilterableTriggeringRule,
};

impl Severity {
const ERROR: &'static str = "error";
const WARNING: &'static str = "warning";
const INFO: &'static str = "info";
const OFF: &'static str = "off";

/// Convert from a sentinel word in WGSL into its associated [`Severity`], if possible.
pub fn from_wgsl_ident(s: &str) -> Option<Self> {
Some(match s {
Self::ERROR => Self::Error,
Self::WARNING => Self::Warning,
Self::INFO => Self::Info,
Self::OFF => Self::Off,
_ => return None,
})
}
}

struct DisplayFilterableTriggeringRule<'a>(&'a FilterableTriggeringRule);

impl Display for DisplayFilterableTriggeringRule<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let &Self(inner) = self;
match *inner {
FilterableTriggeringRule::Standard(rule) => write!(f, "{}", rule.to_wgsl_ident()),
FilterableTriggeringRule::Unknown(ref rule) => write!(f, "{rule}"),
FilterableTriggeringRule::User(ref rules) => {
let &[ref seg1, ref seg2] = rules.as_ref();
write!(f, "{seg1}.{seg2}")
}
}
}
}

impl FilterableTriggeringRule {
/// [`Display`] this rule's identifiers in WGSL.
pub const fn display_wgsl_ident(&self) -> impl Display + '_ {
DisplayFilterableTriggeringRule(self)
}
}

impl StandardFilterableTriggeringRule {
const DERIVATIVE_UNIFORMITY: &'static str = "derivative_uniformity";

/// Convert from a sentinel word in WGSL into its associated
/// [`StandardFilterableTriggeringRule`], if possible.
pub fn from_wgsl_ident(s: &str) -> Option<Self> {
Some(match s {
Self::DERIVATIVE_UNIFORMITY => Self::DerivativeUniformity,
_ => return None,
})
}

/// Maps this [`StandardFilterableTriggeringRule`] into the sentinel word associated with it in
/// WGSL.
pub const fn to_wgsl_ident(self) -> &'static str {
match self {
Self::DerivativeUniformity => Self::DERIVATIVE_UNIFORMITY,
}
}
}

#[cfg(test)]
mod test {
mod parse_sites_not_yet_supported {
use crate::front::wgsl::assert_parse_err;

#[test]
fn user_rules() {
let shader = "
fn myfunc() {
if (true) @diagnostic(off, my.lint) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^ not yet supported, should report an error
}
}
";
assert_parse_err(shader, "\
error: `@diagnostic(…)` attribute(s) not yet implemented
┌─ wgsl:3:15
3 │ if (true) @diagnostic(off, my.lint) {
│ ^^^^^^^^^^^^^^^^^^^^^^^^^ can't use this on compound statements (yet)
= note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5320>, so they can prioritize it!
");
}

#[test]
fn unknown_rules() {
let shader = "
fn myfunc() {
if (true) @diagnostic(off, wat_is_this) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ should emit a warning
}
}
";
assert_parse_err(shader, "\
error: `@diagnostic(…)` attribute(s) not yet implemented
┌─ wgsl:3:12
3 │ if (true) @diagnostic(off, wat_is_this) {
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't use this on compound statements (yet)
= note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5320>, so they can prioritize it!
");
}
}

mod directive_conflict {
use crate::front::wgsl::assert_parse_err;

#[test]
fn user_rules() {
let shader = "
diagnostic(off, my.lint);
diagnostic(warning, my.lint);
";
assert_parse_err(shader, "\
error: found conflicting `diagnostic(…)` rule(s)
┌─ wgsl:2:1
2 │ diagnostic(off, my.lint);
│ ^^^^^^^^^^^^^^^^^^^^^^^^ first rule
3 │ diagnostic(warning, my.lint);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
= note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
= note: You should delete the rule you don't want.
");
}

#[test]
fn unknown_rules() {
let shader = "
diagnostic(off, wat_is_this);
diagnostic(warning, wat_is_this);
";
assert_parse_err(shader, "\
error: found conflicting `diagnostic(…)` rule(s)
┌─ wgsl:2:1
2 │ diagnostic(off, wat_is_this);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first rule
3 │ diagnostic(warning, wat_is_this);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
= note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
= note: You should delete the rule you don't want.
");
}
}

mod attribute_conflict {
use crate::front::wgsl::assert_parse_err;

#[test]
fn user_rules() {
let shader = "
diagnostic(off, my.lint);
diagnostic(warning, my.lint);
";
assert_parse_err(shader, "\
error: found conflicting `diagnostic(…)` rule(s)
┌─ wgsl:2:1
2 │ diagnostic(off, my.lint);
│ ^^^^^^^^^^^^^^^^^^^^^^^^ first rule
3 │ diagnostic(warning, my.lint);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
= note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
= note: You should delete the rule you don't want.
");
}

#[test]
fn unknown_rules() {
let shader = "
diagnostic(off, wat_is_this);
diagnostic(warning, wat_is_this);
";
assert_parse_err(shader, "\
error: found conflicting `diagnostic(…)` rule(s)
┌─ wgsl:2:1
2 │ diagnostic(off, wat_is_this);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first rule
3 │ diagnostic(warning, wat_is_this);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
= note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
= note: You should delete the rule you don't want.
");
}
}
}
1 change: 0 additions & 1 deletion naga/src/front/wgsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Frontend for [WGSL][wgsl] (WebGPU Shading Language).
[wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html
*/

mod diagnostic_filter;
mod error;
mod index;
mod lower;
Expand Down
Loading

0 comments on commit 26124c7

Please sign in to comment.