| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #include "pocketpy/interpreter/vm.h"
- #include "pocketpy/objects/base.h"
- #include "pocketpy/pocketpy.h"
- bool py_isidentical(py_Ref lhs, py_Ref rhs) {
- if(lhs->type != rhs->type) return false;
- switch(lhs->type) {
- case tp_int: return lhs->_i64 == rhs->_i64;
- case tp_float: return lhs->_f64 == rhs->_f64;
- case tp_bool: return lhs->_bool == rhs->_bool;
- case tp_nativefunc: return lhs->_cfunc == rhs->_cfunc;
- case tp_NoneType: return true;
- case tp_NotImplementedType: return true;
- case tp_ellipsis: return true;
- // fallback to pointer comparison
- default: return lhs->is_ptr && rhs->is_ptr && lhs->_obj == rhs->_obj;
- }
- }
- int py_bool(py_Ref val) {
- switch(val->type) {
- case tp_bool: return val->_bool;
- case tp_int: return val->_i64 != 0;
- case tp_float: return val->_f64 != 0;
- case tp_NoneType: return 0;
- default: {
- py_Ref tmp = py_tpfindmagic(val->type, __bool__);
- if(tmp) {
- if(!py_call(tmp, 1, val)) return -1;
- if(!py_checkbool(py_retval())) return -1;
- return py_tobool(py_retval());
- } else {
- tmp = py_tpfindmagic(val->type, __len__);
- if(tmp) {
- if(!py_call(tmp, 1, val)) return -1;
- if(!py_checkint(py_retval())) return -1;
- return py_toint(py_retval());
- } else {
- return 1; // True
- }
- }
- }
- }
- }
- bool py_hash(py_Ref val, int64_t* out) {
- py_Type t = val->type;
- pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
- do {
- py_Ref _hash = &types[t].magic[__hash__];
- if(py_isnone(_hash)) break;
- py_Ref _eq = &types[t].magic[__eq__];
- if(!py_isnil(_hash) && !py_isnil(_eq)) {
- if(!py_call(_hash, 1, val)) return false;
- if(!py_checkint(py_retval())) return false;
- *out = py_toint(py_retval());
- return true;
- }
- t = types[t].base;
- } while(t);
- return TypeError("unhashable type: '%t'", val->type);
- }
- bool py_iter(py_Ref val) {
- py_Ref tmp = py_tpfindmagic(val->type, __iter__);
- if(!tmp) return TypeError("'%t' object is not iterable", val->type);
- return py_call(tmp, 1, val);
- }
- int py_next(py_Ref val) {
- pk_VM* vm = pk_current_vm;
- vm->is_stopiteration = false;
- py_Ref tmp = py_tpfindmagic(val->type, __next__);
- if(!tmp) return TypeError("'%t' object is not an iterator", val->type);
- if(py_call(tmp, 1, val)) return true;
- return vm->is_stopiteration ? 0 : -1;
- }
- bool py_getattr(py_Ref self, py_Name name) {
- // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
- py_Type type = self->type;
- // handle super() proxy
- if(py_istype(self, tp_super)) {
- self = py_getslot(self, 0);
- type = *(py_Type*)py_touserdata(self);
- }
- py_Ref cls_var = py_tpfindname(type, name);
- if(cls_var) {
- // handle descriptor
- if(py_istype(cls_var, tp_property)) {
- py_Ref getter = py_getslot(cls_var, 0);
- return py_call(getter, 1, self);
- }
- }
- // handle instance __dict__
- if(self->is_ptr && self->_obj->slots == -1) {
- if(!py_istype(self, tp_type)) {
- py_Ref res = py_getdict(self, name);
- if(res) {
- py_assign(py_retval(), res);
- return true;
- }
- } else {
- py_Type* inner_type = py_touserdata(self);
- py_Ref res = py_tpfindname(*inner_type, name);
- if(res) {
- if(py_istype(res, tp_staticmethod)) {
- res = py_getslot(res, 0);
- } else if(py_istype(res, tp_classmethod)) {
- // TODO: make a closure
- assert(false);
- }
- py_assign(py_retval(), res);
- return true;
- }
- }
- }
- if(cls_var) {
- // bound method is non-data descriptor
- switch(cls_var->type) {
- case tp_function: assert(false);
- case tp_nativefunc: assert(false);
- case tp_staticmethod: assert(false);
- case tp_classmethod: assert(false);
- default: {
- py_assign(py_retval(), cls_var);
- return true;
- }
- }
- }
- return AttributeError(self, name);
- }
- bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
- py_Type type = self->type;
- // handle super() proxy
- if(py_istype(self, tp_super)) {
- self = py_getslot(self, 0);
- type = *(py_Type*)py_touserdata(self);
- }
- py_Ref cls_var = py_tpfindname(type, name);
- if(cls_var) {
- // handle descriptor
- if(py_istype(cls_var, tp_property)) {
- py_Ref setter = py_getslot(cls_var, 1);
- if(!py_isnone(setter)) {
- py_push(setter);
- py_push(self);
- py_push(val);
- return py_vectorcall(1, 0);
- } else {
- return TypeError("readonly attribute: '%n'", name);
- }
- }
- }
- // handle instance __dict__
- if(self->is_ptr && self->_obj->slots == -1) {
- py_setdict(self, name, val);
- return true;
- }
- return TypeError("cannot set attribute");
- }
- bool py_delattr(py_Ref self, py_Name name) {
- if(self->is_ptr && self->_obj->slots == -1) {
- if(py_deldict(self, name)) return true;
- return AttributeError(self, name);
- }
- return TypeError("cannot delete attribute");
- }
- bool py_getitem(py_Ref self, py_Ref key) {
- py_push(self);
- py_push(key);
- bool ok = pk_callmagic(__getitem__, 2, py_peek(-2));
- py_shrink(2);
- return ok;
- }
- bool py_setitem(py_Ref self, py_Ref key, py_Ref val) {
- py_push(self);
- py_push(key);
- py_push(val);
- bool ok = pk_callmagic(__setitem__, 3, py_peek(-3));
- py_shrink(3);
- return ok;
- }
- bool py_delitem(py_Ref self, py_Ref key) {
- py_push(self);
- py_push(key);
- bool ok = pk_callmagic(__delitem__, 2, py_peek(-2));
- py_shrink(2);
- return ok;
- }
- int py_equal(py_Ref lhs, py_Ref rhs){
- if(!py_eq(lhs, rhs)) return -1;
- return py_bool(py_retval());
- }
- int py_less(py_Ref lhs, py_Ref rhs){
- if(!py_lt(lhs, rhs)) return -1;
- return py_bool(py_retval());
- }
|