forked from AbleOS/holey-bytes
75 lines
2.1 KiB
Rust
75 lines
2.1 KiB
Rust
macro_rules! bail {
|
|
($kind:ident, $start:expr, $curr:expr, $offset:expr) => {
|
|
return Err(Error {
|
|
kind: ErrorKind::$kind,
|
|
index: ($curr.as_ptr() as usize) - ($start.as_ptr() as usize) + $offset,
|
|
})
|
|
};
|
|
($kind:ident, $start:expr, $curr:expr) => {
|
|
bail!($kind, $start, $curr, 0)
|
|
};
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum ErrorKind {
|
|
InvalidInstruction,
|
|
InvalidRegister,
|
|
Unimplemented,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub struct Error {
|
|
pub kind: ErrorKind,
|
|
pub index: usize,
|
|
}
|
|
|
|
pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
|
use hbbytecode::opcode::*;
|
|
|
|
#[inline]
|
|
fn reg(regs: &[u8]) -> Option<usize> {
|
|
regs.iter()
|
|
.enumerate()
|
|
.filter_map(|(n, &r)| (r > 59).then_some(n))
|
|
.next()
|
|
}
|
|
|
|
let start = program;
|
|
loop {
|
|
program = match program {
|
|
[] => return Ok(()),
|
|
// N
|
|
[NOP | RET | ECALL, rest @ ..] => rest,
|
|
// RRR
|
|
[ADD..=CMPU | ADDF..=DIVF, _, _, _, rest @ ..] => {
|
|
if let Some(n) = reg(&program[1..=3]) {
|
|
bail!(InvalidRegister, start, program, n + 1);
|
|
}
|
|
rest
|
|
}
|
|
// RR
|
|
[NOT | CP, _, _, rest @ ..] => {
|
|
if let Some(n) = reg(&program[1..=2]) {
|
|
bail!(InvalidRegister, start, program, n + 1);
|
|
}
|
|
rest
|
|
}
|
|
// RI
|
|
[LI | JMP, reg, _, _, _, _, _, _, _, _, rest @ ..] => {
|
|
if *reg > 59 {
|
|
bail!(InvalidRegister, start, program, 1);
|
|
}
|
|
rest
|
|
}
|
|
// RRI
|
|
[ADDI..=MULFI | LB..=SO | JEQ..=JGTU, _, _, _, _, _, _, _, _, _, _, rest @ ..] => {
|
|
if let Some(n) = reg(&program[1..=2]) {
|
|
bail!(InvalidRegister, start, program, n + 1);
|
|
}
|
|
rest
|
|
}
|
|
_ => bail!(InvalidInstruction, start, program),
|
|
}
|
|
}
|
|
}
|