use std::{env, fs}; use std::fs::File; use std::io::{BufWriter, Write}; use std::path::Path; use serde::Deserialize; #[derive(Deserialize)] struct Document { pub instructions: Vec, } // dont warn about unused fields in json instruction struct #[allow(dead_code)] #[derive(Deserialize)] struct Instruction { pub name: String, pub args: Vec, pub output: String, pub description: String, } fn main() { let output_path = Path::new(&env::var("OUT_DIR").unwrap()) .join("hyphae_instr.rs"); let input = fs::read_to_string("instructions.toml") .unwrap(); let mut output_file = BufWriter::new(File::create(&output_path).unwrap()); let instruction_table: Document = toml::from_str(&input) .expect("hyphae: failed to parse instructions.toml"); let mut isa = "#[repr(transparent)]\n".to_owned(); isa += "#[derive(Clone, Debug, PartialEq)]\n"; isa += "pub struct Operation(pub u8);\n\n"; let mut isa_from_byte = "impl TryFrom for Operation {\n".to_owned(); isa_from_byte += " type Error = &'static str;\n"; isa_from_byte += " fn try_from(v: u8) -> Result {\n"; isa_from_byte += " match v {\n"; let mut isa_fromstr = "impl FromStr for Operation {\n".to_owned(); isa_fromstr += " type Err = &'static str;\n"; isa_fromstr += " fn from_str(v: &str) -> Result {\n"; isa_fromstr += " match v {\n"; let mut isa_from_str = "impl TryFrom<&str> for Operation {\n".to_owned(); isa_from_str += " type Error = &'static str;\n"; isa_from_str += " fn try_from(v: &str) -> Result {\n"; isa_from_str += " match v {\n"; let mut isa_num_args = "impl Operation {\n".to_owned(); isa_num_args += " pub fn num_args(&self) -> Result {\n"; isa_num_args += " match self.0 {\n"; instruction_table.instructions.iter() .enumerate() .for_each(|(idx, instr)| { let const_name = instr.name.to_ascii_uppercase(); isa += format!("pub const {}: Operation = Operation({});\n", const_name, idx).as_str(); isa_from_byte += format!(" {} => Ok({}),\n", idx, const_name) .as_str(); isa_from_str += format!(" \"{}\" => Ok({}),\n", const_name, const_name).as_str(); isa_fromstr += format!(" \"{}\" => Ok({}),\n", const_name, const_name).as_str(); isa_num_args += format!(" {} => Ok({}),\n", idx, instr.args.len()) .as_str() }); isa_from_byte += " _ => Err(\"illegal instruction\"),\n"; isa_from_byte += " }\n"; isa_from_byte += " }\n"; isa_from_byte += "}\n\n"; isa_from_str += " _ => Err(\"illegal instruction\"),\n"; isa_from_str += " }\n"; isa_from_str += " }\n"; isa_from_str += "}\n\n"; isa_fromstr += " _ => Err(\"illegal instruction\"),\n"; isa_fromstr += " }\n"; isa_fromstr += " }\n"; isa_fromstr += "}\n\n"; isa_num_args += " _ => Err(\"illegal instruction\"),\n"; isa_num_args += " }\n"; isa_num_args += " }\n"; isa_num_args += "}\n\n"; isa += "\n"; isa += isa_from_byte.as_str(); isa += isa_from_str.as_str(); isa += isa_fromstr.as_str(); isa += isa_num_args.as_str(); write!(&mut output_file, "use core::str::FromStr;\n\n\n").unwrap(); write!(&mut output_file, "{}", isa).unwrap(); println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=instructions.json"); }