M src/compile/mod.rs +7 -0
@@ 662,6 662,13 @@ impl CContext {
}
*/
}
+
+ /// Returns the generated output instructions.
+ /// Consumes self.
+ pub fn output(self) -> Vec<u32> {
+ use rspirv::binary::Assemble;
+ self.b.module().assemble()
+ }
}
pub fn compile(ctx: &verify::VContext) -> Result<CContext, crate::Error> {
M src/lib.rs +48 -0
@@ 32,6 32,54 @@ impl From<rspirv::mr::Error> for Error {
}
}
+/// TODO: Parser.
+pub fn parse(input: &str) -> Vec<ast::Decl> {
+ use pest::Parser;
+ let parser = ChParser::parse(Rule::program, input).expect("Could not parse program!");
+ for pair in parser {
+ println!("Pair: {:?}", pair);
+ }
+ vec![]
+}
+
+/// Well, SPIR-V is defined to be a list of u32 words, but its byte order is undefined,
+/// and we need a slice of bytes to write to a file. So, this is just a convenient
+/// converter function that encodes it in little-endian format. Since in practice all
+/// systems that matter are little-endian anyway.
+///
+/// We COULD use unsafe to just cast the `&[u32]` to `&[u8]`, but that would be lame
+/// and platform-specific, so we do it RIGHT, copying the buffer in the process.
+/// Fite me.
+pub fn words_to_bytes_le(words: &[u32]) -> Vec<u8> {
+ /* Iterating over the [u8;4]'s is *problematic*,
+ all the solutions I can come up with borrow it first
+ when I want to move it. Oh well, we do it the dumb way.
+ */
+ /*
+ words
+ .iter()
+ .copied()
+ .flat_map(|word| word.to_le_bytes().into_iter())
+ .cloned()
+ .collect()
+ */
+ let mut res = Vec::with_capacity(words.len() * 4);
+ for word in words {
+ let bytes = word.to_le_bytes();
+ res.extend(&bytes[..]);
+ }
+ res
+}
+
+/// Top-level driver function that goes from a source string to
+/// SPIR-V output. Currently panics on error.
+pub fn compile(input: &str) -> Vec<u32> {
+ let ast = parse(input);
+ let ctx = verify::verify(ast).expect("Verification failed");
+ let cc = compile::compile(&ctx).expect("Compilation failed!");
+ cc.output()
+}
+
#[cfg(test)]
mod tests {
use super::*;
M src/main.rs +7 -1
@@ 1,3 1,4 @@
+use chrysanthemum as c;
use structopt::StructOpt;
use std::fs;
@@ 15,7 16,12 @@ struct Opt {
fn main() {
let opt = Opt::from_args();
- let contents = fs::read_to_string(opt.input).expect("Could not read input file");
+ let contents = fs::read_to_string(&opt.input).expect("Could not read input file");
+
+ let output = c::compile(&contents);
+ let output_bytes = c::words_to_bytes_le(&output);
+
let mut output_path = opt.input.clone();
output_path.set_extension("spv");
+ fs::write(output_path, output_bytes).expect("Could not write to output file");
}
M src/parser.pest +3 -1
@@ 1,4 1,6 @@
alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }
-ident = { (alpha | digit)+ }
No newline at end of file
+ident = { (alpha | digit)+ }
+
+program = { ident }
No newline at end of file