mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20: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.
|
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`.
|
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.
|
@ -308,10 +308,14 @@ __NEXT_STEP:;
|
|||||||
INT_BINARY_OP(<=, __le__)
|
INT_BINARY_OP(<=, __le__)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
TARGET(COMPARE_EQ)
|
TARGET(COMPARE_EQ)
|
||||||
INT_BINARY_OP(==, __eq__)
|
_1 = POPX();
|
||||||
|
_0 = TOP();
|
||||||
|
TOP() = VAR(py_equals(_0, _1));
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
TARGET(COMPARE_NE)
|
TARGET(COMPARE_NE)
|
||||||
INT_BINARY_OP(!=, __ne__)
|
_1 = POPX();
|
||||||
|
_0 = TOP();
|
||||||
|
TOP() = VAR(py_not_equals(_0, _1));
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
TARGET(COMPARE_GT)
|
TARGET(COMPARE_GT)
|
||||||
INT_BINARY_OP(>, __gt__)
|
INT_BINARY_OP(>, __gt__)
|
||||||
|
36
src/cffi.h
36
src/cffi.h
@ -11,7 +11,7 @@ namespace pkpy {
|
|||||||
static const StrName __x1(#name); \
|
static const StrName __x1(#name); \
|
||||||
return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \
|
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))){ \
|
if(!vm->isinstance(val, T::_type(vm))){ \
|
||||||
vm->TypeError("expected '" #mod "." #name "', got " + OBJ_NAME(vm->_t(val)).escape()); \
|
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(void* ptr): ptr(ptr), base_offset(1){}
|
||||||
VoidP(): ptr(nullptr), 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){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_default_constructor<VoidP>(type);
|
vm->bind_default_constructor<VoidP>(type);
|
||||||
|
|
||||||
@ -51,16 +58,25 @@ struct VoidP{
|
|||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_method<1>(type, "__eq__", [](VM* vm, ArgsView args){
|
vm->bind__eq__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
|
||||||
VoidP& self = _CAST(VoidP&, args[0]);
|
if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return false;
|
||||||
VoidP& other = CAST(VoidP&, args[1]);
|
return _CAST(VoidP&, lhs) == _CAST(VoidP&, rhs);
|
||||||
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){
|
||||||
vm->bind_method<1>(type, "__ne__", [](VM* vm, ArgsView args){
|
if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return true;
|
||||||
VoidP& self = _CAST(VoidP&, args[0]);
|
return _CAST(VoidP&, lhs) != _CAST(VoidP&, rhs);
|
||||||
VoidP& other = CAST(VoidP&, args[1]);
|
});
|
||||||
return VAR(self.ptr != other.ptr || self.base_offset != other.base_offset);
|
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){
|
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 "memory.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
|
namespace pkpy{
|
||||||
|
|
||||||
struct Dict{
|
struct Dict{
|
||||||
using Item = std::pair<PyObject*, PyObject*>;
|
using Item = std::pair<PyObject*, PyObject*>;
|
||||||
static constexpr int __Capacity = 8;
|
static constexpr int __Capacity = 8;
|
||||||
static constexpr float __LoadFactor = 0.67;
|
static constexpr float __LoadFactor = 0.67;
|
||||||
static_assert(sizeof(Item) * __Capacity <= 128);
|
static_assert(sizeof(Item) * __Capacity <= 128);
|
||||||
|
|
||||||
|
VM* vm;
|
||||||
int _capacity;
|
int _capacity;
|
||||||
int _mask;
|
int _mask;
|
||||||
int _size;
|
int _size;
|
||||||
int _critical_size;
|
int _critical_size;
|
||||||
Item* _items;
|
Item* _items;
|
||||||
|
|
||||||
void _alloc(int cap){
|
Dict(VM* vm): vm(vm), _capacity(__Capacity),
|
||||||
_items = (Item*)pool128.alloc(cap * sizeof(Item));
|
|
||||||
memset(_items, 0, cap * sizeof(Item));
|
|
||||||
}
|
|
||||||
|
|
||||||
Dict(): _capacity(__Capacity),
|
|
||||||
_mask(__Capacity-1),
|
_mask(__Capacity-1),
|
||||||
_size(0), _critical_size(__Capacity*__LoadFactor+0.5f){
|
_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; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
void _probe(PyObject* key, bool& ok, int& i){
|
void _probe(PyObject* key, bool& ok, int& i) const;
|
||||||
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 set(PyObject* key, PyObject* val){
|
void set(PyObject* key, PyObject* val){
|
||||||
bool ok; int i;
|
bool ok; int i;
|
||||||
@ -56,10 +48,11 @@ struct Dict{
|
|||||||
void _rehash(){
|
void _rehash(){
|
||||||
Item* old_items = _items;
|
Item* old_items = _items;
|
||||||
int old_capacity = _capacity;
|
int old_capacity = _capacity;
|
||||||
_capacity = find_next_power_of_2(_capacity * 2);
|
_capacity *= 2;
|
||||||
_mask = _capacity - 1;
|
_mask = _capacity - 1;
|
||||||
_critical_size = _capacity * __LoadFactor + 0.5f;
|
_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++){
|
for(int i=0; i<old_capacity; i++){
|
||||||
if(old_items[i].first == nullptr) continue;
|
if(old_items[i].first == nullptr) continue;
|
||||||
bool ok; int j;
|
bool ok; int j;
|
||||||
@ -79,3 +72,5 @@ struct Dict{
|
|||||||
|
|
||||||
~Dict(){ pool128.dealloc(_items); }
|
~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};
|
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) )
|
#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){
|
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));
|
memset(_items, 0, cap * sizeof(Item));
|
||||||
}
|
}
|
||||||
|
|
||||||
NameDictImpl(float load_factor=0.67, uint16_t capacity=__Capacity, uint16_t hash_seed=kHashSeeds[0]):
|
NameDictImpl(float load_factor=0.67):
|
||||||
_load_factor(load_factor), _capacity(capacity), _size(0),
|
_load_factor(load_factor), _capacity(__Capacity), _size(0),
|
||||||
_hash_seed(hash_seed), _mask(capacity-1) {
|
_hash_seed(kHashSeeds[0]), _mask(__Capacity-1) {
|
||||||
_alloc(capacity);
|
_alloc(__Capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
NameDictImpl(const NameDictImpl& other) {
|
NameDictImpl(const NameDictImpl& other) {
|
||||||
@ -116,7 +110,7 @@ while(!_items[i].first.empty()) { \
|
|||||||
Item* old_items = _items;
|
Item* old_items = _items;
|
||||||
uint16_t old_capacity = _capacity;
|
uint16_t old_capacity = _capacity;
|
||||||
if(resize){
|
if(resize){
|
||||||
_capacity = find_next_power_of_2(_capacity * 2);
|
_capacity *= 2;
|
||||||
_mask = _capacity - 1;
|
_mask = _capacity - 1;
|
||||||
}
|
}
|
||||||
_alloc(_capacity);
|
_alloc(_capacity);
|
||||||
|
119
src/pocketpy.h
119
src/pocketpy.h
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ceval.h"
|
#include "ceval.h"
|
||||||
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "repl.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) {
|
inline void init_builtins(VM* _vm) {
|
||||||
BIND_NUM_ARITH_OPT(__add__, +)
|
BIND_NUM_ARITH_OPT(__add__, +)
|
||||||
BIND_NUM_ARITH_OPT(__sub__, -)
|
BIND_NUM_ARITH_OPT(__sub__, -)
|
||||||
BIND_NUM_ARITH_OPT(__mul__, *)
|
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(__lt__, <, false)
|
||||||
BIND_NUM_LOGICAL_OPT(__le__, <=, false)
|
BIND_NUM_LOGICAL_OPT(__le__, <=, false)
|
||||||
BIND_NUM_LOGICAL_OPT(__gt__, >, false)
|
BIND_NUM_LOGICAL_OPT(__gt__, >, false)
|
||||||
@ -203,8 +202,8 @@ inline void init_builtins(VM* _vm) {
|
|||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<1>("object", "__eq__", CPP_LAMBDA(VAR(args[0] == args[1])));
|
_vm->bind__eq__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return lhs == rhs; });
|
||||||
_vm->bind_method<1>("object", "__ne__", CPP_LAMBDA(VAR(args[0] != args[1])));
|
_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])));
|
_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));
|
return VAR(self.escape(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<1>("str", "__eq__", [](VM* vm, ArgsView args) {
|
_vm->bind__eq__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
if(!is_non_tagged_type(rhs, vm->tp_str)) return false;
|
||||||
if(!is_type(args[1], vm->tp_str)) return VAR(false);
|
return _CAST(Str&, lhs) == _CAST(Str&, rhs);
|
||||||
return VAR(self == CAST(Str&, args[1]));
|
|
||||||
});
|
});
|
||||||
|
_vm->bind__ne__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
|
||||||
_vm->bind_method<1>("str", "__ne__", [](VM* vm, ArgsView args) {
|
if(!is_non_tagged_type(rhs, vm->tp_str)) return true;
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
return _CAST(Str&, lhs) != _CAST(Str&, rhs);
|
||||||
if(!is_type(args[1], vm->tp_str)) return VAR(true);
|
});
|
||||||
return VAR(self != CAST(Str&, args[1]));
|
_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) {
|
_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->_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) {
|
_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");
|
if(args.size() != 1+2 && args.size() != 1+3) vm->TypeError("replace() takes 2 or 3 arguments");
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
@ -654,18 +650,11 @@ inline void init_builtins(VM* _vm) {
|
|||||||
return VAR(Bytes(std::move(buffer)));
|
return VAR(Bytes(std::move(buffer)));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<1>("bytes", "__eq__", [](VM* vm, ArgsView args) {
|
_vm->bind__eq__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) {
|
||||||
const Bytes& self = _CAST(Bytes&, args[0]);
|
return _CAST(Bytes&, lhs) == _CAST(Bytes&, rhs);
|
||||||
if(!is_type(args[1], vm->tp_bytes)) return VAR(false);
|
|
||||||
const Bytes& other = CAST(Bytes&, args[1]);
|
|
||||||
return VAR(self == other);
|
|
||||||
});
|
});
|
||||||
|
_vm->bind__ne__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) {
|
||||||
_vm->bind_method<1>("bytes", "__ne__", [](VM* vm, ArgsView args) {
|
return _CAST(Bytes&, lhs) != _CAST(Bytes&, rhs);
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/************ slice ************/
|
/************ slice ************/
|
||||||
@ -886,7 +875,7 @@ struct ReMatch {
|
|||||||
ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {}
|
ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
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, "start", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).start)));
|
||||||
vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).end)));
|
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);
|
this->_exec(code, this->builtins);
|
||||||
|
|
||||||
// property is defined in builtins.py so we need to add it after builtins is loaded
|
// 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_object)->attr().set("__class__", property(CPP_LAMBDA(vm->_t(args[0]))));
|
||||||
_t(tp_type)->attr().set(__base__, property([](VM* vm, ArgsView args){
|
_t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){
|
||||||
const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])];
|
const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])];
|
||||||
return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj;
|
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;
|
return CAST(BoundMethod&, args[0]).func;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vm->bind_method<1>(_t(tp_bound_method), "__eq__", [](VM* vm, ArgsView args){
|
bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
|
||||||
if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->False;
|
if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return false;
|
||||||
bool ok = _CAST(BoundMethod&, args[0]) == _CAST(BoundMethod&, args[1]);
|
return _CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs);
|
||||||
return VAR(ok);
|
|
||||||
});
|
});
|
||||||
|
bind__ne__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
|
||||||
vm->bind_method<1>(_t(tp_bound_method), "__ne__", [](VM* vm, ArgsView args){
|
if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return true;
|
||||||
if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->True;
|
return _CAST(BoundMethod&, lhs) != _CAST(BoundMethod&, rhs);
|
||||||
bool ok = _CAST(BoundMethod&, args[0]) != _CAST(BoundMethod&, args[1]);
|
|
||||||
return VAR(ok);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){
|
_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){
|
_t(tp_slice)->attr().set("step", property([](VM* vm, ArgsView args){
|
||||||
return CAST(Slice&, args[0]).step;
|
return CAST(Slice&, args[0]).step;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
_t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){
|
_t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){
|
||||||
if(is_tagged(args[0]) || !args[0]->is_attr_valid()){
|
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) vm->AttributeError("__dict__");
|
||||||
vm->AttributeError("__dict__");
|
|
||||||
}
|
|
||||||
return VAR(MappingProxy(args[0]));
|
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::map<Str, uint16_t, std::less<>> StrName::_interned;
|
||||||
inline std::vector<Str> StrName::_r_interned;
|
inline std::vector<Str> StrName::_r_interned;
|
||||||
|
|
||||||
const StrName __class__ = StrName::get("__class__");
|
// other specials
|
||||||
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__");
|
|
||||||
const StrName __init__ = StrName::get("__init__");
|
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 __call__ = StrName::get("__call__");
|
||||||
const StrName __doc__ = StrName::get("__doc__");
|
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_dict = StrName::get("dict");
|
||||||
const StrName m_set = StrName::get("set");
|
const StrName m_set = StrName::get("set");
|
||||||
const StrName m_add = StrName::get("add");
|
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 __add__ = StrName::get("__add__");
|
||||||
const StrName __sub__ = StrName::get("__sub__");
|
const StrName __sub__ = StrName::get("__sub__");
|
||||||
const StrName __mul__ = StrName::get("__mul__");
|
const StrName __mul__ = StrName::get("__mul__");
|
||||||
@ -418,17 +426,15 @@ const StrName __mod__ = StrName::get("__mod__");
|
|||||||
const StrName __pow__ = StrName::get("__pow__");
|
const StrName __pow__ = StrName::get("__pow__");
|
||||||
const StrName __matmul__ = StrName::get("__matmul__");
|
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 __lshift__ = StrName::get("__lshift__");
|
||||||
const StrName __rshift__ = StrName::get("__rshift__");
|
const StrName __rshift__ = StrName::get("__rshift__");
|
||||||
const StrName __and__ = StrName::get("__and__");
|
const StrName __and__ = StrName::get("__and__");
|
||||||
const StrName __or__ = StrName::get("__or__");
|
const StrName __or__ = StrName::get("__or__");
|
||||||
const StrName __xor__ = StrName::get("__xor__");
|
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
|
} // namespace pkpy
|
102
src/vm.h
102
src/vm.h
@ -9,6 +9,7 @@
|
|||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
#include "tuplelist.h"
|
#include "tuplelist.h"
|
||||||
|
#include "dict.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -65,9 +66,47 @@ struct PyTypeInfo{
|
|||||||
Type base;
|
Type base;
|
||||||
Str name;
|
Str name;
|
||||||
bool subclass_enabled;
|
bool subclass_enabled;
|
||||||
|
|
||||||
// cached special methods
|
// 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__getitem__)(VM* vm, PyObject*, PyObject*) = nullptr;
|
||||||
PyObject* (*m__setitem__)(VM* vm, PyObject*, PyObject*, PyObject*) = nullptr;
|
PyObject* (*m__setitem__)(VM* vm, PyObject*, PyObject*, PyObject*) = nullptr;
|
||||||
|
PyObject* (*m__delitem__)(VM* vm, PyObject*, PyObject*) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameId{
|
struct FrameId{
|
||||||
@ -283,6 +322,55 @@ public:
|
|||||||
return &_all_types[obj->type];
|
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>
|
template<int ARGC>
|
||||||
void bind_func(Str type, Str name, NativeFuncC fn) {
|
void bind_func(Str type, Str name, NativeFuncC fn) {
|
||||||
bind_func<ARGC>(_find_type(type), name, fn);
|
bind_func<ARGC>(_find_type(type), name, fn);
|
||||||
@ -353,6 +441,7 @@ public:
|
|||||||
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
||||||
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
||||||
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
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){
|
void AttributeError(PyObject* obj, StrName name){
|
||||||
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
||||||
@ -373,12 +462,12 @@ public:
|
|||||||
|
|
||||||
void check_int(PyObject* obj){
|
void check_int(PyObject* obj){
|
||||||
if(is_int(obj)) return;
|
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){
|
void check_float(PyObject* obj){
|
||||||
if(is_float(obj)) return;
|
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){
|
PyObject* _t(Type t){
|
||||||
@ -1278,4 +1367,13 @@ inline PyObject* PyStrGetItem(VM* vm, PyObject* obj, PyObject* index){
|
|||||||
return VAR(self.u8_getitem(i));
|
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
|
} // namespace pkpy
|
Loading…
x
Reference in New Issue
Block a user