Initial work on the compiler

So far it only generates the metadata
pull/3/head
itycodes 3 weeks ago
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);
}

@ -1,5 +1,6 @@
use std::fmt::Write;
pub mod parser;
pub mod compiler;
fn main() {
let mut ops: Vec<(Option<String>, Vec<String>)> = Vec::new();

@ -11,7 +11,7 @@ pub enum Token {
Symbol(String),
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub enum Ast {
Symbol(String),
List(Vec<Ast>),

@ -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()),
]),

Loading…
Cancel
Save