Implement a fair bit of typifier logic, resolve access ids in WGSL

This commit is contained in:
Dzmitry Malyshau 2020-03-14 18:23:31 -04:00 committed by Dzmitry Malyshau
parent 3c5a12412c
commit a768af6011
3 changed files with 171 additions and 49 deletions

View File

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

View File

@ -1,3 +1,3 @@
mod typifier;
pub use typifier::Typifier;
pub use typifier::{ResolveError, Typifier};

View File

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