From f8c8d192aefa8f720bb97eced0915c32b27fa806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Capucho?= Date: Sun, 2 May 2021 22:17:01 +0100 Subject: [PATCH] [glsl-in] WIP expression parsing --- src/front/glsl/ast.rs | 152 +++++++- src/front/glsl/error.rs | 2 +- src/front/glsl/functions.rs | 671 +++++++++++++++++---------------- src/front/glsl/lex.rs | 13 +- src/front/glsl/mod.rs | 2 +- src/front/glsl/parser.rs | 327 +++++++++++++++- src/front/glsl/parser_tests.rs | 38 +- src/front/glsl/token.rs | 7 +- src/front/glsl/variables.rs | 105 +----- 9 files changed, 842 insertions(+), 475 deletions(-) diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 88f002d770..08c265d311 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -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>>, - pub lookup_global_var_exps: FastHashMap>, - pub lookup_constant_exps: FastHashMap>, + pub scopes: Vec>, + pub lookup_global_var_exps: FastHashMap, + pub lookup_constant_exps: FastHashMap, pub typifier: Typifier, } @@ -217,17 +217,17 @@ impl<'function> FunctionContext<'function> { } } - pub fn lookup_local_var(&self, name: &str) -> Option> { + pub fn lookup_local_var(&self, name: &str) -> Option { 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> { + pub fn lookup_local_var_current_scope(&self, name: &str) -> Option { 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) { + pub fn add_local_var(&mut self, name: String, expr: Handle) { 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, 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, + pub load: Option>, +} + +#[derive(Debug)] +pub struct Expr { + pub kind: ExprKind, + pub meta: TokenMetadata, +} + +#[derive(Debug)] +pub enum ExprKind { + Access { + base: Box, + index: Box, + }, + Select { + base: Box, + field: String, + }, + Constant(Handle), + Binary { + left: Box, + op: BinaryOperator, + right: Box, + }, + Unary { + op: UnaryOperator, + expr: Box, + }, + Variable(VariableReference), + Call(FunctionCall), + Conditional { + condition: Box, + accept: Box, + reject: Box, + }, + Assign { + tgt: Box, + value: Box, + }, +} + #[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, + pub args: Vec, } #[derive(Debug, Clone, Copy)] diff --git a/src/front/glsl/error.rs b/src/front/glsl/error.rs index 154556d317..dd5e0b4c41 100644 --- a/src/front/glsl/error.rs +++ b/src/front/glsl/error.rs @@ -8,7 +8,7 @@ pub enum ErrorKind { InvalidInput, InvalidProfile(TokenMetadata, String), InvalidToken(Token), - InvalidVersion(TokenMetadata, i64), + InvalidVersion(TokenMetadata, u64), IoError(io::Error), ParserFail, ParserStackOverflow, diff --git a/src/front/glsl/functions.rs b/src/front/glsl/functions.rs index c1599e5898..bc0cc33676 100644 --- a/src/front/glsl/functions.rs +++ b/src/front/glsl/functions.rs @@ -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 { - 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 { + // 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(()) } } diff --git a/src/front/glsl/lex.rs b/src/front/glsl/lex.rs index 84e73df488..a07cc4af28 100644 --- a/src/front/glsl/lex.rs +++ b/src/front/glsl/lex.rs @@ -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 diff --git a/src/front/glsl/mod.rs b/src/front/glsl/mod.rs index 7a17300cff..17b8a57845 100644 --- a/src/front/glsl/mod.rs +++ b/src/front/glsl/mod.rs @@ -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)] diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 2e587fe55b..0cc769ccd5 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -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 = std::result::Result; @@ -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 { 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 { + 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 { + 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 { + // 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, + min_bp: u8, + ) -> Result { + 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, + ) -> Result { + 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 { + 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 { + 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, + }) +} diff --git a/src/front/glsl/parser_tests.rs b/src/front/glsl/parser_tests.rs index 42ee511a67..b02324c047 100644 --- a/src/front/glsl/parser_tests.rs +++ b/src/front/glsl/parser_tests.rs @@ -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] diff --git a/src/front/glsl/token.rs b/src/front/glsl/token.rs index bc53d61f3b..e17ba7d5cc 100644 --- a/src/front/glsl/token.rs +++ b/src/front/glsl/token.rs @@ -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, diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index db4755906b..b7d32f4dec 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -9,118 +9,25 @@ impl Program<'_> { &mut self, context: &mut FunctionContext, name: &str, - ) -> Result>, ErrorKind> { + ) -> Result, 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), }