use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
use crate::{
value::{FileHandle, FuncBuiltin, FuncBuiltinRaw, FuncDef, Numeric, Table, Thread},
Error, LuaError, Result, Value, VM,
};
impl VM {
pub fn arg_len(&self) -> usize {
self.frames.last().unwrap().varargs.len()
}
pub fn arg(&mut self, idx: usize) -> Result<Value> {
let args = &mut self.frames.last_mut().unwrap().varargs;
if idx < args.len() {
Ok(mem::replace(&mut args[idx], Value::Nil))
} else {
Err(self.arg_error(idx, Error::from_lua(LuaError::ArgumentExpected)))
}
}
pub fn arg_or_nil(&mut self, idx: usize) -> Value {
let args = &mut self.frames.last_mut().unwrap().varargs;
if idx < args.len() {
mem::replace(&mut args[idx], Value::Nil)
} else {
Value::Nil
}
}
pub fn arg_opt(&mut self, idx: usize) -> Option<Value> {
let args = &mut self.frames.last_mut().unwrap().varargs;
if idx < args.len() {
Some(mem::replace(&mut args[idx], Value::Nil))
} else {
None
}
}
pub fn arg_split(&mut self, at: usize) -> Vec<Value> {
let args = &mut self.frames.last_mut().unwrap().varargs;
if at > args.len() {
vec![]
} else {
args.split_off(at)
}
}
pub fn arg_error(&self, idx: usize, err: Error) -> Error {
let (name, namewhat) = self.call_info(&self.frames, self.frames.len() - 1);
match namewhat {
"method" if idx == 0 => err.map_lua_error(|l| {
LuaError::ArgumentBadSelf(
String::from_utf8_lossy(&name.unwrap_or_default()).into_owned(),
Box::new(l),
)
}),
_ => {
let idx = match namewhat {
"method" => idx - 1,
_ => idx,
};
let name = match &*self.frames.last().unwrap().func_def {
FuncDef::Builtin(FuncBuiltin { module, name, .. })
| FuncDef::BuiltinRaw(FuncBuiltinRaw { module, name, .. }) => {
Some(if module.is_empty() {
name.to_string()
} else {
format!("{}.{}", module, name)
})
}
FuncDef::Defined(..) => name.map(|n| String::from_utf8_lossy(&n).into_owned()),
};
err.map_lua_error(|l| LuaError::ArgumentBad(idx, name, Box::new(l)))
}
}
}
pub fn arg_number_coerce(&mut self, idx: usize) -> Result<Numeric> {
self.arg(idx)?
.to_number_coerce()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_int_coerce(&mut self, idx: usize) -> Result<i64> {
self.arg(idx)?
.to_int_coerce()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_float_coerce(&mut self, idx: usize) -> Result<f64> {
self.arg(idx)?
.to_float_coerce()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_string(&mut self, idx: usize) -> Result<Vec<u8>> {
self.arg(idx)?
.into_string()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_string_coerce(&mut self, idx: usize) -> Result<Vec<u8>> {
self.arg(idx)?
.to_string_coerce()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_func(&mut self, idx: usize) -> Result<Rc<FuncDef>> {
self.arg(idx)?.to_func().map_err(|e| self.arg_error(idx, e))
}
pub fn arg_table(&mut self, idx: usize) -> Result<Rc<RefCell<Table>>> {
self.arg(idx)?
.to_table()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_thread(&mut self, idx: usize) -> Result<Rc<RefCell<Thread>>> {
self.arg(idx)?
.to_thread()
.map_err(|e| self.arg_error(idx, e))
}
pub fn arg_file(&mut self, idx: usize) -> Result<Rc<RefCell<FileHandle>>> {
self.arg(idx)?.to_file().map_err(|e| self.arg_error(idx, e))
}
}