forked from itycodes/shaderc
				
			
							parent
							
								
									da68ab6e73
								
							
						
					
					
						commit
						07dc4d62d9
					
				@ -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