1use std::fmt::Display;
4
5use crate::collections::handle_table::Handle;
6use crate::prelude::Trace;
7use crate::traits::VmFunction;
8use thiserror::Error;
9
10pub type ExecutionResult<T = ()> = Result<T, ExecutionError>;
11
12#[derive(Debug, Clone, Error)]
13pub enum ExecutionErrorPayload {
14 #[error("The program has overflown its call stack")]
15 CallStackOverflow,
16 #[error("Input ended unexpectedly")]
17 UnexpectedEndOfInput,
18 #[error("Program exited with status code: {0}")]
19 ExitCode(i32),
20 #[error("Got an invalid instruction code {0}")]
21 InvalidInstruction(u8),
22 #[error("Got an invalid argument: {}",
23 .context.as_ref().map(|x|x.as_str()).unwrap_or_else(|| ""))]
24 InvalidArgument { context: Option<String> },
25 #[error("Variable {0} was not found!")]
26 VarNotFound(String),
27 #[error("Procedure by the hash {0:?} could not be found")]
28 ProcedureNotFound(Handle),
29 #[error("Unimplemented")]
30 Unimplemented,
31 #[error("The program ran out of memory")]
32 OutOfMemory,
33 #[error("Missing argument to function call")]
34 MissingArgument,
35 #[error("Program timed out")]
36 Timeout,
37 #[error("Subtask [{name}] failed {error}")]
38 TaskFailure {
39 name: String,
40 error: Box<ExecutionErrorPayload>,
41 },
42 #[error("The program has overflowns its stack")]
43 Stackoverflow,
44 #[error("Failed to return from a function {reason}")]
45 BadReturn { reason: String },
46 #[error("Trying to hash an unhashable object")]
47 Unhashable,
48 #[error("Assertion failed: {0}")]
49 AssertionError(String),
50 #[error("Closure requested a non-existent upvalue")]
51 InvalidUpvalue,
52 #[error("Expected to be in the context of a closure")]
53 NotClosure,
54}
55
56#[derive(Debug, Clone, Error)]
57pub struct ExecutionError {
58 pub payload: ExecutionErrorPayload,
59 pub trace: Vec<Trace>,
60}
61
62impl ExecutionError {
63 pub fn new(payload: ExecutionErrorPayload, trace: Vec<Trace>) -> Self {
64 Self { payload, trace }
65 }
66}
67
68impl Display for ExecutionError {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 write!(f, "ExecutionError: {}", self.payload)
71 }
72}
73
74impl ExecutionErrorPayload {
75 pub fn invalid_argument<S>(reason: S) -> Self
76 where
77 S: Into<String>,
78 {
79 Self::InvalidArgument {
80 context: Some(reason.into()),
81 }
82 }
83}
84
85pub(crate) struct Procedure<Aux> {
86 pub fun: std::rc::Rc<dyn VmFunction<Aux>>,
87 pub name: String,
88}
89
90impl<Aux> Clone for Procedure<Aux> {
91 fn clone(&self) -> Self {
92 Self {
93 fun: self.fun.clone(),
94 name: self.name.clone(),
95 }
96 }
97}
98
99impl<Aux> Procedure<Aux> {
100 pub fn name(&self) -> &str {
101 self.name.as_str()
102 }
103}
104
105impl<Aux> std::fmt::Debug for Procedure<Aux> {
106 fn fmt(&self, writer: &mut std::fmt::Formatter) -> std::fmt::Result {
107 writeln!(writer, "Procedure '{}'", self.name)
108 }
109}