commit 0902762066c716b86f0e65b34ac6eb70ef2abfca Author: itycodes Date: Thu Mar 6 09:14:16 2025 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..dd9815e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "shaderc" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a084462 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "shaderc" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..49c0ece --- /dev/null +++ b/src/main.rs @@ -0,0 +1,49 @@ +use std::fmt::Write; +pub mod parser; + +fn main() { + let mut ops: Vec<(Option, Vec)> = Vec::new(); + + // OpMemoryModel Logical GLSL450 + // OpEntryPoint Fragment %main "main" + // OpExecutionMode %main OriginUpperLeft + // OpSource GLSL 450 + // OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + // OpSourceExtension "GL_GOOGLE_include_directive" + // OpName %main "main" + //%void = OpTypeVoid + //%3 = OpTypeFunction %void + //%main = OpFunction %void None %3 + //%5 = OpLabel + // OpReturn + // OpFunctionEnd + + ops.push((None, vec!["OpCapability".to_string(), "Shader".to_string()])); + ops.push((Some("%1".to_string()), vec!["OpExtInstImport".to_string(), "\"GLSL.std.450\"".to_string()])); + ops.push((None, vec!["OpMemoryModel".to_string(), "Logical".to_string(), "GLSL450".to_string()])); + ops.push((None, vec!["OpEntryPoint".to_string(), "Fragment".to_string(), "%main".to_string(), "\"main\"".to_string()])); + ops.push((None, vec!["OpExecutionMode".to_string(), "%main".to_string(), "OriginUpperLeft".to_string()])); + ops.push((None, vec!["OpSource".to_string(), "GLSL".to_string(), "450".to_string()])); + ops.push((None, vec!["OpSourceExtension".to_string(), "\"GL_GOOGLE_cpp_style_line_directive\"".to_string()])); + ops.push((None, vec!["OpSourceExtension".to_string(), "\"GL_GOOGLE_include_directive\"".to_string()])); + ops.push((None, vec!["OpName".to_string(), "%main".to_string(), "\"main\"".to_string()])); + ops.push((Some("%void".to_string()), vec!["OpTypeVoid".to_string()])); + ops.push((Some("%3".to_string()), vec!["OpTypeFunction".to_string(), "%void".to_string()])); + ops.push((Some("%main".to_string()), vec!["OpFunction".to_string(), "%void".to_string(), "None".to_string(), "%3".to_string()])); + ops.push((Some("%5".to_string()), vec!["OpLabel".to_string()])); + ops.push((None, vec!["OpReturn".to_string()])); + ops.push((None, vec!["OpFunctionEnd".to_string()])); + + let mut out: String = String::new(); + + for op in ops { + if op.0.is_some() { + write!(out, "{} = ", op.0.unwrap()).unwrap(); + } + for arg in op.1 { + write!(out, "{} ", arg).unwrap(); + } + writeln!(out).unwrap(); + } + println!("{}", out); +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs new file mode 100644 index 0000000..c90444f --- /dev/null +++ b/src/parser/mod.rs @@ -0,0 +1,68 @@ +#[cfg(test)] +mod tests; + +use std::iter::Peekable; +use std::vec::IntoIter; + +#[derive(Debug, PartialEq)] +pub enum Token { + LeftParen, + RightParen, + Symbol(String), +} + +#[derive(Debug, PartialEq)] +pub enum Ast { + Symbol(String), + List(Vec), + Root(Vec), +} + +pub fn tokenize(input: &str) -> Vec { + let mut tokens = Vec::new(); + let mut chars = input.chars().peekable(); + while let Some(c) = chars.next() { + match c { + '(' => tokens.push(Token::LeftParen), + ')' => tokens.push(Token::RightParen), + _ if c.is_whitespace() => (), + _ => { + let mut symbol = c.to_string(); + while let Some(&c) = chars.peek() { + if c.is_whitespace() || c == '(' || c == ')' { + break; + } + symbol.push(c); + chars.next(); + } + tokens.push(Token::Symbol(symbol)); + } + } + } + tokens +} + +fn parse_expr(tokens: &mut Peekable>) -> Ast { + match tokens.next() { + Some(Token::LeftParen) => { + let mut list = Vec::new(); + while tokens.peek() != Some(&Token::RightParen) { + list.push(parse_expr(tokens)); + } + tokens.next(); + Ast::List(list) + } + Some(Token::RightParen) => panic!("unexpected )"), + Some(Token::Symbol(s)) => Ast::Symbol(s), + None => panic!("unexpected EOF"), + } +} + +pub fn parse(tokens: Vec) -> Ast { + let mut tokens = tokens.into_iter().peekable(); + let mut ast: Vec = Vec::new(); + while tokens.peek().is_some() { + ast.push(parse_expr(&mut tokens)); + } + Ast::Root(ast) +} \ No newline at end of file diff --git a/src/parser/tests.rs b/src/parser/tests.rs new file mode 100644 index 0000000..da40601 --- /dev/null +++ b/src/parser/tests.rs @@ -0,0 +1,125 @@ +use crate::parser::{tokenize, parse, Token, Ast}; + +#[test] +fn test_tokenize() { + let input = "(+ (* 1:u8 2) 2)"; + let expected = vec![ + Token::LeftParen, + Token::Symbol("+".to_string()), + Token::LeftParen, + Token::Symbol("*".to_string()), + Token::Symbol("1:u8".to_string()), + Token::Symbol("2".to_string()), + Token::RightParen, + Token::Symbol("2".to_string()), + Token::RightParen, + ]; + assert_eq!(tokenize(input), expected); +} + +#[test] +fn test_parse() { + let src = " +(module Shader Logical GLSL450) +(import :std GLSL.std.450) +(bind (frag-coord:*vec4fi) (Builtin FragCoord)) +(bind (out-color:*vec4fo) (Location 0)) +(dec frag-coord:*vec4fi Input) +(dec out-color:*vec4fo Output) +(entry main Fragment OriginUpperLeft (:frag-coord :out-color)) +(fun (main) + (store-ptr (out-color) + (vec4fi (/ (.xy (load-ptr frag-coord)) + (vec2f 1920.0 1080.0)) + 1.0 + 1.0))) +"; + let ast = parse(tokenize(src)); + println!("{:?}", ast); + let test_ast: Ast = Ast::Root(vec![ + Ast::List(vec![ + Ast::Symbol("module".to_string()), + Ast::Symbol("Shader".to_string()), + Ast::Symbol("Logical".to_string()), + Ast::Symbol("GLSL450".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("import".to_string()), + Ast::Symbol(":std".to_string()), + Ast::Symbol("GLSL.std.450".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("bind".to_string()), + Ast::List(vec![ + Ast::Symbol("frag-coord:*vec4fi".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("Builtin".to_string()), + Ast::Symbol("FragCoord".to_string()), + ]), + ]), + Ast::List(vec![ + Ast::Symbol("bind".to_string()), + Ast::List(vec![ + Ast::Symbol("out-color:*vec4fo".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("Location".to_string()), + Ast::Symbol("0".to_string()), + ]), + ]), + Ast::List(vec![ + Ast::Symbol("dec".to_string()), + Ast::Symbol("frag-coord:*vec4fi".to_string()), + Ast::Symbol("Input".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("dec".to_string()), + Ast::Symbol("out-color:*vec4fo".to_string()), + Ast::Symbol("Output".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("entry".to_string()), + Ast::Symbol("main".to_string()), + Ast::Symbol("Fragment".to_string()), + Ast::Symbol("OriginUpperLeft".to_string()), + Ast::List(vec![ + Ast::Symbol(":frag-coord".to_string()), + Ast::Symbol(":out-color".to_string()), + ]), + ]), + Ast::List(vec![ + Ast::Symbol("fun".to_string()), + Ast::List(vec![ + Ast::Symbol("main".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("store-ptr".to_string()), + Ast::List(vec![ + Ast::Symbol("out-color".to_string()), + ]), + Ast::List(vec![ + Ast::Symbol("vec4fi".to_string()), + Ast::List(vec![ + Ast::Symbol("/".to_string()), + Ast::List(vec![ + Ast::Symbol(".xy".to_string()), + Ast::List(vec![ + Ast::Symbol("load-ptr".to_string()), + Ast::Symbol("frag-coord".to_string()), + ]), + ]), + Ast::List(vec![ + Ast::Symbol("vec2f".to_string()), + Ast::Symbol("1920.0".to_string()), + Ast::Symbol("1080.0".to_string()), + ]), + ]), + Ast::Symbol("1.0".to_string()), + Ast::Symbol("1.0".to_string()), + ]), + ]), + ]), + ]); + assert_eq!(ast, test_ast); +} \ No newline at end of file