add py_exec and py_eval prototype

This commit is contained in:
blueloveTH 2024-05-10 12:06:25 +08:00
parent 44aed24d3b
commit 331dedcd28
5 changed files with 69 additions and 25 deletions

View File

@ -90,7 +90,34 @@ struct function<Ret(Params...)>{
template<typename F>
function(F&& f) : _impl(std::forward<F>(f)){
_wrapper = [](const any& impl, Params... params) -> Ret{
return impl.cast<std::decay_t<F>>()(std::forward<Params>(params)...);
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
};
}
Ret operator()(Params... params) const{
if(!_wrapper) throw std::runtime_error("empty function");
return _wrapper(_impl, std::forward<Params>(params)...);
}
};
template<typename T>
struct lightfunction;
template<typename Ret, typename... Params>
struct lightfunction<Ret(Params...)>{
void* _impl;
Ret (*_wrapper)(void*, Params...);
lightfunction() : _impl(nullptr), _wrapper(nullptr) {}
operator bool() const { return _wrapper != nullptr; }
template<typename F>
lightfunction(const F& f){
_impl = (F*)(&f);
_wrapper = [](void* impl, Params... params) -> Ret{
F* f = (F*)(impl);
return (*f)(std::forward<Params>(params)...);
};
}

View File

@ -207,6 +207,9 @@ public:
bool py_ne(PyObject* lhs, PyObject* rhs) { // (lhs, rhs) -> lhs != rhs
return !py_eq(lhs, rhs);
}
void py_exec(std::string_view, PyObject*, PyObject*); // exec(source, globals, locals)
PyObject* py_eval(std::string_view, PyObject*, PyObject*); // eval(source, globals, locals)
#endif
#if PK_REGION("Utility Methods")
@ -408,7 +411,7 @@ public:
#endif
void __breakpoint();
PyObject* __format_object(PyObject*, Str);
PyObject* __run_top_frame();
PyObject* __run_top_frame(lightfunction<void(Frame*)> on_will_pop_base_frame = {});
void __pop_frame();
PyObject* __py_generator(Frame&& frame, ArgsView buffer);
void __op_unpack_sequence(uint16_t arg);

View File

@ -80,7 +80,7 @@ bool VM::py_ge(PyObject* _0, PyObject* _1){
#undef BINARY_F_COMPARE
PyObject* VM::__run_top_frame(){
PyObject* VM::__run_top_frame(lightfunction<void(Frame*)> on_will_pop_base_frame){
Frame* frame = &callstack.top();
const Frame* base_frame = frame;
bool need_raise = false;
@ -709,10 +709,12 @@ __NEXT_STEP:;
} DISPATCH()
case OP_RETURN_VALUE:{
PyObject* _0 = byte.arg == BC_NOARG ? POPX() : None;
__pop_frame();
if(frame == base_frame){ // [ frameBase<- ]
if(on_will_pop_base_frame) on_will_pop_base_frame(frame);
__pop_frame();
return _0;
}else{
__pop_frame();
frame = &callstack.top();
PUSH(_0);
goto __NEXT_FRAME;
@ -982,6 +984,9 @@ __NEXT_STEP:;
PyObject* e_obj = POPX();
Exception& _e = PK_OBJ_GET(Exception, e_obj);
bool is_base_frame_to_be_popped = frame == base_frame;
if(is_base_frame_to_be_popped){
if(on_will_pop_base_frame) on_will_pop_base_frame(frame);
}
__pop_frame();
if(callstack.empty()) throw _e; // propagate to the top level
frame = &callstack.top();

View File

@ -197,29 +197,13 @@ void __init_builtins(VM* _vm) {
}
});
_vm->bind(_vm->builtins, "eval(__source, __globals=None)", [](VM* vm, ArgsView args) {
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE, true);
PyObject* globals = args[1];
if(globals == vm->None){
Frame* frame = &vm->callstack.top();
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
}
vm->check_type(globals, VM::tp_mappingproxy);
PyObject* obj = PK_OBJ_GET(MappingProxy, globals).obj;
return vm->_exec(code, obj);
// we use `_0`, `_1` and `_2` here to disable keyword arguments (but with default values)
_vm->bind(_vm->builtins, "eval(_0, _1=None, _2=None)", [](VM* vm, ArgsView args) {
return vm->py_eval(CAST(Str&, args[0]), args[1], args[2]);
});
_vm->bind(_vm->builtins, "exec(__source, __globals=None)", [](VM* vm, ArgsView args) {
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE, true);
PyObject* globals = args[1];
if(globals == vm->None){
Frame* frame = &vm->callstack.top();
vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
return vm->None;
}
vm->check_type(globals, VM::tp_mappingproxy);
PyObject* obj = PK_OBJ_GET(MappingProxy, globals).obj;
vm->_exec(code, obj);
_vm->bind(_vm->builtins, "exec(_0, _1=None, _2=None)", [](VM* vm, ArgsView args) {
vm->py_exec(CAST(Str&, args[0]), args[1], args[2]);
return vm->None;
});

View File

@ -505,6 +505,31 @@ i64 VM::py_hash(PyObject* obj){
}
}
void VM::py_exec(std::string_view source, PyObject* globals, PyObject* locals){
(void)(locals);
CodeObject_ code = vm->compile(source, "<exec>", EXEC_MODE, true);
if(globals == vm->None){
Frame* frame = &vm->callstack.top();
vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
return;
}
vm->check_type(globals, VM::tp_mappingproxy);
PyObject* obj = PK_OBJ_GET(MappingProxy, globals).obj;
vm->_exec(code, obj);
}
PyObject* VM::py_eval(std::string_view source, PyObject* globals, PyObject* locals){
(void)(locals);
CodeObject_ code = vm->compile(source, "<eval>", EVAL_MODE, true);
if(globals == vm->None){
Frame* frame = &vm->callstack.top();
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
}
vm->check_type(globals, VM::tp_mappingproxy);
PyObject* obj = PK_OBJ_GET(MappingProxy, globals).obj;
return vm->_exec(code, obj);
}
PyObject* VM::__format_object(PyObject* obj, Str spec){
if(spec.empty()) return VAR(py_str(obj));
char type;