mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
...
This commit is contained in:
parent
3f9345fa00
commit
1107cea256
@ -10,3 +10,4 @@ These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined i
|
||||
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`.
|
||||
6. `__eq__`, `__ne__` or `__contains__`, etc.. returns a value that is not a boolean.
|
@ -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__)
|
||||
|
36
src/cffi.h
36
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<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){
|
||||
|
29
src/dict.h
29
src/dict.h
@ -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;
|
||||
@ -79,3 +72,5 @@ struct Dict{
|
||||
|
||||
~Dict(){ pool128.dealloc(_items); }
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
@ -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);
|
||||
|
119
src/pocketpy.h
119
src/pocketpy.h
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ceval.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "obj.h"
|
||||
#include "repl.h"
|
||||
@ -41,29 +42,27 @@ inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool
|
||||
});
|
||||
|
||||
|
||||
|
||||
#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) {
|
||||
BIND_NUM_ARITH_OPT(__add__, +)
|
||||
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]));
|
||||
}));
|
||||
|
||||
|
60
src/str.h
60
src/str.h
@ -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
102
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<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
|
Loading…
x
Reference in New Issue
Block a user