Mycelium/hyphae/build.rs
Ava Affine 4ad319213d HyphaeVM - WIP
This commit is a WORK IN PROGRESS for the base implementation of the
HyphaeVM. This will be squashed into a larger commit eventually when
the work of implementing the HyphaeVM is finished.

Of note, the ISA is mostly finished and much of the VM design is in
place. Yet to be done are a few traps in mycelium, migrating pieces
like the number package and the sexpr package into the VM package,
and of course much testing.

Signed-off-by: Ava Affine <ava@sunnypup.io>
2025-07-24 19:26:31 +00:00

109 lines
3.7 KiB
Rust

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<Instruction>,
}
// dont warn about unused fields in json instruction struct
#[allow(dead_code)]
#[derive(Deserialize)]
struct Instruction {
pub name: String,
pub args: Vec<String>,
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<u8> for Operation {\n".to_owned();
isa_from_byte += " type Error = &'static str;\n";
isa_from_byte += " fn try_from(v: u8) -> Result<Self, Self::Error> {\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<Self, Self::Err> {\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<Self, Self::Error> {\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<u8, &'static str> {\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");
}