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 Error::InvalidCell => VmException::CellOverflow,
71 _ => VmException::Fatal, },
73 Self::DictError => VmException::DictError,
74 }
75 }
76}
77
78impl From<Error> for Box<VmError> {
79 #[inline]
80 fn from(e: Error) -> Self {
81 Box::new(VmError::CellError(e))
82 }
83}
84
85#[cfg(feature = "dump")]
87pub type DumpResult = Result<(), DumpError>;
88
89#[cfg(feature = "dump")]
91#[derive(thiserror::Error, Debug)]
92pub enum DumpError {
93 #[error(transparent)]
94 InvalidCode(#[from] tycho_types::error::Error),
95 #[error("invalid opcode")]
96 InvalidOpcode,
97 #[error("unexpected cell")]
98 CellMismatch,
99 #[error(transparent)]
100 WriterError(#[from] std::fmt::Error),
101}
102
103#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
105#[repr(u8)]
106pub enum VmException {
107 Ok = 0,
108 Alternative = 1,
109 StackUnderflow = 2,
110 StackOverflow = 3,
111 IntOverflow = 4,
112 RangeCheck = 5,
113 InvalidOpcode = 6,
114 TypeCheck = 7,
115 CellOverflow = 8,
116 CellUnderflow = 9,
117 DictError = 10,
118 Unknown = 11,
119 Fatal = 12,
120 OutOfGas = 13,
121 VirtError = 14,
122}
123
124impl VmException {
125 pub const fn as_exit_code(&self) -> i32 {
126 !(*self as i32)
127 }
128}
129
130impl std::fmt::Display for VmException {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 f.write_str(match self {
133 Self::Ok => "normal termination",
134 Self::Alternative => "alternative termination",
135 Self::StackUnderflow => "stack underflow",
136 Self::StackOverflow => "stack overflow",
137 Self::IntOverflow => "integer overflow",
138 Self::RangeCheck => "integer out of range",
139 Self::InvalidOpcode => "invalid opcode",
140 Self::TypeCheck => "type check error",
141 Self::CellOverflow => "cell overflow",
142 Self::CellUnderflow => "cell underflow",
143 Self::DictError => "dictionary error",
144 Self::Unknown => "unknown error",
145 Self::Fatal => "fatal error",
146 Self::OutOfGas => "out of gas",
147 Self::VirtError => "virtualization error",
148 })
149 }
150}