#![feature(iter_next_chunk)] fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=instructions.in"); let mut generated = String::new(); gen_op_structs(&mut generated)?; std::fs::write("src/ops.rs", generated)?; let mut generated = String::new(); gen_op_codes(&mut generated)?; std::fs::write("src/opcode.rs", generated)?; Ok(()) } fn gen_op_structs(generated: &mut String) -> std::fmt::Result { use std::fmt::Write; let mut seen = std::collections::HashSet::new(); writeln!(generated, "use crate::*;")?; for [.., args, _] in instructions() { if !seen.insert(args) { continue; } writeln!(generated, "#[derive(Clone, Copy, Debug)]")?; writeln!(generated, "#[repr(packed)]")?; write!(generated, "pub struct Ops{args}(")?; let mut first = true; for ch in args.chars().filter(|&ch| ch != 'N') { if !std::mem::take(&mut first) { write!(generated, ",")?; } write!(generated, "pub Op{ch}")?; } writeln!(generated, ");")?; writeln!(generated, "unsafe impl BytecodeItem for Ops{args} {{}}")?; } Ok(()) } fn gen_op_codes(generated: &mut String) -> std::fmt::Result { use std::fmt::Write; for [op, name, _, comment] in instructions() { writeln!(generated, "#[doc = {comment}]")?; writeln!(generated, "pub const {name}: u8 = {op};")?; } Ok(()) } fn instructions() -> impl Iterator { include_str!("../hbbytecode/instructions.in") .lines() .map(|line| line.strip_suffix(';').unwrap()) .map(|line| line.splitn(4, ',').map(str::trim).next_chunk().unwrap()) }