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::{
|
use crate::{
|
||||||
arena::{Arena, Handle},
|
arena::{Arena, Handle},
|
||||||
proc::Typifier,
|
proc::{Typifier, ResolveError},
|
||||||
FastHashMap,
|
FastHashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,6 +145,7 @@ pub enum Error<'a> {
|
|||||||
BadInteger(&'a str, std::num::ParseIntError),
|
BadInteger(&'a str, std::num::ParseIntError),
|
||||||
BadFloat(&'a str, std::num::ParseFloatError),
|
BadFloat(&'a str, std::num::ParseFloatError),
|
||||||
BadAccessor(&'a str),
|
BadAccessor(&'a str),
|
||||||
|
InvalidResolve(ResolveError),
|
||||||
UnknownImport(&'a str),
|
UnknownImport(&'a str),
|
||||||
UnknownStorageClass(&'a str),
|
UnknownStorageClass(&'a str),
|
||||||
UnknownDecoration(&'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> {
|
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)
|
self.typifier
|
||||||
|
.resolve(handle, self.expressions, self.types, self.constants, self.global_vars, self.local_vars)
|
||||||
|
.map_err(Error::InvalidResolve)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_binary_op(
|
fn parse_binary_op(
|
||||||
@ -468,7 +471,7 @@ impl Parser {
|
|||||||
name: None,
|
name: None,
|
||||||
specialization: None,
|
specialization: None,
|
||||||
inner: crate::ConstantInner::Bool(true),
|
inner: crate::ConstantInner::Bool(true),
|
||||||
ty: Self::deduce_type_handle(
|
ty: Typifier::deduce_type_handle(
|
||||||
crate::TypeInner::Scalar {
|
crate::TypeInner::Scalar {
|
||||||
kind: crate::ScalarKind::Bool,
|
kind: crate::ScalarKind::Bool,
|
||||||
width: 1,
|
width: 1,
|
||||||
@ -483,7 +486,7 @@ impl Parser {
|
|||||||
name: None,
|
name: None,
|
||||||
specialization: None,
|
specialization: None,
|
||||||
inner: crate::ConstantInner::Bool(false),
|
inner: crate::ConstantInner::Bool(false),
|
||||||
ty: Self::deduce_type_handle(
|
ty: Typifier::deduce_type_handle(
|
||||||
crate::TypeInner::Scalar {
|
crate::TypeInner::Scalar {
|
||||||
kind: crate::ScalarKind::Bool,
|
kind: crate::ScalarKind::Bool,
|
||||||
width: 1,
|
width: 1,
|
||||||
@ -500,7 +503,7 @@ impl Parser {
|
|||||||
name: None,
|
name: None,
|
||||||
specialization: None,
|
specialization: None,
|
||||||
inner,
|
inner,
|
||||||
ty: Self::deduce_type_handle(
|
ty: Typifier::deduce_type_handle(
|
||||||
crate::TypeInner::Scalar { kind, width: 32 },
|
crate::TypeInner::Scalar { kind, width: 32 },
|
||||||
ctx.types,
|
ctx.types,
|
||||||
)
|
)
|
||||||
@ -560,29 +563,64 @@ impl Parser {
|
|||||||
Token::Separator('.') => {
|
Token::Separator('.') => {
|
||||||
let _ = lexer.next();
|
let _ = lexer.next();
|
||||||
let name = lexer.next_ident()?;
|
let name = lexer.next_ident()?;
|
||||||
let type_handle = ctx.resolve_type(handle);
|
let type_handle = ctx.resolve_type(handle)?;
|
||||||
let index = match ctx.types[type_handle].inner {
|
let base_type = &ctx.types[type_handle];
|
||||||
|
let expression = match base_type.inner {
|
||||||
crate::TypeInner::Struct { ref members } => {
|
crate::TypeInner::Struct { ref members } => {
|
||||||
members
|
let index = members
|
||||||
.iter()
|
.iter()
|
||||||
.position(|m| m.name.as_ref().map(|s| s.as_str()) == Some(name))
|
.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::Vector { size, kind, width } |
|
||||||
crate::TypeInner::Matrix { columns: size, .. } => {
|
crate::TypeInner::Matrix { columns: size, kind, width, .. } => {
|
||||||
const MEMBERS: [&'static str; 4] = ["x", "y", "z", "w"];
|
const MEMBERS: [char; 4] = ['x', 'y', 'z', 'w'];
|
||||||
MEMBERS[.. size as usize]
|
if name.len() > 1 {
|
||||||
.iter()
|
let mut components = Vec::with_capacity(name.len());
|
||||||
.position(|&m| m == name)
|
for ch in name.chars() {
|
||||||
.ok_or(Error::BadAccessor(name))? as u32
|
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)),
|
_ => return Err(Error::BadAccessor(name)),
|
||||||
};
|
};
|
||||||
let expr = crate::Expression::AccessIndex {
|
handle = ctx.expressions.append(expression);
|
||||||
base: handle,
|
|
||||||
index,
|
|
||||||
};
|
|
||||||
handle = ctx.expressions.append(expr);
|
|
||||||
}
|
}
|
||||||
Token::Paren('[') => {
|
Token::Paren('[') => {
|
||||||
let _ = lexer.next();
|
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>(
|
fn parse_type_decl<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
lexer: &mut Lexer<'a>,
|
lexer: &mut Lexer<'a>,
|
||||||
@ -1001,7 +1026,7 @@ impl Parser {
|
|||||||
other => return Err(Error::Unexpected(other)),
|
other => return Err(Error::Unexpected(other)),
|
||||||
};
|
};
|
||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
Ok(Self::deduce_type_handle(inner, type_arena))
|
Ok(Typifier::deduce_type_handle(inner, type_arena))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement<'a>(
|
fn parse_statement<'a>(
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
mod typifier;
|
mod typifier;
|
||||||
|
|
||||||
pub use typifier::Typifier;
|
pub use typifier::{ResolveError, Typifier};
|
||||||
|
@ -4,6 +4,11 @@ pub struct Typifier {
|
|||||||
types: Vec<Handle<crate::Type>>,
|
types: Vec<Handle<crate::Type>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ResolveError {
|
||||||
|
InvalidAccessIndex,
|
||||||
|
}
|
||||||
|
|
||||||
impl Typifier {
|
impl Typifier {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Typifier {
|
Typifier {
|
||||||
@ -15,24 +20,42 @@ impl Typifier {
|
|||||||
&mut self,
|
&mut self,
|
||||||
expr_handle: Handle<crate::Expression>,
|
expr_handle: Handle<crate::Expression>,
|
||||||
expressions: &Arena<crate::Expression>,
|
expressions: &Arena<crate::Expression>,
|
||||||
types: &Arena<crate::Type>,
|
types: &mut Arena<crate::Type>,
|
||||||
constants: &Arena<crate::Constant>,
|
constants: &Arena<crate::Constant>,
|
||||||
global_vars: &Arena<crate::GlobalVariable>,
|
global_vars: &Arena<crate::GlobalVariable>,
|
||||||
local_vars: &Arena<crate::LocalVariable>,
|
local_vars: &Arena<crate::LocalVariable>,
|
||||||
) -> Handle<crate::Type> {
|
) -> Result<Handle<crate::Type>, ResolveError> {
|
||||||
if self.types.len() <= expr_handle.index() {
|
if self.types.len() <= expr_handle.index() {
|
||||||
for (_, expr) in expressions.iter().skip(self.types.len()) {
|
for (eh, expr) in expressions.iter().skip(self.types.len()) {
|
||||||
self.types.push(match *expr {
|
let ty = match *expr {
|
||||||
crate::Expression::Access { base, .. } => {
|
crate::Expression::Access { base, .. } => {
|
||||||
match types[self.types[base.index()]].inner {
|
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),
|
ref other => panic!("Can't access into {:?}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::Expression::AccessIndex { base, index } => {
|
crate::Expression::AccessIndex { base, index } => {
|
||||||
match types[self.types[base.index()]].inner {
|
match types[self.types[base.index()]].inner {
|
||||||
crate::TypeInner::Array { base, .. } => self.types[base.index()],
|
crate::TypeInner::Vector { size, kind, width } => {
|
||||||
crate::TypeInner::Struct { ref members } => members[index as usize].ty,
|
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),
|
ref other => panic!("Can't access into {:?}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,16 +67,90 @@ impl Typifier {
|
|||||||
crate::Expression::Load { .. } => unimplemented!(),
|
crate::Expression::Load { .. } => unimplemented!(),
|
||||||
crate::Expression::Mul(_, _) => unimplemented!(),
|
crate::Expression::Mul(_, _) => unimplemented!(),
|
||||||
crate::Expression::ImageSample { .. } => unimplemented!(),
|
crate::Expression::ImageSample { .. } => unimplemented!(),
|
||||||
crate::Expression::Unary { .. } => unimplemented!(),
|
crate::Expression::Unary { expr, .. } => self.types[expr.index()],
|
||||||
crate::Expression::Binary { .. } => unimplemented!(),
|
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::Intrinsic { .. } => unimplemented!(),
|
||||||
crate::Expression::DotProduct(_, _) => unimplemented!(),
|
crate::Expression::DotProduct(_, _) => unimplemented!(),
|
||||||
crate::Expression::CrossProduct(_, _) => unimplemented!(),
|
crate::Expression::CrossProduct(_, _) => unimplemented!(),
|
||||||
crate::Expression::Derivative { .. } => 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