You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
14 KiB
314 lines
14 KiB
use crate::parser::Ast;
|
|
|
|
pub mod backend;
|
|
|
|
use std::fmt;
|
|
|
|
#[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,
|
|
Vertex,
|
|
}
|
|
|
|
#[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,
|
|
}
|
|
|
|
impl fmt::Display for StorageClass {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
StorageClass::Undefined => write!(f, "Undefined"),
|
|
StorageClass::Input => write!(f, "Input"),
|
|
StorageClass::Output => write!(f, "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().replace(":", "")
|
|
},
|
|
_ => 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
|
|
} |