use crate::{ compiler::{ AddressingModel, Capability, EntryPoint, ExecutionMode, ExecutionModel, Memory, MemoryModel, expect_list, expect_one_of, expect_symbol, }, parser::{Ast, Localised, Location}, }; use super::{ BuiltinDecoration, CompilerError, Decoration, Function, GlobalVariable, Import, Module, StorageClass, expect_empty, expect_empty_ast, }; pub fn compile_module>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let _cap = expect_one_of(&["Shader"], expect_symbol(list.next(), &loc)?)?; let _exec = expect_one_of(&["Logical"], expect_symbol(list.next(), &loc)?)?; let _memory = expect_one_of(&["GLSL450"], expect_symbol(list.next(), &loc)?)?; module.memory_model = Memory { addressing_model: AddressingModel::Logical, memory_model: MemoryModel::GLSL450, }; module.capabilities.push(Capability::Shader); expect_empty_ast(list) } pub fn compile_import>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let name = expect_symbol(list.next(), &loc)?.into_inner(); let value = expect_symbol(list.next(), &loc)?.into_inner(); module.imports.push(Import { name, value }); expect_empty_ast(list) } pub fn compile_bind>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let Localised { location: name_and_type_loc, item: name_and_type, } = expect_list(list.next(), &loc)?; let name_and_type = name_and_type .into_iter() .map(|x| expect_symbol(Some(x), &name_and_type_loc).map(Localised::into_inner)) .collect::>()?; let mut name_and_type = name_and_type.split(':').map(|s| s.to_string()); // name_and_type is of the name:type format, like foo:f32 let name: String = name_and_type .next() .ok_or(CompilerError::ExpectedSymbol(name_and_type_loc.clone()))?; let typ: String = name_and_type .next() .ok_or(CompilerError::ExpectedType(name_and_type_loc.tail()))?; expect_empty(name_and_type, name_and_type_loc)?; let Localised { location: bind_loc, item: bind, } = expect_list(list.next(), &loc)?; let bind: Vec = bind .into_iter() .map(|x| expect_symbol(Some(x), &bind_loc).map(Localised::into_inner)) .collect::>()?; let bind_name = bind .get(0) .ok_or(CompilerError::ExpectedSymbol(bind_loc.clone()))?; let bind_name = match bind_name.as_str() { "BuiltIn" => Decoration::BuiltIn(BuiltinDecoration::FragCoord), "Location" => Decoration::Location(bind.get(1).unwrap().parse::().unwrap()), b => return Err(CompilerError::UnknownBind(b.to_string(), bind_loc)), }; let mut exists = false; for var in &module.globals { if var.name == name { exists = true; } } if !exists { module.globals.push(GlobalVariable { name, typ, storage_class: StorageClass::Undefined, decorations: vec![bind_name], }); } expect_empty_ast(list) } pub fn compile_dec>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let Localised { location: name_and_type_loc, item: name_and_type, } = expect_symbol(list.next(), &loc)?; let mut name_and_type = name_and_type.split(':').map(|s| s.to_string()); let name: String = name_and_type .next() .ok_or(CompilerError::ExpectedSymbol(name_and_type_loc.clone()))?; let typ: String = name_and_type .next() .ok_or(CompilerError::ExpectedType(name_and_type_loc.tail()))?; expect_empty(name_and_type, name_and_type_loc)?; let storage_class = expect_symbol(list.next(), &loc)?; let mut exists = false; for var in &module.globals { if var.name.as_str() == name.as_str() { exists = true; } } let storage_class = match storage_class.as_str() { "Input" => StorageClass::Input, "Output" => StorageClass::Output, _ => StorageClass::Undefined, }; if !exists { module.globals.push(GlobalVariable { name: name.to_string(), typ: typ.to_string(), storage_class: storage_class.clone(), decorations: vec![], }); } if exists { module .globals .iter_mut() .find(|x| x.name.as_str() == name.as_str()) .unwrap() .storage_class = storage_class.clone(); } expect_empty_ast(list) } pub fn compile_entry>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let name = expect_symbol(list.next(), &loc)?; let _exec_model = expect_one_of(&["Fragment"], expect_symbol(list.next(), &loc)?)?; let _exec_mode = expect_one_of(&["OriginUpperLeft"], expect_symbol(list.next(), &loc)?)?; let Localised { location: interface_loc, item: interface, } = expect_list(list.next(), &loc)?; let interface: Vec = interface .into_iter() .map(|x| expect_symbol(Some(x), &interface_loc).map(|s| s.into_inner().replace(":", ""))) .collect::>()?; module.entry_points.push(EntryPoint { execution_model: ExecutionModel::Fragment, execution_mode: ExecutionMode::OriginUpperLeft, name: name.to_string(), interface, }); expect_empty_ast(list) } pub fn compile_fun>( module: &mut Module, mut list: I, loc: Location, ) -> Result<(), CompilerError> { let Localised { location: name_loc, item: name, } = expect_list(list.next(), &loc)?; let mut name_it = name.into_iter(); let name = expect_symbol(name_it.next(), &name_loc)?; expect_empty(name_it, name_loc)?; let _return_type = expect_one_of(&[":<>"], expect_symbol(list.next(), &loc)?)?; let return_type = _return_type.into_inner().replace(":", ""); let body = list.collect::>(); let location = if let (Some(s), Some(e)) = ( body.first().map(|a| a.location()), body.last().map(|a| a.location()), ) { Location::range(s, e) } else { Location::Char { line: 0, col: 0 } }; let fun = Function { name: name.to_string(), return_type, arguments: vec![], body: Some(vec![]), ast: Some(Ast::List(Localised { location, item: body, })), }; module.functions.push(fun); Ok(()) }