| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- #include "pocketpy/interpreter/typeinfo.h"
- #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_str: {
- if(lhs->is_ptr && rhs->is_ptr) {
- return lhs->_obj == rhs->_obj;
- } else {
- return strcmp(lhs->_chars, rhs->_chars) == 0;
- }
- }
- 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_TypeInfo* ti = pk__type_info(val->type);
- do {
- py_Ref slot_hash = TypeList__magic_common(ti, __hash__);
- if(py_isnone(slot_hash)) break;
- py_Ref slot_eq = TypeList__magic_common(ti, __eq__);
- if(!py_isnil(slot_eq)) {
- if(py_isnil(slot_hash)) break;
- if(!py_call(slot_hash, 1, val)) return false;
- if(!py_checkint(py_retval())) return false;
- *out = py_toint(py_retval());
- return true;
- }
- ti = ti->base_ti;
- } while(ti);
- 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) {
- VM* vm = pk_current_vm;
- py_Ref tmp = py_tpfindmagic(val->type, __next__);
- if(!tmp) {
- TypeError("'%t' object is not an iterator", val->type);
- return -1;
- }
- if(py_call(tmp, 1, val)) return 1;
- if(vm->curr_exception.type == tp_StopIteration) {
- vm->last_retval = vm->curr_exception;
- py_clearexc(NULL);
- return 0;
- }
- return -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;
- 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)) {
- res = py_getslot(res, 0);
- py_newboundmethod(py_retval(), self, res);
- return true;
- }
- py_assign(py_retval(), res);
- return true;
- }
- }
- }
- if(cls_var) {
- // bound method is non-data descriptor
- switch(cls_var->type) {
- case tp_function: {
- if(name == __new__) goto __STATIC_NEW;
- py_newboundmethod(py_retval(), self, cls_var);
- return true;
- }
- case tp_nativefunc: {
- if(name == __new__) goto __STATIC_NEW;
- py_newboundmethod(py_retval(), self, cls_var);
- return true;
- }
- case tp_staticmethod: {
- py_assign(py_retval(), py_getslot(cls_var, 0));
- return true;
- }
- case tp_classmethod: {
- py_newboundmethod(py_retval(), py_tpobject(type), py_getslot(cls_var, 0));
- return true;
- }
- default: {
- __STATIC_NEW:
- py_assign(py_retval(), cls_var);
- return true;
- }
- }
- }
- py_Ref fallback = py_tpfindmagic(type, __getattr__);
- if(fallback) {
- py_push(fallback);
- py_push(self);
- py_assign(py_pushtmp(), py_name2ref(name));
- return py_vectorcall(1, 0);
- }
- if(self->type == tp_module) {
- py_Ref path = py_getdict(self, __path__);
- c11_sbuf buf;
- c11_sbuf__ctor(&buf);
- pk_sprintf(&buf, "%v.%n", py_tosv(path), name);
- c11_string* new_path = c11_sbuf__submit(&buf);
- int res = py_import(new_path->data);
- c11_string__delete(new_path);
- if(res == -1) {
- return false;
- } else if(res == 1) {
- return true;
- }
- }
- return AttributeError(self, name);
- }
- bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
- py_Type type = self->type;
- 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_isidentical(lhs, rhs)) return 1;
- 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());
- }
|