diff --git a/include/pocketpy/any.h b/include/pocketpy/any.h index 3b32a449..f21478b4 100644 --- a/include/pocketpy/any.h +++ b/include/pocketpy/any.h @@ -90,7 +90,34 @@ struct function{ template function(F&& f) : _impl(std::forward(f)){ _wrapper = [](const any& impl, Params... params) -> Ret{ - return impl.cast>()(std::forward(params)...); + return impl._cast>()(std::forward(params)...); + }; + } + + Ret operator()(Params... params) const{ + if(!_wrapper) throw std::runtime_error("empty function"); + return _wrapper(_impl, std::forward(params)...); + } +}; + +template +struct lightfunction; + +template +struct lightfunction{ + void* _impl; + Ret (*_wrapper)(void*, Params...); + + lightfunction() : _impl(nullptr), _wrapper(nullptr) {} + + operator bool() const { return _wrapper != nullptr; } + + template + lightfunction(const F& f){ + _impl = (F*)(&f); + _wrapper = [](void* impl, Params... params) -> Ret{ + F* f = (F*)(impl); + return (*f)(std::forward(params)...); }; } diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 98ef8601..9af41e66 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -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 on_will_pop_base_frame = {}); void __pop_frame(); PyObject* __py_generator(Frame&& frame, ArgsView buffer); void __op_unpack_sequence(uint16_t arg); diff --git a/src/ceval.cpp b/src/ceval.cpp index 34263d5c..8249c435 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -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 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(); diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index fa7b11ab..34add8db 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -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_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_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; }); diff --git a/src/vm.cpp b/src/vm.cpp index ff46163c..4efb6961 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -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_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_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;