mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[wgsl] structure declarations, better array types
This commit is contained in:
@@ -4,9 +4,9 @@ global_decl = {
|
||||
";"
|
||||
| import_decl ~ ";"
|
||||
| global_variable_decl ~ ";"
|
||||
// | global_constant_decl SEMICOLON
|
||||
// | entry_point_decl SEMICOLON
|
||||
// | type_alias SEMICOLON
|
||||
| global_constant_decl ~ ";"
|
||||
// | entry_point_decl ~ ";"
|
||||
| type_alias ~ ";"
|
||||
// | function_decl
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ global_variable_decl = {
|
||||
| variable_decoration_list ~ variable_decl ~ "=" ~ const_expr
|
||||
}
|
||||
|
||||
global_constant_decl = { "const" ~ variable_ident_decl ~ "=" ~ const_expr }
|
||||
|
||||
variable_decoration_list = { "[[" ~ (variable_decoration ~ ",")* ~ variable_decoration ~ "]]" }
|
||||
|
||||
variable_decoration = {
|
||||
@@ -30,13 +32,36 @@ variable_decl = { "var" ~ variable_storage_decoration? ~ variable_ident_decl }
|
||||
variable_storage_decoration = _{ "<" ~ storage_class ~ ">" }
|
||||
variable_ident_decl = { ident ~ ":" ~ type_decl }
|
||||
|
||||
type_alias = {
|
||||
"type" ~ ident ~ "=" ~ type_decl
|
||||
| "type" ~ ident ~ "=" ~ struct_decl
|
||||
}
|
||||
|
||||
struct_decl = { struct_decoration_decl? ~ "struct" ~ struct_body_decl }
|
||||
|
||||
struct_decoration_decl = { "[[" ~ struct_decoration ~ "]]" }
|
||||
|
||||
struct_decoration = {
|
||||
"block"
|
||||
}
|
||||
|
||||
struct_body_decl = { "{" ~ struct_member* ~ "}" }
|
||||
|
||||
struct_member = { struct_member_decoration_decl? ~ variable_ident_decl ~ ";" }
|
||||
|
||||
struct_member_decoration_decl = { "[[" ~ (struct_member_decoration ~ ",")* ~ struct_member_decoration ~ "]]" }
|
||||
|
||||
struct_member_decoration = {
|
||||
"offset" ~ int_literal
|
||||
}
|
||||
|
||||
storage_class = {
|
||||
"in"
|
||||
| "out"
|
||||
| "uniform"
|
||||
// | WORKGROUP
|
||||
// | UNIFORM_CONSTANT
|
||||
// | STORAGE_BUFFER
|
||||
| "storage_buffer"
|
||||
// | IMAGE
|
||||
// | PUSH_CONSTANT
|
||||
| "private"
|
||||
@@ -56,23 +81,18 @@ const_expr = {
|
||||
| const_literal
|
||||
}
|
||||
|
||||
type_pointer_kind = { "ptr" }
|
||||
type_array_kind = { "array" }
|
||||
type_vec_kind = { "vec2" | "vec3" | "vec4" }
|
||||
type_mat_kind = { "mat2x2" | "mat3x3" | "mat4x4" }
|
||||
|
||||
type_decl = {
|
||||
scalar_type
|
||||
// | VEC2 LESS_THAN type_decl GREATER_THAN
|
||||
// | VEC3 LESS_THAN type_decl GREATER_THAN
|
||||
// | VEC3 LESS_THAN type_decl GREATER_THAN
|
||||
// | PTR LESS_THAN storage_class, type_decl GREATER_THAN
|
||||
// | ARRAY LESS_THAN type_decl COMMA INT_LITERAL GREATER_THAN
|
||||
// | ARRAY LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT2x2 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT2x3 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT2x4 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT3x2 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT3x3 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT3x4 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT4x2 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT4x3 LESS_THAN type_decl GREATER_THAN
|
||||
// | MAT4x4 LESS_THAN type_decl GREATER_THAN
|
||||
| type_vec_kind ~ "<" ~ type_decl ~ ">"
|
||||
| type_pointer_kind ~ "<" ~ storage_class ~ "," ~ type_decl ~ ">"
|
||||
| type_array_kind ~ "<" ~ type_decl ~ "," ~ int_literal ~ ">"
|
||||
| type_array_kind ~ "<" ~ type_decl ~ ">"
|
||||
| type_mat_kind ~ "<" ~ type_decl ~ ">"
|
||||
| ident
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +338,9 @@ impl<W: Write> Writer<W> {
|
||||
Ok(MaybeOwned::Owned(crate::TypeInner::Scalar { kind, width }))
|
||||
}
|
||||
crate::TypeInner::Array { base, size } => {
|
||||
assert!(index < size);
|
||||
if let crate::ArraySize::Static(length) = size {
|
||||
assert!(index < length);
|
||||
}
|
||||
write!(self.out, "[{}]", index)?;
|
||||
Ok(module.borrow_type(base))
|
||||
}
|
||||
@@ -477,7 +479,11 @@ impl<W: Write> Writer<W> {
|
||||
}
|
||||
crate::TypeInner::Array { base, size } => {
|
||||
let base_name = module.types[base].name.or_index(base);
|
||||
write!(self.out, "typedef {} {}[{}]", base_name, name, size)?;
|
||||
write!(self.out, "typedef {} {}[", base_name, name)?;
|
||||
if let crate::ArraySize::Static(length) = size {
|
||||
write!(self.out, "{}", length)?;
|
||||
}
|
||||
write!(self.out, "]")?;
|
||||
}
|
||||
crate::TypeInner::Struct { ref members } => {
|
||||
writeln!(self.out, "struct {} {{", name)?;
|
||||
|
||||
@@ -991,10 +991,29 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
inst.expect(4)?;
|
||||
let id = self.next()?;
|
||||
let type_id = self.next()?;
|
||||
let size = self.next()?;
|
||||
let length = self.next()?;
|
||||
let inner = crate::TypeInner::Array {
|
||||
base: self.lookup_type.lookup(type_id)?.token,
|
||||
size,
|
||||
size: crate::ArraySize::Static(length),
|
||||
};
|
||||
self.lookup_type.insert(id, LookupType {
|
||||
token: module.types.append(crate::Type {
|
||||
name: self.future_decor
|
||||
.remove(&id)
|
||||
.and_then(|dec| dec.name),
|
||||
inner,
|
||||
}),
|
||||
base_id: Some(type_id),
|
||||
});
|
||||
}
|
||||
Op::TypeRuntimeArray => {
|
||||
self.switch(ModuleState::Type, inst.op)?;
|
||||
inst.expect(4)?;
|
||||
let id = self.next()?;
|
||||
let type_id = self.next()?;
|
||||
let inner = crate::TypeInner::Array {
|
||||
base: self.lookup_type.lookup(type_id)?.token,
|
||||
size: crate::ArraySize::Dynamic,
|
||||
};
|
||||
self.lookup_type.insert(id, LookupType {
|
||||
token: module.types.append(crate::Type {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::storage::{Storage, Token};
|
||||
use crate::{
|
||||
storage::{Storage, Token},
|
||||
FastHashMap,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -10,6 +13,7 @@ pub enum Error {
|
||||
Pest(pest::error::Error<Rule>),
|
||||
BadInt(std::num::ParseIntError),
|
||||
BadStorageClass(String),
|
||||
UnknownType(String),
|
||||
}
|
||||
impl From<pest::error::Error<Rule>> for Error {
|
||||
fn from(error: pest::error::Error<Rule>) -> Self {
|
||||
@@ -23,9 +27,16 @@ impl From<std::num::ParseIntError> for Error {
|
||||
}
|
||||
|
||||
pub struct Parser {
|
||||
lookup_type: FastHashMap<String, Token<crate::Type>>,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new() -> Self {
|
||||
Parser {
|
||||
lookup_type: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_uint_literal(pair: pest::iterators::Pair<Rule>) -> Result<u32, Error> {
|
||||
Ok(pair.as_str().parse()?)
|
||||
}
|
||||
@@ -66,27 +77,88 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_type_decl(
|
||||
&self,
|
||||
type_decl: pest::iterators::Pair<Rule>,
|
||||
type_store: &mut Storage<crate::Type>,
|
||||
) -> Result<Token<crate::Type>, Error> {
|
||||
assert_eq!(type_decl.as_rule(), Rule::type_decl);
|
||||
let temp = type_decl.into_inner().next().unwrap();
|
||||
let inner = match temp.as_rule() {
|
||||
Rule::scalar_type => match temp.as_str() {
|
||||
"f32" => crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, width: 32 },
|
||||
"i32" => crate::TypeInner::Scalar { kind: crate::ScalarKind::Sint, width: 32 },
|
||||
"u32" => crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, width: 32 },
|
||||
other => panic!("Unexpected scalar {:?}", other),
|
||||
},
|
||||
Rule::ident => unimplemented!(),
|
||||
let mut type_decl_pairs = type_decl.into_inner();
|
||||
let type_kind = type_decl_pairs.next().unwrap();
|
||||
let inner = match type_kind.as_rule() {
|
||||
Rule::scalar_type => {
|
||||
let kind = match type_kind.as_str() {
|
||||
"f32" => crate::ScalarKind::Float,
|
||||
"i32" => crate::ScalarKind::Sint,
|
||||
"u32" => crate::ScalarKind::Uint,
|
||||
other => panic!("Unexpected scalar kind {:?}", other),
|
||||
};
|
||||
crate::TypeInner::Scalar { kind, width: 32 }
|
||||
}
|
||||
Rule::type_array_kind => {
|
||||
let base = self.parse_type_decl(type_decl_pairs.next().unwrap(), type_store)?;
|
||||
let size = match type_decl_pairs.next() {
|
||||
Some(pair) => crate::ArraySize::Static(Self::parse_uint_literal(pair)?),
|
||||
None => crate::ArraySize::Dynamic,
|
||||
};
|
||||
crate::TypeInner::Array { base, size }
|
||||
}
|
||||
Rule::type_vec_kind => {
|
||||
let size = match type_kind.as_str() {
|
||||
"vec2" => crate::VectorSize::Bi,
|
||||
"vec3" => crate::VectorSize::Tri,
|
||||
"vec4" => crate::VectorSize::Quad,
|
||||
other => panic!("Unexpected vec kind {:?}", other),
|
||||
};
|
||||
crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width: 32 }
|
||||
}
|
||||
Rule::ident => {
|
||||
return self.lookup_type
|
||||
.get(type_kind.as_str())
|
||||
.cloned()
|
||||
.ok_or(Error::UnknownType(type_kind.as_str().to_owned()));
|
||||
}
|
||||
other => panic!("Unexpected type {:?}", other),
|
||||
};
|
||||
if let Some((token, _)) = type_store
|
||||
.iter()
|
||||
.find(|(_, ty)| ty.inner == inner)
|
||||
{
|
||||
return Ok(token);
|
||||
}
|
||||
Ok(type_store.append(crate::Type {
|
||||
name: None, //TODO
|
||||
name: None,
|
||||
inner,
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_struct_decl(
|
||||
&self,
|
||||
struct_body_decl: pest::iterators::Pair<Rule>,
|
||||
type_store: &mut Storage<crate::Type>,
|
||||
) -> Result<crate::TypeInner, Error> {
|
||||
assert_eq!(struct_body_decl.as_rule(), Rule::struct_body_decl);
|
||||
let mut members = Vec::new();
|
||||
for member_decl in struct_body_decl.into_inner() {
|
||||
assert_eq!(member_decl.as_rule(), Rule::struct_member);
|
||||
let mut member_decl_pairs = member_decl.into_inner();
|
||||
let mut body = member_decl_pairs.next().unwrap();
|
||||
let binding = None;
|
||||
if body.as_rule() == Rule::struct_member_decoration_decl {
|
||||
body = member_decl_pairs.next().unwrap(); //TODO: parse properly
|
||||
}
|
||||
assert_eq!(body.as_rule(), Rule::variable_ident_decl);
|
||||
let mut variable_ident_decl_pairs = body.into_inner();
|
||||
let member_name = variable_ident_decl_pairs.next().unwrap().as_str().to_owned();
|
||||
let ty = self.parse_type_decl(variable_ident_decl_pairs.next().unwrap(), type_store)?;
|
||||
members.push(crate::StructMember {
|
||||
name: Some(member_name),
|
||||
binding,
|
||||
ty,
|
||||
});
|
||||
}
|
||||
Ok(crate::TypeInner::Struct { members })
|
||||
}
|
||||
|
||||
pub fn parse(&mut self, source: &str) -> Result<crate::Module, Error> {
|
||||
use pest::Parser as _;
|
||||
let pairs = Tokenizer::parse(Rule::translation_unit, source)?;
|
||||
@@ -118,7 +190,7 @@ impl Parser {
|
||||
assert_eq!(body.as_rule(), Rule::variable_ident_decl);
|
||||
let mut var_ident_decl_pairs = body.into_inner();
|
||||
let name = var_ident_decl_pairs.next().unwrap().as_str().to_owned();
|
||||
let ty = Self::parse_type_decl(var_ident_decl_pairs.next().unwrap(), &mut module.types)?;
|
||||
let ty = self.parse_type_decl(var_ident_decl_pairs.next().unwrap(), &mut module.types)?;
|
||||
module.global_variables.append(crate::GlobalVariable {
|
||||
name: Some(name),
|
||||
class,
|
||||
@@ -126,6 +198,30 @@ impl Parser {
|
||||
ty,
|
||||
});
|
||||
}
|
||||
Rule::type_alias => {
|
||||
let mut type_alias_pairs = global_decl.into_inner();
|
||||
let name = type_alias_pairs.next().unwrap().as_str().to_owned();
|
||||
let something_decl = type_alias_pairs.next().unwrap();
|
||||
match something_decl.as_rule() {
|
||||
Rule::type_decl => {
|
||||
let token = self.parse_type_decl(something_decl, &mut module.types)?;
|
||||
self.lookup_type.insert(name, token);
|
||||
}
|
||||
Rule::struct_decl => {
|
||||
let mut struct_decl_pairs = something_decl.into_inner();
|
||||
let mut body = struct_decl_pairs.next().unwrap();
|
||||
while body.as_rule() == Rule::struct_decoration_decl {
|
||||
body = struct_decl_pairs.next().unwrap(); //skip
|
||||
}
|
||||
let inner = self.parse_struct_decl(body, &mut module.types)?;
|
||||
module.types.append(crate::Type {
|
||||
name: Some(name),
|
||||
inner,
|
||||
});
|
||||
}
|
||||
other => panic!("Unexpected type alias rule {:?}", other),
|
||||
};
|
||||
}
|
||||
unknown => panic!("Unexpected global decl: {:?}", unknown),
|
||||
}
|
||||
}
|
||||
@@ -138,5 +234,5 @@ impl Parser {
|
||||
}
|
||||
|
||||
pub fn parse_str(source: &str) -> Result<crate::Module, Error> {
|
||||
Parser{}.parse(source)
|
||||
Parser::new().parse(source)
|
||||
}
|
||||
|
||||
15
src/lib.rs
15
src/lib.rs
@@ -41,7 +41,14 @@ pub enum ScalarKind {
|
||||
Float,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ArraySize {
|
||||
Static(spirv::Word),
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct StructMember {
|
||||
pub name: Option<String>,
|
||||
pub binding: Option<Binding>,
|
||||
@@ -63,14 +70,14 @@ pub struct Type {
|
||||
pub inner: TypeInner,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum TypeInner {
|
||||
Void,
|
||||
Scalar { kind: ScalarKind, width: Bytes },
|
||||
Vector { size: VectorSize, kind: ScalarKind, width: Bytes },
|
||||
Matrix { columns: VectorSize, rows: VectorSize, kind: ScalarKind, width: Bytes },
|
||||
Pointer { base: Token<Type>, class: spirv::StorageClass },
|
||||
Array { base: Token<Type>, size: u32 },
|
||||
Array { base: Token<Type>, size: ArraySize },
|
||||
Struct { members: Vec<StructMember> },
|
||||
Image { base: Token<Type>, dim: spirv::Dim, flags: ImageFlags },
|
||||
Sampler,
|
||||
@@ -90,7 +97,7 @@ pub enum ConstantInner {
|
||||
Float(f64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Binding {
|
||||
BuiltIn(spirv::BuiltIn),
|
||||
Location(spirv::Word),
|
||||
|
||||
Reference in New Issue
Block a user