support @property.setter

This commit is contained in:
blueloveTH 2023-11-07 04:50:06 +08:00
parent e8ad5b5784
commit e124f635c1
9 changed files with 73 additions and 15 deletions

View File

@ -23,7 +23,7 @@
#include <bitset>
#include <deque>
#define PK_VERSION "1.2.9"
#define PK_VERSION "1.3.0"
#include "config.h"
#include "export.h"

View File

@ -23,6 +23,7 @@ OPCODE(LOAD_NAME)
OPCODE(LOAD_NONLOCAL)
OPCODE(LOAD_GLOBAL)
OPCODE(LOAD_ATTR)
OPCODE(LOAD_CLASS_GLOBAL)
OPCODE(LOAD_METHOD)
OPCODE(LOAD_SUBSCR)

View File

@ -133,7 +133,8 @@ public:
PyObject* StopIteration;
PyObject* _main; // __main__ module
PyObject* _last_exception;
PyObject* _last_exception; // last exception
PyObject* _curr_class; // current class being defined
#if PK_ENABLE_CEVAL_CALLBACK
void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr;

View File

@ -182,10 +182,22 @@ __NEXT_STEP:;
_0 = vm->builtins->attr().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(_name);
}DISPATCH();
TARGET(LOAD_ATTR)
} DISPATCH();
TARGET(LOAD_ATTR){
TOP() = getattr(TOP(), StrName(byte.arg));
DISPATCH();
} DISPATCH();
TARGET(LOAD_CLASS_GLOBAL){
PK_ASSERT(_curr_class != nullptr);
StrName _name(byte.arg);
PyObject* _0 = getattr(_curr_class, _name, false);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
// load global if attribute not found
_0 = frame->f_globals().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
_0 = vm->builtins->attr().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(_name);
} DISPATCH();
TARGET(LOAD_METHOD){
PyObject* _0;
TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true);
@ -723,15 +735,18 @@ __NEXT_STEP:;
PyObject* _0 = POPX(); // super
if(_0 == None) _0 = _t(tp_object);
check_non_tagged_type(_0, tp_type);
PyObject* _1 = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0));
PUSH(_1);
_curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0));
} DISPATCH();
TARGET(END_CLASS) {
PK_ASSERT(_curr_class != nullptr);
_curr_class = nullptr;
} DISPATCH();
TARGET(END_CLASS) POP(); DISPATCH();
TARGET(STORE_CLASS_ATTR){
PK_ASSERT(_curr_class != nullptr);
StrName _name(byte.arg);
PyObject* _0 = POPX();
if(is_non_tagged_type(_0, tp_function)){
PK_OBJ_GET(Function, _0)._class = TOP();
PK_OBJ_GET(Function, _0)._class = _curr_class;
}
TOP()->attr().set(_name, _0);
} DISPATCH();
@ -793,8 +808,8 @@ __NEXT_STEP:;
} DISPATCH();
#if !PK_ENABLE_COMPUTED_GOTO
static_assert(OP_DEC_GLOBAL == 106);
case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: FATAL_ERROR(); break;
static_assert(OP_DEC_GLOBAL == 107);
case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: FATAL_ERROR(); break;
}
#endif
}

View File

@ -127,8 +127,15 @@ namespace pkpy{
ctx->emit_(OP_LOAD_FAST, index, line);
}else{
Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL;
// we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
if(ctx->is_compiling_class && scope == NAME_GLOBAL){
// if we are compiling a class, we should use OP_LOAD_ATTR_GLOBAL instead of OP_LOAD_GLOBAL
// this supports @property.setter
op = OP_LOAD_CLASS_GLOBAL;
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
}else{
// we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
}
ctx->emit_(op, StrName(name).index, line);
}
}

View File

@ -1653,6 +1653,12 @@ void add_module_gc(VM* vm){
void VM::post_init(){
init_builtins(this);
bind_method<1>("property", "setter", [](VM* vm, ArgsView args) {
Property& self = _CAST(Property&, args[0]);
self.setter = args[1];
return args[0];
});
// type
bind__getitem__(tp_type, [](VM* vm, PyObject* self, PyObject* _){
PK_UNUSED(_);

View File

@ -1192,6 +1192,7 @@ void ManagedHeap::mark() {
for(PyObject* obj: vm->s_data) PK_OBJ_MARK(obj);
if(_gc_marker_ex) _gc_marker_ex(vm);
if(vm->_last_exception) PK_OBJ_MARK(vm->_last_exception);
if(vm->_curr_class) PK_OBJ_MARK(vm->_curr_class);
if(vm->_c.error != nullptr) PK_OBJ_MARK(vm->_c.error);
}

View File

@ -109,3 +109,13 @@ class B(A):
# assert B.a == 1 ...bug here
assert B.b == 3
assert B.c == 4
class A:
x = 1
x = x + 1
y = 1
z = x + y
assert A.x == 2
assert A.y == 1
assert A.z == 3

View File

@ -810,12 +810,29 @@ try:
except:
pass
class Vector2:
def __init__(self) -> None:
self._x = 0
@property
def x(self):
return self._x
@x.setter
def x(self, val):
self._x = val
v = Vector2()
assert v.x == 0
v.x = 10
assert v.x == 10
# /************ module timeit ************/
import timeit
def aaa():
for i in range(100):
for j in range(100):
for i in range(10):
for j in range(10):
pass
assert type(timeit.timeit(aaa, 2)) is float