From c2265ca4c8f888310e391725b674ef9b95c050e9 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 3 Mar 2020 11:14:15 -0500 Subject: [PATCH] [wgsl] structure declarations, better array types --- grammars/wgsl.pest | 58 ++++++++++++++------- src/back/msl.rs | 10 +++- src/front/spirv.rs | 23 ++++++++- src/front/wgsl.rs | 122 ++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 15 ++++-- 5 files changed, 188 insertions(+), 40 deletions(-) diff --git a/grammars/wgsl.pest b/grammars/wgsl.pest index 831dd99104..5314c8f2af 100644 --- a/grammars/wgsl.pest +++ b/grammars/wgsl.pest @@ -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 } diff --git a/src/back/msl.rs b/src/back/msl.rs index 1adcae1a05..f1246456cf 100644 --- a/src/back/msl.rs +++ b/src/back/msl.rs @@ -338,7 +338,9 @@ impl Writer { 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 Writer { } 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)?; diff --git a/src/front/spirv.rs b/src/front/spirv.rs index 987ea62145..65a13feece 100644 --- a/src/front/spirv.rs +++ b/src/front/spirv.rs @@ -991,10 +991,29 @@ impl> Parser { 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 { diff --git a/src/front/wgsl.rs b/src/front/wgsl.rs index 99b01bf779..b2a5fa0897 100644 --- a/src/front/wgsl.rs +++ b/src/front/wgsl.rs @@ -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), BadInt(std::num::ParseIntError), BadStorageClass(String), + UnknownType(String), } impl From> for Error { fn from(error: pest::error::Error) -> Self { @@ -23,9 +27,16 @@ impl From for Error { } pub struct Parser { + lookup_type: FastHashMap>, } impl Parser { + pub fn new() -> Self { + Parser { + lookup_type: FastHashMap::default(), + } + } + fn parse_uint_literal(pair: pest::iterators::Pair) -> Result { Ok(pair.as_str().parse()?) } @@ -66,27 +77,88 @@ impl Parser { } fn parse_type_decl( + &self, type_decl: pest::iterators::Pair, type_store: &mut Storage, ) -> Result, 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, + type_store: &mut Storage, + ) -> Result { + 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 { 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 { - Parser{}.parse(source) + Parser::new().parse(source) } diff --git a/src/lib.rs b/src/lib.rs index 2fa24d0a42..902a0b311c 100644 --- a/src/lib.rs +++ b/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, pub binding: Option, @@ -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, class: spirv::StorageClass }, - Array { base: Token, size: u32 }, + Array { base: Token, size: ArraySize }, Struct { members: Vec }, Image { base: Token, 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),