1use luau_common::{BStr, BString, ByteSlice};
2use luau_printf::Arg;
3
4use super::stack::RawStackAccess;
5use super::{LUA_BUFFER_SIZE, LUA_TNONE, Thread};
6use crate::debug::LuaDebug;
7use crate::metamethod::MetamethodRuntime;
8use crate::state::ThreadState;
9use crate::string::{LuaString, printf_error_message};
10use crate::types::{
11 LUA_TBOOLEAN, LUA_TBUFFER, LUA_TINTEGER, LUA_TNIL, LUA_TNUMBER, LUA_TSTRING, LUA_TVECTOR,
12};
13use crate::{VmError, VmErrorResult, VmResult};
14
15fn current_native_function_name(thread: &Thread) -> Option<LuaString> {
17 if unsafe { thread.current_call_info() == thread.base_call_info() } {
18 return None;
19 }
20
21 let closure = unsafe { thread.current_function() };
22 if unsafe { !closure.is_native() } {
23 return None;
24 }
25
26 let debug_name = unsafe { closure.native_debug_name() }?;
27
28 if debug_name.as_bytes() == b"__namecall" {
29 unsafe { thread.name_call() }.map(LuaString::from_interned)
30 } else {
31 Some(debug_name)
32 }
33}
34
35fn tag_error<T>(thread: &Thread, argument: i32, tag: i32) -> VmErrorResult<T> {
37 let expected = unsafe { thread.type_name(tag) };
38 unsafe { thread.lua_type_error(argument, expected.as_bytes()) }
39}
40
41fn where_bytes(thread: &Thread, level: i32) -> VmErrorResult<Option<BString>> {
42 let mut ar = LuaDebug::default();
43 if unsafe { thread.get_info(level, "sl", &mut ar)? } == 0 || ar.currentline <= 0 {
44 return Ok(None);
45 }
46
47 Ok(Some(luau_printf::sprintf!(
48 "%s:%d: ",
49 ar.short_src().as_bstr(),
50 ar.currentline
51 )))
52}
53
54impl Thread {
56 pub unsafe fn push_where(&self, level: i32) -> VmErrorResult {
58 unsafe {
59 self.raw_check_stack(1)?;
60
61 if let Some(prefix) = where_bytes(self, level)? {
62 self.push_string(prefix.as_slice())?;
63 } else {
64 self.push_string("")?;
65 }
66 }
67 Ok(())
68 }
69
70 pub unsafe fn lua_error<'a, T>(
72 &self,
73 format: impl AsRef<[u8]>,
74 mut args: impl AsMut<[Arg<'a>]>,
75 ) -> VmErrorResult<T> {
76 let format = format.as_ref();
77 let args = args.as_mut();
78 let mut formatted = Vec::new();
79 let message_bytes = if args.is_empty() {
80 format
81 } else {
82 formatted.reserve(format.len());
83 match luau_printf::printf_c_locale(&mut formatted, luau_printf::BStr::new(format), args)
84 {
85 Ok(_) => formatted.as_slice(),
86 Err(error) => printf_error_message(&error),
87 }
88 };
89 let message_len = message_bytes
90 .iter()
91 .position(|byte| *byte == 0)
92 .unwrap_or(message_bytes.len())
93 .min(LUA_BUFFER_SIZE - 1);
94
95 let mut message = match where_bytes(self, 1) {
96 Ok(Some(message)) => message,
97 Ok(None) => BString::default(),
98 Err(error) => return Err(error),
99 };
100 message.extend_from_slice(&message_bytes[..message_len]);
101
102 unsafe { self.raw_check_stack(1) }?;
103 unsafe { self.push_string(message.as_slice()) }?;
104 Err(VmError::Runtime)
105 }
106
107 pub unsafe fn lua_type_error<T>(
109 &self,
110 argument: i32,
111 expected_type: impl AsRef<[u8]>,
112 ) -> VmErrorResult<T> {
113 unsafe {
114 let function_name = current_native_function_name(self);
115 let object = self.to_object(argument);
116 let expected_type = expected_type.as_ref();
117
118 if object.is_none() {
119 if let Some(name) = function_name {
120 crate::error!(
121 self,
122 "missing argument #%d to '%s' (%s expected)",
123 argument,
124 &name,
125 expected_type
126 )
127 } else {
128 crate::error!(
129 self,
130 "missing argument #%d (%s expected)",
131 argument,
132 expected_type
133 )
134 }
135 } else {
136 let got = self.obj_type_name(object.unwrap_unchecked());
137 if let Some(name) = function_name {
138 crate::error!(
139 self,
140 "invalid argument #%d to '%s' (%s expected, got %s)",
141 argument,
142 &name,
143 expected_type,
144 &got
145 )
146 } else {
147 crate::error!(
148 self,
149 "invalid argument #%d (%s expected, got %s)",
150 argument,
151 expected_type,
152 &got
153 )
154 }
155 }
156 }
157 }
158
159 pub unsafe fn lua_arg_expected(
161 &self,
162 condition: bool,
163 argument: i32,
164 expected_type: &str,
165 ) -> VmErrorResult {
166 if !condition {
167 return unsafe { self.lua_type_error(argument, expected_type) };
168 }
169 Ok(())
170 }
171
172 pub unsafe fn lua_arg_error<T>(
174 &self,
175 argument: i32,
176 message: impl AsRef<[u8]>,
177 ) -> VmErrorResult<T> {
178 let function_name = current_native_function_name(self);
179 let message = message.as_ref().as_bstr();
180
181 if let Some(name) = function_name {
182 unsafe {
183 crate::error!(
184 self,
185 "invalid argument #%d to '%s' (%s)",
186 argument,
187 &name,
188 message
189 )
190 }
191 } else {
192 unsafe { crate::error!(self, "invalid argument #%d (%s)", argument, message) }
193 }
194 }
195}
196
197impl Thread {
199 pub unsafe fn lua_check_stack(&self, size: i32, message: Option<&str>) -> VmErrorResult {
201 unsafe {
202 if self.check_stack(size) == 0 {
203 if let Some(message) = message {
204 crate::error!(self, "stack overflow (%s)", message)
205 } else {
206 crate::error!(self, "stack overflow")
207 }
208 } else {
209 Ok(())
210 }
211 }
212 }
213
214 pub unsafe fn check_type(&self, argument: i32, expected_type: i32) -> VmErrorResult {
216 if unsafe { self.type_of(argument) } != expected_type {
217 tag_error(self, argument, expected_type)
218 } else {
219 Ok(())
220 }
221 }
222
223 pub unsafe fn check_any(&self, argument: i32) -> VmErrorResult {
225 if unsafe { self.type_of(argument) } == LUA_TNONE {
226 unsafe { crate::error!(self, "missing argument #%d", argument) }
227 } else {
228 Ok(())
229 }
230 }
231
232 pub unsafe fn check_string(&self, argument: i32) -> VmErrorResult<&BStr> {
234 if let Some(bytes) = unsafe { self.to_string(argument)? } {
235 Ok(bytes)
236 } else {
237 tag_error(self, argument, LUA_TSTRING)
238 }
239 }
240
241 pub unsafe fn opt_string(&self, argument: i32) -> VmErrorResult<Option<&BStr>> {
243 let tag = unsafe { self.type_of(argument) };
244 if tag == LUA_TNONE || tag == LUA_TNIL {
245 Ok(None)
246 } else {
247 Ok(Some(unsafe { self.check_string(argument)? }))
248 }
249 }
250
251 pub unsafe fn check_buffer(&self, argument: i32) -> VmErrorResult<(*mut u8, usize)> {
253 if let Some(buffer) = unsafe { self.to_buffer(argument) } {
254 Ok(buffer)
255 } else {
256 tag_error(self, argument, LUA_TBUFFER)
257 }
258 }
259
260 pub unsafe fn check_userdata(&self, argument: i32, type_name: &str) -> VmErrorResult<*mut ()> {
262 unsafe {
263 let userdata = self.to_userdata(argument);
264 if !userdata.is_null() && self.get_metatable(argument)? != 0 {
265 self.raw_get_field(crate::thread::LUA_REGISTRY_INDEX, type_name)?;
266
267 if self.raw_equal(-1, -2) != 0 {
268 self.pop(2);
269 return Ok(userdata);
270 }
271 }
272
273 self.lua_type_error(argument, type_name)
274 }
275 }
276
277 pub unsafe fn check_userdata_tagged(&self, argument: i32, tag: i32) -> VmErrorResult<*mut ()> {
279 let userdata = unsafe { self.to_userdata_tagged(argument, tag) };
280 if !userdata.is_null() {
281 return Ok(userdata);
282 }
283
284 let type_name = unsafe { self.get_userdata_name(tag) };
285 unsafe { self.lua_type_error(argument, type_name.as_bytes()) }
286 }
287
288 pub unsafe fn check_number(&self, argument: i32) -> VmErrorResult<f64> {
290 if let Some(value) = unsafe { self.to_number(argument) } {
291 Ok(value)
292 } else {
293 tag_error(self, argument, LUA_TNUMBER)
294 }
295 }
296
297 pub unsafe fn opt_number(&self, argument: i32, default: f64) -> VmErrorResult<f64> {
299 let tag = unsafe { self.type_of(argument) };
300 if tag == LUA_TNONE || tag == LUA_TNIL {
301 Ok(default)
302 } else {
303 unsafe { self.check_number(argument) }
304 }
305 }
306
307 pub unsafe fn check_boolean(&self, argument: i32) -> VmErrorResult<i32> {
309 if unsafe { self.type_of(argument) } != LUA_TBOOLEAN {
310 tag_error(self, argument, LUA_TBOOLEAN)
311 } else {
312 Ok(unsafe { self.to_boolean(argument) })
313 }
314 }
315
316 pub unsafe fn opt_boolean(&self, argument: i32, default: i32) -> VmErrorResult<i32> {
318 let tag = unsafe { self.type_of(argument) };
319 if tag == LUA_TNONE || tag == LUA_TNIL {
320 Ok(default)
321 } else {
322 unsafe { self.check_boolean(argument) }
323 }
324 }
325
326 pub unsafe fn check_integer(&self, argument: i32) -> VmErrorResult<i32> {
328 if let Some(value) = unsafe { self.to_integer(argument) } {
329 Ok(value)
330 } else {
331 tag_error(self, argument, LUA_TNUMBER)
332 }
333 }
334
335 pub unsafe fn opt_integer(&self, argument: i32, default: i32) -> VmErrorResult<i32> {
337 let tag = unsafe { self.type_of(argument) };
338 if tag == LUA_TNONE || tag == LUA_TNIL {
339 Ok(default)
340 } else {
341 unsafe { self.check_integer(argument) }
342 }
343 }
344
345 pub unsafe fn check_integer64(&self, argument: i32) -> VmErrorResult<i64> {
347 if let Some(value) = unsafe { self.to_integer64(argument) } {
348 Ok(value)
349 } else {
350 tag_error(self, argument, LUA_TINTEGER)
351 }
352 }
353
354 pub unsafe fn opt_integer64(&self, argument: i32, default: i64) -> VmErrorResult<i64> {
356 let tag = unsafe { self.type_of(argument) };
357 if tag == LUA_TNONE || tag == LUA_TNIL {
358 Ok(default)
359 } else {
360 unsafe { self.check_integer64(argument) }
361 }
362 }
363
364 pub unsafe fn check_unsigned(&self, argument: i32) -> VmErrorResult<u32> {
366 if let Some(value) = unsafe { self.to_unsigned(argument) } {
367 Ok(value)
368 } else {
369 tag_error(self, argument, LUA_TNUMBER)
370 }
371 }
372
373 pub unsafe fn opt_unsigned(&self, argument: i32, default: u32) -> VmErrorResult<u32> {
375 let tag = unsafe { self.type_of(argument) };
376 if tag == LUA_TNONE || tag == LUA_TNIL {
377 Ok(default)
378 } else {
379 unsafe { self.check_unsigned(argument) }
380 }
381 }
382
383 pub unsafe fn check_vector(
385 &self,
386 argument: i32,
387 ) -> VmErrorResult<[f32; crate::types::LUA_VECTOR_SIZE]> {
388 if let Some(vector) = unsafe { self.to_vector(argument) } {
389 Ok(vector)
390 } else {
391 tag_error(self, argument, LUA_TVECTOR)
392 }
393 }
394
395 pub unsafe fn opt_vector(
397 &self,
398 argument: i32,
399 ) -> VmErrorResult<Option<[f32; crate::types::LUA_VECTOR_SIZE]>> {
400 let tag = unsafe { self.type_of(argument) };
401 if tag == LUA_TNONE || tag == LUA_TNIL {
402 Ok(None)
403 } else {
404 Ok(Some(unsafe { self.check_vector(argument)? }))
405 }
406 }
407
408 pub unsafe fn check_option(
410 &self,
411 argument: i32,
412 default: Option<&str>,
413 options: &[&str],
414 ) -> VmErrorResult<i32> {
415 unsafe {
416 let name = if let Some(default) = default {
417 let tag = self.type_of(argument);
418 if tag == LUA_TNONE || tag == LUA_TNIL {
419 default.as_bytes()
420 } else {
421 self.check_string(argument)?.as_bytes()
422 }
423 } else {
424 self.check_string(argument)?.as_bytes()
425 };
426
427 for (index, option) in options.iter().enumerate() {
428 if option.as_bytes() == name {
429 return Ok(index as i32);
430 }
431 }
432
433 let message = luau_printf::sprintf!("invalid option '%s'", name.as_bstr());
434 self.lua_arg_error(argument, message.as_bstr())
435 }
436 }
437}
438
439impl Thread {
441 fn append_pointer_hex(bytes: &mut BString, mut value: usize) {
442 const HEX: &[u8; 16] = b"0123456789abcdef";
443
444 let mut buffer = [0u8; 2 * core::mem::size_of::<usize>()];
445 for digit in buffer.iter_mut().rev() {
446 *digit = HEX[value & 0xf];
447 value >>= 4;
448 }
449
450 bytes.extend_from_slice(&buffer);
451 }
452
453 pub unsafe fn lua_type_name(&self, index: i32) -> LuaString {
455 let object = unsafe { self.to_object(index) };
456 if object.is_none() {
457 LuaString::from_static(b"no value".as_bstr())
458 } else {
459 unsafe { self.obj_type_name(object.unwrap_unchecked()) }
460 }
461 }
462
463 pub unsafe fn lua_to_string(&self, index: i32) -> VmResult<&BStr> {
465 unsafe {
466 if self.call_meta(index, "__tostring")? != 0 {
467 let Some(result) = self.to_string(-1)? else {
468 return crate::error!(self, "'__tostring' must return a string")
469 .map_err(Into::into);
470 };
471
472 return Ok(result);
473 }
474
475 match self.type_of(index) {
476 LUA_TNIL => self.push_string("nil")?,
477 LUA_TBOOLEAN => self.push_string(if self.to_boolean(index) != 0 {
478 "true"
479 } else {
480 "false"
481 })?,
482 LUA_TNUMBER => {
483 let mut buffer = [0u8; crate::number::LUAI_MAXNUM2STR];
484 let number_len = crate::number::num_to_str(
485 &mut buffer,
486 self.to_number(index).unwrap_or(0.0),
487 );
488 self.push_string(&buffer[..number_len])?;
489 }
490 LUA_TVECTOR => {
491 let vector = self.to_vector(index).unwrap_unchecked();
492 let mut bytes = BString::new(Vec::with_capacity(
493 crate::number::LUAI_MAXNUM2STR * crate::types::LUA_VECTOR_SIZE,
494 ));
495
496 for (component_index, component) in vector.iter().enumerate() {
497 if component_index != 0 {
498 bytes.extend_from_slice(b", ");
499 }
500
501 let mut component_buffer = [0u8; crate::number::LUAI_MAXNUM2STR];
502 let component_len =
503 crate::number::num_to_str(&mut component_buffer, f64::from(*component));
504 bytes.extend_from_slice(&component_buffer[..component_len]);
505 }
506
507 self.push_string(bytes.as_slice())?;
508 }
509 LUA_TSTRING => self.push_value(index)?,
510 LUA_TINTEGER => {
511 let mut buffer = [0u8; crate::number::LUAI_MAXINT2STR];
512 let integer_len = crate::number::int_to_str(
513 &mut buffer,
514 self.to_integer64(index).unwrap_or(0),
515 );
516 self.push_string(&buffer[..integer_len])?;
517 }
518 _ => {
519 let type_name = self.lua_type_name(index);
520 let mut bytes = BString::new(Vec::new());
521 bytes.extend_from_slice(type_name.as_bytes());
522 bytes.extend_from_slice(b": 0x");
523 let encoded = self.encode_pointer(self.to_pointer(index) as usize);
524 Self::append_pointer_hex(&mut bytes, encoded);
525 self.push_string(bytes.as_slice())?;
526 }
527 }
528
529 Ok(self.to_string(-1)?.unwrap_unchecked())
530 }
531 }
532}