From 1107cea2564c850828e1816535be7c66217f5917 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 19 May 2023 16:54:39 +0800 Subject: [PATCH] ... --- docs/features/ub.md | 3 +- src/ceval.h | 8 ++- src/cffi.h | 36 ++++++++++---- src/dict.h | 33 ++++++------ src/namedict.h | 16 ++---- src/pocketpy.h | 119 +++++++++++++++++++------------------------- src/str.h | 60 ++++++++++++---------- src/vm.h | 102 ++++++++++++++++++++++++++++++++++++- 8 files changed, 238 insertions(+), 139 deletions(-) diff --git a/docs/features/ub.md b/docs/features/ub.md index da7f8120..28923e80 100644 --- a/docs/features/ub.md +++ b/docs/features/ub.md @@ -9,4 +9,5 @@ These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined i 2. Call an unbound method with the wrong type of `self`. For example, `int.__add__('1', 2)`. 3. Use goto statement to jump out of a context block. 4. Type `T`'s `__new__` returns an object that is not an instance of `T`. -5. Call `__new__` with a type that is not a subclass of `type`. \ No newline at end of file +5. Call `__new__` with a type that is not a subclass of `type`. +6. `__eq__`, `__ne__` or `__contains__`, etc.. returns a value that is not a boolean. \ No newline at end of file diff --git a/src/ceval.h b/src/ceval.h index a8bee5a3..2238aacf 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -308,10 +308,14 @@ __NEXT_STEP:; INT_BINARY_OP(<=, __le__) DISPATCH() TARGET(COMPARE_EQ) - INT_BINARY_OP(==, __eq__) + _1 = POPX(); + _0 = TOP(); + TOP() = VAR(py_equals(_0, _1)); DISPATCH() TARGET(COMPARE_NE) - INT_BINARY_OP(!=, __ne__) + _1 = POPX(); + _0 = TOP(); + TOP() = VAR(py_not_equals(_0, _1)); DISPATCH() TARGET(COMPARE_GT) INT_BINARY_OP(>, __gt__) diff --git a/src/cffi.h b/src/cffi.h index dff8700f..4f806489 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -11,7 +11,7 @@ namespace pkpy { static const StrName __x1(#name); \ return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ } \ - static void _check_type(VM* vm, PyObject* val){ \ + static void _check_type(VM* vm, PyObject* val){ \ if(!vm->isinstance(val, T::_type(vm))){ \ vm->TypeError("expected '" #mod "." #name "', got " + OBJ_NAME(vm->_t(val)).escape()); \ } \ @@ -39,6 +39,13 @@ struct VoidP{ VoidP(void* ptr): ptr(ptr), base_offset(1){} VoidP(): ptr(nullptr), base_offset(1){} + bool operator==(const VoidP& other) const { + return ptr == other.ptr && base_offset == other.base_offset; + } + bool operator!=(const VoidP& other) const { + return ptr != other.ptr || base_offset != other.base_offset; + } + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_default_constructor(type); @@ -51,16 +58,25 @@ struct VoidP{ return VAR(ss.str()); }); - vm->bind_method<1>(type, "__eq__", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - VoidP& other = CAST(VoidP&, args[1]); - return VAR(self.ptr == other.ptr && self.base_offset == other.base_offset); + vm->bind__eq__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return false; + return _CAST(VoidP&, lhs) == _CAST(VoidP&, rhs); }); - - vm->bind_method<1>(type, "__ne__", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - VoidP& other = CAST(VoidP&, args[1]); - return VAR(self.ptr != other.ptr || self.base_offset != other.base_offset); + vm->bind__ne__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return true; + return _CAST(VoidP&, lhs) != _CAST(VoidP&, rhs); + }); + vm->bind__gt__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + return _CAST(VoidP&, lhs).ptr > CAST(VoidP&, rhs).ptr; + }); + vm->bind__lt__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + return _CAST(VoidP&, lhs).ptr < CAST(VoidP&, rhs).ptr; + }); + vm->bind__ge__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + return _CAST(VoidP&, lhs).ptr >= CAST(VoidP&, rhs).ptr; + }); + vm->bind__le__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ + return _CAST(VoidP&, lhs).ptr <= CAST(VoidP&, rhs).ptr; }); vm->bind_method<1>(type, "set_base_offset", [](VM* vm, ArgsView args){ diff --git a/src/dict.h b/src/dict.h index 6dbe601d..33026235 100644 --- a/src/dict.h +++ b/src/dict.h @@ -5,39 +5,31 @@ #include "memory.h" #include "str.h" +namespace pkpy{ + struct Dict{ using Item = std::pair; static constexpr int __Capacity = 8; static constexpr float __LoadFactor = 0.67; static_assert(sizeof(Item) * __Capacity <= 128); + VM* vm; int _capacity; int _mask; int _size; int _critical_size; Item* _items; - - void _alloc(int cap){ - _items = (Item*)pool128.alloc(cap * sizeof(Item)); - memset(_items, 0, cap * sizeof(Item)); - } - - Dict(): _capacity(__Capacity), + + Dict(VM* vm): vm(vm), _capacity(__Capacity), _mask(__Capacity-1), _size(0), _critical_size(__Capacity*__LoadFactor+0.5f){ - _alloc(__Capacity); + _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); + memset(_items, 0, _capacity * sizeof(Item)); } int size() const { return _size; } - void _probe(PyObject* key, bool& ok, int& i){ - ok = false; - i = PyHash(key) & _mask; - while(_items[i].first != nullptr) { - if(PyEquals(_items[i].first, key)) { ok = true; break; } - i = (i + 1) & _mask; - } - } + void _probe(PyObject* key, bool& ok, int& i) const; void set(PyObject* key, PyObject* val){ bool ok; int i; @@ -56,10 +48,11 @@ struct Dict{ void _rehash(){ Item* old_items = _items; int old_capacity = _capacity; - _capacity = find_next_power_of_2(_capacity * 2); + _capacity *= 2; _mask = _capacity - 1; _critical_size = _capacity * __LoadFactor + 0.5f; - _alloc(_capacity); + _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); + memset(_items, 0, _capacity * sizeof(Item)); for(int i=0; i kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143}; -inline uint16_t find_next_power_of_2(uint16_t n){ - uint16_t x = 2; - while(x < n) x <<= 1; - return x; -} - #define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) ) inline uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector& keys){ @@ -53,10 +47,10 @@ struct NameDictImpl { memset(_items, 0, cap * sizeof(Item)); } - NameDictImpl(float load_factor=0.67, uint16_t capacity=__Capacity, uint16_t hash_seed=kHashSeeds[0]): - _load_factor(load_factor), _capacity(capacity), _size(0), - _hash_seed(hash_seed), _mask(capacity-1) { - _alloc(capacity); + NameDictImpl(float load_factor=0.67): + _load_factor(load_factor), _capacity(__Capacity), _size(0), + _hash_seed(kHashSeeds[0]), _mask(__Capacity-1) { + _alloc(__Capacity); } NameDictImpl(const NameDictImpl& other) { @@ -116,7 +110,7 @@ while(!_items[i].first.empty()) { \ Item* old_items = _items; uint16_t old_capacity = _capacity; if(resize){ - _capacity = find_next_power_of_2(_capacity * 2); + _capacity *= 2; _mask = _capacity - 1; } _alloc(_capacity); diff --git a/src/pocketpy.h b/src/pocketpy.h index e3325176..df44e4a5 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -1,6 +1,7 @@ #pragma once #include "ceval.h" +#include "common.h" #include "compiler.h" #include "obj.h" #include "repl.h" @@ -39,24 +40,6 @@ inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool _vm->bind_method<1>("float", #name, [](VM* vm, ArgsView args){ \ return VAR(_CAST(f64, args[0]) op vm->num_to_float(args[1])); \ }); - - - -#define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \ - _vm->bind_method<1>("int", #name, [](VM* vm, ArgsView args){ \ - if(is_int(args[1])) return VAR(_CAST(i64, args[0]) op _CAST(i64, args[1])); \ - if(is_float(args[1])) return VAR(vm->num_to_float(args[0]) op _CAST(f64, args[1])); \ - if constexpr(is_eq) return VAR(args[0] op args[1]); \ - vm->TypeError("unsupported operand type(s) for " #op ); \ - return vm->None; \ - }); \ - _vm->bind_method<1>("float", #name, [](VM* vm, ArgsView args){ \ - if(is_float(args[1])) return VAR(_CAST(f64, args[0]) op _CAST(f64, args[1])); \ - if(is_int(args[1])) return VAR(_CAST(f64, args[0]) op _CAST(i64, args[1])); \ - if constexpr(is_eq) return VAR(args[0] op args[1]); \ - vm->TypeError("unsupported operand type(s) for " #op ); \ - return vm->None; \ - }); inline void init_builtins(VM* _vm) { @@ -64,6 +47,22 @@ inline void init_builtins(VM* _vm) { BIND_NUM_ARITH_OPT(__sub__, -) BIND_NUM_ARITH_OPT(__mul__, *) +#define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \ + _vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { \ + if(is_int(rhs)) return _CAST(i64, lhs) op _CAST(i64, rhs); \ + if(is_float(rhs)) return _CAST(i64, lhs) op _CAST(f64, rhs); \ + if constexpr(is_eq) return false; \ + vm->TypeError("unsupported operand type(s) for " #op ); \ + return false; \ + }); \ + _vm->bind##name(_vm->tp_float, [](VM* vm, PyObject* lhs, PyObject* rhs) { \ + if(is_int(rhs)) return _CAST(f64, lhs) == _CAST(i64, rhs); \ + if(is_float(rhs)) return _CAST(f64, lhs) == _CAST(f64, rhs); \ + if constexpr(is_eq) return false; \ + vm->TypeError("unsupported operand type(s) for " #op ); \ + return false; \ + }); + BIND_NUM_LOGICAL_OPT(__lt__, <, false) BIND_NUM_LOGICAL_OPT(__le__, <=, false) BIND_NUM_LOGICAL_OPT(__gt__, >, false) @@ -203,8 +202,8 @@ inline void init_builtins(VM* _vm) { return VAR(ss.str()); }); - _vm->bind_method<1>("object", "__eq__", CPP_LAMBDA(VAR(args[0] == args[1]))); - _vm->bind_method<1>("object", "__ne__", CPP_LAMBDA(VAR(args[0] != args[1]))); + _vm->bind__eq__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return lhs == rhs; }); + _vm->bind__ne__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return lhs != rhs; }); _vm->bind_constructor<2>("type", CPP_LAMBDA(vm->_t(args[1]))); @@ -376,16 +375,25 @@ inline void init_builtins(VM* _vm) { return VAR(self.escape(false)); }); - _vm->bind_method<1>("str", "__eq__", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - if(!is_type(args[1], vm->tp_str)) return VAR(false); - return VAR(self == CAST(Str&, args[1])); + _vm->bind__eq__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + if(!is_non_tagged_type(rhs, vm->tp_str)) return false; + return _CAST(Str&, lhs) == _CAST(Str&, rhs); }); - - _vm->bind_method<1>("str", "__ne__", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - if(!is_type(args[1], vm->tp_str)) return VAR(true); - return VAR(self != CAST(Str&, args[1])); + _vm->bind__ne__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + if(!is_non_tagged_type(rhs, vm->tp_str)) return true; + return _CAST(Str&, lhs) != _CAST(Str&, rhs); + }); + _vm->bind__gt__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Str&, lhs) > CAST(Str&, rhs); + }); + _vm->bind__lt__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Str&, lhs) < CAST(Str&, rhs); + }); + _vm->bind__ge__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Str&, lhs) >= CAST(Str&, rhs); + }); + _vm->bind__le__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Str&, lhs) <= CAST(Str&, rhs); }); _vm->bind_method<1>("str", "__getitem__", [](VM* vm, ArgsView args) { @@ -393,18 +401,6 @@ inline void init_builtins(VM* _vm) { }); _vm->_type_info("str")->m__getitem__ = PyStrGetItem; - _vm->bind_method<1>("str", "__gt__", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& obj = CAST(Str&, args[1]); - return VAR(self > obj); - }); - - _vm->bind_method<1>("str", "__lt__", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& obj = CAST(Str&, args[1]); - return VAR(self < obj); - }); - _vm->bind_method<-1>("str", "replace", [](VM* vm, ArgsView args) { if(args.size() != 1+2 && args.size() != 1+3) vm->TypeError("replace() takes 2 or 3 arguments"); const Str& self = _CAST(Str&, args[0]); @@ -654,18 +650,11 @@ inline void init_builtins(VM* _vm) { return VAR(Bytes(std::move(buffer))); }); - _vm->bind_method<1>("bytes", "__eq__", [](VM* vm, ArgsView args) { - const Bytes& self = _CAST(Bytes&, args[0]); - if(!is_type(args[1], vm->tp_bytes)) return VAR(false); - const Bytes& other = CAST(Bytes&, args[1]); - return VAR(self == other); + _vm->bind__eq__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Bytes&, lhs) == _CAST(Bytes&, rhs); }); - - _vm->bind_method<1>("bytes", "__ne__", [](VM* vm, ArgsView args) { - const Bytes& self = _CAST(Bytes&, args[0]); - if(!is_type(args[1], vm->tp_bytes)) return VAR(true); - const Bytes& other = CAST(Bytes&, args[1]); - return VAR(self != other); + _vm->bind__ne__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) { + return _CAST(Bytes&, lhs) != _CAST(Bytes&, rhs); }); /************ slice ************/ @@ -886,7 +875,7 @@ struct ReMatch { ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {} static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); + vm->bind_constructor<-1>(type, CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).start))); vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).end))); @@ -1033,8 +1022,8 @@ inline void VM::post_init(){ this->_exec(code, this->builtins); // property is defined in builtins.py so we need to add it after builtins is loaded - _t(tp_object)->attr().set(__class__, property(CPP_LAMBDA(vm->_t(args[0])))); - _t(tp_type)->attr().set(__base__, property([](VM* vm, ArgsView args){ + _t(tp_object)->attr().set("__class__", property(CPP_LAMBDA(vm->_t(args[0])))); + _t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){ const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])]; return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj; })); @@ -1050,16 +1039,13 @@ inline void VM::post_init(){ return CAST(BoundMethod&, args[0]).func; })); - vm->bind_method<1>(_t(tp_bound_method), "__eq__", [](VM* vm, ArgsView args){ - if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->False; - bool ok = _CAST(BoundMethod&, args[0]) == _CAST(BoundMethod&, args[1]); - return VAR(ok); + bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){ + if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return false; + return _CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs); }); - - vm->bind_method<1>(_t(tp_bound_method), "__ne__", [](VM* vm, ArgsView args){ - if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->True; - bool ok = _CAST(BoundMethod&, args[0]) != _CAST(BoundMethod&, args[1]); - return VAR(ok); + bind__ne__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){ + if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return true; + return _CAST(BoundMethod&, lhs) != _CAST(BoundMethod&, rhs); }); _t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){ @@ -1071,10 +1057,9 @@ inline void VM::post_init(){ _t(tp_slice)->attr().set("step", property([](VM* vm, ArgsView args){ return CAST(Slice&, args[0]).step; })); + _t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){ - if(is_tagged(args[0]) || !args[0]->is_attr_valid()){ - vm->AttributeError("__dict__"); - } + if(is_tagged(args[0]) || !args[0]->is_attr_valid()) vm->AttributeError("__dict__"); return VAR(MappingProxy(args[0])); })); diff --git a/src/str.h b/src/str.h index a8f07c66..4d680e32 100644 --- a/src/str.h +++ b/src/str.h @@ -381,34 +381,42 @@ struct FastStrStream{ inline std::map> StrName::_interned; inline std::vector StrName::_r_interned; -const StrName __class__ = StrName::get("__class__"); -const StrName __base__ = StrName::get("__base__"); -const StrName __iter__ = StrName::get("__iter__"); -const StrName __next__ = StrName::get("__next__"); -const StrName __str__ = StrName::get("__str__"); -const StrName __repr__ = StrName::get("__repr__"); -const StrName __getitem__ = StrName::get("__getitem__"); -const StrName __setitem__ = StrName::get("__setitem__"); -const StrName __delitem__ = StrName::get("__delitem__"); -const StrName __contains__ = StrName::get("__contains__"); +// other specials const StrName __init__ = StrName::get("__init__"); -const StrName __json__ = StrName::get("__json__"); -const StrName __name__ = StrName::get("__name__"); -const StrName __len__ = StrName::get("__len__"); -const StrName __get__ = StrName::get("__get__"); -const StrName __set__ = StrName::get("__set__"); -const StrName __getattr__ = StrName::get("__getattr__"); -const StrName __setattr__ = StrName::get("__setattr__"); const StrName __call__ = StrName::get("__call__"); const StrName __doc__ = StrName::get("__doc__"); +const StrName __enter__ = StrName::get("__enter__"); +const StrName __exit__ = StrName::get("__exit__"); +const StrName __name__ = StrName::get("__name__"); +const StrName __get__ = StrName::get("__get__"); +const StrName __set__ = StrName::get("__set__"); -const StrName m_self = StrName::get("self"); +// special names const StrName m_dict = StrName::get("dict"); const StrName m_set = StrName::get("set"); const StrName m_add = StrName::get("add"); -const StrName __enter__ = StrName::get("__enter__"); -const StrName __exit__ = StrName::get("__exit__"); +// unary operators +const StrName __repr__ = StrName::get("__repr__"); +const StrName __str__ = StrName::get("__str__"); +const StrName __hash__ = StrName::get("__hash__"); // unused +const StrName __len__ = StrName::get("__len__"); +const StrName __iter__ = StrName::get("__iter__"); +const StrName __next__ = StrName::get("__next__"); // unused +const StrName __json__ = StrName::get("__json__"); +const StrName __neg__ = StrName::get("__neg__"); // unused +const StrName __bool__ = StrName::get("__bool__"); // unused + +// logical operators +const StrName __eq__ = StrName::get("__eq__"); +const StrName __ne__ = StrName::get("__ne__"); +const StrName __lt__ = StrName::get("__lt__"); +const StrName __le__ = StrName::get("__le__"); +const StrName __gt__ = StrName::get("__gt__"); +const StrName __ge__ = StrName::get("__ge__"); +const StrName __contains__ = StrName::get("__contains__"); + +// binary operators const StrName __add__ = StrName::get("__add__"); const StrName __sub__ = StrName::get("__sub__"); const StrName __mul__ = StrName::get("__mul__"); @@ -418,17 +426,15 @@ const StrName __mod__ = StrName::get("__mod__"); const StrName __pow__ = StrName::get("__pow__"); const StrName __matmul__ = StrName::get("__matmul__"); -const StrName __lt__ = StrName::get("__lt__"); -const StrName __le__ = StrName::get("__le__"); -const StrName __eq__ = StrName::get("__eq__"); -const StrName __ne__ = StrName::get("__ne__"); -const StrName __gt__ = StrName::get("__gt__"); -const StrName __ge__ = StrName::get("__ge__"); - const StrName __lshift__ = StrName::get("__lshift__"); const StrName __rshift__ = StrName::get("__rshift__"); const StrName __and__ = StrName::get("__and__"); const StrName __or__ = StrName::get("__or__"); const StrName __xor__ = StrName::get("__xor__"); +// indexer +const StrName __getitem__ = StrName::get("__getitem__"); +const StrName __setitem__ = StrName::get("__setitem__"); +const StrName __delitem__ = StrName::get("__delitem__"); + } // namespace pkpy \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index 8b173e86..c37fa711 100644 --- a/src/vm.h +++ b/src/vm.h @@ -9,6 +9,7 @@ #include "obj.h" #include "str.h" #include "tuplelist.h" +#include "dict.h" namespace pkpy{ @@ -65,9 +66,47 @@ struct PyTypeInfo{ Type base; Str name; bool subclass_enabled; + // cached special methods + // unary operators + PyObject* (*m__repr__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__str__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__hash__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__len__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__iter__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__next__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__json__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__neg__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__bool__)(VM* vm, PyObject*) = nullptr; + + bool (*m__eq__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__ne__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__lt__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__le__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__gt__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__ge__)(VM* vm, PyObject*, PyObject*) = nullptr; + bool (*m__contains__)(VM* vm, PyObject*, PyObject*) = nullptr; + + // binary operators + PyObject* (*m__add__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__sub__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__mul__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__truediv__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__floordiv__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__mod__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__pow__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__matmul__)(VM* vm, PyObject*, PyObject*) = nullptr; + + PyObject* (*m__lshift__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__rshift__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__and__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__or__)(VM* vm, PyObject*, PyObject*) = nullptr; + PyObject* (*m__xor__)(VM* vm, PyObject*, PyObject*) = nullptr; + + // indexer PyObject* (*m__getitem__)(VM* vm, PyObject*, PyObject*) = nullptr; PyObject* (*m__setitem__)(VM* vm, PyObject*, PyObject*, PyObject*) = nullptr; + PyObject* (*m__delitem__)(VM* vm, PyObject*, PyObject*) = nullptr; }; struct FrameId{ @@ -283,6 +322,55 @@ public: return &_all_types[obj->type]; } +#define BIND_LOGICAL_SPECIAL(name) \ + void bind##name(Type type, bool (*f)(VM* vm, PyObject* lhs, PyObject* rhs)){ \ + PyObject* obj = _t(type); \ + _all_types[type].m##name = f; \ + bind_method<1>(obj, #name, [](VM* vm, ArgsView args){ \ + bool ok = vm->_inst_type_info(args[0])->m##name(vm, args[0], args[1]); \ + return ok ? vm->True : vm->False; \ + }); \ + } + + BIND_LOGICAL_SPECIAL(__eq__) + BIND_LOGICAL_SPECIAL(__ne__) + BIND_LOGICAL_SPECIAL(__lt__) + BIND_LOGICAL_SPECIAL(__le__) + BIND_LOGICAL_SPECIAL(__gt__) + BIND_LOGICAL_SPECIAL(__ge__) + BIND_LOGICAL_SPECIAL(__contains__) + +#undef BIND_LOGICAL_SPECIAL + + +#define BIND_BINARY_SPECIAL(name) \ + void bind##name(Type type, PyObject* (*f)(VM* vm, PyObject* lhs, PyObject* rhs)){ \ + PyObject* obj = _t(type); \ + _all_types[type].m##name = f; \ + bind_method<1>(obj, #name, [](VM* vm, ArgsView args){ \ + return vm->_inst_type_info(args[0])->m##name(vm, args[0], args[1]); \ + }); \ + } + + BIND_BINARY_SPECIAL(__add__) + BIND_BINARY_SPECIAL(__sub__) + BIND_BINARY_SPECIAL(__mul__) + BIND_BINARY_SPECIAL(__truediv__) + + bool py_equals(PyObject* lhs, PyObject* rhs){ + if(lhs == rhs) return true; + const PyTypeInfo* ti = _inst_type_info(lhs); + if(ti->m__eq__) return ti->m__eq__(this, lhs, rhs); + return call_method(lhs, __eq__, rhs) == True; + } + + bool py_not_equals(PyObject* lhs, PyObject* rhs){ + if(lhs == rhs) return false; + const PyTypeInfo* ti = _inst_type_info(lhs); + if(ti->m__ne__) return ti->m__ne__(this, lhs, rhs); + return call_method(lhs, __ne__, rhs) == True; + } + template void bind_func(Str type, Str name, NativeFuncC fn) { bind_func(_find_type(type), name, fn); @@ -353,6 +441,7 @@ public: void IndexError(const Str& msg){ _error("IndexError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } + void KeyError(const Str& msg){ _error("KeyError", msg); } void AttributeError(PyObject* obj, StrName name){ // OBJ_NAME calls getattr, which may lead to a infinite recursion @@ -373,12 +462,12 @@ public: void check_int(PyObject* obj){ if(is_int(obj)) return; - check_type(obj, tp_int); + check_type(obj, tp_int); // if failed, redirect to check_type to raise TypeError } void check_float(PyObject* obj){ if(is_float(obj)) return; - check_type(obj, tp_float); + check_type(obj, tp_float); // if failed, redirect to check_type to raise TypeError } PyObject* _t(Type t){ @@ -1278,4 +1367,13 @@ inline PyObject* PyStrGetItem(VM* vm, PyObject* obj, PyObject* index){ return VAR(self.u8_getitem(i)); } +inline void Dict::_probe(PyObject *key, bool &ok, int &i) const{ + ok = false; + i = vm->hash(key) & _mask; + while(_items[i].first != nullptr) { + if(vm->py_equals(_items[i].first, key)) { ok = true; break; } + i = (i + 1) & _mask; + } +} + } // namespace pkpy \ No newline at end of file