mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-23 23:34:29 +00:00
Implement a fair bit of typifier logic, resolve access ids in WGSL
This commit is contained in:
parent
3c5a12412c
commit
a768af6011
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
arena::{Arena, Handle},
|
||||
proc::Typifier,
|
||||
proc::{Typifier, ResolveError},
|
||||
FastHashMap,
|
||||
};
|
||||
|
||||
@ -145,6 +145,7 @@ pub enum Error<'a> {
|
||||
BadInteger(&'a str, std::num::ParseIntError),
|
||||
BadFloat(&'a str, std::num::ParseFloatError),
|
||||
BadAccessor(&'a str),
|
||||
InvalidResolve(ResolveError),
|
||||
UnknownImport(&'a str),
|
||||
UnknownStorageClass(&'a str),
|
||||
UnknownDecoration(&'a str),
|
||||
@ -312,8 +313,10 @@ impl<'a> ExpressionContext<'a, '_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_type(&mut self, handle: Handle<crate::Expression>) -> Handle<crate::Type> {
|
||||
self.typifier.resolve(handle, self.expressions, self.types, self.constants, self.global_vars, self.local_vars)
|
||||
fn resolve_type(&mut self, handle: Handle<crate::Expression>) -> Result<Handle<crate::Type>, Error<'a>> {
|
||||
self.typifier
|
||||
.resolve(handle, self.expressions, self.types, self.constants, self.global_vars, self.local_vars)
|
||||
.map_err(Error::InvalidResolve)
|
||||
}
|
||||
|
||||
fn parse_binary_op(
|
||||
@ -468,7 +471,7 @@ impl Parser {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Bool(true),
|
||||
ty: Self::deduce_type_handle(
|
||||
ty: Typifier::deduce_type_handle(
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Bool,
|
||||
width: 1,
|
||||
@ -483,7 +486,7 @@ impl Parser {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner: crate::ConstantInner::Bool(false),
|
||||
ty: Self::deduce_type_handle(
|
||||
ty: Typifier::deduce_type_handle(
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Bool,
|
||||
width: 1,
|
||||
@ -500,7 +503,7 @@ impl Parser {
|
||||
name: None,
|
||||
specialization: None,
|
||||
inner,
|
||||
ty: Self::deduce_type_handle(
|
||||
ty: Typifier::deduce_type_handle(
|
||||
crate::TypeInner::Scalar { kind, width: 32 },
|
||||
ctx.types,
|
||||
)
|
||||
@ -560,29 +563,64 @@ impl Parser {
|
||||
Token::Separator('.') => {
|
||||
let _ = lexer.next();
|
||||
let name = lexer.next_ident()?;
|
||||
let type_handle = ctx.resolve_type(handle);
|
||||
let index = match ctx.types[type_handle].inner {
|
||||
let type_handle = ctx.resolve_type(handle)?;
|
||||
let base_type = &ctx.types[type_handle];
|
||||
let expression = match base_type.inner {
|
||||
crate::TypeInner::Struct { ref members } => {
|
||||
members
|
||||
let index = members
|
||||
.iter()
|
||||
.position(|m| m.name.as_ref().map(|s| s.as_str()) == Some(name))
|
||||
.ok_or(Error::BadAccessor(name))? as u32
|
||||
.ok_or(Error::BadAccessor(name))? as u32;
|
||||
crate::Expression::AccessIndex {
|
||||
base: handle,
|
||||
index,
|
||||
}
|
||||
}
|
||||
crate::TypeInner::Vector { size, .. } |
|
||||
crate::TypeInner::Matrix { columns: size, .. } => {
|
||||
const MEMBERS: [&'static str; 4] = ["x", "y", "z", "w"];
|
||||
MEMBERS[.. size as usize]
|
||||
.iter()
|
||||
.position(|&m| m == name)
|
||||
.ok_or(Error::BadAccessor(name))? as u32
|
||||
crate::TypeInner::Vector { size, kind, width } |
|
||||
crate::TypeInner::Matrix { columns: size, kind, width, .. } => {
|
||||
const MEMBERS: [char; 4] = ['x', 'y', 'z', 'w'];
|
||||
if name.len() > 1 {
|
||||
let mut components = Vec::with_capacity(name.len());
|
||||
for ch in name.chars() {
|
||||
let expr = crate::Expression::AccessIndex {
|
||||
base: handle,
|
||||
index: MEMBERS[.. size as usize]
|
||||
.iter()
|
||||
.position(|&m| m == ch)
|
||||
.ok_or(Error::BadAccessor(name))? as u32,
|
||||
};
|
||||
components.push(ctx.expressions.append(expr));
|
||||
}
|
||||
let size = match name.len() {
|
||||
2 => crate::VectorSize::Bi,
|
||||
3 => crate::VectorSize::Tri,
|
||||
4 => crate::VectorSize::Quad,
|
||||
_ => return Err(Error::BadAccessor(name)),
|
||||
};
|
||||
let inner = if let crate::TypeInner::Matrix { rows, .. } = base_type.inner {
|
||||
crate::TypeInner::Matrix { columns: size, rows, kind, width }
|
||||
} else {
|
||||
crate::TypeInner::Vector { size, kind, width }
|
||||
};
|
||||
crate::Expression::Compose {
|
||||
ty: Typifier::deduce_type_handle(inner, ctx.types),
|
||||
components,
|
||||
}
|
||||
} else {
|
||||
let ch = name.chars().next().unwrap();
|
||||
let index = MEMBERS[.. size as usize]
|
||||
.iter()
|
||||
.position(|&m| m == ch)
|
||||
.ok_or(Error::BadAccessor(name))? as u32;
|
||||
crate::Expression::AccessIndex {
|
||||
base: handle,
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::BadAccessor(name)),
|
||||
};
|
||||
let expr = crate::Expression::AccessIndex {
|
||||
base: handle,
|
||||
index,
|
||||
};
|
||||
handle = ctx.expressions.append(expr);
|
||||
handle = ctx.expressions.append(expression);
|
||||
}
|
||||
Token::Paren('[') => {
|
||||
let _ = lexer.next();
|
||||
@ -876,19 +914,6 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn deduce_type_handle<'a>(inner: crate::TypeInner, arena: &mut Arena<crate::Type>) -> Handle<crate::Type> {
|
||||
if let Some((token, _)) = arena
|
||||
.iter()
|
||||
.find(|(_, ty)| ty.inner == inner)
|
||||
{
|
||||
return token;
|
||||
}
|
||||
arena.append(crate::Type {
|
||||
name: None,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_type_decl<'a>(
|
||||
&mut self,
|
||||
lexer: &mut Lexer<'a>,
|
||||
@ -1001,7 +1026,7 @@ impl Parser {
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
};
|
||||
self.scopes.pop();
|
||||
Ok(Self::deduce_type_handle(inner, type_arena))
|
||||
Ok(Typifier::deduce_type_handle(inner, type_arena))
|
||||
}
|
||||
|
||||
fn parse_statement<'a>(
|
||||
|
@ -1,3 +1,3 @@
|
||||
mod typifier;
|
||||
|
||||
pub use typifier::Typifier;
|
||||
pub use typifier::{ResolveError, Typifier};
|
||||
|
@ -4,6 +4,11 @@ pub struct Typifier {
|
||||
types: Vec<Handle<crate::Type>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ResolveError {
|
||||
InvalidAccessIndex,
|
||||
}
|
||||
|
||||
impl Typifier {
|
||||
pub fn new() -> Self {
|
||||
Typifier {
|
||||
@ -15,24 +20,42 @@ impl Typifier {
|
||||
&mut self,
|
||||
expr_handle: Handle<crate::Expression>,
|
||||
expressions: &Arena<crate::Expression>,
|
||||
types: &Arena<crate::Type>,
|
||||
types: &mut Arena<crate::Type>,
|
||||
constants: &Arena<crate::Constant>,
|
||||
global_vars: &Arena<crate::GlobalVariable>,
|
||||
local_vars: &Arena<crate::LocalVariable>,
|
||||
) -> Handle<crate::Type> {
|
||||
) -> Result<Handle<crate::Type>, ResolveError> {
|
||||
if self.types.len() <= expr_handle.index() {
|
||||
for (_, expr) in expressions.iter().skip(self.types.len()) {
|
||||
self.types.push(match *expr {
|
||||
for (eh, expr) in expressions.iter().skip(self.types.len()) {
|
||||
let ty = match *expr {
|
||||
crate::Expression::Access { base, .. } => {
|
||||
match types[self.types[base.index()]].inner {
|
||||
crate::TypeInner::Array { base, .. } => self.types[base.index()],
|
||||
crate::TypeInner::Array { base, .. } => base,
|
||||
ref other => panic!("Can't access into {:?}", other),
|
||||
}
|
||||
}
|
||||
crate::Expression::AccessIndex { base, index } => {
|
||||
match types[self.types[base.index()]].inner {
|
||||
crate::TypeInner::Array { base, .. } => self.types[base.index()],
|
||||
crate::TypeInner::Struct { ref members } => members[index as usize].ty,
|
||||
crate::TypeInner::Vector { size, kind, width } => {
|
||||
if index >= size as u32 {
|
||||
return Err(ResolveError::InvalidAccessIndex)
|
||||
}
|
||||
let inner = crate::TypeInner::Scalar { kind, width };
|
||||
Self::deduce_type_handle(inner, types)
|
||||
}
|
||||
crate::TypeInner::Matrix { columns, rows, kind, width } => {
|
||||
if index >= columns as u32 {
|
||||
return Err(ResolveError::InvalidAccessIndex)
|
||||
}
|
||||
let inner = crate::TypeInner::Vector { size: rows, kind, width };
|
||||
Self::deduce_type_handle(inner, types)
|
||||
}
|
||||
crate::TypeInner::Array { base, .. } => base,
|
||||
crate::TypeInner::Struct { ref members } => {
|
||||
members.get(index as usize)
|
||||
.ok_or(ResolveError::InvalidAccessIndex)?
|
||||
.ty
|
||||
}
|
||||
ref other => panic!("Can't access into {:?}", other),
|
||||
}
|
||||
}
|
||||
@ -44,16 +67,90 @@ impl Typifier {
|
||||
crate::Expression::Load { .. } => unimplemented!(),
|
||||
crate::Expression::Mul(_, _) => unimplemented!(),
|
||||
crate::Expression::ImageSample { .. } => unimplemented!(),
|
||||
crate::Expression::Unary { .. } => unimplemented!(),
|
||||
crate::Expression::Binary { .. } => unimplemented!(),
|
||||
crate::Expression::Unary { expr, .. } => self.types[expr.index()],
|
||||
crate::Expression::Binary { op, left, right } => {
|
||||
match op {
|
||||
crate::BinaryOperator::Add |
|
||||
crate::BinaryOperator::Subtract |
|
||||
crate::BinaryOperator::Divide |
|
||||
crate::BinaryOperator::Modulo => {
|
||||
self.types[left.index()]
|
||||
}
|
||||
crate::BinaryOperator::Multiply => {
|
||||
let ty_left = self.types[left.index()];
|
||||
let ty_right = self.types[right.index()];
|
||||
if ty_left == ty_right {
|
||||
ty_left
|
||||
} else if let crate::TypeInner::Scalar { .. } = types[ty_right].inner {
|
||||
ty_left
|
||||
} else if let crate::TypeInner::Matrix { columns, kind, width, .. } = types[ty_left].inner {
|
||||
let inner = crate::TypeInner::Vector { size: columns, kind, width};
|
||||
Self::deduce_type_handle(inner, types)
|
||||
} else {
|
||||
panic!("Incompatible arguments {:?} x {:?}", types[ty_left], types[ty_right]);
|
||||
}
|
||||
}
|
||||
crate::BinaryOperator::Equal |
|
||||
crate::BinaryOperator::NotEqual |
|
||||
crate::BinaryOperator::Less |
|
||||
crate::BinaryOperator::LessEqual |
|
||||
crate::BinaryOperator::Greater |
|
||||
crate::BinaryOperator::GreaterEqual |
|
||||
crate::BinaryOperator::LogicalAnd |
|
||||
crate::BinaryOperator::LogicalOr => {
|
||||
self.types[left.index()]
|
||||
}
|
||||
crate::BinaryOperator::And |
|
||||
crate::BinaryOperator::ExclusiveOr |
|
||||
crate::BinaryOperator::InclusiveOr |
|
||||
crate::BinaryOperator::ShiftLeftLogical |
|
||||
crate::BinaryOperator::ShiftRightLogical |
|
||||
crate::BinaryOperator::ShiftRightArithmetic => {
|
||||
self.types[left.index()]
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::Expression::Intrinsic { .. } => unimplemented!(),
|
||||
crate::Expression::DotProduct(_, _) => unimplemented!(),
|
||||
crate::Expression::CrossProduct(_, _) => unimplemented!(),
|
||||
crate::Expression::Derivative { .. } => unimplemented!(),
|
||||
crate::Expression::Call { .. } => unimplemented!(),
|
||||
});
|
||||
crate::Expression::Call { ref name, ref arguments } => {
|
||||
match name.as_str() {
|
||||
"distance" | "length" => {
|
||||
let ty_handle = self.types[arguments[0].index()];
|
||||
let inner = match types[ty_handle].inner {
|
||||
crate::TypeInner::Vector { kind, width, .. } => {
|
||||
crate::TypeInner::Scalar { kind, width }
|
||||
}
|
||||
ref other => panic!("Unexpected argument {:?}", other),
|
||||
};
|
||||
Self::deduce_type_handle(inner, types)
|
||||
}
|
||||
"normalize" | "fclamp" => self.types[arguments[0].index()],
|
||||
_ => panic!("Unknown '{}' call", name),
|
||||
}
|
||||
}
|
||||
};
|
||||
log::debug!("Resolving {:?} = {:?} : {:?}", eh, expr, ty);
|
||||
self.types.push(ty);
|
||||
};
|
||||
}
|
||||
self.types[expr_handle.index()]
|
||||
Ok(self.types[expr_handle.index()])
|
||||
}
|
||||
|
||||
pub fn deduce_type_handle(
|
||||
inner: crate::TypeInner,
|
||||
arena: &mut Arena<crate::Type>,
|
||||
) -> Handle<crate::Type> {
|
||||
if let Some((token, _)) = arena
|
||||
.iter()
|
||||
.find(|(_, ty)| ty.inner == inner)
|
||||
{
|
||||
return token;
|
||||
}
|
||||
arena.append(crate::Type {
|
||||
name: None,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user