cambridge_asm/exec/
error.rs1#![allow(clippy::module_name_repetitions)]
7
8use std::{
9 fmt::{Debug, Display, Formatter, Result as FmtResult},
10 ops::Deref,
11};
12use thiserror::Error;
13
14#[derive(Debug, Error)]
16pub enum RtError {
17 #[error("{0}")]
18 Other(String),
19 #[error("Unexpected I/O error, caused by: {0}")]
20 IoError(#[from] std::io::Error),
21 #[error("#x{0:X} is not a valid UTF-8 byte.")]
22 InvalidUtf8Byte(usize),
23 #[error("Operand is not a memory address, register, or literal")]
24 InvalidOperand,
25 #[error("No operand needed")]
26 NoOpInst,
27 #[error("Operand missing")]
28 NoOperand,
29 #[error("Invalid memory address `{0}`")]
30 InvalidAddr(usize),
31 #[error("Invalid indirect access address {redirect} at memory address {src}")]
32 InvalidIndirectAddr { src: usize, redirect: usize },
33 #[error("Invalid indexed access address `{}` from {src} + {offset}", .src +.offset)]
34 InvalidIndexedAddr { src: usize, offset: usize },
35 #[error("Invalid operand sequence")]
36 InvalidMultiOp,
37}
38
39impl From<&'static str> for RtError {
40 fn from(value: &'static str) -> Self {
41 Self::Other(value.to_string())
42 }
43}
44
45impl From<String> for RtError {
46 fn from(value: String) -> Self {
47 Self::Other(value)
48 }
49}
50
51pub type RtResult<T = ()> = Result<T, RtError>;
52
53#[derive(Debug, Default, Clone)]
55#[repr(transparent)]
56pub struct Source(Vec<String>);
57
58impl Source {
59 pub fn handle_err(
60 &self,
61 write: &mut impl std::io::Write,
62 err: &RtError,
63 pos: usize,
64 ) -> std::io::Result<()> {
65 writeln!(write, "Runtime Error:")?;
66 writeln!(write)?;
67
68 if self.0.is_empty() {
69 writeln!(write, "(source empty, error at position {pos})")?;
70 return writeln!(write, "message: {err}");
71 }
72
73 for (i, s) in self.0.iter().enumerate() {
74 if pos == i {
75 if let Some(prev) = self.0.get(i - 1) {
76 writeln!(write, "{num:>w$} {prev}", num = i, w = self.whitespace())?;
77 }
78
79 writeln!(
80 write,
81 "{num:>w$} {s} <-",
82 num = i + 1,
83 w = self.whitespace()
84 )?;
85
86 if let Some(next) = self.0.get(i + 1) {
87 writeln!(
88 write,
89 "{num:>w$} {next}",
90 num = i + 2,
91 w = self.whitespace()
92 )?;
93 }
94
95 writeln!(write)?;
96 writeln!(write, "message: {err}")?;
97 break;
98 }
99 }
100 writeln!(write)
101 }
102
103 fn whitespace(&self) -> usize {
104 self.0.len().to_string().len()
105 }
106}
107
108impl<T: Deref<Target = str>> From<T> for Source {
109 fn from(s: T) -> Self {
110 Source(
111 s.to_string()
112 .lines()
113 .filter(|&el| !el.starts_with("//"))
114 .map(String::from)
115 .collect(),
116 )
117 }
118}
119
120impl Display for Source {
121 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
122 for inst in &self.0 {
123 writeln!(f, " {inst}")?;
124 }
125
126 Ok(())
127 }
128}