109 lines
3.6 KiB
Rust
109 lines
3.6 KiB
Rust
use oden_js_sys as sys;
|
|
use std::ffi::{CString, NulError};
|
|
use thiserror::Error;
|
|
|
|
mod atom;
|
|
mod callback;
|
|
mod class;
|
|
mod context;
|
|
mod conversion;
|
|
pub mod module;
|
|
mod runtime;
|
|
mod value;
|
|
|
|
pub use atom::{Atom, AtomRef};
|
|
pub use class::{Class, ClassID};
|
|
pub use context::{Context, ContextRef, EvalFlags};
|
|
pub use conversion::*;
|
|
pub use runtime::Runtime;
|
|
pub use value::{Value, ValueRef, ValueType};
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Error {
|
|
#[error("too many classes have been registered")]
|
|
TooManyClasses,
|
|
#[error("the specified value is not an instance of the class {0}")]
|
|
WrongClass(String),
|
|
#[error("input script contained an embedded NUL byte")]
|
|
UnexpectedNul,
|
|
#[error("the target context is from a different runtime")]
|
|
DifferentRuntime,
|
|
#[error("the specified value had the wrong type (expected {expected:?}, found {found:?})")]
|
|
InvalidType {
|
|
expected: ValueType,
|
|
found: ValueType,
|
|
},
|
|
#[error("argument count mismatch, expected {expected} but received {received}")]
|
|
ArgumentCountMismatch { expected: usize, received: usize },
|
|
#[error("a conversion error occurred: {0}")]
|
|
ConversionError(String),
|
|
#[error("an error occurred calling a rust function: {0}")]
|
|
RustFunctionError(String),
|
|
#[error("an exception was thrown during evaluation: {1}\nStack: {2}")]
|
|
Exception(Value, String, String),
|
|
#[error("out of memory")]
|
|
OutOfMemory,
|
|
#[error("an io error occurred: {0}")]
|
|
IOError(std::io::Error),
|
|
#[error("one or more errors occurred parsing {0}: {1}")]
|
|
ParseError(String, String),
|
|
}
|
|
|
|
impl From<NulError> for Error {
|
|
fn from(_: NulError) -> Self {
|
|
Error::UnexpectedNul
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for Error {
|
|
fn from(e: std::io::Error) -> Self {
|
|
Error::IOError(e)
|
|
}
|
|
}
|
|
|
|
pub type Result<T> = core::result::Result<T, Error>;
|
|
pub type ValueResult = core::result::Result<Value, Error>;
|
|
|
|
pub(crate) fn throw_error(context: &ContextRef, error: Error) -> sys::JSValue {
|
|
match error {
|
|
Error::Exception(v, _, _) => unsafe {
|
|
sys::JS_DupValue(context.ctx, v.val);
|
|
sys::JS_Throw(context.ctx, v.val)
|
|
},
|
|
other => throw_string(context, other.to_string()),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn throw_string(context: &ContextRef, message: String) -> sys::JSValue {
|
|
let ctx = context.ctx;
|
|
match context.new_string(&message) {
|
|
Ok(e) => unsafe {
|
|
// Because context.new_string yields an owned Value, and will
|
|
// clean it up on the way out, we need to explicitly DupValue a
|
|
// reference for the `Throw` to own.
|
|
let err = sys::JS_NewError(ctx);
|
|
if sys::JS_ValueGetTag(err) == sys::JS_TAG_EXCEPTION {
|
|
// GIVE UP; this is out of memory anyway things probably went
|
|
// wrong because of that.
|
|
return err;
|
|
}
|
|
|
|
sys::JS_DupValue(ctx, e.val); // SetProperty takes ownership.
|
|
let prop = CString::new("message").unwrap();
|
|
if sys::JS_SetPropertyStr(ctx, err, prop.as_ptr(), e.val) == -1 {
|
|
// Also an out of memory but we need to free the error object
|
|
// on our way out.
|
|
sys::JS_FreeValue(ctx, err);
|
|
return sys::JS_MakeException(); // JS_EXCEPTION
|
|
}
|
|
|
|
sys::JS_Throw(ctx, err)
|
|
},
|
|
Err(_) => unsafe {
|
|
sys::JS_Throw(
|
|
ctx,
|
|
sys::JS_NewString(ctx, "Errors within errors: embedded nulls in the description of the error that occurred".as_bytes().as_ptr() as *const i8),
|
|
)
|
|
},
|
|
}
|
|
}
|