mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[glsl-in] WIP expression parsing
This commit is contained in:
committed by
Dzmitry Malyshau
parent
3073ade8a4
commit
f8c8d192ae
@@ -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)]
|
||||
|
||||
@@ -8,7 +8,7 @@ pub enum ErrorKind {
|
||||
InvalidInput,
|
||||
InvalidProfile(TokenMetadata, String),
|
||||
InvalidToken(Token),
|
||||
InvalidVersion(TokenMetadata, i64),
|
||||
InvalidVersion(TokenMetadata, u64),
|
||||
IoError(io::Error),
|
||||
ParserFail,
|
||||
ParserStackOverflow,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user