forked from itycodes/shaderc
				
			
							parent
							
								
									e2bd50a3a1
								
							
						
					
					
						commit
						0916a1910d
					
				| @ -0,0 +1,297 @@ | ||||
| use crate::parser::Ast; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum Capability { | ||||
|     #[default] | ||||
|     Shader | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum ExecutionMode { | ||||
|     #[default] | ||||
|     OriginUpperLeft | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum ExecutionModel { | ||||
|     #[default] | ||||
|     Fragment | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct EntryPoint { | ||||
|     pub execution_model: ExecutionModel, | ||||
|     pub execution_mode: ExecutionMode, | ||||
|     pub name: String, | ||||
|     pub interface: Vec<String>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum AddressingModel { | ||||
|     #[default] | ||||
|     Logical, | ||||
|     Physical32, | ||||
|     Physical64, | ||||
|     PhysicalStorageBuffer64 | ||||
| } | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum MemoryModel { | ||||
|     #[default] | ||||
|     GLSL450, | ||||
|     OpenCL, | ||||
|     VulkanKHR, | ||||
|     Simple | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct Memory { | ||||
|     pub addressing_model: AddressingModel, | ||||
|     pub memory_model: MemoryModel, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum BuiltinDecoration { | ||||
|     #[default] | ||||
|     FragCoord, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| pub enum Decoration { | ||||
|     Builtin(BuiltinDecoration), | ||||
|     Location(u32), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub enum StorageClass { | ||||
|     #[default] | ||||
|     Undefined, | ||||
|     Input, | ||||
|     Output, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct GlobalVariable { | ||||
|     pub name: String, | ||||
|     pub typ: String, | ||||
|     pub storage_class: StorageClass, | ||||
|     pub decorations: Vec<Decoration>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct Instruction { | ||||
|     pub result_id: Option<String>, | ||||
|     pub op: String, | ||||
|     pub operands: Vec<String>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct Function { | ||||
|     pub name: String, | ||||
|     pub return_type: String, | ||||
|     pub arguments: Vec<String>, | ||||
|     pub body: Option<Vec<Instruction>>, | ||||
|     pub ast: Option<Ast>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct Import { | ||||
|     pub name: String, | ||||
|     pub value: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Default, Clone)] | ||||
| pub struct Module { | ||||
|     pub capabilities: Vec<Capability>, | ||||
|     pub entry_points: Vec<EntryPoint>, | ||||
|     pub globals: Vec<GlobalVariable>, | ||||
|     pub functions: Vec<Function>, | ||||
|     pub memory_model: Memory, | ||||
|     pub imports: Vec<Import>, | ||||
| } | ||||
| 
 | ||||
| pub fn meta_compile(ast: &mut Ast) -> Module { | ||||
|     let mut module: Module = Module::default(); | ||||
|     match ast { | ||||
|         Ast::Root(root) => { | ||||
|             for node in root { | ||||
|                 match node { | ||||
|                     Ast::List(list) => { | ||||
|                         let keyword = list[0].clone(); | ||||
|                         match keyword { | ||||
|                             Ast::Symbol(sym) => { | ||||
|                                 match sym.as_str() { | ||||
|                                     "module" => { | ||||
|                                         let cap = list[1].clone(); | ||||
|                                         let exec = list[2].clone(); | ||||
|                                         let memory = list[3].clone(); | ||||
|                                         module.memory_model = Memory { | ||||
|                                             addressing_model: AddressingModel::Logical, | ||||
|                                             memory_model: MemoryModel::GLSL450, | ||||
|                                         }; | ||||
|                                         module.capabilities.push(Capability::Shader); | ||||
|                                         assert_eq!(exec, Ast::Symbol("Logical".to_string())); | ||||
|                                         assert_eq!(memory, Ast::Symbol("GLSL450".to_string())); | ||||
|                                         assert_eq!(cap, Ast::Symbol("Shader".to_string())); | ||||
|                                     } | ||||
|                                     "import" => { | ||||
|                                         let name = match &list[1] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[1]), | ||||
|                                         }; | ||||
|                                         let value = match &list[2] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[2]), | ||||
|                                         }; | ||||
|                                         module.imports.push(Import { | ||||
|                                             name: name.to_string(), | ||||
|                                             value: value.to_string(), | ||||
|                                         }); | ||||
|                                     } | ||||
|                                     "bind" => { | ||||
|                                         let name_and_type = match &list[1] { | ||||
|                                             Ast::List(l) => l, | ||||
|                                             _ => panic!("Expected list! {:?}", list[1]), | ||||
|                                         }; | ||||
|                                         let name_and_type: String = name_and_type.iter().map(|x| { | ||||
|                                             match x { | ||||
|                                                 Ast::Symbol(s) => s.to_string(), | ||||
|                                                 _ => panic!("Expected symbol! {:?}", x), | ||||
|                                             } | ||||
|                                         }).collect(); | ||||
|                                         // name_and_type is of the name:type format, like foo:f32
 | ||||
|                                         let name: String = name_and_type.split(":").collect::<Vec<&str>>()[0].to_string(); | ||||
|                                         let typ: String = name_and_type.split(":").collect::<Vec<&str>>()[1].to_string(); | ||||
|                                         let bind = match &list[2] { | ||||
|                                             Ast::List(l) => l, | ||||
|                                             _ => panic!("Expected list! {:?}", list[2]), | ||||
|                                         }; | ||||
|                                         let bind: Vec<String> = bind.iter().map(|x| { | ||||
|                                             match x { | ||||
|                                                 Ast::Symbol(s) => s.to_string(), | ||||
|                                                 _ => panic!("Expected symbol! {:?}", x), | ||||
|                                             } | ||||
|                                         }).collect(); | ||||
|                                         let bind_name = match bind[0].as_str() { | ||||
|                                             "Builtin" => Decoration::Builtin(BuiltinDecoration::FragCoord), | ||||
|                                             "Location" => Decoration::Location(bind[1].parse::<u32>().unwrap()), | ||||
|                                             _ => panic!("Unknown bind! {:?}", bind), | ||||
|                                         }; | ||||
|                                         let mut exists = false; | ||||
|                                         for var in &module.globals { | ||||
|                                             if var.name == name { | ||||
|                                                 exists = true; | ||||
|                                             } | ||||
|                                         } | ||||
|                                         if !exists { | ||||
|                                             module.globals.push(GlobalVariable { | ||||
|                                                 name: name, | ||||
|                                                 typ: typ, | ||||
|                                                 storage_class: StorageClass::Undefined, | ||||
|                                                 decorations: vec![bind_name], | ||||
|                                             }); | ||||
|                                         } | ||||
|                                     } | ||||
|                                     "dec" => { | ||||
|                                         let name_and_type = match &list[1] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[1]), | ||||
|                                         }; | ||||
|                                         let name: String = name_and_type.split(":").collect::<Vec<&str>>()[0].to_string(); | ||||
|                                         let typ: String = name_and_type.split(":").collect::<Vec<&str>>()[1].to_string(); | ||||
|                                         let storage_class = match &list[2] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[2]), | ||||
|                                         }; | ||||
|                                         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(); | ||||
|                                         } | ||||
|                                     } | ||||
|                                     "entry" => { | ||||
|                                         let name = match &list[1] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[1]), | ||||
|                                         }; | ||||
|                                         let exec_model = match &list[2] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[2]), | ||||
|                                         }; | ||||
|                                         let exec_mode = match &list[3] { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", list[3]), | ||||
|                                         }; | ||||
|                                         let interface = match &list[4] { | ||||
|                                             Ast::List(l) => l, | ||||
|                                             _ => panic!("Expected list! {:?}", list[4]), | ||||
|                                         }; | ||||
|                                         let interface: Vec<String> = interface.iter().map(|x| { | ||||
|                                             match x { | ||||
|                                                 Ast::Symbol(s) => s.to_string(), | ||||
|                                                 _ => panic!("Expected symbol! {:?}", x), | ||||
|                                             } | ||||
|                                         }).collect(); | ||||
|                                         module.entry_points.push(EntryPoint { | ||||
|                                             execution_model: ExecutionModel::Fragment, | ||||
|                                             execution_mode: ExecutionMode::OriginUpperLeft, | ||||
|                                             name: name.to_string(), | ||||
|                                             interface: interface, | ||||
|                                         }); | ||||
|                                         assert_eq!(exec_model, "Fragment"); | ||||
|                                         assert_eq!(exec_mode, "OriginUpperLeft"); | ||||
|                                     } | ||||
|                                     "fun" => { | ||||
|                                         let name = match &list[1] { | ||||
|                                             Ast::List(l) => l[0].clone(), | ||||
|                                             _ => panic!("Expected list! {:?}", list[1]), | ||||
|                                         }; | ||||
|                                         let name = match name { | ||||
|                                             Ast::Symbol(s) => s, | ||||
|                                             _ => panic!("Expected symbol! {:?}", name), | ||||
|                                         }; | ||||
|                                         let body = list[2..].to_vec(); | ||||
|                                         let fun = Function { | ||||
|                                             name: name.to_string(), | ||||
|                                             return_type: "void".to_string(), | ||||
|                                             arguments: vec![], | ||||
|                                             body: Some(vec![]), | ||||
|                                             ast: Some(Ast::List(body)), | ||||
|                                         }; | ||||
|                                         module.functions.push(fun); | ||||
|                                     } | ||||
|                                     _ => panic!("Unknown keyword! {:?}", sym), | ||||
|                                 } | ||||
|                             } | ||||
|                             _ => panic!("List where a keyword was expected! {:?}", keyword), | ||||
|                         } | ||||
|                     } | ||||
|                     _ => panic!("Top-level symbol! {:?}", node), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         _ => panic!("Non-root ast") | ||||
|     } | ||||
|     module | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| use crate::parser::{tokenize, parse}; | ||||
| use crate::compiler::meta_compile; | ||||
| 
 | ||||
| #[test] | ||||
| fn test_compile() { | ||||
|     let src = " | ||||
| (module Shader Logical GLSL450) | ||||
| (import :std GLSL.std.450) | ||||
| (bind (frag-coord:*v4f32i) (Builtin FragCoord)) | ||||
| (bind (out-color:*v4f32o) (Location 0)) | ||||
| (dec frag-coord:*v4f32i Input) | ||||
| (dec out-color:*v4f32o Output) | ||||
| (entry main Fragment OriginUpperLeft (:frag-coord :out-color)) | ||||
| (fun (main) | ||||
|   (store-ptr (out-color) | ||||
|     (v4f32i (/ (.xy (load-ptr frag-coord)) | ||||
|                (v2f32 1920.0 1080.0)) 
 | ||||
|             1.0 
 | ||||
|             1.0))) | ||||
| "; | ||||
|     let mut ast = parse(tokenize(src)); | ||||
|     println!("{:?}", ast); | ||||
|     let module = meta_compile(&mut ast); | ||||
|     println!("{:?}", module); | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue