aranya_policy_vm/
error.rs1extern crate alloc;
2
3use alloc::{borrow::ToOwned as _, string::String};
4use core::{convert::Infallible, fmt};
5
6use aranya_policy_ast::Identifier;
7use aranya_policy_module::{CodeMap, Label, ValueConversionError};
8use buggy::Bug;
9
10use crate::io::MachineIOError;
11
12#[derive(Debug, PartialEq, Eq, thiserror::Error)]
16pub enum MachineErrorType {
17 #[error("stack underflow")]
20 StackUnderflow,
21 #[error("stack overflow")]
24 StackOverflow,
25 #[error("name `{0}` already defined")]
28 AlreadyDefined(Identifier),
29 #[error("name `{0}` not defined")]
32 NotDefined(String),
33 #[error("expected type {want}, but got {got}: {msg}")]
36 InvalidType {
37 want: String,
39 got: String,
41 msg: String,
43 },
44 #[error("invalid struct member `{0}`")]
47 InvalidStructMember(Identifier),
48 #[error("invalid fact: {0}")]
51 InvalidFact(Identifier),
52 #[error("invalid schema: {0}")]
55 InvalidSchema(Identifier),
56 #[error("unresolved branch/jump target: {0}")]
59 UnresolvedTarget(Label),
60 #[error("invalid address: {0}")]
64 InvalidAddress(Identifier),
65 #[error("bad state: {0}")]
68 BadState(&'static str),
69 #[error("integer wrap")]
72 IntegerOverflow,
73 #[error("invalid instruction")]
77 InvalidInstruction,
78 #[error("call stack")]
81 CallStack,
82 #[error("IO: {0}")]
84 IO(MachineIOError),
85 #[error("FFI module not defined: {0}")]
87 FfiModuleNotDefined(usize),
88 #[error("FFI proc {0} not defined in module {1}")]
90 FfiProcedureNotDefined(Identifier, usize),
91 #[error("Attempted call with invalid context")]
93 ContextMismatch,
94 #[error("bug: {0}")]
96 Bug(Bug),
97 #[error("unknown error: {0}")]
99 Unknown(String),
100}
101
102impl MachineErrorType {
103 pub fn invalid_type(
105 want: impl Into<String>,
106 got: impl Into<String>,
107 msg: impl Into<String>,
108 ) -> Self {
109 Self::InvalidType {
110 want: want.into(),
111 got: got.into(),
112 msg: msg.into(),
113 }
114 }
115}
116
117impl From<Infallible> for MachineErrorType {
118 fn from(err: Infallible) -> Self {
119 match err {}
120 }
121}
122
123impl From<ValueConversionError> for MachineErrorType {
124 fn from(value: ValueConversionError) -> Self {
125 match value {
126 ValueConversionError::InvalidType { want, got, msg } => {
127 Self::InvalidType { want, got, msg }
128 }
129 ValueConversionError::InvalidStructMember(s) => Self::InvalidStructMember(s),
130 ValueConversionError::OutOfRange => Self::InvalidType {
131 want: "Int".to_owned(),
132 got: "Int".to_owned(),
133 msg: "out of range".to_owned(),
134 },
135 ValueConversionError::BadState => Self::BadState("value conversion error"),
136 }
137 }
138}
139
140#[derive(Debug, PartialEq)]
142struct MachineErrorSource {
143 linecol: (usize, usize),
145 text: String,
147}
148
149#[derive(Debug, PartialEq, thiserror::Error)]
151pub struct MachineError {
152 #[source]
154 pub err_type: MachineErrorType,
155 source: Option<MachineErrorSource>,
157}
158
159impl MachineError {
160 pub fn new(err_type: MachineErrorType) -> Self {
162 Self {
163 err_type,
164 source: None,
165 }
166 }
167
168 pub(crate) fn from_position(
169 err_type: MachineErrorType,
170 pc: usize,
171 codemap: Option<&CodeMap>,
172 ) -> Self {
173 Self {
174 err_type,
175 source: None,
176 }
177 .with_position(pc, codemap)
178 }
179
180 pub(crate) fn with_position(mut self, pc: usize, codemap: Option<&CodeMap>) -> Self {
181 if self.source.is_none()
182 && let Some(codemap) = codemap
183 {
184 self.source = codemap
185 .span_from_instruction(pc)
186 .ok()
187 .map(|span| MachineErrorSource {
188 linecol: span.start_linecol(),
189 text: span.as_str().to_owned(),
190 });
191 }
192 self
193 }
194}
195
196impl fmt::Display for MachineError {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 match &self.source {
199 Some(source) => write!(
200 f,
201 "{} at line {} col {}:\n\t{}",
202 self.err_type, source.linecol.0, source.linecol.1, source.text
203 ),
204 None => write!(f, "{}", self.err_type),
205 }
206 }
207}
208
209impl From<MachineErrorType> for MachineError {
210 fn from(value: MachineErrorType) -> Self {
211 Self::new(value)
212 }
213}
214
215impl From<Infallible> for MachineError {
216 fn from(err: Infallible) -> Self {
217 match err {}
218 }
219}
220
221impl From<Bug> for MachineError {
222 fn from(bug: Bug) -> Self {
223 Self::new(MachineErrorType::Bug(bug))
224 }
225}