Skip to content

Commit 301f373

Browse files
committed
Use a bitflags type for the WGSL front end's LanguageExtensions.
1 parent a1ccbf5 commit 301f373

6 files changed

Lines changed: 91 additions & 171 deletions

File tree

naga/src/front/wgsl/error.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError};
77
use crate::{Scalar, SourceLocation, Span};
88

99
use super::parse::directive::enable_extension::EnableExtensions;
10-
use super::parse::directive::language_extension::{
11-
LanguageExtension, UnimplementedLanguageExtension,
12-
};
10+
use super::parse::directive::language_extension::LanguageExtensions;
1311
use super::parse::lexer::Token;
1412

1513
use codespan_reporting::diagnostic::{Diagnostic, Label};
@@ -381,7 +379,7 @@ pub(crate) enum Error<'a> {
381379
span: Span,
382380
},
383381
LanguageExtensionNotYetImplemented {
384-
kind: UnimplementedLanguageExtension,
382+
kind: LanguageExtensions,
385383
span: Span,
386384
},
387385
DiagnosticInvalidSeverity {
@@ -1234,7 +1232,7 @@ impl<'a> Error<'a> {
12341232
Error::LanguageExtensionNotYetImplemented { kind, span } => ParseError {
12351233
message: format!(
12361234
"the `{}` language extension is not yet supported",
1237-
LanguageExtension::Unimplemented(kind).to_ident()
1235+
kind.to_ident()
12381236
),
12391237
labels: vec![(span, "".into())],
12401238
notes: vec![format!(
@@ -1243,7 +1241,7 @@ impl<'a> Error<'a> {
12431241
"<https://github.com/gfx-rs/wgpu/issues/{}>, ",
12441242
"so they can prioritize it!"
12451243
),
1246-
kind.tracking_issue_num()
1244+
kind.tracking_issue_num().unwrap(),
12471245
)],
12481246
},
12491247
Error::DiagnosticInvalidSeverity {

naga/src/front/wgsl/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ mod parse;
1212
mod tests;
1313

1414
pub use parse::directive::enable_extension::EnableExtensions;
15+
pub use parse::directive::language_extension::LanguageExtensions;
1516

1617
pub use crate::front::wgsl::error::ParseError;
17-
pub use crate::front::wgsl::parse::directive::language_extension::{
18-
ImplementedLanguageExtension, LanguageExtension, UnimplementedLanguageExtension,
19-
};
2018
pub use crate::front::wgsl::parse::Options;
2119

2220
use alloc::boxed::Box;

naga/src/front/wgsl/parse/directive.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,59 @@
22
//!
33
//! See also <https://www.w3.org/TR/WGSL/#directives>.
44
5+
/// Define a bitflags type representing a set of extensions, with their source names.
6+
///
7+
/// This is used to define bitflags types for language and enable
8+
/// extensions.
9+
///
10+
/// An invocation of this macro defines a `bitflags` type that
11+
/// implements `Copy` and `Eq`, with methods `from_ident` and
12+
/// `to_ident` that convert to and from the WGSL source name for the
13+
/// extension.
14+
macro_rules! define_extensions {
15+
{
16+
$( #[ $( $meta:meta )* ] )*
17+
pub struct $typename:ident: $type:ty
18+
{
19+
$(
20+
$( #[ $inner:ident $( $args:tt )* ] )*
21+
const $name:ident, $wgsl:literal = $value:expr ;
22+
)*
23+
}
24+
} => {
25+
bitflags::bitflags! {
26+
$( #[ $( $meta )* ] )*
27+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28+
pub struct $typename: $type {
29+
$(
30+
$( #[ $inner $( $args )* ] )*
31+
const $name = $value ;
32+
)*
33+
}
34+
}
35+
36+
impl $typename {
37+
pub fn from_ident(wgsl: &str) -> Option<Self> {
38+
match wgsl {
39+
$(
40+
$wgsl => Some($typename :: $name),
41+
)*
42+
_ => None,
43+
}
44+
}
45+
46+
pub fn to_ident(self) -> &'static str {
47+
match self {
48+
$(
49+
$typename :: $name => $wgsl,
50+
)*
51+
_ => unreachable!("should have exactly one extension bit set"),
52+
}
53+
}
54+
}
55+
}
56+
}
57+
558
pub mod enable_extension;
659
pub(crate) mod language_extension;
760

naga/src/front/wgsl/parse/directive/enable_extension.rs

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,7 @@
22
//!
33
//! The focal point of this module is the [`EnableExtensions`] bitflags type.
44
5-
macro_rules! define_enable_extensions {
6-
{
7-
$( #[ $( $meta:meta )* ] )*
8-
pub struct $typename:ident: $type:ty
9-
{
10-
$(
11-
$( #[ $inner:ident $( $args:tt )* ] )*
12-
const $name:ident, $wgsl:literal = $value:expr ;
13-
)*
14-
}
15-
} => {
16-
bitflags::bitflags! {
17-
$( #[ $( $meta )* ] )*
18-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19-
pub struct $typename: $type {
20-
$(
21-
$( #[ $inner $( $args )* ] )*
22-
const $name = $value ;
23-
)*
24-
}
25-
}
26-
27-
impl $typename {
28-
pub fn from_ident(wgsl: &str) -> Option<Self> {
29-
match wgsl {
30-
$(
31-
$wgsl => Some($typename :: $name),
32-
)*
33-
_ => None,
34-
}
35-
}
36-
37-
pub fn to_ident(self) -> &'static str {
38-
match self {
39-
$(
40-
$typename :: $name => $wgsl,
41-
)*
42-
_ => unreachable!("should have exactly one extension bit set"),
43-
}
44-
}
45-
}
46-
}
47-
}
48-
49-
50-
define_enable_extensions! {
5+
define_extensions! {
516
/// All enable extensions known to Naga.
527
///
538
/// This includes extensions that Naga does not implement; the [`IMPLEMENTED`]

naga/src/front/wgsl/parse/directive/language_extension.rs

Lines changed: 22 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,113 +2,35 @@
22
//!
33
//! The focal point of this module is the [`LanguageExtension`] API.
44
5-
/// A language extension recognized by Naga, but not guaranteed to be present in all environments.
6-
///
7-
/// WGSL spec.: <https://www.w3.org/TR/WGSL/#language-extensions-sec>
8-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
9-
pub enum LanguageExtension {
10-
#[allow(unused)]
11-
Implemented(ImplementedLanguageExtension),
12-
Unimplemented(UnimplementedLanguageExtension),
13-
}
14-
15-
impl LanguageExtension {
16-
const READONLY_AND_READWRITE_STORAGE_TEXTURES: &'static str =
17-
"readonly_and_readwrite_storage_textures";
18-
const PACKED4X8_INTEGER_DOT_PRODUCT: &'static str = "packed_4x8_integer_dot_product";
19-
const UNRESTRICTED_POINTER_PARAMETERS: &'static str = "unrestricted_pointer_parameters";
20-
const POINTER_COMPOSITE_ACCESS: &'static str = "pointer_composite_access";
21-
22-
/// Convert from a sentinel word in WGSL into its associated [`LanguageExtension`], if possible.
23-
pub fn from_ident(s: &str) -> Option<Self> {
24-
Some(match s {
25-
Self::READONLY_AND_READWRITE_STORAGE_TEXTURES => {
26-
Self::Implemented(ImplementedLanguageExtension::ReadOnlyAndReadWriteStorageTextures)
27-
}
28-
Self::PACKED4X8_INTEGER_DOT_PRODUCT => {
29-
Self::Implemented(ImplementedLanguageExtension::Packed4x8IntegerDotProduct)
30-
}
31-
Self::UNRESTRICTED_POINTER_PARAMETERS => {
32-
Self::Unimplemented(UnimplementedLanguageExtension::UnrestrictedPointerParameters)
33-
}
34-
Self::POINTER_COMPOSITE_ACCESS => {
35-
Self::Implemented(ImplementedLanguageExtension::PointerCompositeAccess)
36-
}
37-
_ => return None,
38-
})
39-
}
40-
41-
/// Maps this [`LanguageExtension`] into the sentinel word associated with it in WGSL.
42-
pub const fn to_ident(self) -> &'static str {
43-
match self {
44-
Self::Implemented(kind) => kind.to_ident(),
45-
Self::Unimplemented(kind) => match kind {
46-
UnimplementedLanguageExtension::UnrestrictedPointerParameters => {
47-
Self::UNRESTRICTED_POINTER_PARAMETERS
48-
}
49-
},
50-
}
5+
define_extensions! {
6+
/// A language extension recognized by Naga, but not guaranteed to be present in all environments.
7+
///
8+
/// WGSL spec.: <https://www.w3.org/TR/WGSL/#language-extensions-sec>
9+
#[derive(Default)]
10+
pub struct LanguageExtensions: u32 {
11+
const READONLY_AND_READWRITE_STORAGE_TEXTURES, "readonly_and_readwrite_storage_textures" = 0x1;
12+
const PACKED4X8_INTEGER_DOT_PRODUCT, "packed_4x8_integer_dot_product" = 0x2;
13+
const UNRESTRICTED_POINTER_PARAMETERS, "unrestricted_pointer_parameters" = 0x4;
14+
const POINTER_COMPOSITE_ACCESS, "pointer_composite_access" = 0x8;
5115
}
5216
}
5317

54-
/// A variant of [`LanguageExtension::Implemented`].
55-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
56-
#[cfg_attr(test, derive(strum::VariantArray))]
57-
pub enum ImplementedLanguageExtension {
58-
ReadOnlyAndReadWriteStorageTextures,
59-
Packed4x8IntegerDotProduct,
60-
PointerCompositeAccess,
61-
}
18+
impl LanguageExtensions {
19+
pub const IMPLEMENTED: Self =
20+
Self::empty()
21+
.union(Self::READONLY_AND_READWRITE_STORAGE_TEXTURES)
22+
.union(Self::PACKED4X8_INTEGER_DOT_PRODUCT)
23+
.union(Self::POINTER_COMPOSITE_ACCESS);
6224

63-
impl ImplementedLanguageExtension {
64-
/// A slice of all variants of [`ImplementedLanguageExtension`].
65-
pub const VARIANTS: &'static [Self] = &[
66-
Self::ReadOnlyAndReadWriteStorageTextures,
67-
Self::Packed4x8IntegerDotProduct,
68-
Self::PointerCompositeAccess,
69-
];
25+
pub const UNIMPLEMENTED: Self = Self::IMPLEMENTED.complement();
7026

71-
/// Returns slice of all variants of [`ImplementedLanguageExtension`].
72-
pub const fn all() -> &'static [Self] {
73-
Self::VARIANTS
74-
}
75-
76-
/// Maps this [`ImplementedLanguageExtension`] into the sentinel word associated with it in WGSL.
77-
pub const fn to_ident(self) -> &'static str {
27+
pub(crate) const fn tracking_issue_num(self) -> Option<u16> {
7828
match self {
79-
ImplementedLanguageExtension::ReadOnlyAndReadWriteStorageTextures => {
80-
LanguageExtension::READONLY_AND_READWRITE_STORAGE_TEXTURES
81-
}
82-
ImplementedLanguageExtension::Packed4x8IntegerDotProduct => {
83-
LanguageExtension::PACKED4X8_INTEGER_DOT_PRODUCT
84-
}
85-
ImplementedLanguageExtension::PointerCompositeAccess => {
86-
LanguageExtension::POINTER_COMPOSITE_ACCESS
29+
Self::UNRESTRICTED_POINTER_PARAMETERS => Some(5158),
30+
other => {
31+
assert!(Self::IMPLEMENTED.contains(other));
32+
None
8733
}
8834
}
8935
}
9036
}
91-
92-
#[test]
93-
/// Asserts that the manual implementation of VARIANTS is the same as the derived strum version would be
94-
/// while still allowing strum to be a dev-only dependency
95-
fn test_manual_variants_array_is_correct() {
96-
assert_eq!(
97-
<ImplementedLanguageExtension as strum::VariantArray>::VARIANTS,
98-
ImplementedLanguageExtension::VARIANTS
99-
);
100-
}
101-
102-
/// A variant of [`LanguageExtension::Unimplemented`].
103-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
104-
pub enum UnimplementedLanguageExtension {
105-
UnrestrictedPointerParameters,
106-
}
107-
108-
impl UnimplementedLanguageExtension {
109-
pub(crate) const fn tracking_issue_num(self) -> u16 {
110-
match self {
111-
Self::UnrestrictedPointerParameters => 5158,
112-
}
113-
}
114-
}

naga/src/front/wgsl/parse/mod.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use alloc::{boxed::Box, vec::Vec};
2+
use directive::language_extension::LanguageExtensions;
23

34
use crate::diagnostic_filter::{
45
self, DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, FilterableTriggeringRule,
56
ShouldConflictOnFullDuplicate, StandardFilterableTriggeringRule,
67
};
78
use crate::front::wgsl::error::{DiagnosticAttributeNotSupportedPosition, Error, ExpectedToken};
89
use crate::front::wgsl::parse::directive::enable_extension::EnableExtensions;
9-
use crate::front::wgsl::parse::directive::language_extension::LanguageExtension;
1010
use crate::front::wgsl::parse::directive::DirectiveKind;
1111
use crate::front::wgsl::parse::lexer::{Lexer, Token};
1212
use crate::front::wgsl::parse::number::Number;
@@ -3246,22 +3246,16 @@ impl Parser {
32463246
}
32473247
DirectiveKind::Requires => {
32483248
self.directive_ident_list(&mut lexer, |ident, span| {
3249-
match LanguageExtension::from_ident(ident) {
3250-
Some(LanguageExtension::Implemented(_kind)) => {
3251-
// NOTE: No further validation is needed for an extension, so
3252-
// just throw parsed information away. If we ever want to apply
3253-
// what we've parsed to diagnostics, maybe we'll want to refer
3254-
// to enabled extensions later?
3255-
Ok(())
3256-
}
3257-
Some(LanguageExtension::Unimplemented(kind)) => {
3258-
Err(Box::new(Error::LanguageExtensionNotYetImplemented {
3259-
kind,
3260-
span,
3261-
}))
3262-
}
3263-
None => Err(Box::new(Error::UnknownLanguageExtension(span, ident))),
3249+
let extension = LanguageExtensions::from_ident(ident)
3250+
.ok_or_else(|| Error::UnknownLanguageExtension(span, ident))?;
3251+
if !LanguageExtensions::IMPLEMENTED.contains(extension) {
3252+
return Err(Box::new(Error::LanguageExtensionNotYetImplemented { kind: extension, span }));
32643253
}
3254+
// NOTE: No further validation is needed for an extension, so
3255+
// just throw parsed information away. If we ever want to apply
3256+
// what we've parsed to diagnostics, maybe we'll want to refer
3257+
// to enabled extensions later?
3258+
Ok(())
32653259
})?;
32663260
}
32673261
}

0 commit comments

Comments
 (0)