diff --git a/crates/capi/src/ceval.rs b/crates/capi/src/ceval.rs index d137cb17dab..366cb0071bb 100644 --- a/crates/capi/src/ceval.rs +++ b/crates/capi/src/ceval.rs @@ -1,3 +1,4 @@ +use crate::pyframe::PyFrameObject; use crate::pystate::with_vm; use crate::unicodeobject::decode_fsdefault_and_size; use core::ffi::{CStr, c_char, c_int}; @@ -5,8 +6,8 @@ use core::ptr::NonNull; use rustpython_vm::builtins::{PyCode, PyDict}; use rustpython_vm::function::ArgMapping; use rustpython_vm::scope::Scope; -use rustpython_vm::version; use rustpython_vm::{AsObject, PyObject, TryFromObject}; +use rustpython_vm::{PyObjectRef, version}; #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_CompileString( @@ -42,6 +43,16 @@ pub unsafe extern "C" fn PyEval_EvalCode( }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyEval_EvalFrame(f: *mut PyFrameObject) -> *mut PyObject { + unsafe { PyEval_EvalFrameEx(f, 0) } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyEval_EvalFrameEx(f: *mut PyFrameObject, _exc: c_int) -> *mut PyObject { + with_vm(|vm| vm.run_frame(unsafe { &*f }.to_owned())) +} + #[unsafe(no_mangle)] pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject { with_vm(|vm| { @@ -52,6 +63,82 @@ pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject { }) } +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetFrame() -> *mut PyFrameObject { + with_vm(|vm| -> *mut PyObject { + vm.current_frame() + .map(|frame| frame.as_object().as_raw().cast_mut()) + .unwrap_or_default() + }) + .cast() +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetFrameBuiltins() -> *mut PyObject { + with_vm(|vm| { + vm.current_frame().map_or_else( + || vm.builtins.as_object().to_owned(), + |frame| frame.builtins.as_object().to_owned(), + ) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetFrameGlobals() -> *mut PyObject { + with_vm(|vm| { + vm.current_frame() + .map(|frame| frame.globals.as_object().to_owned().into_raw().as_ptr()) + .unwrap_or_default() + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetFrameLocals() -> *mut PyObject { + with_vm(|vm| { + let Some(frame) = vm.current_frame() else { + return Ok(core::ptr::null_mut()); + }; + let locals: PyObjectRef = frame.locals(vm)?.into(); + Ok(locals.into_raw().as_ptr()) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetGlobals() -> *mut PyObject { + with_vm(|vm| { + vm.current_frame() + .map(|frame| frame.globals.as_object().as_raw()) + .unwrap_or_default() + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyEval_GetLocals() -> *mut PyObject { + with_vm(|vm| { + let Some(frame) = vm.current_frame() else { + return Ok(core::ptr::null_mut()); + }; + let _ = frame.locals(vm)?; + Ok(frame.locals.as_object(vm).as_raw().cast_mut()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyEval_GetFuncDesc(func: *mut PyObject) -> *const c_char { + with_vm(|vm| { + let func = unsafe { &*func }; + let cls = func.class(); + if cls.is(vm.ctx.types.bound_method_type) + || cls.is(vm.ctx.types.function_type) + || cls.is(vm.ctx.types.builtin_function_or_method_type) + { + c"()" + } else { + c" object" + } + }) +} + #[cfg(test)] mod tests { use pyo3::exceptions::PyException; diff --git a/crates/capi/src/pyframe.rs b/crates/capi/src/pyframe.rs index d8e9d124bb0..5c9ad371708 100644 --- a/crates/capi/src/pyframe.rs +++ b/crates/capi/src/pyframe.rs @@ -1,19 +1,21 @@ -use crate::PyObject; use crate::pystate::with_vm; +use core::ffi::c_int; +use rustpython_vm::Py; +use rustpython_vm::builtins::PyCode; use rustpython_vm::frame::Frame; +pub type PyFrameObject = Py; +pub type PyCodeObject = Py; + #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyFrame_GetCode(frame: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let frame = unsafe { &*frame }.try_downcast_ref::(vm)?; - Ok(frame.f_code()) - }) +pub unsafe extern "C" fn PyFrame_GetCode(frame: *mut PyFrameObject) -> *mut PyCodeObject { + with_vm(|_vm| Ok(unsafe { &*frame }.f_code())) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyFrame_GetLineNumber(frame: *mut PyObject) -> core::ffi::c_int { - with_vm(|vm| { - let frame = unsafe { &*frame }.try_downcast_ref::(vm)?; - Ok(frame.f_lineno() as core::ffi::c_int) +pub unsafe extern "C" fn PyFrame_GetLineNumber(frame: *mut PyFrameObject) -> c_int { + with_vm(|_vm| { + let lineno = unsafe { &*frame }.f_lineno(); + Ok(lineno.try_into().unwrap_or(c_int::MAX)) }) } diff --git a/crates/capi/src/util.rs b/crates/capi/src/util.rs index ccb8ee254af..6bbda7654fe 100644 --- a/crates/capi/src/util.rs +++ b/crates/capi/src/util.rs @@ -1,7 +1,7 @@ use crate::PyObject; use core::convert::Infallible; -use core::ffi::{c_char, c_double, c_int, c_long, c_ulong, c_void}; -use rustpython_vm::{PyObjectRef, PyRef, PyResult, VirtualMachine}; +use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_ulong, c_void}; +use rustpython_vm::{Py, PyObjectRef, PyRef, PyResult, VirtualMachine}; pub(crate) trait FfiResult { const ERR_VALUE: Output; @@ -36,6 +36,17 @@ where } } +impl FfiResult<*mut Py> for PyRef +where + Self: Into, +{ + const ERR_VALUE: *mut Py = core::ptr::null_mut(); + + fn into_output(self, _vm: &VirtualMachine) -> *mut Py { + self.into().into_raw().as_ptr().cast() + } +} + impl FfiResult<*mut PyObject> for PyObjectRef { const ERR_VALUE: *mut PyObject = core::ptr::null_mut(); @@ -92,6 +103,14 @@ impl FfiResult for *const c_char { } } +impl FfiResult<*const c_char> for &CStr { + const ERR_VALUE: *const c_char = core::ptr::null_mut(); + + fn into_output(self, _vm: &VirtualMachine) -> *const c_char { + self.as_ptr() + } +} + impl FfiResult for usize { const ERR_VALUE: isize = -1;