mod ffi; pub mod parse; use std::ffi::{CStr, CString}; use parse::QuickJSBinary; pub fn compile(src: &[u8], filename: &str) -> QuickJSBinary { unsafe { let filename = CString::new(filename).unwrap(); let rt = ffi::JS_NewRuntime(); let ctx = ffi::JS_NewContext(rt); let obj = ffi::JS_Eval( ctx, src.as_ptr(), src.len(), filename.as_ptr().cast(), ffi::JS_EVAL_FLAG_COMPILE_ONLY | ffi::JS_EVAL_TYPE_MODULE, ); assert!(obj.tag != ffi::JS_TAG_EXCEPTION, "{}", get_exception(ctx)); let mut len = 0; let buf = ffi::JS_WriteObject(ctx, &mut len, obj, ffi::JS_WRITE_OBJ_BYTECODE); ffi::JS_FreeValue(ctx, obj); assert!(!buf.is_null()); let bytes = std::slice::from_raw_parts(buf, len).to_vec(); // TODO: Are we sure other cleanup is not necessary? ffi::JS_FreeContext(ctx); ffi::JS_FreeRuntime(rt); QuickJSBinary::parse(&bytes).unwrap().1 } } fn get_exception(ctx: *mut ffi::JSContext) -> String { unsafe { let err = ffi::JS_GetException(ctx); let text = ffi::JS_ToCStringLen2(ctx, std::ptr::null_mut(), err, false); let message = if text.is_null() { "quickjs raised an exception it could not describe".to_string() } else { CStr::from_ptr(text).to_string_lossy().into_owned() }; message } }