mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
impl py_exec
and py_eval
This commit is contained in:
parent
331dedcd28
commit
5cfd66f8b2
@ -156,6 +156,7 @@ public:
|
||||
PyObject* __curr_class;
|
||||
PyObject* __cached_object_new;
|
||||
std::map<std::string_view, CodeObject_> __cached_codes;
|
||||
FuncDecl_ __dynamic_func_decl;
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
LineProfiler* _profiler = nullptr;
|
||||
@ -409,9 +410,10 @@ public:
|
||||
#if PK_DEBUG_CEVAL_STEP
|
||||
void __log_s_data(const char* title = nullptr);
|
||||
#endif
|
||||
PyObject* __py_exec_internal(const CodeObject_& code, PyObject* globals, PyObject* locals);
|
||||
void __breakpoint();
|
||||
PyObject* __format_object(PyObject*, Str);
|
||||
PyObject* __run_top_frame(lightfunction<void(Frame*)> on_will_pop_base_frame = {});
|
||||
PyObject* __run_top_frame();
|
||||
void __pop_frame();
|
||||
PyObject* __py_generator(Frame&& frame, ArgsView buffer);
|
||||
void __op_unpack_sequence(uint16_t arg);
|
||||
|
@ -80,7 +80,7 @@ bool VM::py_ge(PyObject* _0, PyObject* _1){
|
||||
|
||||
#undef BINARY_F_COMPARE
|
||||
|
||||
PyObject* VM::__run_top_frame(lightfunction<void(Frame*)> on_will_pop_base_frame){
|
||||
PyObject* VM::__run_top_frame(){
|
||||
Frame* frame = &callstack.top();
|
||||
const Frame* base_frame = frame;
|
||||
bool need_raise = false;
|
||||
@ -260,8 +260,17 @@ __NEXT_STEP:;
|
||||
PyObject* _0 = POPX();
|
||||
if(frame->_callable != nullptr){
|
||||
PyObject** slot = frame->_locals.try_get_name(_name);
|
||||
if(slot == nullptr) vm->UnboundLocalError(_name);
|
||||
*slot = _0;
|
||||
if(slot != nullptr){
|
||||
*slot = _0; // store in locals if possible
|
||||
}else{
|
||||
Function& func = PK_OBJ_GET(Function, frame->_callable);
|
||||
if(func.decl == __dynamic_func_decl){
|
||||
PK_DEBUG_ASSERT(func._closure != nullptr);
|
||||
func._closure->set(_name, _0);
|
||||
}else{
|
||||
vm->UnboundLocalError(_name);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
frame->f_globals().set(_name, _0);
|
||||
}
|
||||
@ -307,8 +316,18 @@ __NEXT_STEP:;
|
||||
StrName _name(byte.arg);
|
||||
if(frame->_callable != nullptr){
|
||||
PyObject** slot = frame->_locals.try_get_name(_name);
|
||||
if(slot == nullptr) vm->UnboundLocalError(_name);
|
||||
*slot = PY_NULL;
|
||||
if(slot != nullptr){
|
||||
*slot = PY_NULL;
|
||||
}else{
|
||||
Function& func = PK_OBJ_GET(Function, frame->_callable);
|
||||
if(func.decl == __dynamic_func_decl){
|
||||
PK_DEBUG_ASSERT(func._closure != nullptr);
|
||||
bool ok = func._closure->del(_name);
|
||||
if(!ok) vm->UnboundLocalError(_name);
|
||||
}else{
|
||||
vm->UnboundLocalError(_name);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(!frame->f_globals().del(_name)) vm->NameError(_name);
|
||||
}
|
||||
@ -709,12 +728,10 @@ __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;
|
||||
@ -984,9 +1001,6 @@ __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();
|
||||
|
@ -1609,6 +1609,10 @@ void VM::__post_init_builtin_types(){
|
||||
_lazy_modules["itertools"] = kPythonLibs_itertools;
|
||||
|
||||
try{
|
||||
// initialize dummy func_decl for exec/eval
|
||||
CodeObject_ dynamic_co = compile("def _(): pass", "<dynamic>", EXEC_MODE);
|
||||
__dynamic_func_decl = dynamic_co->func_decls.at(0);
|
||||
// initialize builtins
|
||||
CodeObject_ code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
|
||||
this->_exec(code, this->builtins);
|
||||
code = compile(kPythonLibs__set, "<set>", EXEC_MODE);
|
||||
|
83
src/vm.cpp
83
src/vm.cpp
@ -505,29 +505,76 @@ 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;
|
||||
PyObject* VM::__py_exec_internal(const CodeObject_& code, PyObject* globals, PyObject* locals){
|
||||
Frame* frame = &vm->callstack.top();
|
||||
|
||||
// fast path
|
||||
if(globals == vm->None && locals == vm->None){
|
||||
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;
|
||||
vm->_exec(code, obj);
|
||||
|
||||
PyObject* globals_obj = nullptr;
|
||||
Dict* globals_dict = nullptr;
|
||||
|
||||
NameDict_ locals_closure = nullptr;
|
||||
Dict* locals_dict = nullptr;
|
||||
|
||||
if(globals == vm->None){
|
||||
globals_obj = frame->_module;
|
||||
}else{
|
||||
if(is_type(globals, VM::tp_mappingproxy)){
|
||||
globals_obj = PK_OBJ_GET(MappingProxy, globals).obj;
|
||||
}else{
|
||||
check_compatible_type(globals, VM::tp_dict);
|
||||
// make a temporary object and copy globals into it
|
||||
globals_obj = heap.gcnew<DummyInstance>(VM::tp_object);
|
||||
globals_obj->_enable_instance_dict();
|
||||
globals_dict = &PK_OBJ_GET(Dict, globals);
|
||||
globals_dict->apply([&](PyObject* k, PyObject* v){
|
||||
globals_obj->attr().set(CAST(Str&, k), v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* retval = nullptr;
|
||||
|
||||
if(locals == vm->None){
|
||||
retval = vm->_exec(code, globals_obj); // only globals
|
||||
}else{
|
||||
check_compatible_type(locals, VM::tp_dict);
|
||||
locals_dict = &PK_OBJ_GET(Dict, locals);
|
||||
locals_closure = std::make_shared<NameDict>();
|
||||
locals_dict->apply([&](PyObject* k, PyObject* v){
|
||||
locals_closure->set(CAST(Str&, k), v);
|
||||
});
|
||||
PyObject* _callable = VAR(Function(__dynamic_func_decl, globals_obj, nullptr, locals_closure));
|
||||
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
|
||||
}
|
||||
|
||||
if(globals_dict){
|
||||
globals_dict->clear();
|
||||
globals_obj->attr().apply([&](StrName k, PyObject* v){
|
||||
globals_dict->set(VAR(k.sv()), v);
|
||||
});
|
||||
}
|
||||
|
||||
if(locals_dict){
|
||||
locals_dict->clear();
|
||||
locals_closure->apply([&](StrName k, PyObject* v){
|
||||
locals_dict->set(VAR(k.sv()), v);
|
||||
});
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void VM::py_exec(std::string_view source, PyObject* globals, PyObject* locals){
|
||||
CodeObject_ code = vm->compile(source, "<exec>", EXEC_MODE, true);
|
||||
__py_exec_internal(code, globals, locals);
|
||||
}
|
||||
|
||||
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);
|
||||
return __py_exec_internal(code, globals, locals);
|
||||
}
|
||||
|
||||
PyObject* VM::__format_object(PyObject* obj, Str spec){
|
||||
|
@ -38,4 +38,17 @@ def abc():
|
||||
exec('a=1', g.__dict__)
|
||||
return g.a
|
||||
|
||||
assert abc() == 1
|
||||
res = abc()
|
||||
assert (res==1), res
|
||||
|
||||
|
||||
# test locals and globals
|
||||
globals = {'a': 1}
|
||||
locals = {'a': 1}
|
||||
|
||||
exec('a=2', globals, locals)
|
||||
assert locals == {'a': 2}
|
||||
assert globals == {'a': 1}
|
||||
|
||||
exec('a=2', globals)
|
||||
assert globals == {'a': 2}
|
||||
|
Loading…
x
Reference in New Issue
Block a user