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