diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs new file mode 100644 index 0000000..2bf5e06 --- /dev/null +++ b/src/compiler/mod.rs @@ -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, +} + +#[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, +} + +#[derive(Debug, PartialEq, Default, Clone)] +pub struct Instruction { + pub result_id: Option, + pub op: String, + pub operands: Vec, +} + +#[derive(Debug, PartialEq, Default, Clone)] +pub struct Function { + pub name: String, + pub return_type: String, + pub arguments: Vec, + pub body: Option>, + pub ast: Option, +} + +#[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, + pub entry_points: Vec, + pub globals: Vec, + pub functions: Vec, + pub memory_model: Memory, + pub imports: Vec, +} + +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::>()[0].to_string(); + let typ: String = name_and_type.split(":").collect::>()[1].to_string(); + let bind = match &list[2] { + Ast::List(l) => l, + _ => panic!("Expected list! {:?}", list[2]), + }; + let bind: Vec = 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::().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::>()[0].to_string(); + let typ: String = name_and_type.split(":").collect::>()[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 = 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 +} \ No newline at end of file diff --git a/src/compiler/tests.rs b/src/compiler/tests.rs new file mode 100644 index 0000000..c8012a1 --- /dev/null +++ b/src/compiler/tests.rs @@ -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); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 49c0ece..ebebce3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::fmt::Write; pub mod parser; +pub mod compiler; fn main() { let mut ops: Vec<(Option, Vec)> = Vec::new(); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c90444f..c56d16f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -11,7 +11,7 @@ pub enum Token { Symbol(String), } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum Ast { Symbol(String), List(Vec), diff --git a/src/parser/tests.rs b/src/parser/tests.rs index be5484b..6251515 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -22,15 +22,15 @@ fn test_parse() { let src = " (module Shader Logical GLSL450) (import :std GLSL.std.450) -(bind (frag-coord:*v4fi) (Builtin FragCoord)) -(bind (out-color:*v4fo) (Location 0)) -(dec frag-coord:*v4fi Input) -(dec out-color:*v4fo Output) +(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) - (v4fi (/ (.xy (load-ptr frag-coord)) - (v2f 1920.0 1080.0)) + (v4f32i (/ (.xy (load-ptr frag-coord)) + (v2f32 1920.0 1080.0)) 1.0 1.0))) "; @@ -51,7 +51,7 @@ fn test_parse() { Ast::List(vec![ Ast::Symbol("bind".to_string()), Ast::List(vec![ - Ast::Symbol("frag-coord:*v4fi".to_string()), + Ast::Symbol("frag-coord:*v4f32i".to_string()), ]), Ast::List(vec![ Ast::Symbol("Builtin".to_string()), @@ -61,7 +61,7 @@ fn test_parse() { Ast::List(vec![ Ast::Symbol("bind".to_string()), Ast::List(vec![ - Ast::Symbol("out-color:*v4fo".to_string()), + Ast::Symbol("out-color:*v4f32o".to_string()), ]), Ast::List(vec![ Ast::Symbol("Location".to_string()), @@ -70,12 +70,12 @@ fn test_parse() { ]), Ast::List(vec![ Ast::Symbol("dec".to_string()), - Ast::Symbol("frag-coord:*v4fi".to_string()), + Ast::Symbol("frag-coord:*v4f32i".to_string()), Ast::Symbol("Input".to_string()), ]), Ast::List(vec![ Ast::Symbol("dec".to_string()), - Ast::Symbol("out-color:*v4fo".to_string()), + Ast::Symbol("out-color:*v4f32o".to_string()), Ast::Symbol("Output".to_string()), ]), Ast::List(vec![ @@ -99,7 +99,7 @@ fn test_parse() { Ast::Symbol("out-color".to_string()), ]), Ast::List(vec![ - Ast::Symbol("v4fi".to_string()), + Ast::Symbol("v4f32i".to_string()), Ast::List(vec![ Ast::Symbol("/".to_string()), Ast::List(vec![ @@ -110,7 +110,7 @@ fn test_parse() { ]), ]), Ast::List(vec![ - Ast::Symbol("v2f".to_string()), + Ast::Symbol("v2f32".to_string()), Ast::Symbol("1920.0".to_string()), Ast::Symbol("1080.0".to_string()), ]),