[wgsl] structure declarations, better array types

This commit is contained in:
Dzmitry Malyshau
2020-03-03 11:14:15 -05:00
parent aba9e8a0f2
commit c2265ca4c8
5 changed files with 188 additions and 40 deletions

View File

@@ -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
}

View File

@@ -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)?;

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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),