py_ops.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include "pocketpy/interpreter/typeinfo.h"
  2. #include "pocketpy/interpreter/vm.h"
  3. #include "pocketpy/objects/base.h"
  4. #include "pocketpy/pocketpy.h"
  5. bool py_isidentical(py_Ref lhs, py_Ref rhs) {
  6. if(lhs->type != rhs->type) return false;
  7. switch(lhs->type) {
  8. case tp_int: return lhs->_i64 == rhs->_i64;
  9. case tp_float: return lhs->_f64 == rhs->_f64;
  10. case tp_bool: return lhs->_bool == rhs->_bool;
  11. case tp_str: {
  12. if(lhs->is_ptr && rhs->is_ptr) {
  13. return lhs->_obj == rhs->_obj;
  14. } else {
  15. return strcmp(lhs->_chars, rhs->_chars) == 0;
  16. }
  17. }
  18. case tp_nativefunc: return lhs->_cfunc == rhs->_cfunc;
  19. case tp_NoneType: return true;
  20. case tp_NotImplementedType: return true;
  21. case tp_ellipsis: return true;
  22. // fallback to pointer comparison
  23. default: return lhs->is_ptr && rhs->is_ptr && lhs->_obj == rhs->_obj;
  24. }
  25. }
  26. int py_bool(py_Ref val) {
  27. switch(val->type) {
  28. case tp_bool: return val->_bool;
  29. case tp_int: return val->_i64 != 0;
  30. case tp_float: return val->_f64 != 0;
  31. case tp_NoneType: return 0;
  32. default: {
  33. py_Ref tmp = py_tpfindmagic(val->type, __bool__);
  34. if(tmp) {
  35. if(!py_call(tmp, 1, val)) return -1;
  36. if(!py_checkbool(py_retval())) return -1;
  37. return py_tobool(py_retval());
  38. } else {
  39. tmp = py_tpfindmagic(val->type, __len__);
  40. if(tmp) {
  41. if(!py_call(tmp, 1, val)) return -1;
  42. if(!py_checkint(py_retval())) return -1;
  43. return py_toint(py_retval());
  44. } else {
  45. return 1; // True
  46. }
  47. }
  48. }
  49. }
  50. }
  51. bool py_hash(py_Ref val, int64_t* out) {
  52. py_TypeInfo* ti = pk__type_info(val->type);
  53. do {
  54. py_Ref slot_hash = TypeList__magic_common(ti, __hash__);
  55. if(py_isnone(slot_hash)) break;
  56. py_Ref slot_eq = TypeList__magic_common(ti, __eq__);
  57. if(!py_isnil(slot_eq)) {
  58. if(py_isnil(slot_hash)) break;
  59. if(!py_call(slot_hash, 1, val)) return false;
  60. if(!py_checkint(py_retval())) return false;
  61. *out = py_toint(py_retval());
  62. return true;
  63. }
  64. ti = ti->base_ti;
  65. } while(ti);
  66. return TypeError("unhashable type: '%t'", val->type);
  67. }
  68. bool py_iter(py_Ref val) {
  69. py_Ref tmp = py_tpfindmagic(val->type, __iter__);
  70. if(!tmp) return TypeError("'%t' object is not iterable", val->type);
  71. return py_call(tmp, 1, val);
  72. }
  73. int py_next(py_Ref val) {
  74. VM* vm = pk_current_vm;
  75. py_Ref tmp = py_tpfindmagic(val->type, __next__);
  76. if(!tmp) {
  77. TypeError("'%t' object is not an iterator", val->type);
  78. return -1;
  79. }
  80. if(py_call(tmp, 1, val)) return 1;
  81. if(vm->curr_exception.type == tp_StopIteration) {
  82. vm->last_retval = vm->curr_exception;
  83. py_clearexc(NULL);
  84. return 0;
  85. }
  86. return -1;
  87. }
  88. bool py_getattr(py_Ref self, py_Name name) {
  89. // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
  90. py_Type type = self->type;
  91. py_Ref cls_var = py_tpfindname(type, name);
  92. if(cls_var) {
  93. // handle descriptor
  94. if(py_istype(cls_var, tp_property)) {
  95. py_Ref getter = py_getslot(cls_var, 0);
  96. return py_call(getter, 1, self);
  97. }
  98. }
  99. // handle instance __dict__
  100. if(self->is_ptr && self->_obj->slots == -1) {
  101. if(!py_istype(self, tp_type)) {
  102. py_Ref res = py_getdict(self, name);
  103. if(res) {
  104. py_assign(py_retval(), res);
  105. return true;
  106. }
  107. } else {
  108. py_Type* inner_type = py_touserdata(self);
  109. py_Ref res = py_tpfindname(*inner_type, name);
  110. if(res) {
  111. if(py_istype(res, tp_staticmethod)) {
  112. res = py_getslot(res, 0);
  113. } else if(py_istype(res, tp_classmethod)) {
  114. res = py_getslot(res, 0);
  115. py_newboundmethod(py_retval(), self, res);
  116. return true;
  117. }
  118. py_assign(py_retval(), res);
  119. return true;
  120. }
  121. }
  122. }
  123. if(cls_var) {
  124. // bound method is non-data descriptor
  125. switch(cls_var->type) {
  126. case tp_function: {
  127. if(name == __new__) goto __STATIC_NEW;
  128. py_newboundmethod(py_retval(), self, cls_var);
  129. return true;
  130. }
  131. case tp_nativefunc: {
  132. if(name == __new__) goto __STATIC_NEW;
  133. py_newboundmethod(py_retval(), self, cls_var);
  134. return true;
  135. }
  136. case tp_staticmethod: {
  137. py_assign(py_retval(), py_getslot(cls_var, 0));
  138. return true;
  139. }
  140. case tp_classmethod: {
  141. py_newboundmethod(py_retval(), py_tpobject(type), py_getslot(cls_var, 0));
  142. return true;
  143. }
  144. default: {
  145. __STATIC_NEW:
  146. py_assign(py_retval(), cls_var);
  147. return true;
  148. }
  149. }
  150. }
  151. py_Ref fallback = py_tpfindmagic(type, __getattr__);
  152. if(fallback) {
  153. py_push(fallback);
  154. py_push(self);
  155. py_assign(py_pushtmp(), py_name2ref(name));
  156. return py_vectorcall(1, 0);
  157. }
  158. if(self->type == tp_module) {
  159. py_Ref path = py_getdict(self, __path__);
  160. c11_sbuf buf;
  161. c11_sbuf__ctor(&buf);
  162. pk_sprintf(&buf, "%v.%n", py_tosv(path), name);
  163. c11_string* new_path = c11_sbuf__submit(&buf);
  164. int res = py_import(new_path->data);
  165. c11_string__delete(new_path);
  166. if(res == -1) {
  167. return false;
  168. } else if(res == 1) {
  169. return true;
  170. }
  171. }
  172. return AttributeError(self, name);
  173. }
  174. bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
  175. py_Type type = self->type;
  176. py_Ref cls_var = py_tpfindname(type, name);
  177. if(cls_var) {
  178. // handle descriptor
  179. if(py_istype(cls_var, tp_property)) {
  180. py_Ref setter = py_getslot(cls_var, 1);
  181. if(!py_isnone(setter)) {
  182. py_push(setter);
  183. py_push(self);
  184. py_push(val);
  185. return py_vectorcall(1, 0);
  186. } else {
  187. return TypeError("readonly attribute: '%n'", name);
  188. }
  189. }
  190. }
  191. // handle instance __dict__
  192. if(self->is_ptr && self->_obj->slots == -1) {
  193. py_setdict(self, name, val);
  194. return true;
  195. }
  196. return TypeError("cannot set attribute");
  197. }
  198. bool py_delattr(py_Ref self, py_Name name) {
  199. if(self->is_ptr && self->_obj->slots == -1) {
  200. if(py_deldict(self, name)) return true;
  201. return AttributeError(self, name);
  202. }
  203. return TypeError("cannot delete attribute");
  204. }
  205. bool py_getitem(py_Ref self, py_Ref key) {
  206. py_push(self);
  207. py_push(key);
  208. bool ok = pk_callmagic(__getitem__, 2, py_peek(-2));
  209. py_shrink(2);
  210. return ok;
  211. }
  212. bool py_setitem(py_Ref self, py_Ref key, py_Ref val) {
  213. py_push(self);
  214. py_push(key);
  215. py_push(val);
  216. bool ok = pk_callmagic(__setitem__, 3, py_peek(-3));
  217. py_shrink(3);
  218. return ok;
  219. }
  220. bool py_delitem(py_Ref self, py_Ref key) {
  221. py_push(self);
  222. py_push(key);
  223. bool ok = pk_callmagic(__delitem__, 2, py_peek(-2));
  224. py_shrink(2);
  225. return ok;
  226. }
  227. int py_equal(py_Ref lhs, py_Ref rhs) {
  228. if(py_isidentical(lhs, rhs)) return 1;
  229. if(!py_eq(lhs, rhs)) return -1;
  230. return py_bool(py_retval());
  231. }
  232. int py_less(py_Ref lhs, py_Ref rhs) {
  233. if(!py_lt(lhs, rhs)) return -1;
  234. return py_bool(py_retval());
  235. }