1use crate::status::LuaStatus;
4use crate::value::LuaValue;
5use std::fmt;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct LuaExit(pub i32);
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct LuaThreadClose(pub LuaStatus);
17
18#[derive(Debug, Clone)]
29pub enum LuaError {
30 Runtime(LuaValue),
31 Syntax(LuaValue),
32 RuntimeMsg(Box<[u8]>),
33 SyntaxMsg(Box<[u8]>),
34 Memory,
35 Error,
36 Yield,
37 File,
38 Gc,
39}
40
41impl LuaError {
42 pub fn runtime(args: fmt::Arguments<'_>) -> Self {
48 LuaError::RuntimeMsg(format!("{}", args).into_bytes().into_boxed_slice())
49 }
50 pub fn syntax(args: fmt::Arguments<'_>) -> Self {
51 LuaError::SyntaxMsg(format!("{}", args).into_bytes().into_boxed_slice())
52 }
53 pub fn syntax_at(args: fmt::Arguments<'_>, source: &[u8], line: i32) -> Self {
54 LuaError::SyntaxMsg(
55 format!("{}:{}: {}", String::from_utf8_lossy(source), line, args)
56 .into_bytes()
57 .into_boxed_slice(),
58 )
59 }
60 pub fn syntax_raw(msg: &[u8]) -> Self {
61 LuaError::SyntaxMsg(msg.to_vec().into_boxed_slice())
62 }
63
64 pub fn type_error(v: &LuaValue, op: &str) -> Self {
66 LuaError::runtime(format_args!("attempt to {} a {} value", op, v.type_name()))
67 }
68 pub fn call_error(v: &LuaValue) -> Self {
69 Self::type_error(v, "call")
70 }
71 pub fn concat_error(p1: &LuaValue, p2: &LuaValue) -> Self {
72 let bad = if matches!(p1, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_)) {
73 p2
74 } else {
75 p1
76 };
77 LuaError::runtime(format_args!(
78 "attempt to concatenate a {} value",
79 bad.type_name()
80 ))
81 }
82 pub fn arith_error(p1: &LuaValue, p2: &LuaValue, _msg: &str) -> Self {
83 let bad = if matches!(p1, LuaValue::Int(_) | LuaValue::Float(_)) {
84 p2
85 } else {
86 p1
87 };
88 LuaError::runtime(format_args!(
89 "attempt to perform arithmetic on a {} value",
90 bad.type_name()
91 ))
92 }
93 pub fn int_overflow(_p1: &LuaValue, _p2: &LuaValue) -> Self {
94 LuaError::runtime(format_args!("number has no integer representation"))
95 }
96 pub fn order_error(p1: &LuaValue, p2: &LuaValue) -> Self {
97 LuaError::runtime(format_args!(
98 "attempt to compare {} with {}",
99 p1.type_name(),
100 p2.type_name()
101 ))
102 }
103 pub fn for_error(v: &LuaValue, what: &str) -> Self {
104 LuaError::runtime(format_args!(
105 "bad 'for' {} (number expected, got {})",
106 what,
107 v.type_name()
108 ))
109 }
110 pub fn arg_error(narg: i32, msg: &str) -> Self {
111 LuaError::runtime(format_args!("bad argument #{} ({})", narg, msg))
112 }
113 pub fn type_arg_error(narg: i32, expected: &str, got: &LuaValue) -> Self {
114 LuaError::runtime(format_args!(
115 "bad argument #{} ({} expected, got {})",
116 narg,
117 expected,
118 got.type_name()
119 ))
120 }
121
122 pub fn from_value(v: LuaValue) -> Self {
124 LuaError::Runtime(v)
127 }
128 pub fn with_status(status: LuaStatus) -> Self {
129 match status {
130 LuaStatus::Ok => LuaError::Error,
131 LuaStatus::Yield => LuaError::Yield,
132 LuaStatus::ErrRun => LuaError::Runtime(LuaValue::Nil),
133 LuaStatus::ErrSyntax => LuaError::Syntax(LuaValue::Nil),
134 LuaStatus::ErrMem => LuaError::Memory,
135 LuaStatus::ErrErr => LuaError::Error,
136 LuaStatus::ErrFile => LuaError::File,
137 LuaStatus::ErrGc => LuaError::Gc,
138 }
139 }
140
141 pub fn to_status(&self) -> LuaStatus {
142 match self {
143 LuaError::Runtime(_) | LuaError::RuntimeMsg(_) => LuaStatus::ErrRun,
144 LuaError::Syntax(_) | LuaError::SyntaxMsg(_) => LuaStatus::ErrSyntax,
145 LuaError::Memory => LuaStatus::ErrMem,
146 LuaError::Error => LuaStatus::ErrErr,
147 LuaError::Yield => LuaStatus::Yield,
148 LuaError::File => LuaStatus::ErrFile,
149 LuaError::Gc => LuaStatus::ErrGc,
150 }
151 }
152
153 pub fn message_bytes(&self) -> Option<&[u8]> {
159 match self {
160 LuaError::Runtime(LuaValue::Str(s)) | LuaError::Syntax(LuaValue::Str(s)) => {
161 Some(s.as_bytes())
162 }
163 LuaError::RuntimeMsg(b) | LuaError::SyntaxMsg(b) => Some(b),
164 _ => None,
165 }
166 }
167
168 pub fn into_value(self) -> LuaValue {
186 match self {
187 LuaError::Runtime(v) | LuaError::Syntax(v) => v,
188 LuaError::RuntimeMsg(b) | LuaError::SyntaxMsg(b) => LuaValue::Str(
189 crate::gc::GcRef::new(crate::string::LuaString::from_bytes(b.into_vec())),
190 ),
191 _ => LuaValue::Nil,
192 }
193 }
194
195 pub fn message_lossy(&self) -> String {
201 match self {
202 LuaError::Runtime(v) | LuaError::Syntax(v) => lua_value_message_lossy(v),
203 LuaError::RuntimeMsg(b) | LuaError::SyntaxMsg(b) => {
204 String::from_utf8_lossy(b).into_owned()
205 }
206 LuaError::Memory => "not enough memory".to_string(),
207 LuaError::Error => "error in error handling".to_string(),
208 LuaError::Yield => "attempt to yield across a C-call boundary".to_string(),
209 LuaError::File => "file error".to_string(),
210 LuaError::Gc => "garbage collector error".to_string(),
211 }
212 }
213}
214
215fn lua_value_message_lossy(value: &LuaValue) -> String {
216 match value {
217 LuaValue::Str(s) => String::from_utf8_lossy(s.as_bytes()).into_owned(),
218 LuaValue::Nil => "nil".to_string(),
219 LuaValue::Bool(v) => v.to_string(),
220 LuaValue::Int(v) => v.to_string(),
221 LuaValue::Float(v) => v.to_string(),
222 other => format!("{} error", other.type_name()),
223 }
224}
225
226impl fmt::Display for LuaError {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 LuaError::RuntimeMsg(b) | LuaError::SyntaxMsg(b) => {
230 write!(f, "{}", String::from_utf8_lossy(b))
231 }
232 other => write!(f, "{:?}", other),
233 }
234 }
235}
236impl std::error::Error for LuaError {}
237
238