use super::error::ErrorKind; use crate::{ proc::{ResolveContext, Typifier}, Arena, BinaryOperator, Binding, Expression, FastHashMap, Function, GlobalVariable, Handle, Interpolation, LocalVariable, Module, ShaderStage, Statement, StorageClass, Type, }; #[derive(Debug)] pub struct Program { pub version: u16, pub profile: Profile, pub shader_stage: ShaderStage, pub entry: Option, pub lookup_function: FastHashMap>, pub lookup_type: FastHashMap>, pub lookup_global_variables: FastHashMap>, pub context: Context, pub module: Module, } impl Program { pub fn new(shader_stage: ShaderStage, entry: &str) -> Program { Program { version: 0, profile: Profile::Core, shader_stage, entry: Some(entry.to_string()), lookup_function: FastHashMap::default(), lookup_type: FastHashMap::default(), lookup_global_variables: FastHashMap::default(), context: Context { expressions: Arena::::new(), local_variables: Arena::::new(), scopes: vec![FastHashMap::default()], lookup_global_var_exps: FastHashMap::default(), typifier: Typifier::new(), }, module: Module::generate_empty(), } } pub fn binary_expr( &mut self, op: BinaryOperator, left: &ExpressionRule, right: &ExpressionRule, ) -> ExpressionRule { ExpressionRule::from_expression(self.context.expressions.append(Expression::Binary { op, left: left.expression, right: right.expression, })) } pub fn resolve_type( &mut self, handle: Handle, ) -> Result<&crate::TypeInner, ErrorKind> { let functions = Arena::new(); //TODO let arguments = Vec::new(); //TODO let resolve_ctx = ResolveContext { constants: &self.module.constants, global_vars: &self.module.global_variables, local_vars: &self.context.local_variables, functions: &functions, arguments: &arguments, }; match self.context.typifier.grow( handle, &self.context.expressions, &mut self.module.types, &resolve_ctx, ) { //TODO: better error report Err(_) => Err(ErrorKind::SemanticError("Can't resolve type")), Ok(()) => Ok(self.context.typifier.get(handle, &self.module.types)), } } } #[derive(Debug)] pub enum Profile { Core, } #[derive(Debug)] pub struct Context { pub expressions: Arena, pub local_variables: Arena, //TODO: Find less allocation heavy representation pub scopes: Vec>>, pub lookup_global_var_exps: FastHashMap>, pub typifier: Typifier, } impl Context { 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); } } None } #[cfg(feature = "glsl-validate")] pub fn lookup_local_var_current_scope(&self, name: &str) -> Option> { if let Some(current) = self.scopes.last() { current.get(name).cloned() } else { None } } pub fn clear_scopes(&mut self) { self.scopes.clear(); self.scopes.push(FastHashMap::default()); } /// Add variable to current scope pub fn add_local_var(&mut self, name: String, handle: Handle) { if let Some(current) = self.scopes.last_mut() { (*current).insert(name, handle); } } /// Add new empty scope pub fn push_scope(&mut self) { self.scopes.push(FastHashMap::default()); } pub fn remove_current_scope(&mut self) { self.scopes.pop(); } } #[derive(Debug)] pub struct ExpressionRule { pub expression: Handle, pub statements: Vec, pub sampler: Option>, } impl ExpressionRule { pub fn from_expression(expression: Handle) -> ExpressionRule { ExpressionRule { expression, statements: vec![], sampler: None, } } } #[derive(Debug)] pub enum TypeQualifier { StorageClass(StorageClass), Binding(Binding), Interpolation(Interpolation), } #[derive(Debug)] pub struct VarDeclaration { pub type_qualifiers: Vec, pub ids_initializers: Vec<(Option, Option)>, pub ty: Handle, } #[derive(Debug)] pub enum FunctionCallKind { TypeConstructor(Handle), Function(String), } #[derive(Debug)] pub struct FunctionCall { pub kind: FunctionCallKind, pub args: Vec, }