fix a bug of LOAD_NAME, STORE_NAME and DELETE_NAME

This commit is contained in:
BLUELOVETH 2023-07-06 20:26:39 +08:00
parent 7993eb9000
commit a34e8b2b36
7 changed files with 38 additions and 37 deletions

View File

@ -20,7 +20,7 @@
#include <variant> #include <variant>
#include <type_traits> #include <type_traits>
#define PK_VERSION "1.0.8" #define PK_VERSION "1.0.9"
#include "config.h" #include "config.h"

View File

@ -22,10 +22,7 @@ struct FastLocals{
FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {} FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {}
FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {} FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {}
PyObject* try_get(StrName name); PyObject** try_get_name(StrName name);
bool contains(StrName name);
void erase(StrName name);
bool try_set(StrName name, PyObject* value);
NameDict_ to_namedict(); NameDict_ to_namedict();
}; };

View File

@ -351,6 +351,7 @@ public:
void IndexError(const Str& msg){ _error("IndexError", msg); } void IndexError(const Str& msg){ _error("IndexError", msg); }
void ValueError(const Str& msg){ _error("ValueError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); }
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
void UnboundLocalError(StrName name){ _error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); }
void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); } void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); }
void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); } void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); }

View File

@ -111,11 +111,15 @@ __NEXT_STEP:;
if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]); if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]);
PUSH(_0); PUSH(_0);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NAME) TARGET(LOAD_NAME) {
heap._auto_collect(); heap._auto_collect();
_name = StrName(byte.arg); _name = StrName(byte.arg);
_0 = frame->_locals.try_get(_name); PyObject** slot = frame->_locals.try_get_name(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(slot != nullptr) {
if(*slot == PY_NULL) vm->UnboundLocalError(_name);
PUSH(*slot);
DISPATCH();
}
_0 = frame->f_closure_try_get(_name); _0 = frame->f_closure_try_get(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
_0 = frame->f_globals().try_get(_name); _0 = frame->f_globals().try_get(_name);
@ -123,7 +127,7 @@ __NEXT_STEP:;
_0 = vm->builtins->attr().try_get(_name); _0 = vm->builtins->attr().try_get(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(_name); vm->NameError(_name);
DISPATCH(); } DISPATCH();
TARGET(LOAD_NONLOCAL) { TARGET(LOAD_NONLOCAL) {
heap._auto_collect(); heap._auto_collect();
_name = StrName(byte.arg); _name = StrName(byte.arg);
@ -164,16 +168,17 @@ __NEXT_STEP:;
TARGET(STORE_FAST) TARGET(STORE_FAST)
frame->_locals[byte.arg] = POPX(); frame->_locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
TARGET(STORE_NAME) TARGET(STORE_NAME){
_name = StrName(byte.arg); _name = StrName(byte.arg);
_0 = POPX(); _0 = POPX();
if(frame->_callable != nullptr){ if(frame->_callable != nullptr){
bool ok = frame->_locals.try_set(_name, _0); PyObject** slot = frame->_locals.try_get_name(_name);
if(!ok) vm->NameError(_name); if(slot == nullptr) vm->UnboundLocalError(_name);
*slot = _0;
}else{ }else{
frame->f_globals().set(_name, _0); frame->f_globals().set(_name, _0);
} }
DISPATCH(); } DISPATCH();
TARGET(STORE_GLOBAL) TARGET(STORE_GLOBAL)
frame->f_globals().set(StrName(byte.arg), POPX()); frame->f_globals().set(StrName(byte.arg), POPX());
DISPATCH(); DISPATCH();
@ -202,8 +207,9 @@ __NEXT_STEP:;
TARGET(DELETE_NAME) TARGET(DELETE_NAME)
_name = StrName(byte.arg); _name = StrName(byte.arg);
if(frame->_callable != nullptr){ if(frame->_callable != nullptr){
if(!frame->_locals.contains(_name)) vm->NameError(_name); PyObject** slot = frame->_locals.try_get_name(_name);
frame->_locals.erase(_name); if(slot == nullptr) vm->UnboundLocalError(_name);
*slot = PY_NULL;
}else{ }else{
if(!frame->f_globals().contains(_name)) vm->NameError(_name); if(!frame->f_globals().contains(_name)) vm->NameError(_name);
frame->f_globals().erase(_name); frame->f_globals().erase(_name);

View File

@ -1,28 +1,10 @@
#include "pocketpy/frame.h" #include "pocketpy/frame.h"
namespace pkpy{ namespace pkpy{
PyObject** FastLocals::try_get_name(StrName name){
PyObject* FastLocals::try_get(StrName name){
int index = varnames_inv->try_get(name); int index = varnames_inv->try_get(name);
if(index == -1) return nullptr; if(index == -1) return nullptr;
return a[index]; return &a[index];
}
bool FastLocals::contains(StrName name){
return varnames_inv->contains(name);
}
void FastLocals::erase(StrName name){
int index = varnames_inv->try_get(name);
if(index == -1) FATAL_ERROR();
a[index] = nullptr;
}
bool FastLocals::try_set(StrName name, PyObject* value){
int index = varnames_inv->try_get(name);
if(index == -1) return false;
a[index] = value;
return true;
} }
NameDict_ FastLocals::to_namedict(){ NameDict_ FastLocals::to_namedict(){

View File

@ -450,7 +450,7 @@ PyObject* VM::new_module(StrName name) {
static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){ static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
switch(byte.op){ switch(byte.op){
case OP_LOAD_CONST: case OP_LOAD_CONST: case OP_FORMAT_STRING:
if(vm != nullptr){ if(vm != nullptr){
argStr += fmt(" (", CAST(Str, vm->py_repr(co->consts[byte.arg])), ")"); argStr += fmt(" (", CAST(Str, vm->py_repr(co->consts[byte.arg])), ")");
} }

View File

@ -56,4 +56,19 @@ def f():
f() f()
# class A: a=b=1 # class A: a=b=1
# class A: a, b = 1, 2 # class A: a, b = 1, 2
bmi = 0.0
def test(a):
if a:
bmi = 1.4
return f'{bmi:.2f}'
assert test(1) == '1.40'
try:
assert test(0) == '0.00'
exit(1)
except UnboundLocalError:
pass