use thiserror::Error;
#[derive(Debug, Error)]
#[expect(
missing_docs,
reason = "error variants are documented via their #[error(...)] display strings"
)]
pub enum VerifierError {
#[error(
"jump at byte {offset:#06x} references undefined target label {label} \
(program has {target_count} targets)"
)]
UndefinedJumpTarget {
offset: usize,
label: u16,
target_count: usize,
},
#[error("loop instruction at byte {offset:#06x} executed outside any active loop")]
NoActiveLoop { offset: usize },
#[error(
"unmatched loop: RANGE/ITER at byte {offset:#06x} has no corresponding NEXT \
({depth} loop(s) still open at end of program)"
)]
UnmatchedLoop { offset: usize, depth: usize },
#[error("truncated instruction at byte {offset:#06x}")]
TruncatedInstruction { offset: usize },
#[error("unknown opcode {byte:#04x} at byte {offset:#06x}")]
BadOpcode { offset: usize, byte: u8 },
#[error("register r{reg} read at byte {offset:#06x} before being written")]
ReadUnsetRegister { offset: usize, reg: u8 },
#[error("register r{reg} at byte {offset:#06x}: expected {expected}, got {got}")]
RegisterTypeMismatch {
offset: usize,
reg: u8,
expected: &'static str,
got: &'static str,
},
#[error("stack underflow at byte {offset:#06x}")]
StackUnderflow { offset: usize },
#[error("potential stack overflow at byte {offset:#06x} (depth {depth})")]
StackOverflowRisk { offset: usize, depth: usize },
#[error(
"loop starting at byte {opener:#06x} has non-zero stack effect \
(entry depth {entry}, exit depth {exit})"
)]
LoopStackImbalance {
opener: usize,
entry: usize,
exit: usize,
},
#[error(
"stack depth mismatch at join point byte {target_offset:#06x}: \
one path has depth {depth_a}, another has depth {depth_b}"
)]
StackDepthMismatch {
target_offset: usize,
depth_a: usize,
depth_b: usize,
},
}
impl VerifierError {
pub fn variant_name(&self) -> &'static str {
match self {
Self::UndefinedJumpTarget { .. } => "UndefinedJumpTarget",
Self::NoActiveLoop { .. } => "NoActiveLoop",
Self::UnmatchedLoop { .. } => "UnmatchedLoop",
Self::TruncatedInstruction { .. } => "TruncatedInstruction",
Self::BadOpcode { .. } => "BadOpcode",
Self::ReadUnsetRegister { .. } => "ReadUnsetRegister",
Self::RegisterTypeMismatch { .. } => "RegisterTypeMismatch",
Self::StackUnderflow { .. } => "StackUnderflow",
Self::StackOverflowRisk { .. } => "StackOverflowRisk",
Self::LoopStackImbalance { .. } => "LoopStackImbalance",
Self::StackDepthMismatch { .. } => "StackDepthMismatch",
}
}
}