1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
use std::{error::Error, fmt::Display};

use crate::{IndexError, KeyError, ModuleLoadError, SliceError, ValueError, data::DataSourceError};

use super::{resolver::SelectorError};

/// Type alias for `Result<T, RuntimeError>`
pub type RuntimeResult<T> = Result<T, RuntimeError>;
/// A runtime error raised by a Rant program.
#[derive(Debug)]
pub struct RuntimeError {
  /// The type of runtime error.
  pub error_type: RuntimeErrorType,
  /// A description of what went wrong.
  pub description: Option<String>,
  /// A stack trace describing the location of the error.
  pub stack_trace: Option<String>,
}

impl Error for RuntimeError {
  fn source(&self) -> Option<&(dyn Error + 'static)> {
    match &self.error_type {
      RuntimeErrorType::IndexError(err) => Some(err),
      RuntimeErrorType::KeyError(err) => Some(err),
      RuntimeErrorType::ValueError(err) => Some(err),
      _ => None,
    }
  }

  fn cause(&self) -> Option<&dyn Error> {
    self.source()
  }
}

impl Display for RuntimeError {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "[{}] ", self.error_type.id())?;
    if let Some(desc) =& self.description {
      write!(f, "{}", desc)?;
    } else {
      write!(f, "{}", self.error_type)?;
    }
    Ok(())
  }
}

/// Provides general categories of runtime errors encountered in Rant.
#[derive(Debug)]
pub enum RuntimeErrorType {
  /// Stack has overflowed.
  ///
  /// Rant error ID: `STACK_OVERFLOW_ERROR`
  StackOverflow,
  /// Stack has underflowed.
  ///
  /// Rant error ID: `STACK_UNDERFLOW_ERROR`
  StackUnderflow,
  /// Variable access error, such as attempting to access a nonexistent variable or write to a constant
  ///
  /// Rant error ID: `INVALID_ACCESS_ERROR`
  InvalidAccess,
  /// Operation is not valid for the current program state
  ///
  /// Rant error ID: `INVALID_OP_ERROR`
  InvalidOperation,
  /// Internal VM error, usually indicating a bug or corrupted data
  ///
  /// Rant error ID: `INTERNAL_ERROR`
  InternalError,
  /// Too few/many arguments were passed to a function
  ///
  /// Rant error ID: `ARG_MISMATCH_ERROR`
  ArgumentMismatch,
  /// Invalid argument passed to function
  ///
  /// Rant error ID: `ARG_ERROR`
  ArgumentError,
  /// Tried to invoke a non-function
  ///
  /// Rant error ID: `INVOKE_ERROR`
  CannotInvokeValue,
  /// Assertion failed
  ///
  /// Rant error ID: `ASSERT_ERROR`
  AssertError,
  /// Error occurred due to unexpected value type
  ///
  /// Rant error ID: `TYPE_ERROR`
  TypeError,
  /// Error occurred when creating value
  ///
  /// Rant error ID: `VALUE_ERROR`
  ValueError(ValueError),
  /// Error occurred while indexing value
  ///
  /// Rant error ID: `INDEX_ERROR`
  IndexError(IndexError),
  /// Error occurred while keying value
  ///
  /// Rant error ID: `KEY_ERROR`
  KeyError(KeyError),
  /// Error occurred while slicing value
  ///
  /// Rant error ID: `SLICE_ERROR`
  SliceError(SliceError),
  /// Error occurred while iterating selector
  ///
  /// Rant error ID: `SELECTOR_ERROR`
  SelectorError(SelectorError),
  /// Error occurred while trying to load a module
  ///
  /// Rant error ID: `MODULE_ERROR`
  ModuleLoadError(ModuleLoadError),
  /// Error manually triggered by program
  ///
  /// Rant error ID: `USER_ERROR`
  UserError,
  /// Error during control flow operation (e.g. return or break)
  ///
  /// Rant error ID: `CONTROL_FLOW_ERROR`
  ControlFlowError,
  /// Error occurred during data source operation.
  ///
  /// Rant error ID: `DATA_SOURCE_ERROR`
  DataSourceError(DataSourceError),
}

impl RuntimeErrorType {
  pub fn id(&self) -> &'static str {
    match self {
      Self::StackOverflow => "STACK_OVERFLOW_ERROR",
      Self::StackUnderflow => "STACK_UNDERFLOW_ERROR",
      Self::InvalidAccess => "INVALID_ACCESS_ERROR",
      Self::InvalidOperation => "INVALID_OP_ERROR",
      Self::InternalError => "INTERNAL_ERROR",
      Self::ArgumentMismatch => "ARG_MISMATCH_ERROR",
      Self::ArgumentError => "ARG_ERROR",
      Self::CannotInvokeValue => "INVOKE_ERROR",
      Self::UserError => "USER_ERROR",
      Self::AssertError => "ASSERT_ERROR",
      Self::TypeError => "TYPE_ERROR",
      Self::ValueError(_) => "VALUE_ERROR",
      Self::IndexError(_) => "INDEX_ERROR",
      Self::KeyError(_) => "KEY_ERROR",
      Self::SliceError(_) => "SLICE_ERROR",
      Self::SelectorError(_) => "SELECTOR_ERROR",
      Self::ModuleLoadError(_) => "MODULE_ERROR",
      Self::ControlFlowError => "CONTROL_FLOW_ERROR",
      Self::DataSourceError(_) => "DATA_SOURCE_ERROR",
    }
  }
}

impl Display for RuntimeErrorType {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
      Self::ValueError(e) => write!(f, "{}", e),
      Self::IndexError(e) => write!(f, "{}", e),
      Self::KeyError(e) => write!(f, "{}", e),
      Self::SliceError(e) => write!(f, "{}", e),
      Self::SelectorError(e) => write!(f, "{}", e),
      Self::ModuleLoadError(e) => write!(f, "{}", e),
      Self::DataSourceError(e) => write!(f, "{}", e),
      _ => write!(f, "{}", self.id()),
    }
  }
}

pub(crate) trait IntoRuntimeResult<T> {
  fn into_runtime_result(self) -> RuntimeResult<T>;
}