Skip to content

Commit 00c0b14

Browse files
Add more eval functions to c-api
1 parent 5c36d5c commit 00c0b14

2 files changed

Lines changed: 124 additions & 3 deletions

File tree

crates/capi/src/ceval.rs

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use crate::pystate::with_vm;
22
use crate::unicodeobject::decode_fsdefault_and_size;
33
use core::ffi::{CStr, c_char, c_int};
44
use core::ptr::NonNull;
5-
use rustpython_vm::builtins::{PyCode, PyDict};
5+
use rustpython_vm::builtins::{PyCode, PyDict, PyStr};
6+
use rustpython_vm::frame::Frame;
67
use rustpython_vm::function::ArgMapping;
78
use rustpython_vm::scope::Scope;
8-
use rustpython_vm::version;
99
use rustpython_vm::{AsObject, PyObject, TryFromObject};
10+
use rustpython_vm::{PyObjectRef, version};
1011

1112
#[unsafe(no_mangle)]
1213
pub unsafe extern "C" fn Py_CompileString(
@@ -42,6 +43,19 @@ pub unsafe extern "C" fn PyEval_EvalCode(
4243
})
4344
}
4445

46+
#[unsafe(no_mangle)]
47+
pub unsafe extern "C" fn PyEval_EvalFrame(f: *mut PyObject) -> *mut PyObject {
48+
unsafe { PyEval_EvalFrameEx(f, 0) }
49+
}
50+
51+
#[unsafe(no_mangle)]
52+
pub unsafe extern "C" fn PyEval_EvalFrameEx(f: *mut PyObject, _exc: c_int) -> *mut PyObject {
53+
with_vm(|vm| {
54+
let frame = unsafe { &*f }.try_downcast_ref::<Frame>(vm)?.to_owned();
55+
vm.run_frame(frame)
56+
})
57+
}
58+
4559
#[unsafe(no_mangle)]
4660
pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject {
4761
with_vm(|vm| {
@@ -52,6 +66,105 @@ pub extern "C" fn PyEval_GetBuiltins() -> *mut PyObject {
5266
})
5367
}
5468

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

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)