All checks were successful
per-push tests / build (push) Successful in 1m11s
per-push tests / test-frontend (push) Successful in 1m3s
per-push tests / test-utility (push) Successful in 1m3s
per-push tests / test-backend (push) Successful in 58s
per-push tests / timed-decomposer-parse (push) Successful in 1m3s
This commit extends the documentation held in instructions.toml into a full description of the hyphaeVM design and capabilities. Additionally, instructions.toml is renamed to vm.toml. Finally, the build script outputs a text file (hyphae_manual.txt) that provides a comprehensive manual on the use and effects of HyphaeVM. fixes: #37 Signed-off-by: Ava Affine <ava@sunnypup.io>
272 lines
10 KiB
Rust
272 lines
10 KiB
Rust
use std::{env, fs};
|
|
use std::fs::File;
|
|
use std::io::{BufWriter, Write};
|
|
use std::path::Path;
|
|
use serde::Deserialize;
|
|
|
|
const DOCUMENTATION_TITLE: &str = r"
|
|
▗▖ ▗▖▗▖ ▗▖▗▄▄▖ ▗▖ ▗▖ ▗▄▖ ▗▄▄▄▖ ▗▖ ▗▖▗▖ ▗▖
|
|
▐▌ ▐▌ ▝▚▞▘ ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ ▐▌▐▛▚▞▜▌
|
|
▐▛▀▜▌ ▐▌ ▐▛▀▘ ▐▛▀▜▌▐▛▀▜▌▐▛▀▀▘ ▐▌ ▐▌▐▌ ▐▌
|
|
▐▌ ▐▌ ▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌▐▙▄▄▖ ▝▚▞▘ ▐▌ ▐▌
|
|
";
|
|
|
|
const DOCUMENTATION_MODES: &str = r"
|
|
▗▄▖ ▗▄▄▄ ▗▄▄▄ ▗▄▄▖ ▗▄▄▄▖ ▗▄▄▖ ▗▄▄▖▗▄▄▄▖▗▖ ▗▖ ▗▄▄▖ ▗▖ ▗▖ ▗▄▖ ▗▄▄▄ ▗▄▄▄▖ ▗▄▄▖
|
|
▐▌ ▐▌▐▌ █▐▌ █▐▌ ▐▌▐▌ ▐▌ ▐▌ █ ▐▛▚▖▐▌▐▌ ▐▛▚▞▜▌▐▌ ▐▌▐▌ █▐▌ ▐▌
|
|
▐▛▀▜▌▐▌ █▐▌ █▐▛▀▚▖▐▛▀▀▘ ▝▀▚▖ ▝▀▚▖ █ ▐▌ ▝▜▌▐▌▝▜▌ ▐▌ ▐▌▐▌ ▐▌▐▌ █▐▛▀▀▘ ▝▀▚▖
|
|
▐▌ ▐▌▐▙▄▄▀▐▙▄▄▀▐▌ ▐▌▐▙▄▄▖▗▄▄▞▘▗▄▄▞▘▗▄█▄▖▐▌ ▐▌▝▚▄▞▘ ▐▌ ▐▌▝▚▄▞▘▐▙▄▄▀▐▙▄▄▖▗▄▄▞▘
|
|
";
|
|
|
|
const DOCUMENTATION_REGS: &str = r"
|
|
▗▄▄▖ ▗▄▄▄▖ ▗▄▄▖▗▄▄▄▖ ▗▄▄▖▗▄▄▄▖▗▄▄▄▖▗▄▄▖ ▗▄▄▖
|
|
▐▌ ▐▌▐▌ ▐▌ █ ▐▌ █ ▐▌ ▐▌ ▐▌▐▌
|
|
▐▛▀▚▖▐▛▀▀▘▐▌▝▜▌ █ ▝▀▚▖ █ ▐▛▀▀▘▐▛▀▚▖ ▝▀▚▖
|
|
▐▌ ▐▌▐▙▄▄▖▝▚▄▞▘▗▄█▄▖▗▄▄▞▘ █ ▐▙▄▄▖▐▌ ▐▌▗▄▄▞▘
|
|
";
|
|
|
|
const DOCUMENTATION_DTS: &str = r"
|
|
▗▄▄▄ ▗▄▖▗▄▄▄▖▗▄▖ ▗▄▄▄▖▗▖ ▗▖▗▄▄▖ ▗▄▄▄▖ ▗▄▄▖
|
|
▐▌ █▐▌ ▐▌ █ ▐▌ ▐▌ █ ▝▚▞▘ ▐▌ ▐▌▐▌ ▐▌
|
|
▐▌ █▐▛▀▜▌ █ ▐▛▀▜▌ █ ▐▌ ▐▛▀▘ ▐▛▀▀▘ ▝▀▚▖
|
|
▐▙▄▄▀▐▌ ▐▌ █ ▐▌ ▐▌ █ ▐▌ ▐▌ ▐▙▄▄▖▗▄▄▞▘
|
|
";
|
|
|
|
const DOCUMENTATION_INSTRS: &str = r"
|
|
▗▄▄▄▖▗▖ ▗▖ ▗▄▄▖▗▄▄▄▖▗▄▄▖ ▗▖ ▗▖ ▗▄▄▖▗▄▄▄▖▗▄▄▄▖ ▗▄▖ ▗▖ ▗▖ ▗▄▄▖
|
|
█ ▐▛▚▖▐▌▐▌ █ ▐▌ ▐▌▐▌ ▐▌▐▌ █ █ ▐▌ ▐▌▐▛▚▖▐▌▐▌
|
|
█ ▐▌ ▝▜▌ ▝▀▚▖ █ ▐▛▀▚▖▐▌ ▐▌▐▌ █ █ ▐▌ ▐▌▐▌ ▝▜▌ ▝▀▚▖
|
|
▗▄█▄▖▐▌ ▐▌▗▄▄▞▘ █ ▐▌ ▐▌▝▚▄▞▘▝▚▄▄▖ █ ▗▄█▄▖▝▚▄▞▘▐▌ ▐▌▗▄▄▞▘
|
|
";
|
|
|
|
#[derive(Deserialize)]
|
|
struct Document {
|
|
pub description: String,
|
|
pub datum: String,
|
|
pub error_handling: String,
|
|
pub sym_table: String,
|
|
pub traps: String,
|
|
pub registers: Vec<Description>,
|
|
pub data_types: Vec<Description>,
|
|
pub instructions: Vec<Instruction>,
|
|
pub addressing_modes: Vec<AddressingMode>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct Description {
|
|
pub name: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct AddressingMode {
|
|
pub name: String,
|
|
pub mutable: bool,
|
|
pub symbol: String,
|
|
pub example: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct Instruction {
|
|
pub name: String,
|
|
pub args: Vec<String>,
|
|
pub output: String,
|
|
pub description: String,
|
|
}
|
|
|
|
fn main() {
|
|
let mut peak = 0;
|
|
let output_path = Path::new(&env::var("OUT_DIR").unwrap())
|
|
.join("hyphae_instr.rs");
|
|
let doc_path = Path::new(&env::var("OUT_DIR").unwrap())
|
|
.join("hyphae_manual.txt");
|
|
let input = fs::read_to_string("vm.toml")
|
|
.unwrap();
|
|
let mut output_file =
|
|
BufWriter::new(File::create(&output_path).unwrap());
|
|
let mut manual_file =
|
|
BufWriter::new(File::create(&doc_path).unwrap());
|
|
|
|
let doc: 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";
|
|
|
|
doc.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();
|
|
|
|
peak = idx + 1;
|
|
});
|
|
|
|
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();
|
|
write!(&mut output_file, "\n\npub const TOTAL_INSTRUCTIONS: usize = {};", peak)
|
|
.unwrap();
|
|
|
|
let separator = "----------------------------\n";
|
|
let section_end = "\n\n\n";
|
|
let mut documentation = String::from("");
|
|
|
|
documentation += DOCUMENTATION_TITLE;
|
|
documentation += separator;
|
|
documentation += &doc.description;
|
|
documentation += section_end;
|
|
|
|
documentation += "Datum\n";
|
|
documentation += separator;
|
|
documentation += &doc.datum;
|
|
documentation += section_end;
|
|
|
|
documentation += "Error Handling\n";
|
|
documentation += separator;
|
|
documentation += &doc.error_handling;
|
|
documentation += section_end;
|
|
|
|
documentation += "Symbol Table\n";
|
|
documentation += separator;
|
|
documentation += &doc.sym_table;
|
|
documentation += section_end;
|
|
|
|
documentation += "Traps\n";
|
|
documentation += separator;
|
|
documentation += &doc.traps;
|
|
documentation += section_end;
|
|
|
|
documentation += DOCUMENTATION_MODES;
|
|
documentation += "\n\n";
|
|
doc.addressing_modes.iter()
|
|
.for_each(|i| {
|
|
documentation += &i.name;
|
|
documentation += "\n";
|
|
documentation += separator;
|
|
if i.mutable {
|
|
documentation += "Provides mutable access.\n\n";
|
|
}
|
|
documentation += "symbol: ";
|
|
documentation += &i.symbol;
|
|
documentation += "\nexample: ";
|
|
documentation += &i.example;
|
|
documentation += "\n\n";
|
|
documentation += &i.description;
|
|
documentation += section_end;
|
|
});
|
|
documentation += "\n";
|
|
|
|
documentation += DOCUMENTATION_DTS;
|
|
documentation += "\n\n";
|
|
doc.data_types.iter()
|
|
.for_each(|i| {
|
|
documentation += "> ";
|
|
documentation += &i.name;
|
|
documentation += "\n";
|
|
documentation += &i.description;
|
|
documentation += section_end;
|
|
});
|
|
|
|
documentation += DOCUMENTATION_REGS;
|
|
documentation += "\n\n";
|
|
doc.registers.iter()
|
|
.for_each(|i| {
|
|
documentation += "> ";
|
|
documentation += &i.name;
|
|
documentation += "\n";
|
|
documentation += &i.description;
|
|
documentation += section_end;
|
|
});
|
|
|
|
documentation += DOCUMENTATION_INSTRS;
|
|
documentation += "\n\n";
|
|
doc.instructions.iter()
|
|
.for_each(|i| {
|
|
documentation += &i.name;
|
|
documentation += "\n";
|
|
documentation += separator;
|
|
documentation += "Arguments:";
|
|
i.args.iter().for_each(|j| {
|
|
documentation += " ";
|
|
documentation += j;
|
|
});
|
|
documentation += "\n";
|
|
documentation += "Sets expression register to: ";
|
|
documentation += if !i.output.is_empty() {
|
|
&i.output
|
|
} else {
|
|
"<doesn't write expression register>"
|
|
};
|
|
documentation += "\n\n";
|
|
documentation += &i.description;
|
|
documentation += section_end;
|
|
});
|
|
|
|
write!(manual_file, "{}", documentation).unwrap();
|
|
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
println!("cargo::rerun-if-changed=vm.toml");
|
|
}
|