Merge pull request #34 from jonas-schievink/better-error
[WIP] Enhanced errors
This commit is contained in:
commit
16f57d18e5
|
@ -33,7 +33,7 @@ fn main() {
|
|||
);
|
||||
break;
|
||||
}
|
||||
Err(Error::IncompleteStatement(_)) => {
|
||||
Err(Error::SyntaxError { incomplete_input: true, .. }) => {
|
||||
// continue reading input and append it to `line`
|
||||
line.push_str("\n"); // separate input lines
|
||||
prompt = ">> ";
|
||||
|
|
|
@ -39,9 +39,11 @@ impl<'lua> FromLua<'lua> for Table<'lua> {
|
|||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
|
||||
match value {
|
||||
Value::Table(table) => Ok(table),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to table".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "table",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,9 +58,11 @@ impl<'lua> FromLua<'lua> for Function<'lua> {
|
|||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
|
||||
match value {
|
||||
Value::Function(table) => Ok(table),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to function".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "function",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +77,11 @@ impl<'lua> FromLua<'lua> for Thread<'lua> {
|
|||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
|
||||
match value {
|
||||
Value::Thread(t) => Ok(t),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to thread".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "thread",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,9 +96,11 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
|
|||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
|
||||
match value {
|
||||
Value::UserData(ud) => Ok(ud),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to userdata".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "userdata",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,9 +115,11 @@ impl<'lua, T: UserData + Clone> FromLua<'lua> for T {
|
|||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<T> {
|
||||
match value {
|
||||
Value::UserData(ud) => Ok(ud.borrow::<T>()?.clone()),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to userdata".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "userdata",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,12 +166,14 @@ impl<'lua> ToLua<'lua> for LightUserData {
|
|||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for LightUserData {
|
||||
fn from_lua(v: Value, _: &'lua Lua) -> Result<Self> {
|
||||
match v {
|
||||
fn from_lua(value: Value, _: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
Value::LightUserData(ud) => Ok(ud),
|
||||
_ => Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to lightuserdata".to_owned(),
|
||||
)),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "light userdata",
|
||||
message: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,9 +253,11 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
|
|||
if let Value::Table(table) = value {
|
||||
table.sequence_values().collect()
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to table for Vec".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Vec",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,9 +273,11 @@ impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for Has
|
|||
if let Value::Table(table) = value {
|
||||
table.pairs().collect()
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to table for HashMap".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "HashMap",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,9 +293,11 @@ impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<
|
|||
if let Value::Table(table) = value {
|
||||
table.pairs().collect()
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to table for BTreeMap".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "BTreeMap",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
102
src/error.rs
102
src/error.rs
|
@ -6,25 +6,40 @@ use std::result::Result as StdResult;
|
|||
/// Error type returned by rlua methods.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Error {
|
||||
/// Lua syntax error, aka `LUA_ERRSYNTAX` that is NOT an incomplete statement.
|
||||
SyntaxError(String),
|
||||
/// Lua syntax error that IS an incomplete statement. Useful for implementing a REPL.
|
||||
IncompleteStatement(String),
|
||||
/// Syntax error while parsing Lua source code.
|
||||
SyntaxError {
|
||||
/// The error message as returned by Lua.
|
||||
message: String,
|
||||
/// `true` if the error can likely be fixed by appending more input to the source code.
|
||||
///
|
||||
/// This is useful for implementing REPLs as they can query the user for more input if this
|
||||
/// is set.
|
||||
incomplete_input: bool,
|
||||
},
|
||||
/// Lua runtime error, aka `LUA_ERRRUN`.
|
||||
///
|
||||
/// The Lua VM returns this error when a builtin operation is performed on incompatible types.
|
||||
/// Among other things, this includes invoking operators on wrong types (such as calling or
|
||||
/// indexing a `nil` value).
|
||||
RuntimeError(String),
|
||||
/// Lua error from inside an error handler, aka `LUA_ERRERR`.
|
||||
///
|
||||
/// To prevent an infinite recursion when invoking an error handler, this error will be returned
|
||||
/// instead of invoking the error handler.
|
||||
ErrorError(String),
|
||||
/// A Rust value could not be converted to a Lua value.
|
||||
ToLuaConversionError(String),
|
||||
ToLuaConversionError {
|
||||
/// Name of the Rust type that could not be converted.
|
||||
from: &'static str,
|
||||
/// Name of the Lua type that could not be created.
|
||||
to: &'static str,
|
||||
/// A message indicating why the conversion failed in more detail.
|
||||
message: Option<String>,
|
||||
},
|
||||
/// A Lua value could not be converted to the expected Rust type.
|
||||
FromLuaConversionError(String),
|
||||
FromLuaConversionError {
|
||||
/// Name of the Lua type that could not be converted.
|
||||
from: &'static str,
|
||||
/// Name of the Rust type that could not be created.
|
||||
to: &'static str,
|
||||
/// A string containing more detailed error information.
|
||||
message: Option<String>,
|
||||
},
|
||||
/// [`Thread::resume`] was called on an inactive coroutine.
|
||||
///
|
||||
/// A coroutine is inactive if its main function has returned or if an error has occured inside
|
||||
|
@ -64,9 +79,12 @@ pub enum Error {
|
|||
/// [`UserData`]: trait.UserData.html
|
||||
UserDataBorrowMutError,
|
||||
/// A Rust callback returned `Err`, raising the contained `Error` as a Lua error.
|
||||
///
|
||||
/// The first field is the Lua traceback, the second field holds the original error.
|
||||
CallbackError(String, Arc<Error>),
|
||||
CallbackError {
|
||||
/// Lua call stack backtrace.
|
||||
traceback: String,
|
||||
/// Original error returned by the Rust code.
|
||||
cause: Arc<Error>,
|
||||
},
|
||||
/// A custom error.
|
||||
///
|
||||
/// This can be used for returning user-defined errors from callbacks.
|
||||
|
@ -83,23 +101,27 @@ pub type Result<T> = StdResult<T, Error>;
|
|||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::SyntaxError(ref msg) => write!(fmt, "Lua syntax error: {}", msg),
|
||||
Error::IncompleteStatement(ref msg) => {
|
||||
write!(fmt, "Lua syntax error (incomplete statement): {}", msg)
|
||||
Error::SyntaxError { ref message, .. } => write!(fmt, "syntax error: {}", message),
|
||||
Error::RuntimeError(ref msg) => write!(fmt, "runtime error: {}", msg),
|
||||
Error::ToLuaConversionError { from, to, ref message } => {
|
||||
write!(fmt, "error converting {} to Lua {}", from, to)?;
|
||||
match *message {
|
||||
None => Ok(()),
|
||||
Some(ref message) => write!(fmt, " ({})", message),
|
||||
}
|
||||
}
|
||||
Error::RuntimeError(ref msg) => write!(fmt, "Lua runtime error: {}", msg),
|
||||
Error::ErrorError(ref msg) => write!(fmt, "Lua error in error handler: {}", msg),
|
||||
Error::ToLuaConversionError(ref msg) => {
|
||||
write!(fmt, "Error converting rust type to lua: {}", msg)
|
||||
Error::FromLuaConversionError { from, to, ref message } => {
|
||||
write!(fmt, "error converting Lua {} to {}", from, to)?;
|
||||
match *message {
|
||||
None => Ok(()),
|
||||
Some(ref message) => write!(fmt, " ({})", message),
|
||||
}
|
||||
}
|
||||
Error::FromLuaConversionError(ref msg) => {
|
||||
write!(fmt, "Error converting lua type to rust: {}", msg)
|
||||
}
|
||||
Error::CoroutineInactive => write!(fmt, "Cannot resume inactive coroutine"),
|
||||
Error::UserDataTypeMismatch => write!(fmt, "Userdata not expected type"),
|
||||
Error::UserDataBorrowError => write!(fmt, "Userdata already mutably borrowed"),
|
||||
Error::UserDataBorrowMutError => write!(fmt, "Userdata already borrowed"),
|
||||
Error::CallbackError(ref msg, _) => write!(fmt, "Error during lua callback: {}", msg),
|
||||
Error::CoroutineInactive => write!(fmt, "cannot resume inactive coroutine"),
|
||||
Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
|
||||
Error::UserDataBorrowError => write!(fmt, "userdata already mutably borrowed"),
|
||||
Error::UserDataBorrowMutError => write!(fmt, "userdata already borrowed"),
|
||||
Error::CallbackError { ref cause, .. } => write!(fmt, "{}", cause),
|
||||
Error::ExternalError(ref err) => err.fmt(fmt),
|
||||
}
|
||||
}
|
||||
|
@ -108,24 +130,22 @@ impl fmt::Display for Error {
|
|||
impl StdError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::SyntaxError(_) => "lua syntax error",
|
||||
Error::IncompleteStatement(_) => "lua incomplete statement",
|
||||
Error::RuntimeError(_) => "lua runtime error",
|
||||
Error::ErrorError(_) => "lua error handling error",
|
||||
Error::ToLuaConversionError(_) => "conversion error to lua",
|
||||
Error::FromLuaConversionError(_) => "conversion error from lua",
|
||||
Error::CoroutineInactive => "lua coroutine inactive",
|
||||
Error::UserDataTypeMismatch => "lua userdata type mismatch",
|
||||
Error::UserDataBorrowError => "lua userdata already mutably borrowed",
|
||||
Error::UserDataBorrowMutError => "lua userdata already borrowed",
|
||||
Error::CallbackError(_, _) => "lua callback error",
|
||||
Error::SyntaxError { .. } => "syntax error",
|
||||
Error::RuntimeError(_) => "runtime error",
|
||||
Error::ToLuaConversionError { .. } => "conversion error to lua",
|
||||
Error::FromLuaConversionError { .. } => "conversion error from lua",
|
||||
Error::CoroutineInactive => "attempt to resume inactive coroutine",
|
||||
Error::UserDataTypeMismatch => "userdata type mismatch",
|
||||
Error::UserDataBorrowError => "userdata already mutably borrowed",
|
||||
Error::UserDataBorrowMutError => "userdata already borrowed",
|
||||
Error::CallbackError { ref cause, .. } => cause.description(),
|
||||
Error::ExternalError(ref err) => err.description(),
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
Error::CallbackError(_, ref cause) => Some(cause.as_ref()),
|
||||
Error::CallbackError { ref cause, .. } => Some(cause.as_ref()),
|
||||
Error::ExternalError(ref err) => err.cause(),
|
||||
_ => None,
|
||||
}
|
||||
|
|
76
src/lua.rs
76
src/lua.rs
|
@ -47,6 +47,24 @@ pub enum Value<'lua> {
|
|||
}
|
||||
pub use self::Value::Nil;
|
||||
|
||||
impl<'lua> Value<'lua> {
|
||||
pub(crate) fn type_name(&self) -> &'static str {
|
||||
match *self {
|
||||
Value::Nil => "nil",
|
||||
Value::Boolean(_) => "boolean",
|
||||
Value::LightUserData(_) => "light userdata",
|
||||
Value::Integer(_) => "integer",
|
||||
Value::Number(_) => "number",
|
||||
Value::String(_) => "string",
|
||||
Value::Table(_) => "table",
|
||||
Value::Function(_) => "function",
|
||||
Value::Thread(_) => "thread",
|
||||
Value::UserData(_) => "userdata",
|
||||
Value::Error(_) => "userdata",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types convertible to `Value`.
|
||||
pub trait ToLua<'a> {
|
||||
/// Performs the conversion.
|
||||
|
@ -190,7 +208,11 @@ impl<'lua> String<'lua> {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn to_str(&self) -> Result<&str> {
|
||||
str::from_utf8(self.as_bytes()).map_err(|e| Error::FromLuaConversionError(e.to_string()))
|
||||
str::from_utf8(self.as_bytes()).map_err(|e| Error::FromLuaConversionError {
|
||||
from: "string",
|
||||
to: "&str",
|
||||
message: Some(e.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the bytes that make up this string.
|
||||
|
@ -1083,10 +1105,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
method(lua, &userdata, A::from_lua_multi(args, lua)?)?
|
||||
.to_lua_multi(lua)
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"No userdata supplied as first argument to method"
|
||||
.to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: "missing argument",
|
||||
to: "userdata",
|
||||
message: None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1102,11 +1125,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
method(lua, &mut userdata, A::from_lua_multi(args, lua)?)?
|
||||
.to_lua_multi(lua)
|
||||
} else {
|
||||
Err(
|
||||
Error::FromLuaConversionError(
|
||||
"No userdata supplied as first argument to method".to_owned(),
|
||||
).into(),
|
||||
)
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: "missing argument",
|
||||
to: "userdata",
|
||||
message: None,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1400,7 +1423,11 @@ impl Lua {
|
|||
self.state,
|
||||
if let Some(name) = name {
|
||||
let name = CString::new(name.to_owned()).map_err(|e| {
|
||||
Error::ToLuaConversionError(e.to_string())
|
||||
Error::ToLuaConversionError {
|
||||
from: "&str",
|
||||
to: "string",
|
||||
message: Some(e.to_string()),
|
||||
}
|
||||
})?;
|
||||
ffi::luaL_loadbuffer(
|
||||
self.state,
|
||||
|
@ -1621,12 +1648,15 @@ impl Lua {
|
|||
v => unsafe {
|
||||
stack_guard(self.state, 0, || {
|
||||
check_stack(self.state, 1);
|
||||
let ty = v.type_name();
|
||||
self.push_value(self.state, v);
|
||||
if ffi::lua_tostring(self.state, -1).is_null() {
|
||||
ffi::lua_pop(self.state, 1);
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to string".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: "String",
|
||||
message: Some("expected string or number".to_string()),
|
||||
})
|
||||
} else {
|
||||
Ok(String(self.pop_ref(self.state)))
|
||||
}
|
||||
|
@ -1645,14 +1675,17 @@ impl Lua {
|
|||
v => unsafe {
|
||||
stack_guard(self.state, 0, || {
|
||||
check_stack(self.state, 1);
|
||||
let ty = v.type_name();
|
||||
self.push_value(self.state, v);
|
||||
let mut isint = 0;
|
||||
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
|
||||
ffi::lua_pop(self.state, 1);
|
||||
if isint == 0 {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to integer".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: "integer",
|
||||
message: None,
|
||||
})
|
||||
} else {
|
||||
Ok(i)
|
||||
}
|
||||
|
@ -1671,14 +1704,17 @@ impl Lua {
|
|||
v => unsafe {
|
||||
stack_guard(self.state, 0, || {
|
||||
check_stack(self.state, 1);
|
||||
let ty = v.type_name();
|
||||
self.push_value(self.state, v);
|
||||
let mut isnum = 0;
|
||||
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
|
||||
ffi::lua_pop(self.state, 1);
|
||||
if isnum == 0 {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"cannot convert lua value to number".to_owned(),
|
||||
))
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: "number",
|
||||
message: Some("number or string coercible to number".to_string()),
|
||||
})
|
||||
} else {
|
||||
Ok(n)
|
||||
}
|
||||
|
|
10
src/tests.rs
10
src/tests.rs
|
@ -69,8 +69,8 @@ fn test_eval() {
|
|||
assert_eq!(lua.eval::<bool>("false == false", None).unwrap(), true);
|
||||
assert_eq!(lua.eval::<i32>("return 1 + 2", None).unwrap(), 3);
|
||||
match lua.eval::<()>("if true then", None) {
|
||||
Err(Error::IncompleteStatement(_)) => {}
|
||||
r => panic!("expected IncompleteStatement, got {:?}", r),
|
||||
Err(Error::SyntaxError { incomplete_input: true, .. }) => {}
|
||||
r => panic!("expected SyntaxError with incomplete_input=true, got {:?}", r),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ fn test_error() {
|
|||
_ => panic!("error not returned"),
|
||||
}
|
||||
match rust_error.call::<_, ()>(()) {
|
||||
Err(Error::CallbackError(_, _)) => {}
|
||||
Err(Error::CallbackError { .. }) => {}
|
||||
Err(_) => panic!("error is not CallbackError kind"),
|
||||
_ => panic!("error not returned"),
|
||||
}
|
||||
|
@ -514,12 +514,12 @@ fn test_error() {
|
|||
assert!(return_string_error.call::<_, Error>(()).is_ok());
|
||||
|
||||
match lua.eval::<()>("if youre happy and you know it syntax error", None) {
|
||||
Err(Error::SyntaxError(_)) => {}
|
||||
Err(Error::SyntaxError { incomplete_input: false, .. }) => {}
|
||||
Err(_) => panic!("error is not LuaSyntaxError::Syntax kind"),
|
||||
_ => panic!("error not returned"),
|
||||
}
|
||||
match lua.eval::<()>("function i_will_finish_what_i()", None) {
|
||||
Err(Error::IncompleteStatement(_)) => {}
|
||||
Err(Error::SyntaxError { incomplete_input: true, .. }) => {}
|
||||
Err(_) => panic!("error is not LuaSyntaxError::IncompleteStatement kind"),
|
||||
_ => panic!("error not returned"),
|
||||
}
|
||||
|
|
56
src/util.rs
56
src/util.rs
|
@ -245,10 +245,10 @@ pub unsafe fn pnext(state: *mut ffi::lua_State, index: c_int) -> Result<c_int> {
|
|||
}
|
||||
|
||||
// If the return code indicates an error, pops the error off of the stack and
|
||||
// returns Err. If the error is actually a WrappedPaic, clears the current lua
|
||||
// stack continues the panic. If the error on the top of the stack is actually
|
||||
// a WrappedError, just returns it. Otherwise, interprets the error as the
|
||||
// appropriate lua error.
|
||||
// returns Err. If the error is actually a WrappedPanic, clears the current lua
|
||||
// stack and continues the panic. If the error on the top of the stack is
|
||||
// actually a WrappedError, just returns it. Otherwise, interprets the error as
|
||||
// the appropriate lua error.
|
||||
pub unsafe fn handle_error(state: *mut ffi::lua_State, err: c_int) -> Result<()> {
|
||||
if err == ffi::LUA_OK || err == ffi::LUA_YIELD {
|
||||
Ok(())
|
||||
|
@ -280,15 +280,20 @@ pub unsafe fn handle_error(state: *mut ffi::lua_State, err: c_int) -> Result<()>
|
|||
Err(match err {
|
||||
ffi::LUA_ERRRUN => Error::RuntimeError(err_string),
|
||||
ffi::LUA_ERRSYNTAX => {
|
||||
// This seems terrible, but as far as I can tell, this is exactly what the stock
|
||||
// lua repl does.
|
||||
if err_string.ends_with("<eof>") {
|
||||
Error::IncompleteStatement(err_string)
|
||||
} else {
|
||||
Error::SyntaxError(err_string)
|
||||
Error::SyntaxError {
|
||||
// This seems terrible, but as far as I can tell, this is exactly what the
|
||||
// stock Lua REPL does.
|
||||
incomplete_input: err_string.ends_with("<eof>"),
|
||||
message: err_string,
|
||||
}
|
||||
}
|
||||
ffi::LUA_ERRERR => Error::ErrorError(err_string),
|
||||
ffi::LUA_ERRERR => {
|
||||
// The Lua manual documents this error wrongly: It is not raised when a message
|
||||
// handler errors, but rather when some specific situations regarding stack
|
||||
// overflow handling occurs. Since it is not very useful do differentiate
|
||||
// between that and "ordinary" runtime errors, we handle them the same way.
|
||||
Error::RuntimeError(err_string)
|
||||
}
|
||||
ffi::LUA_ERRMEM => {
|
||||
// TODO: We should provide lua with custom allocators that guarantee aborting on
|
||||
// OOM, instead of relying on the system allocator. Currently, this is a
|
||||
|
@ -374,18 +379,21 @@ pub unsafe fn pcall_with_traceback(
|
|||
if let Some(error) = pop_wrapped_error(state) {
|
||||
ffi::luaL_traceback(state, state, ptr::null(), 0);
|
||||
let traceback = CStr::from_ptr(ffi::lua_tolstring(state, -1, ptr::null_mut()))
|
||||
.to_str()
|
||||
.unwrap_or_else(|_| "<could not capture traceback>")
|
||||
.to_owned();
|
||||
push_wrapped_error(state, Error::CallbackError(traceback, Arc::new(error)));
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
push_wrapped_error(state, Error::CallbackError {
|
||||
traceback,
|
||||
cause: Arc::new(error),
|
||||
});
|
||||
ffi::lua_remove(state, -2);
|
||||
} else if !is_wrapped_panic(state, 1) {
|
||||
let s = ffi::lua_tolstring(state, 1, ptr::null_mut());
|
||||
if !s.is_null() {
|
||||
ffi::luaL_traceback(state, state, s, 0);
|
||||
let s = if s.is_null() {
|
||||
cstr!("<unprintable Rust panic>")
|
||||
} else {
|
||||
ffi::luaL_traceback(state, state, cstr!("<unprintable lua error>"), 0);
|
||||
}
|
||||
s
|
||||
};
|
||||
ffi::luaL_traceback(state, state, s, 0);
|
||||
ffi::lua_remove(state, -2);
|
||||
}
|
||||
1
|
||||
|
@ -412,7 +420,10 @@ pub unsafe fn resume_with_traceback(
|
|||
.to_str()
|
||||
.unwrap_or_else(|_| "<could not capture traceback>")
|
||||
.to_owned();
|
||||
push_wrapped_error(state, Error::CallbackError(traceback, Arc::new(error)));
|
||||
push_wrapped_error(state, Error::CallbackError {
|
||||
traceback,
|
||||
cause: Arc::new(error),
|
||||
});
|
||||
ffi::lua_remove(state, -2);
|
||||
} else if !is_wrapped_panic(state, 1) {
|
||||
let s = ffi::lua_tolstring(state, 1, ptr::null_mut());
|
||||
|
@ -545,10 +556,7 @@ pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) {
|
|||
Ok(1)
|
||||
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"internal error: userdata mismatch in Error metamethod"
|
||||
.to_owned(),
|
||||
))
|
||||
panic!("internal error: userdata mismatch in Error metamethod");
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue