1use alloc::string::{String, ToString};
2use core::{fmt::Display, ops::ControlFlow};
3use tinywasm_types::FuncType;
4
5#[cfg(feature = "parser")]
6pub use tinywasm_parser::ParseError;
7
8#[derive(Debug)]
10pub enum Error {
11 Trap(Trap),
13
14 Linker(LinkingError),
16
17 UnsupportedFeature(String),
19
20 Other(String),
22
23 FuncDidNotReturn,
25
26 InvalidLabelType,
28
29 InvalidStore,
31
32 #[cfg(feature = "std")]
33 Io(crate::std::io::Error),
35
36 #[cfg(feature = "parser")]
37 ParseError(ParseError),
39}
40
41#[derive(Debug)]
42pub enum LinkingError {
44 UnknownImport {
46 module: String,
48 name: String,
50 },
51
52 IncompatibleImportType {
54 module: String,
56 name: String,
58 },
59}
60
61impl LinkingError {
62 pub(crate) fn incompatible_import_type(import: &tinywasm_types::Import) -> Self {
63 Self::IncompatibleImportType { module: import.module.to_string(), name: import.name.to_string() }
64 }
65
66 pub(crate) fn unknown_import(import: &tinywasm_types::Import) -> Self {
67 Self::UnknownImport { module: import.module.to_string(), name: import.name.to_string() }
68 }
69}
70
71#[derive(Debug)]
72pub enum Trap {
76 Unreachable,
78
79 MemoryOutOfBounds {
81 offset: usize,
83 len: usize,
85 max: usize,
87 },
88
89 TableOutOfBounds {
91 offset: usize,
93 len: usize,
95 max: usize,
97 },
98
99 DivisionByZero,
101
102 InvalidConversionToInt,
104
105 IntegerOverflow,
107
108 CallStackOverflow,
110
111 UndefinedElement {
113 index: usize,
115 },
116
117 UninitializedElement {
119 index: usize,
121 },
122
123 IndirectCallTypeMismatch {
125 expected: FuncType,
127 actual: FuncType,
129 },
130}
131
132impl Trap {
133 pub fn message(&self) -> &'static str {
135 match self {
136 Self::Unreachable => "unreachable",
137 Self::MemoryOutOfBounds { .. } => "out of bounds memory access",
138 Self::TableOutOfBounds { .. } => "out of bounds table access",
139 Self::DivisionByZero => "integer divide by zero",
140 Self::InvalidConversionToInt => "invalid conversion to integer",
141 Self::IntegerOverflow => "integer overflow",
142 Self::CallStackOverflow => "call stack exhausted",
143 Self::UndefinedElement { .. } => "undefined element",
144 Self::UninitializedElement { .. } => "uninitialized element",
145 Self::IndirectCallTypeMismatch { .. } => "indirect call type mismatch",
146 }
147 }
148}
149
150impl LinkingError {
151 pub fn message(&self) -> &'static str {
153 match self {
154 Self::UnknownImport { .. } => "unknown import",
155 Self::IncompatibleImportType { .. } => "incompatible import type",
156 }
157 }
158}
159
160impl From<LinkingError> for Error {
161 fn from(value: LinkingError) -> Self {
162 Self::Linker(value)
163 }
164}
165
166impl From<Trap> for Error {
167 fn from(value: Trap) -> Self {
168 Self::Trap(value)
169 }
170}
171
172impl Display for Error {
173 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 match self {
175 #[cfg(feature = "parser")]
176 Self::ParseError(err) => write!(f, "error parsing module: {err:?}"),
177
178 #[cfg(feature = "std")]
179 Self::Io(err) => write!(f, "I/O error: {err}"),
180
181 Self::Trap(trap) => write!(f, "trap: {trap}"),
182 Self::Linker(err) => write!(f, "linking error: {err}"),
183 Self::InvalidLabelType => write!(f, "invalid label type"),
184 Self::Other(message) => write!(f, "unknown error: {message}"),
185 Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {feature}"),
186 Self::FuncDidNotReturn => write!(f, "function did not return"),
187 Self::InvalidStore => write!(f, "invalid store"),
188 }
189 }
190}
191
192impl Display for LinkingError {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 match self {
195 Self::UnknownImport { module, name } => write!(f, "unknown import: {}.{}", module, name),
196 Self::IncompatibleImportType { module, name } => {
197 write!(f, "incompatible import type: {}.{}", module, name)
198 }
199 }
200 }
201}
202
203impl Display for Trap {
204 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
205 match self {
206 Self::Unreachable => write!(f, "unreachable"),
207 Self::MemoryOutOfBounds { offset, len, max } => {
208 write!(f, "out of bounds memory access: offset={offset}, len={len}, max={max}")
209 }
210 Self::TableOutOfBounds { offset, len, max } => {
211 write!(f, "out of bounds table access: offset={offset}, len={len}, max={max}")
212 }
213 Self::DivisionByZero => write!(f, "integer divide by zero"),
214 Self::InvalidConversionToInt => write!(f, "invalid conversion to integer"),
215 Self::IntegerOverflow => write!(f, "integer overflow"),
216 Self::CallStackOverflow => write!(f, "call stack exhausted"),
217 Self::UndefinedElement { index } => write!(f, "undefined element: index={index}"),
218 Self::UninitializedElement { index } => {
219 write!(f, "uninitialized element: index={index}")
220 }
221 Self::IndirectCallTypeMismatch { expected, actual } => {
222 write!(f, "indirect call type mismatch: expected={expected:?}, actual={actual:?}")
223 }
224 }
225 }
226}
227
228#[cfg(any(feature = "std", all(not(feature = "std"), feature = "nightly")))]
229impl crate::std::error::Error for Error {}
230
231#[cfg(feature = "parser")]
232impl From<tinywasm_parser::ParseError> for Error {
233 fn from(value: tinywasm_parser::ParseError) -> Self {
234 Self::ParseError(value)
235 }
236}
237
238pub type Result<T, E = Error> = crate::std::result::Result<T, E>;
240
241pub(crate) trait Controlify<T> {
242 fn to_cf(self) -> ControlFlow<Option<Error>, T>;
243}
244
245impl<T> Controlify<T> for Result<T, Error> {
246 fn to_cf(self) -> ControlFlow<Option<Error>, T> {
247 match self {
248 Ok(value) => ControlFlow::Continue(value),
249 Err(err) => ControlFlow::Break(Some(err)),
250 }
251 }
252}