This commit is contained in:
blueloveTH 2023-05-19 16:54:39 +08:00
parent 3f9345fa00
commit 1107cea256
8 changed files with 238 additions and 139 deletions

View File

@ -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`.
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.

View File

@ -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__)

View File

@ -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<VoidP>(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){

View File

@ -5,39 +5,31 @@
#include "memory.h"
#include "str.h"
namespace pkpy{
struct Dict{
using Item = std::pair<PyObject*, PyObject*>;
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<old_capacity; i++){
if(old_items[i].first == nullptr) continue;
bool ok; int j;
@ -78,4 +71,6 @@ struct Dict{
}
~Dict(){ pool128.dealloc(_items); }
};
};
} // namespace pkpy

View File

@ -8,12 +8,6 @@ namespace pkpy{
const std::vector<uint16_t> 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<StrName>& 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);

View File

@ -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]));
}));

View File

@ -381,34 +381,42 @@ struct FastStrStream{
inline std::map<Str, uint16_t, std::less<>> StrName::_interned;
inline std::vector<Str> 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

102
src/vm.h
View File

@ -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<int ARGC>
void bind_func(Str type, Str name, NativeFuncC fn) {
bind_func<ARGC>(_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