Skip to content

Commit 51bc472

Browse files
Add more eval functions to c-api
1 parent 5c36d5c commit 51bc472

3 files changed

Lines changed: 125 additions & 3 deletions

File tree

crates/capi/src/ceval.rs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
use crate::pyframe::PyFrameObject;
12
use crate::pystate::with_vm;
23
use crate::unicodeobject::decode_fsdefault_and_size;
34
use core::ffi::{CStr, c_char, c_int};
45
use core::ptr::NonNull;
5-
use rustpython_vm::builtins::{PyCode, PyDict};
6+
use rustpython_vm::builtins::{PyCode, PyDict, PyStr};
7+
use rustpython_vm::frame::Frame;
68
use rustpython_vm::function::ArgMapping;
79
use rustpython_vm::scope::Scope;
8-
use rustpython_vm::version;
910
use rustpython_vm::{AsObject, PyObject, TryFromObject};
11+
use rustpython_vm::{PyObjectRef, version};
1012

1113
#[unsafe(no_mangle)]
1214
pub unsafe extern "C" fn Py_CompileString(
@@ -42,6 +44,16 @@ pub unsafe extern "C" fn PyEval_EvalCode(
4244
})
4345
}
4446

47+
#[unsafe(no_mangle)]
48+
pub unsafe extern "C" fn PyEval_EvalFrame(f: *mut PyFrameObject) -> *mut PyObject {
49+
unsafe { PyEval_EvalFrameEx(f, 0) }
50+
}
51+
52+
#[unsafe(no_mangle)]
53+
pub unsafe extern "C" fn PyEval_EvalFrameEx(f: *mut PyFrameObject, _exc: c_int) -> *mut PyObject {
54+
with_vm(|vm| vm.run_frame(unsafe { &*f }.to_owned()))
55+
}
56+
4557
#[unsafe(no_mangle)]
4658
pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject {
4759
with_vm(|vm| {
@@ -52,6 +64,105 @@ pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject {
5264
})
5365
}
5466

67+
#[unsafe(no_mangle)]
68+
pub extern "C" fn PyEval_GetFrame() -> *mut PyObject {
69+
with_vm(|vm| {
70+
vm.current_frame()
71+
.map(|frame| frame.as_object().as_raw())
72+
.unwrap_or_default()
73+
})
74+
}
75+
76+
#[unsafe(no_mangle)]
77+
pub extern "C" fn PyEval_GetFrameBuiltins() -> *mut PyObject {
78+
with_vm(|vm| {
79+
vm.current_frame().map_or_else(
80+
|| vm.builtins.as_object().to_owned(),
81+
|frame| frame.builtins.as_object().to_owned(),
82+
)
83+
})
84+
}
85+
86+
#[unsafe(no_mangle)]
87+
pub extern "C" fn PyEval_GetFrameGlobals() -> *mut PyObject {
88+
with_vm(|vm| {
89+
vm.current_frame()
90+
.map(|frame| frame.globals.as_object().to_owned().into_raw().as_ptr())
91+
.unwrap_or_default()
92+
})
93+
}
94+
95+
#[unsafe(no_mangle)]
96+
pub extern "C" fn PyEval_GetFrameLocals() -> *mut PyObject {
97+
with_vm(|vm| {
98+
let Some(frame) = vm.current_frame() else {
99+
return Ok(core::ptr::null_mut());
100+
};
101+
let locals: PyObjectRef = frame.locals(vm)?.into();
102+
Ok(locals.into_raw().as_ptr())
103+
})
104+
}
105+
106+
#[unsafe(no_mangle)]
107+
pub extern "C" fn PyEval_GetGlobals() -> *mut PyObject {
108+
with_vm(|vm| {
109+
vm.current_frame()
110+
.map(|frame| frame.globals.as_object().as_raw())
111+
.unwrap_or_default()
112+
})
113+
}
114+
115+
#[unsafe(no_mangle)]
116+
pub extern "C" fn PyEval_GetLocals() -> *mut PyObject {
117+
with_vm(|vm| {
118+
vm.current_frame()
119+
.map(|frame| frame.locals.as_object(vm).as_raw())
120+
.unwrap_or_default()
121+
})
122+
}
123+
124+
#[unsafe(no_mangle)]
125+
pub unsafe extern "C" fn PyEval_GetFuncName(func: *mut PyObject) -> *const c_char {
126+
with_vm(|vm| {
127+
let func = unsafe { &*func };
128+
let cls = func.class();
129+
130+
if cls.is(vm.ctx.types.bound_method_type) {
131+
let function = func.get_attr("__func__", vm)?;
132+
return Ok(unsafe { PyEval_GetFuncName(function.as_object().as_raw().cast_mut()) });
133+
}
134+
135+
let name = if cls.is(vm.ctx.types.function_type)
136+
|| cls.is(vm.ctx.types.builtin_function_or_method_type)
137+
{
138+
func.get_attr(rustpython_vm::identifier!(vm, __name__), vm)?
139+
.downcast_ref::<PyStr>()
140+
.and_then(|s| s.to_str())
141+
.map_or_else(|| cls.name().as_ptr(), |s| s.as_ptr())
142+
} else {
143+
cls.name().as_ptr()
144+
};
145+
146+
Ok(name.cast())
147+
})
148+
}
149+
150+
#[unsafe(no_mangle)]
151+
pub unsafe extern "C" fn PyEval_GetFuncDesc(func: *mut PyObject) -> *const c_char {
152+
with_vm(|vm| {
153+
let func = unsafe { &*func };
154+
let cls = func.class();
155+
if cls.is(vm.ctx.types.bound_method_type)
156+
|| cls.is(vm.ctx.types.function_type)
157+
|| cls.is(vm.ctx.types.builtin_function_or_method_type)
158+
{
159+
c"()"
160+
} else {
161+
c" object"
162+
}
163+
})
164+
}
165+
55166
#[cfg(test)]
56167
mod tests {
57168
use pyo3::exceptions::PyException;

crates/capi/src/pyframe.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use crate::PyObject;
22
use crate::pystate::with_vm;
3+
use rustpython_vm::Py;
34
use rustpython_vm::frame::Frame;
45

6+
pub type PyFrameObject = Py<Frame>;
7+
58
#[unsafe(no_mangle)]
69
pub unsafe extern "C" fn PyFrame_GetCode(frame: *mut PyObject) -> *mut PyObject {
710
with_vm(|vm| {

crates/capi/src/util.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::PyObject;
22
use core::convert::Infallible;
3-
use core::ffi::{c_char, c_double, c_int, c_long, c_ulong, c_void};
3+
use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_ulong, c_void};
44
use rustpython_vm::{PyObjectRef, PyRef, PyResult, VirtualMachine};
55

66
pub(crate) trait FfiResult<Output = Self> {
@@ -92,6 +92,14 @@ impl FfiResult for *const c_char {
9292
}
9393
}
9494

95+
impl FfiResult<*const c_char> for &CStr {
96+
const ERR_VALUE: *const c_char = core::ptr::null_mut();
97+
98+
fn into_output(self, _vm: &VirtualMachine) -> *const c_char {
99+
self.as_ptr()
100+
}
101+
}
102+
95103
impl FfiResult<isize> for usize {
96104
const ERR_VALUE: isize = -1;
97105

0 commit comments

Comments
 (0)