cao_lang/
procedures.rs

1//! Helper module for dealing with function extensions.
2//!
3use 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}