This commit is contained in:
blueloveTH 2023-01-29 05:10:59 +08:00
parent 0d99fbb947
commit f0eb29e816
6 changed files with 377 additions and 467 deletions

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit 10ce041877fee516e825365d05e89975ae7d2d46
Subproject commit 4bbbb85979391fd8b1aa349ad81d6527db069ab2

View File

@ -178,13 +178,13 @@ private:
public:
const _Code code;
PyVar _module;
PyVarDict f_locals;
pkpy::shared_ptr<PyVarDict> _locals;
inline PyVarDict f_locals_copy() const { return f_locals; }
inline PyVarDict& f_locals(){ return *_locals; }
inline PyVarDict& f_globals(){ return _module->attribs; }
Frame(const _Code code, PyVar _module, PyVarDict&& locals)
: code(code), _module(_module), f_locals(std::move(locals)) {
Frame(const _Code code, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
: code(code), _module(_module), _locals(_locals) {
}
inline const Bytecode& next_bytecode() {

View File

@ -54,15 +54,22 @@ void __initializeBuiltinFunctions(VM* _vm) {
});
_vm->bindBuiltinFunc<0>("super", [](VM* vm, const pkpy::ArgList& args) {
auto it = vm->top_frame()->f_locals.find(m_self);
if(it == vm->top_frame()->f_locals.end()) vm->typeError("super() can only be called in a class method");
auto it = vm->top_frame()->f_locals().find(m_self);
if(it == vm->top_frame()->f_locals().end()) vm->typeError("super() can only be called in a class method");
return vm->new_object(vm->_tp_super, it->second);
});
_vm->bindBuiltinFunc<1>("eval", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<eval>", EVAL_MODE);
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->f_locals_copy());
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
});
_vm->bindBuiltinFunc<1>("exec", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<exec>", EXEC_MODE);
vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
return vm->None;
});
_vm->bindBuiltinFunc<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
@ -91,7 +98,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
});
_vm->bindBuiltinFunc<0>("locals", [](VM* vm, const pkpy::ArgList& args) {
const auto& d = vm->top_frame()->f_locals;
const auto& d = vm->top_frame()->f_locals();
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
@ -532,7 +539,7 @@ void __addModuleJson(VM* vm){
vm->bindFunc<1>(mod, "loads", [](VM* vm, const pkpy::ArgList& args) {
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = vm->compile(expr, "<json>", JSON_MODE);
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->f_locals_copy());
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
});
vm->bindFunc<1>(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {
@ -789,7 +796,7 @@ extern "C" {
// add builtins | no exception handler | must succeed
_Code code = vm->compile(__BUILTINS_CODE, "<builtins>", EXEC_MODE);
vm->_exec(code, vm->builtins, {});
vm->_exec(code, vm->builtins, pkpy::make_shared<PyVarDict>());
pkpy_vm_add_module(vm, "random", __RANDOM_CODE);
pkpy_vm_add_module(vm, "os", __OS_CODE);

View File

@ -311,7 +311,7 @@ protected:
const _Str& source = it2->second;
_Code code = compile(source, name, EXEC_MODE);
PyVar _m = newModule(name);
_exec(code, _m, {});
_exec(code, _m, pkpy::make_shared<PyVarDict>());
frame->push(_m);
_lazy_modules.erase(it2);
}
@ -459,7 +459,9 @@ public:
return f(this, args);
} else if((*callable)->is_type(_tp_function)){
const _Func& fn = PyFunction_AS_C((*callable));
PyVarDict locals;
pkpy::shared_ptr<PyVarDict> _locals = pkpy::make_shared<PyVarDict>();
PyVarDict& locals = *_locals;
int i = 0;
for(const auto& name : fn->args){
if(i < args.size()){
@ -507,10 +509,10 @@ public:
PyVar* it_m = (*callable)->attribs.try_get(__module__);
PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
if(opCall){
__pushNewFrame(fn->code, _module, std::move(locals));
__push_new_frame(fn->code, _module, _locals);
return __py2py_call_signal;
}
return _exec(fn->code, _module, std::move(locals));
return _exec(fn->code, _module, _locals);
}
typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
return None;
@ -523,7 +525,7 @@ public:
try {
_Code code = compile(source, filename, mode);
//if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
return _exec(code, _module, {});
return _exec(code, _module, pkpy::make_shared<PyVarDict>());
}catch (const _Error& e){
*_stderr << e.what() << '\n';
}
@ -534,18 +536,18 @@ public:
return nullptr;
}
Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
if(code == nullptr) UNREACHABLE();
template<typename ...Args>
Frame* __push_new_frame(Args&&... args){
if(callstack.size() > maxRecursionDepth){
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
}
Frame* frame = new Frame(code, _module, std::move(locals));
callstack.emplace_back(frame);
return frame;
callstack.emplace_back(std::make_unique<Frame>(std::forward<Args>(args)...));
return callstack.back().get();
}
PyVar _exec(_Code code, PyVar _module, PyVarDict&& locals){
Frame* frame = __pushNewFrame(code, _module, std::move(locals));
template<typename ...Args>
PyVar _exec(Args&&... args){
Frame* frame = __push_new_frame(std::forward<Args>(args)...);
Frame* frameBase = frame;
PyVar ret = nullptr;
@ -945,7 +947,7 @@ public:
PyVar NameRef::get(VM* vm, Frame* frame) const{
PyVar* val;
val = frame->f_locals.try_get(pair->first);
val = frame->f_locals().try_get(pair->first);
if(val) return *val;
val = frame->f_globals().try_get(pair->first);
if(val) return *val;
@ -957,10 +959,10 @@ PyVar NameRef::get(VM* vm, Frame* frame) const{
void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
switch(pair->second) {
case NAME_LOCAL: frame->f_locals[pair->first] = std::move(val); break;
case NAME_LOCAL: frame->f_locals()[pair->first] = std::move(val); break;
case NAME_GLOBAL:
{
PyVar* existing = frame->f_locals.try_get(pair->first);
PyVar* existing = frame->f_locals().try_get(pair->first);
if(existing != nullptr){
*existing = std::move(val);
}else{
@ -974,16 +976,16 @@ void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
void NameRef::del(VM* vm, Frame* frame) const{
switch(pair->second) {
case NAME_LOCAL: {
if(frame->f_locals.contains(pair->first)){
frame->f_locals.erase(pair->first);
if(frame->f_locals().contains(pair->first)){
frame->f_locals().erase(pair->first);
}else{
vm->nameError(pair->first);
}
} break;
case NAME_GLOBAL:
{
if(frame->f_locals.contains(pair->first)){
frame->f_locals.erase(pair->first);
if(frame->f_locals().contains(pair->first)){
frame->f_locals().erase(pair->first);
}else{
if(frame->f_globals().contains(pair->first)){
frame->f_globals().erase(pair->first);

20
tests/_eval.py Normal file
View File

@ -0,0 +1,20 @@
assert eval('1+1') == 2
assert eval('[1,2,3]') == [1,2,3]
def f(x):
return eval('x')
assert f(1) == 1
a = 0
assert eval('a') == 0
exec('a = 1')
assert a == 1
def f(x):
exec('a = x')
return a
assert f(2) == 2