riscv_interpreter/src/err.rs

99 lines
3.5 KiB
Rust

use std::{
cmp::Ordering,
fmt::{self, Display, Formatter},
};
use itertools::Itertools;
use crate::instructions::instruction;
#[derive(Debug, Clone)]
pub enum SyntaxErr {
/// false for '(' true for ')'
UnmatchedParen(bool),
UnexpectedChar,
OutsideOp(String),
InvalidRegister,
}
impl Display for SyntaxErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
SyntaxErr::UnmatchedParen(_) => write!(f, "unmatched parenthesis"),
SyntaxErr::UnexpectedChar => write!(f, "unexpected character"),
SyntaxErr::OutsideOp(kind) => write!(f, "'{kind}' before opcode"),
SyntaxErr::InvalidRegister => write!(f, "invalid register"),
}
}
}
impl SyntaxErr {
pub fn note(&self) -> String {
match self {
SyntaxErr::UnmatchedParen(false) => "add `)` after the register name".to_string(),
SyntaxErr::UnmatchedParen(true) => "add `(` before the register name".to_string(),
SyntaxErr::UnexpectedChar => "ensure the input is well-formed".to_string(),
SyntaxErr::OutsideOp(_) => format!("only add arguments after the opcode"),
SyntaxErr::InvalidRegister => {
"registers are either xN (N < 32 with no leading 0) or the standard aliases"
.to_string()
}
}
}
}
#[derive(Debug, Clone)]
pub enum RuntimeErr {
InvalidOp,
/// op, actual, expected
InvalidOpArity(String, usize, usize),
/// actual, expected
InvalidType(String, String),
LabelNotFound,
}
impl Display for RuntimeErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
RuntimeErr::InvalidOp => write!(f, "invalid opcode"),
RuntimeErr::InvalidOpArity(_, actual, expected) => {
write!(f, "expected {} args, got {}", expected, actual)
}
RuntimeErr::InvalidType(actual, expected) => {
write!(f, "expected '{}', got '{}'", expected, actual)
}
RuntimeErr::LabelNotFound => write!(f, "label not found"),
}
}
}
impl RuntimeErr {
pub fn note(&self) -> String {
match self {
RuntimeErr::InvalidOp => "check the ref sheet for the avaliable opcodes".to_string(),
RuntimeErr::InvalidOpArity(op, actual, expected) => {
let args = instruction(op).unwrap().1;
match actual.cmp(expected) {
Ordering::Equal => unreachable!(),
Ordering::Greater if actual - expected == 1 => {
"remove the extra argument".to_string()
}
Ordering::Greater => "remove the extra arguments".to_string(),
Ordering::Less if expected - actual == 1 => {
format!("add the extra '{}' argument", args.last().unwrap().kind())
}
Ordering::Less => format!(
"add the extra `{}` arguments",
args.get((actual - 1)..)
.unwrap()
.iter()
.map(|arg| arg.kind())
.join("', '")
),
}
}
RuntimeErr::InvalidType(_, _) => "ensure the operation is valid".to_string(),
RuntimeErr::LabelNotFound => "ensure the label is spelled correctly".to_string(),
}
}
}