1use tycho_types::error::Error;
2
3use crate::stack::StackValueType;
4
5pub type VmResult<T> = Result<T, Box<VmError>>;
7
8#[derive(Debug, thiserror::Error)]
10pub enum VmError {
11 #[error("stack underflow at depth {0}")]
12 StackUnderflow(usize),
13 #[error("too many arguments copied into a closure continuation: {0}")]
14 TooManyArguments(usize),
15 #[error("expected integer in range {min}..={max}, found {actual}")]
16 IntegerOutOfRange {
17 min: isize,
18 max: isize,
19 actual: String,
20 },
21 #[error("control register index out of range: {0}")]
22 ControlRegisterOutOfRange(usize),
23 #[error("control register redefined")]
24 ControlRegisterRedefined,
25 #[error("integer overflow")]
26 IntegerOverflow,
27 #[error("invalid opcode")]
28 InvalidOpcode,
29 #[error(
30 "expected type {}, found {}",
31 StackValueType::display_raw(*expected),
32 StackValueType::display_raw(*actual),
33 )]
34 InvalidType { expected: u8, actual: u8 },
35 #[error("out of gas")]
36 OutOfGas,
37 #[error(transparent)]
38 CellError(#[from] Error),
39 #[error("dict error")]
40 DictError,
41 #[error("unknown error. {0}")]
42 Unknown(String),
43}
44
45impl VmError {
46 pub fn is_out_of_gas(&self) -> bool {
47 matches!(self, Self::OutOfGas | Self::CellError(Error::Cancelled))
48 }
49
50 pub fn as_exception(&self) -> VmException {
51 match self {
52 Self::StackUnderflow(_) => VmException::StackUnderflow,
53 Self::TooManyArguments(_) => VmException::StackOverflow,
54 Self::IntegerOutOfRange { .. } => VmException::RangeCheck,
55 Self::ControlRegisterOutOfRange(_) => VmException::RangeCheck,
56 Self::ControlRegisterRedefined => VmException::TypeCheck,
57 Self::IntegerOverflow => VmException::IntOverflow,
58 Self::InvalidOpcode => VmException::InvalidOpcode,
59 Self::InvalidType { .. } => VmException::TypeCheck,
60 Self::OutOfGas => VmException::OutOfGas,
61 Self::Unknown(_) => VmException::Unknown,
62 Self::CellError(e) => match e {
63 Error::CellUnderflow => VmException::CellUnderflow,
64 Error::CellOverflow => VmException::CellOverflow,
65 Error::UnexpectedExoticCell | Error::UnexpectedOrdinaryCell => {
66 VmException::VirtError
67 }
68 Error::Cancelled => VmException::OutOfGas, Error::IntOverflow => VmException::IntOverflow,
70 _ => VmException::Fatal, },
72 Self::DictError => VmException::DictError,
73 }
74 }
75}
76
77impl From<Error> for Box<VmError> {
78 #[inline]
79 fn from(e: Error) -> Self {
80 Box::new(VmError::CellError(e))
81 }
82}
83
84#[cfg(feature = "dump")]
86pub type DumpResult = Result<(), DumpError>;
87
88#[cfg(feature = "dump")]
90#[derive(thiserror::Error, Debug)]
91pub enum DumpError {
92 #[error(transparent)]
93 InvalidCode(#[from] tycho_types::error::Error),
94 #[error("invalid opcode")]
95 InvalidOpcode,
96 #[error("unexpected cell")]
97 CellMismatch,
98 #[error(transparent)]
99 WriterError(#[from] std::fmt::Error),
100}
101
102#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
104#[repr(u8)]
105pub enum VmException {
106 Ok = 0,
107 Alternative = 1,
108 StackUnderflow = 2,
109 StackOverflow = 3,
110 IntOverflow = 4,
111 RangeCheck = 5,
112 InvalidOpcode = 6,
113 TypeCheck = 7,
114 CellOverflow = 8,
115 CellUnderflow = 9,
116 DictError = 10,
117 Unknown = 11,
118 Fatal = 12,
119 OutOfGas = 13,
120 VirtError = 14,
121}
122
123impl VmException {
124 pub const fn as_exit_code(&self) -> i32 {
125 !(*self as i32)
126 }
127}
128
129impl std::fmt::Display for VmException {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.write_str(match self {
132 Self::Ok => "normal termination",
133 Self::Alternative => "alternative termination",
134 Self::StackUnderflow => "stack underflow",
135 Self::StackOverflow => "stack overflow",
136 Self::IntOverflow => "integer overflow",
137 Self::RangeCheck => "integer out of range",
138 Self::InvalidOpcode => "invalid opcode",
139 Self::TypeCheck => "type check error",
140 Self::CellOverflow => "cell overflow",
141 Self::CellUnderflow => "cell underflow",
142 Self::DictError => "dictionary error",
143 Self::Unknown => "unknown error",
144 Self::Fatal => "fatal error",
145 Self::OutOfGas => "out of gas",
146 Self::VirtError => "virtualization error",
147 })
148 }
149}