[glsl-in] WIP expression parsing

This commit is contained in:
João Capucho
2021-05-02 22:17:01 +01:00
committed by Dzmitry Malyshau
parent 3073ade8a4
commit f8c8d192ae
9 changed files with 842 additions and 475 deletions

View File

@@ -1,4 +1,4 @@
use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind};
use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind, TokenMetadata};
use crate::{
proc::ResolveContext, Arena, ArraySize, BinaryOperator, Binding, Constant, Expression,
FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, Module,
@@ -200,9 +200,9 @@ pub enum Profile {
pub struct FunctionContext<'function> {
pub function: &'function mut Function,
//TODO: Find less allocation heavy representation
pub scopes: Vec<FastHashMap<String, Handle<Expression>>>,
pub lookup_global_var_exps: FastHashMap<String, Handle<Expression>>,
pub lookup_constant_exps: FastHashMap<String, Handle<Expression>>,
pub scopes: Vec<FastHashMap<String, VariableReference>>,
pub lookup_global_var_exps: FastHashMap<String, VariableReference>,
pub lookup_constant_exps: FastHashMap<String, VariableReference>,
pub typifier: Typifier,
}
@@ -217,17 +217,17 @@ impl<'function> FunctionContext<'function> {
}
}
pub fn lookup_local_var(&self, name: &str) -> Option<Handle<Expression>> {
pub fn lookup_local_var(&self, name: &str) -> Option<VariableReference> {
for scope in self.scopes.iter().rev() {
if let Some(var) = scope.get(name) {
return Some(*var);
return Some(var.clone());
}
}
None
}
#[cfg(feature = "glsl-validate")]
pub fn lookup_local_var_current_scope(&self, name: &str) -> Option<Handle<Expression>> {
pub fn lookup_local_var_current_scope(&self, name: &str) -> Option<VariableReference> {
if let Some(current) = self.scopes.last() {
current.get(name).cloned()
} else {
@@ -241,13 +241,20 @@ impl<'function> FunctionContext<'function> {
}
/// Add variable to current scope
pub fn add_local_var(&mut self, name: String, handle: Handle<Expression>) {
pub fn add_local_var(&mut self, name: String, expr: Handle<Expression>) {
if let Some(current) = self.scopes.last_mut() {
let expr = self
let load = self
.function
.expressions
.append(Expression::Load { pointer: handle });
(*current).insert(name, expr);
.append(Expression::Load { pointer: expr });
(*current).insert(
name,
VariableReference {
expr,
load: Some(load),
},
);
}
}
@@ -266,7 +273,8 @@ impl<'function> FunctionContext<'function> {
.function
.expressions
.append(Expression::FunctionArgument(index as u32));
(*current).insert(name, expr);
(*current).insert(name, VariableReference { expr, load: None });
}
}
}
@@ -279,6 +287,79 @@ impl<'function> FunctionContext<'function> {
pub fn remove_current_scope(&mut self) {
self.scopes.pop();
}
pub fn resolve(
&mut self,
program: &mut Program,
expr: Expr,
lhs: bool,
) -> Result<Handle<Expression>, ErrorKind> {
Ok(match expr.kind {
ExprKind::Access { base, index } => {
let base = self.resolve(program, *base, lhs)?;
let index = self.resolve(program, *index, false)?;
self.function
.expressions
.append(Expression::Access { base, index })
}
ExprKind::Select { base, field } => {
let base = self.resolve(program, *base, lhs)?;
program.field_selection(self, base, &field, expr.meta)?
}
ExprKind::Constant(constant) => self
.function
.expressions
.append(Expression::Constant(constant)),
ExprKind::Binary { left, op, right } => {
let left = self.resolve(program, *left, false)?;
let right = self.resolve(program, *right, false)?;
self.function
.expressions
.append(Expression::Binary { left, op, right })
}
ExprKind::Unary { op, expr } => {
let expr = self.resolve(program, *expr, false)?;
self.function
.expressions
.append(Expression::Unary { op, expr })
}
ExprKind::Variable(var) => {
if lhs {
var.expr
} else {
var.load.unwrap_or(var.expr)
}
}
ExprKind::Call(_) => todo!(),
ExprKind::Conditional {
condition,
accept,
reject,
} => {
let condition = self.resolve(program, *condition, false)?;
let accept = self.resolve(program, *accept, false)?;
let reject = self.resolve(program, *reject, false)?;
self.function.expressions.append(Expression::Select {
condition,
accept,
reject,
})
}
ExprKind::Assign { tgt, value } => {
let pointer = self.resolve(program, *tgt, false)?;
let value = self.resolve(program, *value, false)?;
self.function.body.push(Statement::Store { pointer, value });
value
}
})
}
}
#[derive(Debug)]
@@ -298,6 +379,51 @@ impl ExpressionRule {
}
}
#[derive(Debug, Clone)]
pub struct VariableReference {
pub expr: Handle<Expression>,
pub load: Option<Handle<Expression>>,
}
#[derive(Debug)]
pub struct Expr {
pub kind: ExprKind,
pub meta: TokenMetadata,
}
#[derive(Debug)]
pub enum ExprKind {
Access {
base: Box<Expr>,
index: Box<Expr>,
},
Select {
base: Box<Expr>,
field: String,
},
Constant(Handle<Constant>),
Binary {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
Unary {
op: UnaryOperator,
expr: Box<Expr>,
},
Variable(VariableReference),
Call(FunctionCall),
Conditional {
condition: Box<Expr>,
accept: Box<Expr>,
reject: Box<Expr>,
},
Assign {
tgt: Box<Expr>,
value: Box<Expr>,
},
}
#[derive(Debug)]
pub enum TypeQualifier {
StorageQualifier(StorageQualifier),
@@ -325,7 +451,7 @@ pub enum FunctionCallKind {
#[derive(Debug)]
pub struct FunctionCall {
pub kind: FunctionCallKind,
pub args: Vec<ExpressionRule>,
pub args: Vec<Expr>,
}
#[derive(Debug, Clone, Copy)]

View File

@@ -8,7 +8,7 @@ pub enum ErrorKind {
InvalidInput,
InvalidProfile(TokenMetadata, String),
InvalidToken(Token),
InvalidVersion(TokenMetadata, i64),
InvalidVersion(TokenMetadata, u64),
IoError(io::Error),
ParserFail,
ParserStackOverflow,

View File

@@ -1,298 +1,298 @@
use crate::{
BinaryOperator, Expression, MathFunction, RelationalFunction, SampleLevel, ScalarKind,
TypeInner,
proc::ensure_block_returns, BinaryOperator, EntryPoint, Expression, Function, MathFunction,
RelationalFunction, SampleLevel, TypeInner,
};
use super::{ast::*, error::ErrorKind};
impl Program<'_> {
pub fn function_call(
&mut self,
context: &mut FunctionContext,
fc: FunctionCall,
) -> Result<ExpressionRule, ErrorKind> {
match fc.kind {
FunctionCallKind::TypeConstructor(ty) => {
let h = if fc.args.len() == 1 {
let is_vec = match *self.resolve_type(context, fc.args[0].expression)? {
TypeInner::Vector { .. } => true,
_ => false,
};
// pub fn function_call(
// &mut self,
// context: &mut FunctionContext,
// fc: FunctionCall,
// ) -> Result<ExpressionRule, ErrorKind> {
// match fc.kind {
// FunctionCallKind::TypeConstructor(ty) => {
// let h = if fc.args.len() == 1 {
// let is_vec = match *self.resolve_type(context, fc.args[0].expression)? {
// TypeInner::Vector { .. } => true,
// _ => false,
// };
match self.module.types[ty].inner {
TypeInner::Vector { size, .. } if !is_vec => {
context.function.expressions.append(Expression::Splat {
size,
value: fc.args[0].expression,
})
}
TypeInner::Scalar { kind, width }
| TypeInner::Vector { kind, width, .. } => {
context.function.expressions.append(Expression::As {
kind,
expr: fc.args[0].expression,
convert: Some(width),
})
}
TypeInner::Matrix {
columns,
rows,
width,
} => {
let value = context.function.expressions.append(Expression::As {
kind: ScalarKind::Float,
expr: fc.args[0].expression,
convert: Some(width),
});
// match self.module.types[ty].inner {
// TypeInner::Vector { size, .. } if !is_vec => {
// context.function.expressions.append(Expression::Splat {
// size,
// value: fc.args[0].expression,
// })
// }
// TypeInner::Scalar { kind, width }
// | TypeInner::Vector { kind, width, .. } => {
// context.function.expressions.append(Expression::As {
// kind,
// expr: fc.args[0].expression,
// convert: Some(width),
// })
// }
// TypeInner::Matrix {
// columns,
// rows,
// width,
// } => {
// let value = context.function.expressions.append(Expression::As {
// kind: ScalarKind::Float,
// expr: fc.args[0].expression,
// convert: Some(width),
// });
let column = if is_vec {
value
} else {
context
.function
.expressions
.append(Expression::Splat { size: rows, value })
};
// let column = if is_vec {
// value
// } else {
// context
// .function
// .expressions
// .append(Expression::Splat { size: rows, value })
// };
let columns =
std::iter::repeat(column).take(columns as usize).collect();
// let columns =
// std::iter::repeat(column).take(columns as usize).collect();
context.function.expressions.append(Expression::Compose {
ty,
components: columns,
})
}
_ => return Err(ErrorKind::SemanticError("Bad cast".into())),
}
} else {
context.function.expressions.append(Expression::Compose {
ty,
components: fc.args.iter().map(|a| a.expression).collect(),
})
};
// context.function.expressions.append(Expression::Compose {
// ty,
// components: columns,
// })
// }
// _ => return Err(ErrorKind::SemanticError("Bad cast".into())),
// }
// } else {
// context.function.expressions.append(Expression::Compose {
// ty,
// components: fc.args.iter().map(|a| a.expression).collect(),
// })
// };
Ok(ExpressionRule {
expression: h,
statements: fc
.args
.into_iter()
.map(|a| a.statements)
.flatten()
.collect(),
sampler: None,
})
}
FunctionCallKind::Function(name) => {
match name.as_str() {
"sampler2D" => {
if fc.args.len() != 2 {
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
}
Ok(ExpressionRule {
expression: fc.args[0].expression,
sampler: Some(fc.args[1].expression),
statements: fc
.args
.into_iter()
.map(|a| a.statements)
.flatten()
.collect(),
})
}
"texture" => {
if fc.args.len() != 2 {
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
}
if let Some(sampler) = fc.args[0].sampler {
Ok(ExpressionRule {
expression: context.function.expressions.append(
Expression::ImageSample {
image: fc.args[0].expression,
sampler,
coordinate: fc.args[1].expression,
array_index: None, //TODO
offset: None, //TODO
level: SampleLevel::Auto,
depth_ref: None,
},
),
sampler: None,
statements: fc
.args
.into_iter()
.map(|a| a.statements)
.flatten()
.collect(),
})
} else {
Err(ErrorKind::SemanticError("Bad call to texture".into()))
}
}
"textureLod" => {
if fc.args.len() != 3 {
return Err(ErrorKind::WrongNumberArgs(name, 3, fc.args.len()));
}
if let Some(sampler) = fc.args[0].sampler {
Ok(ExpressionRule {
expression: context.function.expressions.append(
Expression::ImageSample {
image: fc.args[0].expression,
sampler,
coordinate: fc.args[1].expression,
array_index: None, //TODO
offset: None, //TODO
level: SampleLevel::Exact(fc.args[2].expression),
depth_ref: None,
},
),
sampler: None,
statements: fc
.args
.into_iter()
.map(|a| a.statements)
.flatten()
.collect(),
})
} else {
Err(ErrorKind::SemanticError("Bad call to textureLod".into()))
}
}
"ceil" | "round" | "floor" | "fract" | "trunc" | "sin" | "abs" | "sqrt"
| "inversesqrt" | "exp" | "exp2" | "sign" | "transpose" | "inverse"
| "normalize" => {
if fc.args.len() != 1 {
return Err(ErrorKind::WrongNumberArgs(name, 1, fc.args.len()));
}
Ok(ExpressionRule {
expression: context.function.expressions.append(Expression::Math {
fun: match name.as_str() {
"ceil" => MathFunction::Ceil,
"round" => MathFunction::Round,
"floor" => MathFunction::Floor,
"fract" => MathFunction::Fract,
"trunc" => MathFunction::Trunc,
"sin" => MathFunction::Sin,
"abs" => MathFunction::Abs,
"sqrt" => MathFunction::Sqrt,
"inversesqrt" => MathFunction::InverseSqrt,
"exp" => MathFunction::Exp,
"exp2" => MathFunction::Exp2,
"sign" => MathFunction::Sign,
"transpose" => MathFunction::Transpose,
"inverse" => MathFunction::Inverse,
"normalize" => MathFunction::Normalize,
_ => unreachable!(),
},
arg: fc.args[0].expression,
arg1: None,
arg2: None,
}),
sampler: None,
statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
})
}
"pow" | "dot" | "max" => {
if fc.args.len() != 2 {
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
}
Ok(ExpressionRule {
expression: context.function.expressions.append(Expression::Math {
fun: match name.as_str() {
"pow" => MathFunction::Pow,
"dot" => MathFunction::Dot,
"max" => MathFunction::Max,
_ => unreachable!(),
},
arg: fc.args[0].expression,
arg1: Some(fc.args[1].expression),
arg2: None,
}),
sampler: None,
statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
})
}
"mix" | "clamp" => {
if fc.args.len() != 3 {
return Err(ErrorKind::WrongNumberArgs(name, 3, fc.args.len()));
}
Ok(ExpressionRule {
expression: context.function.expressions.append(Expression::Math {
fun: match name.as_str() {
"mix" => MathFunction::Mix,
"clamp" => MathFunction::Clamp,
_ => unreachable!(),
},
arg: fc.args[0].expression,
arg1: Some(fc.args[1].expression),
arg2: Some(fc.args[2].expression),
}),
sampler: None,
statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
})
}
"lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal"
| "notEqual" => {
if fc.args.len() != 2 {
return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
}
Ok(ExpressionRule {
expression: context.function.expressions.append(Expression::Binary {
op: match name.as_str() {
"lessThan" => BinaryOperator::Less,
"greaterThan" => BinaryOperator::Greater,
"lessThanEqual" => BinaryOperator::LessEqual,
"greaterThanEqual" => BinaryOperator::GreaterEqual,
"equal" => BinaryOperator::Equal,
"notEqual" => BinaryOperator::NotEqual,
_ => unreachable!(),
},
left: fc.args[0].expression,
right: fc.args[1].expression,
}),
sampler: None,
statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
})
}
"isinf" => {
self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsInf)
}
"isnan" => {
self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsNan)
}
"all" => {
self.parse_relational_fun(context, name, fc.args, RelationalFunction::All)
}
"any" => {
self.parse_relational_fun(context, name, fc.args, RelationalFunction::Any)
}
func_name => {
let function = *self.lookup_function.get(func_name).ok_or_else(|| {
ErrorKind::SemanticError(
format!("Unknown function: {}", func_name).into(),
)
})?;
let arguments: Vec<_> = fc.args.iter().map(|a| a.expression).collect();
let mut statements: Vec<_> =
fc.args.into_iter().flat_map(|a| a.statements).collect();
let expression = context
.function
.expressions
.append(Expression::Call(function));
statements.push(crate::Statement::Call {
function,
arguments,
result: Some(expression),
});
Ok(ExpressionRule {
expression,
sampler: None,
statements,
})
}
}
}
}
}
// Ok(ExpressionRule {
// expression: h,
// statements: fc
// .args
// .into_iter()
// .map(|a| a.statements)
// .flatten()
// .collect(),
// sampler: None,
// })
// }
// FunctionCallKind::Function(name) => {
// match name.as_str() {
// "sampler2D" => {
// if fc.args.len() != 2 {
// return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
// }
// Ok(ExpressionRule {
// expression: fc.args[0].expression,
// sampler: Some(fc.args[1].expression),
// statements: fc
// .args
// .into_iter()
// .map(|a| a.statements)
// .flatten()
// .collect(),
// })
// }
// "texture" => {
// if fc.args.len() != 2 {
// return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
// }
// if let Some(sampler) = fc.args[0].sampler {
// Ok(ExpressionRule {
// expression: context.function.expressions.append(
// Expression::ImageSample {
// image: fc.args[0].expression,
// sampler,
// coordinate: fc.args[1].expression,
// array_index: None, //TODO
// offset: None, //TODO
// level: SampleLevel::Auto,
// depth_ref: None,
// },
// ),
// sampler: None,
// statements: fc
// .args
// .into_iter()
// .map(|a| a.statements)
// .flatten()
// .collect(),
// })
// } else {
// Err(ErrorKind::SemanticError("Bad call to texture".into()))
// }
// }
// "textureLod" => {
// if fc.args.len() != 3 {
// return Err(ErrorKind::WrongNumberArgs(name, 3, fc.args.len()));
// }
// if let Some(sampler) = fc.args[0].sampler {
// Ok(ExpressionRule {
// expression: context.function.expressions.append(
// Expression::ImageSample {
// image: fc.args[0].expression,
// sampler,
// coordinate: fc.args[1].expression,
// array_index: None, //TODO
// offset: None, //TODO
// level: SampleLevel::Exact(fc.args[2].expression),
// depth_ref: None,
// },
// ),
// sampler: None,
// statements: fc
// .args
// .into_iter()
// .map(|a| a.statements)
// .flatten()
// .collect(),
// })
// } else {
// Err(ErrorKind::SemanticError("Bad call to textureLod".into()))
// }
// }
// "ceil" | "round" | "floor" | "fract" | "trunc" | "sin" | "abs" | "sqrt"
// | "inversesqrt" | "exp" | "exp2" | "sign" | "transpose" | "inverse"
// | "normalize" => {
// if fc.args.len() != 1 {
// return Err(ErrorKind::WrongNumberArgs(name, 1, fc.args.len()));
// }
// Ok(ExpressionRule {
// expression: context.function.expressions.append(Expression::Math {
// fun: match name.as_str() {
// "ceil" => MathFunction::Ceil,
// "round" => MathFunction::Round,
// "floor" => MathFunction::Floor,
// "fract" => MathFunction::Fract,
// "trunc" => MathFunction::Trunc,
// "sin" => MathFunction::Sin,
// "abs" => MathFunction::Abs,
// "sqrt" => MathFunction::Sqrt,
// "inversesqrt" => MathFunction::InverseSqrt,
// "exp" => MathFunction::Exp,
// "exp2" => MathFunction::Exp2,
// "sign" => MathFunction::Sign,
// "transpose" => MathFunction::Transpose,
// "inverse" => MathFunction::Inverse,
// "normalize" => MathFunction::Normalize,
// _ => unreachable!(),
// },
// arg: fc.args[0].expression,
// arg1: None,
// arg2: None,
// }),
// sampler: None,
// statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
// })
// }
// "pow" | "dot" | "max" => {
// if fc.args.len() != 2 {
// return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
// }
// Ok(ExpressionRule {
// expression: context.function.expressions.append(Expression::Math {
// fun: match name.as_str() {
// "pow" => MathFunction::Pow,
// "dot" => MathFunction::Dot,
// "max" => MathFunction::Max,
// _ => unreachable!(),
// },
// arg: fc.args[0].expression,
// arg1: Some(fc.args[1].expression),
// arg2: None,
// }),
// sampler: None,
// statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
// })
// }
// "mix" | "clamp" => {
// if fc.args.len() != 3 {
// return Err(ErrorKind::WrongNumberArgs(name, 3, fc.args.len()));
// }
// Ok(ExpressionRule {
// expression: context.function.expressions.append(Expression::Math {
// fun: match name.as_str() {
// "mix" => MathFunction::Mix,
// "clamp" => MathFunction::Clamp,
// _ => unreachable!(),
// },
// arg: fc.args[0].expression,
// arg1: Some(fc.args[1].expression),
// arg2: Some(fc.args[2].expression),
// }),
// sampler: None,
// statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
// })
// }
// "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal"
// | "notEqual" => {
// if fc.args.len() != 2 {
// return Err(ErrorKind::WrongNumberArgs(name, 2, fc.args.len()));
// }
// Ok(ExpressionRule {
// expression: context.function.expressions.append(Expression::Binary {
// op: match name.as_str() {
// "lessThan" => BinaryOperator::Less,
// "greaterThan" => BinaryOperator::Greater,
// "lessThanEqual" => BinaryOperator::LessEqual,
// "greaterThanEqual" => BinaryOperator::GreaterEqual,
// "equal" => BinaryOperator::Equal,
// "notEqual" => BinaryOperator::NotEqual,
// _ => unreachable!(),
// },
// left: fc.args[0].expression,
// right: fc.args[1].expression,
// }),
// sampler: None,
// statements: fc.args.into_iter().flat_map(|a| a.statements).collect(),
// })
// }
// "isinf" => {
// self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsInf)
// }
// "isnan" => {
// self.parse_relational_fun(context, name, fc.args, RelationalFunction::IsNan)
// }
// "all" => {
// self.parse_relational_fun(context, name, fc.args, RelationalFunction::All)
// }
// "any" => {
// self.parse_relational_fun(context, name, fc.args, RelationalFunction::Any)
// }
// func_name => {
// let function = *self.lookup_function.get(func_name).ok_or_else(|| {
// ErrorKind::SemanticError(
// format!("Unknown function: {}", func_name).into(),
// )
// })?;
// let arguments: Vec<_> = fc.args.iter().map(|a| a.expression).collect();
// let mut statements: Vec<_> =
// fc.args.into_iter().flat_map(|a| a.statements).collect();
// let expression = context
// .function
// .expressions
// .append(Expression::Call(function));
// statements.push(crate::Statement::Call {
// function,
// arguments,
// result: Some(expression),
// });
// Ok(ExpressionRule {
// expression,
// sampler: None,
// statements,
// })
// }
// }
// }
// }
// }
pub fn parse_relational_fun(
&mut self,
@@ -314,47 +314,70 @@ impl Program<'_> {
})
}
pub fn add_function_prelude(&mut self, context: &mut FunctionContext) {
for (var_handle, var) in self.module.global_variables.iter() {
if let Some(name) = var.name.as_ref() {
let expr = context
.function
.expressions
.append(Expression::GlobalVariable(var_handle));
context.lookup_global_var_exps.insert(name.clone(), expr);
} else {
let ty = &self.module.types[var.ty];
// anonymous structs
if let TypeInner::Struct { ref members, .. } = ty.inner {
let base = context
.function
.expressions
.append(Expression::GlobalVariable(var_handle));
for (idx, member) in members.iter().enumerate() {
if let Some(name) = member.name.as_ref() {
let exp =
context
.function
.expressions
.append(Expression::AccessIndex {
base,
index: idx as u32,
});
context.lookup_global_var_exps.insert(name.clone(), exp);
}
}
}
}
}
// TODO: Reenable later
// pub fn add_function_prelude(&mut self, context: &mut FunctionContext) {
// for (var_handle, var) in self.module.global_variables.iter() {
// if let Some(name) = var.name.as_ref() {
// let expr = context
// .function
// .expressions
// .append(Expression::GlobalVariable(var_handle));
// context.lookup_global_var_exps.insert(name.clone(), expr);
// } else {
// let ty = &self.module.types[var.ty];
// // anonymous structs
// if let TypeInner::Struct { ref members, .. } = ty.inner {
// let base = context
// .function
// .expressions
// .append(Expression::GlobalVariable(var_handle));
// for (idx, member) in members.iter().enumerate() {
// if let Some(name) = member.name.as_ref() {
// let exp =
// context
// .function
// .expressions
// .append(Expression::AccessIndex {
// base,
// index: idx as u32,
// });
// context.lookup_global_var_exps.insert(name.clone(), exp);
// }
// }
// }
// }
// }
for (handle, constant) in self.module.constants.iter() {
if let Some(name) = constant.name.as_ref() {
let expr = context
.function
.expressions
.append(Expression::Constant(handle));
context.lookup_constant_exps.insert(name.clone(), expr);
}
// for (handle, constant) in self.module.constants.iter() {
// if let Some(name) = constant.name.as_ref() {
// let expr = context
// .function
// .expressions
// .append(Expression::Constant(handle));
// context.lookup_constant_exps.insert(name.clone(), expr);
// }
// }
// }
pub fn add_function(&mut self, mut function: Function) -> Result<(), ErrorKind> {
ensure_block_returns(&mut function.body);
let name = function
.name
.clone()
.ok_or_else(|| ErrorKind::SemanticError("Unnamed function".into()))?;
let stage = self.entry_points.get(&name);
if let Some(&stage) = stage {
self.module.entry_points.push(EntryPoint {
name,
stage,
early_depth_test: None,
workgroup_size: [0; 3], //TODO
function,
});
} else {
let handle = self.module.functions.append(function);
self.lookup_function.insert(name, handle);
}
Ok(())
}
}

View File

@@ -62,7 +62,7 @@ impl<'a> Iterator for Lexer<'a> {
}
TokenValue::Extension
}
PPTokenValue::Float(float) => TokenValue::FloatConstant(float.value),
PPTokenValue::Float(float) => TokenValue::FloatConstant(float),
PPTokenValue::Ident(ident) => {
match ident.as_str() {
"layout" => TokenValue::Layout,
@@ -103,8 +103,7 @@ impl<'a> Iterator for Lexer<'a> {
},
}
}
//TODO: unsigned etc
PPTokenValue::Integer(integer) => TokenValue::IntConstant(integer.value as i64),
PPTokenValue::Integer(integer) => TokenValue::IntConstant(integer),
PPTokenValue::Punct(punct) => match punct {
// Compound assignments
Punct::AddAssign => TokenValue::AddAssign,
@@ -179,6 +178,8 @@ impl<'a> Iterator for Lexer<'a> {
#[cfg(test)]
mod tests {
use pp_rs::token::Integer;
use super::{
super::token::{Token, TokenMetadata, TokenValue},
Lexer,
@@ -203,7 +204,11 @@ mod tests {
assert_eq!(
lex.next().unwrap(),
Token {
value: TokenValue::IntConstant(450),
value: TokenValue::IntConstant(Integer {
signed: true,
value: 450,
width: 32
}),
meta: TokenMetadata {
line: 1,
chars: 9..10 //TODO

View File

@@ -14,7 +14,7 @@ mod error;
pub use error::ParseError;
mod constants;
// TODO: Remove later
#[allow(dead_code)]
#[allow(dead_code, unused_imports)]
mod functions;
mod parser;
#[cfg(test)]

View File

@@ -1,16 +1,19 @@
use super::{
ast::{FunctionContext, Profile, StorageQualifier, StructLayout, TypeQualifier},
ast::{
Expr, ExprKind, FunctionContext, Profile, StorageQualifier, StructLayout, TypeQualifier,
},
error::ErrorKind,
lex::Lexer,
token::{Token, TokenMetadata, TokenValue},
Program,
};
use crate::{
arena::Handle, ArraySize, Binding, Function, FunctionResult, ResourceBinding, StorageClass,
Type, TypeInner,
arena::Handle, ArraySize, BinaryOperator, Binding, Constant, ConstantInner, Function,
FunctionResult, ResourceBinding, ScalarValue, Statement, StorageClass, Type, TypeInner,
UnaryOperator,
};
use core::convert::TryFrom;
use core::iter::Peekable;
use std::iter::Peekable;
type Result<T> = std::result::Result<T, ErrorKind>;
@@ -78,9 +81,9 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
let version = self.bump()?;
match version.value {
TokenValue::IntConstant(i) => match i {
440 | 450 | 460 => self.program.version = i as u16,
_ => return Err(ErrorKind::InvalidVersion(version.meta, i)),
TokenValue::IntConstant(i) => match i.value {
440 | 450 | 460 => self.program.version = i.value as u16,
_ => return Err(ErrorKind::InvalidVersion(version.meta, i.value)),
},
_ => return Err(ErrorKind::InvalidToken(version)),
}
@@ -288,7 +291,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
fn parse_constant_expression(&mut self) -> Result<i64> {
let token = self.bump()?;
match token.value {
TokenValue::IntConstant(value) => Ok(value),
TokenValue::IntConstant(int) => Ok(int.value as i64),
_ => Err(ErrorKind::InvalidToken(token)),
}
}
@@ -355,11 +358,11 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
let token = self.bump()?;
match token.value {
// Function prototypes
// TODO: Function prototypes
TokenValue::Semicolon => todo!(),
TokenValue::LeftBrace if external => {
// TODO: body
self.expect(TokenValue::RightBrace)?;
self.parse_compound_statement(&mut context)?;
self.program.add_function(function)?;
Ok(true)
}
@@ -392,6 +395,288 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
}
}
fn parse_primary(&mut self, ctx: &mut FunctionContext) -> Result<Expr> {
let token = self.bump()?;
let (width, value) = match token.value {
TokenValue::IntConstant(int) => (
(int.width / 8) as u8,
if int.signed {
ScalarValue::Sint(int.value as i64)
} else {
ScalarValue::Uint(int.value)
},
),
TokenValue::FloatConstant(float) => (
(float.width / 8) as u8,
ScalarValue::Float(float.value as f64),
),
TokenValue::BoolConstant(value) => (1, ScalarValue::Bool(value)),
TokenValue::LeftParen => {
let expr = self.parse_expression(ctx)?;
self.expect(TokenValue::RightParen)?;
return Ok(expr);
}
_ => return Err(ErrorKind::InvalidToken(token)),
};
let handle = self.program.module.constants.append(Constant {
name: None,
specialization: None,
inner: ConstantInner::Scalar { width, value },
});
Ok(Expr {
kind: ExprKind::Constant(handle),
meta: token.meta,
})
}
fn parse_postfix(&mut self, ctx: &mut FunctionContext) -> Result<Expr> {
let mut expr = match self.expect_peek()?.value {
TokenValue::Identifier(_) => {
let (name, meta) = self.expect_ident()?;
// TODO: function calls
// let mut args = Vec::new();
// while TokenValue::RightBracket != self.bump()?.value {
// args.push(self.parse_expression(ctx)?)
// }
let var = match self.program.lookup_variable(ctx, &name)? {
Some(var) => var,
None => return Err(ErrorKind::UnknownVariable(meta, name)),
};
Expr {
kind: ExprKind::Variable(var),
meta,
}
}
_ => self.parse_primary(ctx)?,
};
// TODO: postfix inc/dec
while let TokenValue::LeftBracket | TokenValue::Dot = self.expect_peek()?.value {
let Token { value, meta } = self.bump()?;
match value {
TokenValue::LeftBracket => {
let index = Box::new(self.parse_expression(ctx)?);
self.expect(TokenValue::RightBracket)?;
// TODO: metadata unification
expr = Expr {
kind: ExprKind::Access {
base: Box::new(expr),
index,
},
meta,
}
}
TokenValue::Dot => {
let field = self.expect_ident()?.0;
// TODO: metadata unification
expr = Expr {
kind: ExprKind::Select {
base: Box::new(expr),
field,
},
meta,
}
}
_ => unreachable!(),
}
}
Ok(expr)
}
fn parse_unary(&mut self, ctx: &mut FunctionContext) -> Result<Expr> {
// TODO: prefix inc/dec
match self.expect_peek()?.value {
TokenValue::Plus | TokenValue::Dash | TokenValue::Bang | TokenValue::Tilde => {
let Token { value, meta } = self.bump()?;
let expr = self.parse_unary(ctx)?;
let kind = match value {
TokenValue::Dash => ExprKind::Unary {
op: UnaryOperator::Negate,
expr: Box::new(expr),
},
TokenValue::Bang | TokenValue::Tilde => ExprKind::Unary {
op: UnaryOperator::Not,
expr: Box::new(expr),
},
_ => return Ok(expr),
};
// TODO: metadata unification
Ok(Expr { kind, meta })
}
_ => self.parse_postfix(ctx),
}
}
fn parse_binary(
&mut self,
ctx: &mut FunctionContext,
passtrough: Option<Expr>,
min_bp: u8,
) -> Result<Expr> {
let mut expr = passtrough
.ok_or(ErrorKind::EndOfFile /* Dummy error */)
.or_else(|_| self.parse_unary(ctx))?;
while let Some((l_bp, r_bp)) = binding_power(&self.expect_peek()?.value) {
if l_bp < min_bp {
break;
}
let Token { value, meta } = self.bump()?;
let right = Box::new(self.parse_binary(ctx, None, r_bp)?);
expr = Expr {
kind: ExprKind::Binary {
left: Box::new(expr),
op: match value {
TokenValue::LogicalOr => BinaryOperator::LogicalOr,
TokenValue::LogicalXor => BinaryOperator::NotEqual,
TokenValue::LogicalAnd => BinaryOperator::LogicalAnd,
TokenValue::VerticalBar => BinaryOperator::InclusiveOr,
TokenValue::Caret => BinaryOperator::ExclusiveOr,
TokenValue::Ampersand => BinaryOperator::And,
TokenValue::Equal => BinaryOperator::Equal,
TokenValue::NotEqual => BinaryOperator::NotEqual,
TokenValue::GreaterEqual => BinaryOperator::GreaterEqual,
TokenValue::LessEqual => BinaryOperator::LessEqual,
TokenValue::LeftAngle => BinaryOperator::Greater,
TokenValue::RightAngle => BinaryOperator::Less,
TokenValue::LeftShift => BinaryOperator::ShiftLeft,
TokenValue::RightShift => BinaryOperator::ShiftRight,
TokenValue::Plus => BinaryOperator::Add,
TokenValue::Dash => BinaryOperator::Subtract,
TokenValue::Star => BinaryOperator::Multiply,
TokenValue::Slash => BinaryOperator::Divide,
TokenValue::Percent => BinaryOperator::Modulo,
_ => unreachable!(),
},
right,
},
meta,
}
}
Ok(expr)
}
fn parse_conditional(
&mut self,
ctx: &mut FunctionContext,
passtrough: Option<Expr>,
) -> Result<Expr> {
let mut condition = self.parse_binary(ctx, passtrough, 0)?;
if let TokenValue::Question = self.expect_peek()?.value {
let meta = self.bump()?.meta;
let accept = Box::new(self.parse_expression(ctx)?);
self.expect(TokenValue::Colon)?;
let reject = Box::new(self.parse_assignment(ctx)?);
condition = Expr {
kind: ExprKind::Conditional {
condition: Box::new(condition),
accept,
reject,
},
meta,
};
}
Ok(condition)
}
fn parse_assignment(&mut self, ctx: &mut FunctionContext) -> Result<Expr> {
let pointer = self.parse_unary(ctx)?;
if let TokenValue::Assign = self.expect_peek()?.value {
let meta = self.bump()?.meta;
let value = Box::new(self.parse_assignment(ctx)?);
Ok(Expr {
kind: ExprKind::Assign {
tgt: Box::new(pointer),
value,
},
meta,
})
} else {
self.parse_conditional(ctx, Some(pointer))
}
}
fn parse_expression(&mut self, ctx: &mut FunctionContext) -> Result<Expr> {
let mut expr = self.parse_assignment(ctx)?;
while let TokenValue::Comma = self.expect_peek()?.value {
self.bump()?;
expr = self.parse_assignment(ctx)?;
}
Ok(expr)
}
fn parse_compound_statement(&mut self, ctx: &mut FunctionContext) -> Result<()> {
loop {
let token = self.bump()?;
match token.value {
TokenValue::Continue => {
ctx.function.body.push(Statement::Continue);
self.expect(TokenValue::Semicolon)?;
}
TokenValue::Break => {
ctx.function.body.push(Statement::Break);
self.expect(TokenValue::Semicolon)?;
}
TokenValue::Return => {
let value = match self.expect_peek()?.value {
TokenValue::Semicolon => {
self.bump()?;
None
}
_ => {
let expr = self.parse_expression(ctx)?;
self.expect(TokenValue::Semicolon)?;
Some(ctx.resolve(self.program, expr, false)?)
}
};
ctx.function.body.push(Statement::Return { value })
}
TokenValue::Discard => {
ctx.function.body.push(Statement::Kill);
self.expect(TokenValue::Semicolon)?;
}
TokenValue::LeftBrace => {
ctx.push_scope();
self.parse_compound_statement(ctx)?;
ctx.remove_current_scope();
}
TokenValue::RightBrace => break,
_ => {}
}
}
Ok(())
}
fn parse_function_args(&mut self, context: &mut FunctionContext) -> Result<()> {
loop {
// TODO: parameter qualifier
@@ -428,3 +713,23 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
Ok(())
}
}
fn binding_power(value: &TokenValue) -> Option<(u8, u8)> {
Some(match *value {
TokenValue::LogicalOr => (1, 2),
TokenValue::LogicalXor => (3, 4),
TokenValue::LogicalAnd => (5, 6),
TokenValue::VerticalBar => (7, 8),
TokenValue::Caret => (9, 10),
TokenValue::Ampersand => (11, 12),
TokenValue::Equal | TokenValue::NotEqual => (13, 14),
TokenValue::GreaterEqual
| TokenValue::LessEqual
| TokenValue::LeftAngle
| TokenValue::RightAngle => (15, 16),
TokenValue::LeftShift | TokenValue::RightShift => (17, 18),
TokenValue::Plus | TokenValue::Dash => (19, 20),
TokenValue::Star | TokenValue::Slash | TokenValue::Percent => (21, 22),
_ => return None,
})
}

View File

@@ -256,27 +256,27 @@ fn functions() {
)
.unwrap();
// parse_program(
// r#"
// # version 450
// float test(float a) { return a; }
parse_program(
r#"
# version 450
float test(float a) { return a; }
// void main() {}
// "#,
// &entry_points,
// )
// .unwrap();
void main() {}
"#,
&entry_points,
)
.unwrap();
// parse_program(
// r#"
// # version 450
// float test(vec4 p) {
// return p.x;
// }
// "#,
// &entry_points,
// )
// .unwrap();
parse_program(
r#"
# version 450
float test(vec4 p) {
return p.x;
}
"#,
&entry_points,
)
.unwrap();
}
#[test]

View File

@@ -1,5 +1,6 @@
pub use pp_rs::token::{Float, Integer, PreprocessorError};
use crate::{Interpolation, Sampling, Type};
use pp_rs::token::PreprocessorError;
use std::ops::Range;
#[derive(Debug, Clone)]
@@ -25,8 +26,8 @@ pub enum TokenValue {
Version,
Pragma,
FloatConstant(f32),
IntConstant(i64),
FloatConstant(Float),
IntConstant(Integer),
BoolConstant(bool),
Layout,

View File

@@ -9,118 +9,25 @@ impl Program<'_> {
&mut self,
context: &mut FunctionContext,
name: &str,
) -> Result<Option<Handle<Expression>>, ErrorKind> {
) -> Result<Option<VariableReference>, ErrorKind> {
if let Some(local_var) = context.lookup_local_var(name) {
return Ok(Some(local_var));
}
if let Some(global_var) = context.lookup_global_var_exps.get(name) {
return Ok(Some(*global_var));
return Ok(Some(global_var.clone()));
}
if let Some(constant) = context.lookup_constant_exps.get(name) {
return Ok(Some(*constant));
return Ok(Some(constant.clone()));
}
match name {
"gl_Position" => {
/*let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Output,
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
ty: self.module.types.fetch_or_append(Type {
name: None,
inner: TypeInner::Vector {
size: VectorSize::Quad,
kind: ScalarKind::Float,
width: 4,
},
}),
init: None,
interpolation: None,
storage_access: StorageAccess::empty(),
});
self.lookup_global_variables.insert(name.into(), h);
let exp = self
.context
.expressions
.append(Expression::GlobalVariable(h));*/
let exp = context
.function
.expressions
.append(Expression::FunctionArgument(0)); //TODO
context.lookup_global_var_exps.insert(name.into(), exp);
Ok(Some(exp))
todo!()
}
"gl_VertexIndex" => {
/* TODO
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,
binding: Some(Binding::BuiltIn(BuiltIn::VertexIndex)),
ty: self.module.types.fetch_or_append(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Uint,
width: 4,
},
}),
init: None,
interpolation: None,
storage_access: StorageAccess::empty(),
});
self.lookup_global_variables.insert(name.into(), h);
let mut expr = self
.context
.expressions
.append(Expression::GlobalVariable(h));
expr = self.context.expressions.append(Expression::As {
expr,
kind: ScalarKind::Sint,
convert: true,
});
*/
let expr = context
.function
.expressions
.append(Expression::FunctionArgument(0)); //TODO
context.lookup_global_var_exps.insert(name.into(), expr);
Ok(Some(expr))
todo!()
}
"gl_InstanceIndex" => {
/* TODO
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,
binding: Some(Binding::BuiltIn(BuiltIn::InstanceIndex)),
ty: self.module.types.fetch_or_append(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Uint,
width: 4,
},
}),
init: None,
interpolation: None,
storage_access: StorageAccess::empty(),
});
self.lookup_global_variables.insert(name.into(), h);
let mut expr = self
.context
.expressions
.append(Expression::GlobalVariable(h));
expr = self.context.expressions.append(Expression::As {
expr,
kind: ScalarKind::Sint,
convert: true,
});
*/
let expr = context
.function
.expressions
.append(Expression::FunctionArgument(0)); //TODO
context.lookup_global_var_exps.insert(name.into(), expr);
Ok(Some(expr))
todo!()
}
_ => Ok(None),
}