Compare commits

..

No commits in common. 'f8d95a6891b36a14ad174a271acc97d53d912dbe' and 'db7be30a7a1248df9716f6407af718eaa347a430' have entirely different histories.

@ -1,7 +0,0 @@
A simplistic low-level compiler for a high-level shader bytecode.
##### Compiler backend, parser, bad prototype Rust:
*ity*
##### Compiler frontend (error reporting, validation...), fixing & cleaning up ity's bad Rust:
*Avery*

@ -1,12 +1,12 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::compiler::{ use crate::compiler::Module;
AddressingModel, ExecutionMode, ExecutionModel, MemoryModel, Module, StorageClass,
};
use std::fmt; use std::fmt;
use std::fmt::Write; use std::fmt::Write;
use super::StorageClass;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Type { pub enum Type {
Pointer(Box<Type>, StorageClass), Pointer(Box<Type>, StorageClass),
@ -14,13 +14,11 @@ pub enum Type {
Float(u32), Float(u32),
Int(u32), Int(u32),
Unsigned(u32), Unsigned(u32),
Void,
} }
impl fmt::Display for Type { impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Type::Void => write!(f, "<>"),
Type::Pointer(typ, storage_class) => match storage_class { Type::Pointer(typ, storage_class) => match storage_class {
StorageClass::Input => write!(f, "*{}i", typ), StorageClass::Input => write!(f, "*{}i", typ),
StorageClass::Output => write!(f, "*{}o", typ), StorageClass::Output => write!(f, "*{}o", typ),
@ -44,10 +42,6 @@ pub fn parse_type(typ: &String) -> Type {
let c = typ.chars().next().unwrap(); let c = typ.chars().next().unwrap();
match c { match c {
'<' => {
assert_eq!(typ.as_str(), "<>");
Type::Void
}
'*' => { '*' => {
let mut chars = typ.chars(); let mut chars = typ.chars();
chars.next(); chars.next();
@ -85,9 +79,6 @@ pub fn parse_type(typ: &String) -> Type {
fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) { fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
match &typ { match &typ {
Type::Void => {
ops.push(("%void".to_string(), "OpTypeVoid".to_string()));
}
Type::Unsigned(size) => { Type::Unsigned(size) => {
ops.push(( ops.push((
format!("%u{}", size).to_string(), format!("%u{}", size).to_string(),
@ -138,13 +129,7 @@ fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
} }
fn fix_name(name: &String) -> String { fn fix_name(name: &String) -> String {
format!( format!("%{}", name.clone().replace("-", "_").replace("*", "p"))
"%{}",
name.clone()
.replace("-", "_")
.replace("*", "p")
.replace("<>", "void")
)
} }
fn has_id(name: String, ops: &Vec<(Option<String>, Vec<String>)>) -> bool { fn has_id(name: String, ops: &Vec<(Option<String>, Vec<String>)>) -> bool {
@ -170,15 +155,15 @@ pub fn spirv_meta(module: Module) -> String {
} }
let memory_model_address = match module.memory_model.addressing_model { let memory_model_address = match module.memory_model.addressing_model {
AddressingModel::Logical => "Logical", crate::compiler::AddressingModel::Logical => "Logical",
AddressingModel::Physical32 => "Physical32", crate::compiler::AddressingModel::Physical32 => "Physical32",
AddressingModel::Physical64 => "Physical64", crate::compiler::AddressingModel::Physical64 => "Physical64",
AddressingModel::PhysicalStorageBuffer64 => "PhysicalStorageBuffer64", crate::compiler::AddressingModel::PhysicalStorageBuffer64 => "PhysicalStorageBuffer64",
}; };
let memory_model_model = match module.memory_model.memory_model { let memory_model_model = match module.memory_model.memory_model {
MemoryModel::Simple => "Simple", crate::compiler::MemoryModel::Simple => "Simple",
MemoryModel::GLSL450 => "GLSL450", crate::compiler::MemoryModel::GLSL450 => "GLSL450",
MemoryModel::OpenCL => "OpenCL", crate::compiler::MemoryModel::OpenCL => "OpenCL",
_ => todo!(), _ => todo!(),
}; };
ops.push(( ops.push((
@ -192,8 +177,8 @@ pub fn spirv_meta(module: Module) -> String {
for entry in module.entry_points { for entry in module.entry_points {
let exec_model = match entry.execution_model { let exec_model = match entry.execution_model {
ExecutionModel::Fragment => "Fragment", crate::compiler::ExecutionModel::Fragment => "Fragment",
ExecutionModel::Vertex => "Vertex", crate::compiler::ExecutionModel::Vertex => "Vertex",
}; };
let name = entry.name; let name = entry.name;
let interface: Vec<String> = entry let interface: Vec<String> = entry
@ -202,7 +187,7 @@ pub fn spirv_meta(module: Module) -> String {
.map(|i| fix_name(&i.to_string())) .map(|i| fix_name(&i.to_string()))
.collect(); .collect();
let exec_mode = match entry.execution_mode { let exec_mode = match entry.execution_mode {
ExecutionMode::OriginUpperLeft => "OriginUpperLeft", crate::compiler::ExecutionMode::OriginUpperLeft => "OriginUpperLeft",
}; };
ops.push(( ops.push((
None, None,
@ -226,14 +211,14 @@ pub fn spirv_meta(module: Module) -> String {
for global in module.globals { for global in module.globals {
let name = fix_name(&global.name); let name = fix_name(&global.name);
let typ = global.typ; let _typ = global.typ;
let storage_class = match global.storage_class { let storage_class = match global.storage_class {
StorageClass::Input => "Input", crate::compiler::StorageClass::Input => "Input",
StorageClass::Output => "Output", crate::compiler::StorageClass::Output => "Output",
StorageClass::Undefined => panic!("Bound a non-declared variable"), crate::compiler::StorageClass::Undefined => panic!("Bound a non-declared variable"),
}; };
let mut type_ops = Vec::new(); let mut type_ops = Vec::new();
emit_type(parse_type(&typ), &mut type_ops); emit_type(parse_type(&_typ), &mut type_ops);
for op in type_ops { for op in type_ops {
if has_id(op.0.clone(), &ops) { if has_id(op.0.clone(), &ops) {
continue; continue;
@ -244,7 +229,7 @@ pub fn spirv_meta(module: Module) -> String {
Some(name.clone()), Some(name.clone()),
vec![ vec![
"OpVariable".to_string(), "OpVariable".to_string(),
fix_name(&typ), fix_name(&_typ),
storage_class.to_string(), storage_class.to_string(),
], ],
)); ));
@ -263,24 +248,6 @@ pub fn spirv_meta(module: Module) -> String {
} }
} }
for fun in module.functions {
let name = fix_name(&fun.name);
let return_type = fix_name(&fun.return_type);
let mut type_ops = Vec::new();
emit_type(parse_type(&fun.return_type), &mut type_ops);
for op in type_ops {
if has_id(op.0.clone(), &ops) {
continue;
}
ops.push((Some(op.0), vec![op.1]));
}
// Push OpFunctionType
ops.push((
Some(name.clone()),
vec!["OpTypeFunction".to_string(), return_type.clone()],
));
}
for op in ops { for op in ops {
if op.0.is_some() { if op.0.is_some() {
write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap(); write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();

@ -11,7 +11,7 @@ fn test_emit() {
(dec frag-coord:*v4f32i Input) (dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output) (dec out-color:*v4f32o Output)
(entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
(fun (main) :<> (fun (main)
(store-ptr (out-color) (store-ptr (out-color)
(v4f32i (/ (.xy (load-ptr frag-coord)) (v4f32i (/ (.xy (load-ptr frag-coord))
(v2f32 1920.0 1080.0)) (v2f32 1920.0 1080.0))

@ -181,8 +181,6 @@ pub fn compile_fun<I: Iterator<Item = Ast>>(
let mut name_it = name.into_iter(); let mut name_it = name.into_iter();
let name = expect_symbol(name_it.next(), &name_loc)?; let name = expect_symbol(name_it.next(), &name_loc)?;
expect_empty(name_it, name_loc)?; expect_empty(name_it, name_loc)?;
let _return_type = expect_one_of(&[":<>"], expect_symbol(list.next(), &loc)?)?;
let return_type = _return_type.into_inner().replace(":", "");
let body = list.collect::<Vec<_>>(); let body = list.collect::<Vec<_>>();
let location = if let (Some(s), Some(e)) = ( let location = if let (Some(s), Some(e)) = (
body.first().map(|a| a.location()), body.first().map(|a| a.location()),
@ -194,7 +192,7 @@ pub fn compile_fun<I: Iterator<Item = Ast>>(
}; };
let fun = Function { let fun = Function {
name: name.to_string(), name: name.to_string(),
return_type: return_type, return_type: "void".to_string(),
arguments: vec![], arguments: vec![],
body: Some(vec![]), body: Some(vec![]),
ast: Some(Ast::List(Localised { ast: Some(Ast::List(Localised {

@ -14,7 +14,7 @@ fn test_compile() {
(dec frag-coord:*v4f32i Input) (dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output) (dec out-color:*v4f32o Output)
(entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
(fun (main) :<> (fun (main)
(store-ptr (out-color) (store-ptr (out-color)
(v4f32i (/ (.xy (load-ptr frag-coord)) (v4f32i (/ (.xy (load-ptr frag-coord))
(v2f32 1920.0 1080.0)) (v2f32 1920.0 1080.0))
@ -49,7 +49,7 @@ fn test_compile() {
], ],
functions: vec![Function { functions: vec![Function {
name: "main".to_string(), name: "main".to_string(),
return_type: "<>".to_string(), return_type: "void".to_string(),
arguments: vec![], arguments: vec![],
body: Some(vec![]), body: Some(vec![]),
ast: Some(Ast::List(Localised::dummy_location(vec![Ast::List( ast: Some(Ast::List(Localised::dummy_location(vec![Ast::List(
@ -107,7 +107,7 @@ fn expected_symbol() {
(dec frag-coord:*v4f32i Input) (dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output) (dec out-color:*v4f32o Output)
(entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
(fun (main) :<> (fun (main)
(store-ptr (out-color) (store-ptr (out-color)
(v4f32i (/ (.xy (load-ptr frag-coord)) (v4f32i (/ (.xy (load-ptr frag-coord))
(v2f32 1920.0 1080.0)) (v2f32 1920.0 1080.0))

@ -1,213 +0,0 @@
use std::fmt::{self, Display, Write};
use crate::{
compiler::CompilerError,
parser::{Location, ParseError},
};
pub fn print_error<E: FormattedLocatedError>(err: E, src: Option<&str>) {
let mut buf = String::new();
match src {
Some(src) => {
err.fmt_with_src(&mut buf, &src).unwrap();
}
None => err.fmt(&mut buf).unwrap(),
}
print!("{buf}");
}
pub trait FormattedLocatedError {
fn fmt<W: fmt::Write>(&self, w: &mut W) -> fmt::Result;
fn fmt_with_src<W: fmt::Write>(&self, w: &mut W, src: &str) -> fmt::Result;
}
impl Display for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Location::Char { line, col } => write!(f, "{line}:{col}"),
Location::String { lines, cols } => write!(f, "{}:{}", lines.start(), cols.start()),
Location::All => write!(f, "Entire file"),
}
}
}
impl FormattedLocatedError for ParseError {
fn fmt<W: fmt::Write>(&self, w: &mut W) -> fmt::Result {
match self {
ParseError::UnexpectedParenClose(location) => {
writeln!(w, "Unexpected closing paren at {location}")?
}
ParseError::UnexpectedEof => writeln!(w, "Unexpected end of file")?,
}
Ok(())
}
fn fmt_with_src<W: fmt::Write>(&self, w: &mut W, src: &str) -> fmt::Result {
match self {
ParseError::UnexpectedParenClose(location) => {
writeln!(w, "Unexpected closing paren at {location}")?;
here(location, src, Some("Unexpected ')'".to_string()), w)?;
}
ParseError::UnexpectedEof => writeln!(w, "Unexpected end of file")?,
}
Ok(())
}
}
impl FormattedLocatedError for CompilerError {
fn fmt<W: fmt::Write>(&self, w: &mut W) -> fmt::Result {
match self {
CompilerError::ExpectedSymbol(location) => {
writeln!(
w,
"Expected a symbol but got a list or nothing at {location}"
)
}
CompilerError::ExpectedList(location) => {
writeln!(
w,
"Expected a list but got a symbol or nothing at {location}"
)
}
CompilerError::UnknownKeyword(k, location) => {
writeln!(w, "Got unexpected keyword {k} at {location}")?;
writeln!(w, "Expected one of: module, import, bind, dec, entry, fun")
}
CompilerError::ExpectedOneOf(vec, k, location) => {
writeln!(w, "Got unexpected token {k} at {location}")?;
writeln!(w, "Expected one of: {}", vec.join(", "))
}
CompilerError::TrailingTokens(location) => {
writeln!(w, "Got unexpected trailing tokens at {location}")?;
writeln!(w, "Expected end of list")
}
CompilerError::UnknownBind(b, location) => {
writeln!(w, "Got unexpected keyword {b} at {location}")?;
writeln!(w, "Expected one of: BuiltIn, Location")
}
CompilerError::ExpectedType(location) => {
writeln!(w, "Expected name:type but got name at {location}")
}
}
}
fn fmt_with_src<W: fmt::Write>(&self, w: &mut W, src: &str) -> fmt::Result {
match self {
CompilerError::ExpectedSymbol(location) => {
writeln!(
w,
"Expected a symbol but got a list or nothing at {location}"
)?;
here(location, src, Some("Expected symbol".to_string()), w)
}
CompilerError::ExpectedList(location) => {
writeln!(
w,
"Expected a list but got a symbol or nothing at {location}"
)?;
here(location, src, Some("Expected List".to_string()), w)
}
CompilerError::UnknownKeyword(k, location) => {
writeln!(w, "Got unexpected keyword {k} at {location}")?;
writeln!(w, "Expected one of: module, import, bind, dec, entry, fun")?;
here(location, src, Some("Unexpected keyword".to_string()), w)
}
CompilerError::ExpectedOneOf(vec, k, location) => {
writeln!(w, "Got unexpected token {k} at {location}")?;
writeln!(w, "Expected one of: {}", vec.join(", "))?;
here(location, src, Some("Unexpected token".to_string()), w)
}
CompilerError::TrailingTokens(location) => {
writeln!(w, "Got unexpected trailing tokens at {location}")?;
writeln!(w, "Expected end of list")?;
here(location, src, Some("Unexpected token".to_string()), w)
}
CompilerError::UnknownBind(b, location) => {
writeln!(w, "Got unexpected keyword {b} at {location}")?;
writeln!(w, "Expected one of: BuiltIn, Location")?;
here(location, src, Some("Unexpected keyword".to_string()), w)
}
CompilerError::ExpectedType(location) => {
writeln!(w, "Expected name:type but got name at {location}")?;
here(location, src, None, w)
}
}
}
}
fn here<W: fmt::Write>(
loc: &Location,
src: &str,
comment: Option<String>,
w: &mut W,
) -> fmt::Result {
writeln!(w, "Here:")?;
writeln!(
w,
"{}",
annotate_src(&loc, src, comment.unwrap_or_default())
)?;
Ok(())
}
fn annotate_src(loc: &Location, src: &str, comment: String) -> String {
let src_lines = src.split('\n').collect::<Vec<_>>();
let mut buf = String::new();
match loc {
Location::Char { line, col } => {
writeln!(buf, "{}|{}", line_num(*line - 1), src_lines[*line - 2]).unwrap();
writeln!(buf, "{}|{}", line_num(*line), src_lines[*line - 1]).unwrap();
writeln!(buf, "{}|{}^ {}", " ", " ".repeat(col - 1), comment).unwrap();
writeln!(buf, "{}|{}", line_num(*line + 1), src_lines[*line]).unwrap();
}
Location::String { lines, cols } => {
writeln!(
buf,
"{}|{}",
line_num(*lines.start() - 1),
src_lines[*lines.start() - 2]
)
.unwrap();
writeln!(
buf,
"{}",
src_lines[(lines.start() - 1)..*lines.end()]
.iter()
.zip(lines.clone())
.map(|(l, n)| format!("{}|{}", line_num(n), l))
.collect::<Vec<_>>()
.join("\n")
)
.unwrap();
writeln!(
buf,
"{}|{}{} {}",
" ",
" ".repeat(cols.start() - 1),
"^".repeat(cols.end() - cols.start() + 1),
comment
)
.unwrap();
writeln!(
buf,
"{}|{}",
line_num(*lines.end() + 1),
src_lines[*lines.end()]
)
.unwrap();
}
Location::All => todo!(),
}
buf
}
fn line_num(num: usize) -> String {
let num = format!("{num}");
format!("{num}{}", " ".repeat(6 - num.len()))
}

@ -1,273 +1,115 @@
use compiler::{backend::spirv_meta, meta_compile}; use std::fmt::Write;
use error::print_error;
use std::{env, fs, path::PathBuf};
use parser::{parse_string, tokenize, Token};
pub mod compiler; pub mod compiler;
mod error;
pub mod parser; pub mod parser;
#[derive(Debug, Default, PartialEq)]
enum Trace {
Tokens,
AST,
#[default] Normal
}
#[derive(Debug, Default)]
struct CompilerArgs {
input: Option<PathBuf>,
output: Option<PathBuf>,
trace: Trace,
print_help: bool,
print_version: bool,
}
const SPIRV_VERSION: &'static str = "1.0";
fn main() { fn main() {
let args = parse_args(); let mut ops: Vec<(Option<String>, Vec<String>)> = Vec::new();
if args.print_version || args.print_help {
if args.print_help { // OpMemoryModel Logical GLSL450
print_help(); // OpEntryPoint Fragment %main "main"
} // OpExecutionMode %main OriginUpperLeft
if args.print_version { // OpSource GLSL 450
print_version(); // OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
} // OpSourceExtension "GL_GOOGLE_include_directive"
return; // OpName %main "main"
} //%void = OpTypeVoid
//%3 = OpTypeFunction %void
let Some(input) = args.input else { //%main = OpFunction %void None %3
eprintln!("No input specified"); //%5 = OpLabel
return; // OpReturn
}; // OpFunctionEnd
let output = args.output.unwrap_or(PathBuf::from("./out.spv")); ops.push((None, vec!["OpCapability".to_string(), "Shader".to_string()]));
ops.push((
let src = match fs::read_to_string(input) { Some("%1".to_string()),
Ok(i) => i, vec![
Err(e) => { "OpExtInstImport".to_string(),
eprintln!("{e}"); "\"GLSL.std.450\"".to_string(),
return; ],
} ));
}; ops.push((
if args.trace == Trace::Tokens { None,
let tokens = tokenize(&src); vec![
for tok in tokens { "OpMemoryModel".to_string(),
match tok.item { "Logical".to_string(),
Token::LeftParen => println!("{:>3}:{:<3} LeftParen",tok.location.line_start(), tok.location.col_start()), "GLSL450".to_string(),
Token::RightParen => println!("{:>3}:{:<3} RightParen",tok.location.line_start(), tok.location.col_start()), ],
Token::Symbol( val ) => println!("{:>3}:{:<3} Symbol `{}`",tok.location.line_start(), tok.location.col_start(), val) ));
} ops.push((
} None,
return; vec![
} "OpEntryPoint".to_string(),
"Fragment".to_string(),
let ast = match parse_string(&src) { "%main".to_string(),
Ok(i) => i, "\"main\"".to_string(),
Err(e) => { ],
print_error(e, Some(&src)); ));
return; ops.push((
} None,
}; vec![
"OpExecutionMode".to_string(),
if args.trace == Trace::AST { "%main".to_string(),
ast.pretty_print(None,None); "OriginUpperLeft".to_string(),
return; ],
} ));
ops.push((
let module = match meta_compile(ast) { None,
Ok(m) => m, vec![
Err(e) => { "OpSource".to_string(),
print_error(e, Some(&src)); "GLSL".to_string(),
return; "450".to_string(),
} ],
}; ));
ops.push((
let res = spirv_meta(module); None,
vec![
fs::write(output, res).unwrap(); "OpSourceExtension".to_string(),
} "\"GL_GOOGLE_cpp_style_line_directive\"".to_string(),
],
fn parse_args() -> CompilerArgs { ));
let mut args = env::args(); ops.push((
None,
let _prog = args.next().unwrap(); vec![
"OpSourceExtension".to_string(),
let mut parsed_args = CompilerArgs::default(); "\"GL_GOOGLE_include_directive\"".to_string(),
],
while let Some(arg) = args.next() { ));
if let Some(arg) = arg.strip_prefix("--") { ops.push((
match arg { None,
"help" => parsed_args.print_help = true, vec![
"version" => parsed_args.print_version = true, "OpName".to_string(),
"input" => { "%main".to_string(),
if parsed_args.input.is_none() { "\"main\"".to_string(),
let Some(input) = args.next() else { ],
eprintln!("input needs a file"); ));
eprintln!(); ops.push((Some("%void".to_string()), vec!["OpTypeVoid".to_string()]));
parsed_args.print_help = true; ops.push((
return parsed_args; Some("%3".to_string()),
}; vec!["OpTypeFunction".to_string(), "%void".to_string()],
));
parsed_args.input = Some(PathBuf::from(input)); ops.push((
} else { Some("%main".to_string()),
eprintln!("input can be passed only once"); vec![
eprintln!(); "OpFunction".to_string(),
parsed_args.print_help = true; "%void".to_string(),
return parsed_args; "None".to_string(),
} "%3".to_string(),
} ],
"output" => { ));
if parsed_args.output.is_none() { ops.push((Some("%5".to_string()), vec!["OpLabel".to_string()]));
let Some(output) = args.next() else { ops.push((None, vec!["OpReturn".to_string()]));
parsed_args.print_help = true; ops.push((None, vec!["OpFunctionEnd".to_string()]));
eprintln!("output needs a file");
eprintln!(); let mut out: String = String::new();
return parsed_args;
}; for op in ops {
if op.0.is_some() {
parsed_args.output = Some(PathBuf::from(output)); write!(out, "{} = ", op.0.unwrap()).unwrap();
} else {
eprintln!("output can be passed only once");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
"trace" => {
if parsed_args.trace == Trace::Normal {
let Some(output) = args.next() else {
parsed_args.print_help = true;
eprintln!("trace needs a file");
eprintln!();
return parsed_args;
};
match output.as_str() {
"ast" | "AST" | "Ast" => {
parsed_args.trace = Trace::AST;
}
"token" | "tokens" => {
parsed_args.trace = Trace::Tokens;
}
a => {
eprintln!("unknown trace value {a}");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
} else {
eprintln!("trace can be passed only once");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
a => {
eprintln!("unknown arg --{a}");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
continue;
} }
for arg in op.1 {
if let Some(arg) = arg.strip_prefix("-") { write!(out, "{} ", arg).unwrap();
let mut chars = arg.chars();
while let Some(arg) = chars.next() {
match arg {
'i' => {
if chars.next().is_some() {
parsed_args.print_help = true;
eprintln!("-i needs to be last in combined args");
return parsed_args;
}
if parsed_args.input.is_none() {
let Some(input) = args.next() else {
eprintln!("input needs a file");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
};
parsed_args.input = Some(PathBuf::from(input));
} else {
eprintln!("input can be passed only once");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
'o' => {
if chars.next().is_some() {
parsed_args.print_help = true;
eprintln!("-o needs to be last in combined args");
eprintln!();
return parsed_args;
}
if parsed_args.output.is_none() {
let Some(output) = args.next() else {
parsed_args.print_help = true;
eprintln!("output needs a file");
return parsed_args;
};
parsed_args.output = Some(PathBuf::from(output));
} else {
eprintln!("output can be passed only once");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
'h' => parsed_args.print_help = true,
'v' => parsed_args.print_version = true,
a => {
eprintln!("unknown arg -{a}");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
}
}
}
continue;
} }
writeln!(out).unwrap();
eprintln!("unknown arg {arg}");
eprintln!();
parsed_args.print_help = true;
return parsed_args;
} }
println!("{}", out);
parsed_args
}
fn print_help() {
println!("-- ShaderC shader compiler --");
println!();
println!("Arguments:");
println!("\t-i --input:");
println!("\t\tThe shader to be parsed and compiled, manadory argument");
println!();
println!("\t-o --output:");
println!("\t\tWhere to output the compiled spirv assembly to, default: out.spv");
println!();
println!("\t-h --help:");
println!("\t\tPrint this and exit");
println!("\t-v --version:");
println!("\t\tPrint the compilers version");
println!();
}
fn print_version() {
println!(
"ShaderC version: {}; SPIR-V version: {}",
env!("CARGO_PKG_VERSION"),
SPIRV_VERSION
)
} }

@ -155,31 +155,6 @@ impl Ast {
Ast::Root(_) => &Location::All, Ast::Root(_) => &Location::All,
} }
} }
pub fn pretty_print(&self, prefix: Option<&String>, body_prefix: Option<&String>) {
let empty_string_to_make_rust_happy = &String::from("");
let prefix_ = prefix.unwrap_or(&empty_string_to_make_rust_happy);
let body_prefix_ = body_prefix.unwrap_or(&empty_string_to_make_rust_happy);
match self {
Ast::Symbol(Localised { item, location }) => {
println!("{} Symbol `{}` ({}:{})", prefix_, item, location.line_start(), location.col_start());
},
Ast::List(Localised { item, location }) => {
println!("{} List ({}:{})", prefix_, location.line_start(), location.col_start());
for i in 0..item.len()-2 {
item[i].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ├─ "))), Some(&(body_prefix_.to_owned() + &String::from(" │ "))));
}
item[item.len()-1].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ╰─ "))), Some(&(body_prefix_.to_owned() + &String::from(" "))));
},
Ast::Root( items ) => {
println!("{} Root", prefix_);
for i in 0..items.len()-2 {
items[i].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ├─ "))), Some(&(body_prefix_.to_owned() + &String::from(" │ "))));
}
items[items.len()-1].pretty_print(Some(&(body_prefix_.to_owned() + &String::from(" ╰─ "))), Some(&(body_prefix_.to_owned() + &String::from(" "))));
},
}
}
} }
pub fn tokenize(input: &str) -> Vec<Localised<Token>> { pub fn tokenize(input: &str) -> Vec<Localised<Token>> {

@ -43,7 +43,7 @@ fn test_parse() {
(dec frag-coord:*v4f32i Input) (dec frag-coord:*v4f32i Input)
(dec out-color:*v4f32o Output) (dec out-color:*v4f32o Output)
(entry main Fragment OriginUpperLeft (:frag-coord :out-color)) (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
(fun (main) :<> (fun (main)
(store-ptr (out-color) (store-ptr (out-color)
(v4f32i (/ (.xy (load-ptr frag-coord)) (v4f32i (/ (.xy (load-ptr frag-coord))
(v2f32 1920.0 1080.0)) (v2f32 1920.0 1080.0))
@ -108,7 +108,6 @@ fn test_parse() {
Ast::List(Localised::dummy_location(vec![Ast::Symbol( Ast::List(Localised::dummy_location(vec![Ast::Symbol(
Localised::dummy_location("main".to_string()), Localised::dummy_location("main".to_string()),
)])), )])),
Ast::Symbol(Localised::dummy_location(":<>".to_string())),
Ast::List(Localised::dummy_location(vec![ Ast::List(Localised::dummy_location(vec![
Ast::Symbol(Localised::dummy_location("store-ptr".to_string())), Ast::Symbol(Localised::dummy_location("store-ptr".to_string())),
Ast::List(Localised::dummy_location(vec![Ast::Symbol( Ast::List(Localised::dummy_location(vec![Ast::Symbol(

@ -1,14 +0,0 @@
(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)
(decr 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)))

@ -1,12 +0,0 @@
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %frag_coord %out_color
OpExecutionMode %main OriginUpperLeft
%f32 = OpTypeFloat 32
%v4f32 = OpTypeVector %f32 4
%pv4f32i = OpTypePointer Input %v4f32
%frag_coord = OpVariable %pv4f32i Input
OpDecorate %frag_coord BuiltIn FragCoord
%pv4f32o = OpTypePointer Output %v4f32
%out_color = OpVariable %pv4f32o Output
OpDecorate %out_color Location 0
Loading…
Cancel
Save