tag pointers

This commit is contained in:
blueloveTH 2023-02-20 02:56:52 +08:00
parent ad99bd5b21
commit 44be9e8bde
5 changed files with 173 additions and 163 deletions

View File

@ -69,7 +69,7 @@ PyVar VM::run_frame(Frame* frame){
pkpy::Args items = frame->pop_n_reversed(byte.arg);
bool done = false;
for(int i=0; i<items.size(); i++){
if(!items[i]->is_type(tp_ref)) {
if(!is_type(items[i], tp_ref)) {
done = true;
for(int j=i; j<items.size(); j++) frame->try_deref(this, items[j]);
frame->push(PyTuple(std::move(items)));

View File

@ -20,38 +20,38 @@ namespace pkpy{
class shared_ptr {
int* counter;
#define _t() ((T*)(counter + 1))
#define _inc_counter() if(counter) ++(*counter)
#define _dec_counter() if(counter && --(*counter) == 0){ SpAllocator<T>::dealloc(counter); }
inline T* _t() const {
if(is_tagged()) UNREACHABLE();
return (T*)(counter + 1);
}
inline void _inc_counter() const { if(counter) ++(*counter); }
inline void _dec_counter() const { if(counter && --(*counter) == 0){ SpAllocator<T>::dealloc(counter); } }
public:
shared_ptr() : counter(nullptr) {}
shared_ptr(int* counter) : counter(counter) {}
shared_ptr(const shared_ptr& other) : counter(other.counter) {
_inc_counter();
if(!is_tagged()) _inc_counter();
}
shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) {
other.counter = nullptr;
}
~shared_ptr() { _dec_counter(); }
~shared_ptr() { if(!is_tagged()) _dec_counter(); }
bool operator==(const shared_ptr& other) const {
return counter == other.counter;
}
bool operator!=(const shared_ptr& other) const {
return counter != other.counter;
}
bool operator==(std::nullptr_t) const {
return counter == nullptr;
}
bool operator!=(std::nullptr_t) const {
return counter != nullptr;
}
bool operator==(const shared_ptr& other) const { return counter == other.counter; }
bool operator!=(const shared_ptr& other) const { return counter != other.counter; }
bool operator<(const shared_ptr& other) const { return counter < other.counter; }
bool operator>(const shared_ptr& other) const { return counter > other.counter; }
bool operator<=(const shared_ptr& other) const { return counter <= other.counter; }
bool operator>=(const shared_ptr& other) const { return counter >= other.counter; }
bool operator==(std::nullptr_t) const { return counter == nullptr; }
bool operator!=(std::nullptr_t) const { return counter != nullptr; }
shared_ptr& operator=(const shared_ptr& other) {
if(is_tagged()) {
counter = other.counter;
return *this;
}
_dec_counter();
counter = other.counter;
_inc_counter();
@ -59,6 +59,11 @@ namespace pkpy{
}
shared_ptr& operator=(shared_ptr&& other) noexcept {
if(is_tagged()) {
counter = other.counter;
other.counter = nullptr;
return *this;
}
_dec_counter();
counter = other.counter;
other.counter = nullptr;
@ -68,17 +73,26 @@ namespace pkpy{
T& operator*() const { return *_t(); }
T* operator->() const { return _t(); }
T* get() const { return _t(); }
int use_count() const { return counter ? *counter : 0; }
int use_count() const {
if(is_tagged()) return 1;
return counter ? *counter : 0;
}
void reset(){
_dec_counter();
if(!is_tagged()) _dec_counter();
counter = nullptr;
}
};
#undef _t
#undef _inc_counter
#undef _dec_counter
template <typename __VAL>
inline __VAL cast() const { return reinterpret_cast<__VAL>(counter); }
inline bool is_tagged() const { return (cast<std::uintptr_t>() & 0b11) != 0b00; }
inline bool is_tag_00() const { return (cast<std::uintptr_t>() & 0b11) == 0b00; }
inline bool is_tag_01() const { return (cast<std::uintptr_t>() & 0b11) == 0b01; }
inline bool is_tag_10() const { return (cast<std::uintptr_t>() & 0b11) == 0b10; }
inline bool is_tag_11() const { return (cast<std::uintptr_t>() & 0b11) == 0b11; }
};
template <typename T, typename U, typename... Args>
shared_ptr<T> make_shared(Args&&... args) {

View File

@ -79,17 +79,13 @@ public:
struct PyObject {
Type type;
pkpy::NameDict* _attr;
// void* _tid;
const int _size;
inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
inline pkpy::NameDict& attr() noexcept { return *_attr; }
inline PyVar& attr(const Str& name) noexcept { return (*_attr)[name]; }
inline bool is_type(Type type) const noexcept{ return this->type == type; }
virtual void* value() = 0;
PyObject(Type type, const int size) : type(type), _size(size) {}
PyObject(Type type) : type(type) {}
virtual ~PyObject() { delete _attr; }
};
@ -97,8 +93,8 @@ template <typename T>
struct Py_ : PyObject {
T _value;
Py_(Type type, const T& val): PyObject(type, sizeof(Py_<T>)), _value(val) { _init(); }
Py_(Type type, T&& val): PyObject(type, sizeof(Py_<T>)), _value(std::move(val)) { _init(); }
Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); }
Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); }
inline void _init() noexcept {
if constexpr (std::is_same_v<T, Dummy> || std::is_same_v<T, Type>) {
@ -113,66 +109,37 @@ struct Py_ : PyObject {
#define OBJ_GET(T, obj) (((Py_<T>*)((obj).get()))->_value)
#define OBJ_NAME(obj) OBJ_GET(Str, (obj)->attr(__name__))
const int kTpIntIndex = 2;
const int kTpFloatIndex = 3;
inline bool is_type(const PyVar& obj, Type type) noexcept {
switch(type.index){
case kTpIntIndex: return obj.is_tag_01();
case kTpFloatIndex: return obj.is_tag_10();
default: return obj->type == type;
}
}
inline bool is_int_or_float(const PyVar& obj) noexcept {
return obj.is_tag_01() || obj.is_tag_10();
}
inline bool is_int(const PyVar& obj) noexcept {
return obj.is_tag_01();
}
inline bool is_float(const PyVar& obj) noexcept {
return obj.is_tag_10();
}
#define PY_CLASS(mod, name) \
inline static Type _type(VM* vm) { return OBJ_GET(Type, vm->_modules[#mod]->attr(#name)); } \
inline static const char* _mod() { return #mod; } \
inline static const char* _name() { return #name; }
namespace pkpy {
template<int N>
struct MemBlock {
std::vector<void*> a;
int block_size;
MemBlock(int block_size) : block_size(block_size) {
new_block();
}
void new_block(){
int8_t* total = (int8_t*)malloc(N * block_size);
for(int i = 0; i < block_size; ++i){
a.push_back((void*)(total + i * N));
}
}
inline void* alloc(){
if(a.empty()) new_block();
void* p = a.back();
a.pop_back();
return p;
}
inline void dealloc(void* p) noexcept{
a.push_back(p);
}
~MemBlock(){
free(a[0]);
}
union __8B {
i64 _int;
f64 _float;
__8B(i64 val) : _int(val) {}
__8B(f64 val) : _float(val) {}
};
constexpr int kMemObjSize = sizeof(int) + sizeof(Py_<i64>);
static THREAD_LOCAL MemBlock<kMemObjSize> _mem_pool(512);
template<>
struct SpAllocator<PyObject> {
template<typename U>
inline static int* alloc(){
if constexpr (sizeof(int) + sizeof(U) == kMemObjSize) {
return (int*)_mem_pool.alloc();
}
return (int*)malloc(sizeof(int) + sizeof(U));
}
inline static void dealloc(int* counter){
PyObject* obj = (PyObject*)(counter + 1);
obj->~PyObject();
if(obj->_size == kMemObjSize - sizeof(int)){
_mem_pool.dealloc(counter);
}else{
free(counter);
}
}
};
}

View File

@ -20,7 +20,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
#define BIND_NUM_ARITH_OPT(name, op) \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \
if(args[0]->is_type(vm->tp_int) && args[1]->is_type(vm->tp_int)){ \
if(is_type(args[0], vm->tp_int) && is_type(args[1], vm->tp_int)){ \
return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \
}else{ \
return vm->PyFloat(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \
@ -29,10 +29,8 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
#define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \
bool _0 = args[0]->is_type(vm->tp_int) || args[0]->is_type(vm->tp_float); \
bool _1 = args[1]->is_type(vm->tp_int) || args[1]->is_type(vm->tp_float); \
if(!_0 || !_1){ \
if constexpr(is_eq) return vm->PyBool(args[0].get() op args[1].get()); \
if(!is_int_or_float(args[0]) || !is_int_or_float(args[1])){ \
if constexpr(is_eq) return vm->PyBool(args[0] op args[1]); \
vm->TypeError("unsupported operand type(s) for " #op ); \
} \
return vm->PyBool(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \
@ -170,7 +168,7 @@ void init_builtins(VM* _vm) {
});
_vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, pkpy::Args& args) {
if(args[0]->is_type(vm->tp_int) && args[1]->is_type(vm->tp_int)){
if(is_int(args[0]) && is_int(args[1])){
i64 lhs = vm->PyInt_AS_C(args[0]);
i64 rhs = vm->PyInt_AS_C(args[1]);
bool flag = false;
@ -190,18 +188,18 @@ void init_builtins(VM* _vm) {
/************ PyInt ************/
_vm->bind_static_method<1>("int", "__new__", [](VM* vm, pkpy::Args& args) {
if (args[0]->is_type(vm->tp_int)) return args[0];
if (args[0]->is_type(vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0]));
if (args[0]->is_type(vm->tp_bool)) return vm->PyInt(vm->PyBool_AS_C(args[0]) ? 1 : 0);
if (args[0]->is_type(vm->tp_str)) {
if (is_type(args[0], vm->tp_int)) return args[0];
if (is_type(args[0], vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0]));
if (is_type(args[0], vm->tp_bool)) return vm->PyInt(vm->PyBool_AS_C(args[0]) ? 1 : 0);
if (is_type(args[0], vm->tp_str)) {
const Str& s = vm->PyStr_AS_C(args[0]);
try{
size_t parsed = 0;
i64 val = std::stoll(s, &parsed, 10);
if(parsed != s.size()) throw std::invalid_argument("");
if(parsed != s.size()) throw std::invalid_argument("<?>");
return vm->PyInt(val);
}catch(std::invalid_argument&){
vm->ValueError("invalid literal for int(): '" + s + "'");
vm->ValueError("invalid literal for int(): " + s.escape(true));
}
}
vm->TypeError("int() argument must be a int, float, bool or str");
@ -236,10 +234,10 @@ void init_builtins(VM* _vm) {
/************ PyFloat ************/
_vm->bind_static_method<1>("float", "__new__", [](VM* vm, pkpy::Args& args) {
if (args[0]->is_type(vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0]));
if (args[0]->is_type(vm->tp_float)) return args[0];
if (args[0]->is_type(vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0);
if (args[0]->is_type(vm->tp_str)) {
if (is_type(args[0], vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0]));
if (is_type(args[0], vm->tp_float)) return args[0];
if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0);
if (is_type(args[0], vm->tp_str)) {
const Str& s = vm->PyStr_AS_C(args[0]);
if(s == "inf") return vm->PyFloat(INFINITY);
if(s == "-inf") return vm->PyFloat(-INFINITY);
@ -258,7 +256,7 @@ void init_builtins(VM* _vm) {
f64 val = vm->PyFloat_AS_C(args[0]);
if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val));
StrStream ss;
ss << std::setprecision(std::numeric_limits<f64>::max_digits10-1) << val;
ss << std::setprecision(std::numeric_limits<f64>::max_digits10-1-2) << val;
std::string s = ss.str();
if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0";
return vm->PyStr(s);
@ -307,13 +305,13 @@ void init_builtins(VM* _vm) {
});
_vm->bind_method<1>("str", "__eq__", [](VM* vm, pkpy::Args& args) {
if(args[0]->is_type(vm->tp_str) && args[1]->is_type(vm->tp_str))
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1]));
return vm->PyBool(args[0] == args[1]);
});
_vm->bind_method<1>("str", "__ne__", [](VM* vm, pkpy::Args& args) {
if(args[0]->is_type(vm->tp_str) && args[1]->is_type(vm->tp_str))
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return vm->PyBool(vm->PyStr_AS_C(args[0]) != vm->PyStr_AS_C(args[1]));
return vm->PyBool(args[0] != args[1]);
});
@ -321,7 +319,7 @@ void init_builtins(VM* _vm) {
_vm->bind_method<1>("str", "__getitem__", [](VM* vm, pkpy::Args& args) {
const Str& _self (vm->PyStr_AS_C(args[0]));
if(args[1]->is_type(vm->tp_slice)){
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(_self.u8_length());
return vm->PyStr(_self.u8_substr(s.start, s.stop));
@ -441,7 +439,7 @@ void init_builtins(VM* _vm) {
_vm->bind_method<1>("list", "__getitem__", [](VM* vm, pkpy::Args& args) {
const pkpy::List& self = vm->PyList_AS_C(args[0]);
if(args[1]->is_type(vm->tp_slice)){
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(self.size());
pkpy::List new_list;
@ -483,7 +481,7 @@ void init_builtins(VM* _vm) {
_vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, pkpy::Args& args) {
const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]);
if(args[1]->is_type(vm->tp_slice)){
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(self.size());
pkpy::List new_list;
@ -592,7 +590,7 @@ void add_module_dis(VM* vm){
PyVar mod = vm->new_module("dis");
vm->bind_func<1>(mod, "dis", [](VM* vm, pkpy::Args& args) {
PyVar f = args[0];
if(f->is_type(vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method;
if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method;
CodeObject_ code = vm->PyFunction_AS_C(f).code;
(*vm->_stdout) << vm->disassemble(code);
return vm->None;

123
src/vm.h
View File

@ -63,15 +63,15 @@ public:
}
PyVar asRepr(const PyVar& obj){
if(obj->is_type(tp_type)) return PyStr("<class '" + OBJ_GET(Str, obj->attr(__name__)) + "'>");
if(is_type(obj, tp_type)) return PyStr("<class '" + OBJ_GET(Str, obj->attr(__name__)) + "'>");
return call(obj, __repr__);
}
const PyVar& asBool(const PyVar& obj){
if(obj->is_type(tp_bool)) return obj;
if(is_type(obj, tp_bool)) return obj;
if(obj == None) return False;
if(obj->is_type(tp_int)) return PyBool(PyInt_AS_C(obj) != 0);
if(obj->is_type(tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0);
if(is_type(obj, tp_int)) return PyBool(PyInt_AS_C(obj) != 0);
if(is_type(obj, tp_float)) return PyBool(PyFloat_AS_C(obj) != 0.0);
PyVarOrNull len_fn = getattr(obj, __len__, false);
if(len_fn != nullptr){
PyVar ret = call(len_fn);
@ -81,7 +81,7 @@ public:
}
PyVar asIter(const PyVar& obj){
if(obj->is_type(tp_native_iterator)) return obj;
if(is_type(obj, tp_native_iterator)) return obj;
PyVarOrNull iter_f = getattr(obj, __iter__, false);
if(iter_f != nullptr) return call(iter_f);
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
@ -89,7 +89,7 @@ public:
}
PyVar asList(const PyVar& iterable){
if(iterable->is_type(tp_list)) return iterable;
if(is_type(iterable, tp_list)) return iterable;
return call(_t(tp_list), pkpy::one_arg(iterable));
}
@ -125,7 +125,7 @@ public:
}
PyVar call(const PyVar& _callable, pkpy::Args args, const pkpy::Args& kwargs, bool opCall){
if(_callable->is_type(tp_type)){
if(is_type(_callable, tp_type)){
PyVar* new_f = _callable->attr().try_get(__new__);
PyVar obj;
if(new_f != nullptr){
@ -139,17 +139,17 @@ public:
}
const PyVar* callable = &_callable;
if((*callable)->is_type(tp_bound_method)){
if(is_type(*callable, tp_bound_method)){
auto& bm = PyBoundMethod_AS_C((*callable));
callable = &bm.method; // get unbound method
args.extend_self(bm.obj);
}
if((*callable)->is_type(tp_native_function)){
if(is_type(*callable, tp_native_function)){
const auto& f = OBJ_GET(pkpy::NativeFunc, *callable);
if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
return f(this, args);
} else if((*callable)->is_type(tp_function)){
} else if(is_type(*callable, tp_function)){
const pkpy::Function& fn = PyFunction_AS_C(*callable);
pkpy::shared_ptr<pkpy::NameDict> _locals = pkpy::make_shared<pkpy::NameDict>();
pkpy::NameDict& locals = *_locals;
@ -285,7 +285,7 @@ public:
}
PyVar new_type_object(PyVar mod, Str name, PyVar base){
if(!base->is_type(tp_type)) UNREACHABLE();
if(!is_type(base, tp_type)) UNREACHABLE();
PyVar obj = pkpy::make_shared<PyObject, Py_<Type>>(tp_type, _all_types.size());
setattr(obj, __base__, base);
Str fullName = name;
@ -306,12 +306,12 @@ public:
template<typename T>
inline PyVar new_object(const PyVar& type, const T& _value) {
if(!type->is_type(tp_type)) UNREACHABLE();
if(!is_type(type, tp_type)) UNREACHABLE();
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), _value);
}
template<typename T>
inline PyVar new_object(const PyVar& type, T&& _value) {
if(!type->is_type(tp_type)) UNREACHABLE();
if(!is_type(type, tp_type)) UNREACHABLE();
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), std::move(_value));
}
@ -340,12 +340,12 @@ public:
pkpy::NameDict::iterator it;
PyObject* cls;
if(obj->is_type(tp_super)){
if(is_type(obj, tp_super)){
const PyVar* root = &obj;
int depth = 1;
while(true){
root = &OBJ_GET(PyVar, *root);
if(!(*root)->is_type(tp_super)) break;
if(!is_type(*root, tp_super)) break;
depth++;
}
cls = _t(*root).get();
@ -364,14 +364,13 @@ public:
while(cls != None.get()) {
it = cls->attr().find(name);
if(it != cls->attr().end()){
PyVar valueFromCls = it->second;
if(valueFromCls->is_type(tp_function) || valueFromCls->is_type(tp_native_function)){
return PyBoundMethod({obj, std::move(valueFromCls)});
if(is_type(it->second, tp_function) || is_type(it->second, tp_native_function)){
return PyBoundMethod({obj, it->second});
}else{
return valueFromCls;
return it->second;
}
}
cls = cls->attr()[__base__].get();
cls = cls->attr(__base__).get();
}
if(throw_err) AttributeError(obj, name);
return nullptr;
@ -379,10 +378,11 @@ public:
template<typename T>
inline void setattr(PyVar& obj, const Str& name, T&& value) {
if(obj.is_tagged()) TypeError("cannot set attribute");
PyObject* p = obj.get();
while(p->is_type(tp_super)) p = static_cast<PyVar*>(p->value())->get();
while(p->type == tp_super) p = static_cast<PyVar*>(p->value())->get();
if(!p->is_attr_valid()) TypeError("cannot set attribute");
p->attr()[name] = std::forward<T>(value);
p->attr(name) = std::forward<T>(value);
}
template<int ARGC>
@ -422,9 +422,9 @@ public:
}
inline f64 num_to_float(const PyVar& obj){
if (obj->is_type(tp_int)){
if (is_int(obj)){
return (f64)PyInt_AS_C(obj);
}else if(obj->is_type(tp_float)){
}else if(is_float(obj)){
return PyFloat_AS_C(obj);
}
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true));
@ -432,12 +432,12 @@ public:
}
PyVar num_negated(const PyVar& obj){
if (obj->is_type(tp_int)){
if (is_int(obj)){
return PyInt(-PyInt_AS_C(obj));
}else if(obj->is_type(tp_float)){
}else if(is_float(obj)){
return PyFloat(-PyFloat_AS_C(obj));
}
TypeError("unsupported operand type(s) for -");
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true));
return nullptr;
}
@ -510,7 +510,7 @@ public:
for(int i=0; i<co->consts.size(); i++){
PyVar obj = co->consts[i];
if(obj->is_type(tp_function)){
if(is_type(obj, tp_function)){
const auto& f = PyFunction_AS_C(obj);
ss << disassemble(f.code);
}
@ -533,8 +533,8 @@ public:
inline const BaseRef* PyRef_AS_C(const PyVar& obj)
{
if(!obj->is_type(tp_ref)) TypeError("expected an l-value");
return (const BaseRef*)(obj->value());
if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
return static_cast<const BaseRef*>(obj->value());
}
inline const Str& PyStr_AS_C(const PyVar& obj) {
@ -550,8 +550,35 @@ public:
return new_object(tp_str, value);
}
DEF_NATIVE(Int, i64, tp_int)
DEF_NATIVE(Float, f64, tp_float)
inline PyVar PyInt(i64 value) {
const i64 MIN_SAFE_INT = -((i64)1 << 62);
const i64 MAX_SAFE_INT = ((i64)1 << 62) - 1;
if(value < MIN_SAFE_INT || value > MAX_SAFE_INT){
_error("OverflowError", std::to_string(value) + " is out of range");
}
value = (value << 2) | 0b01;
return PyVar(reinterpret_cast<int*>(value));
}
inline i64 PyInt_AS_C(const PyVar& obj){
check_type(obj, tp_int);
i64 value = obj.cast<i64>();
return value >> 2;
}
inline PyVar PyFloat(f64 value) {
auto bits = __8B(value);
i64 _int = bits._int;
bits._int = (_int & 0b00) | 0b10;
return PyVar(reinterpret_cast<int*>(bits._int));
}
inline f64 PyFloat_AS_C(const PyVar& obj){
check_type(obj, tp_float);
i64 _int = obj.cast<i64>();
return __8B(_int)._float;
}
DEF_NATIVE(List, pkpy::List, tp_list)
DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
DEF_NATIVE(Function, pkpy::Function, tp_function)
@ -576,9 +603,11 @@ public:
_types["object"] = _tp_object;
_types["type"] = _tp_type;
tp_bool = _new_type_object("bool");
tp_int = _new_type_object("int");
tp_float = _new_type_object("float");
if(tp_int.index != kTpIntIndex || tp_float.index != kTpFloatIndex) UNREACHABLE();
tp_bool = _new_type_object("bool");
tp_str = _new_type_object("str");
tp_list = _new_type_object("list");
tp_tuple = _new_type_object("tuple");
@ -617,15 +646,9 @@ public:
}
i64 hash(const PyVar& obj){
if (obj->is_type(tp_int)) return PyInt_AS_C(obj);
if (obj->is_type(tp_bool)) return PyBool_AS_C(obj) ? 1 : 0;
if (obj->is_type(tp_float)){
f64 val = PyFloat_AS_C(obj);
return (i64)std::hash<f64>()(val);
}
if (obj->is_type(tp_str)) return PyStr_AS_C(obj).hash();
if (obj->is_type(tp_type)) return (i64)obj.get();
if (obj->is_type(tp_tuple)) {
if (is_type(obj, tp_str)) return PyStr_AS_C(obj).hash();
if (is_int(obj)) return PyInt_AS_C(obj);
if (is_type(obj, tp_tuple)) {
i64 x = 1000003;
const pkpy::Tuple& items = PyTuple_AS_C(obj);
for (int i=0; i<items.size(); i++) {
@ -634,6 +657,12 @@ public:
}
return x;
}
if (is_type(obj, tp_type)) return obj.cast<i64>();
if (is_type(obj, tp_bool)) return PyBool_AS_C(obj) ? 1 : 0;
if (is_float(obj)){
f64 val = PyFloat_AS_C(obj);
return (i64)std::hash<f64>()(val);
}
TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape(true));
return 0;
}
@ -673,7 +702,7 @@ public:
}
inline void check_type(const PyVar& obj, Type type){
if(obj->is_type(type)) return;
if(is_type(obj, type)) return;
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
}
@ -682,6 +711,8 @@ public:
}
inline PyVar& _t(const PyVar& obj){
if(is_int(obj)) return _t(tp_int);
if(is_float(obj)) return _t(tp_float);
return _all_types[OBJ_GET(Type, _t(obj->type)).index];
}
@ -805,10 +836,10 @@ void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
if(args.size() < objs.size()) vm->ValueError("not enough values to unpack"); \
for (int i = 0; i < objs.size(); i++) vm->PyRef_AS_C(objs[i])->set(vm, frame, args[i]);
if(val->is_type(vm->tp_tuple)){
if(is_type(val, vm->tp_tuple)){
const pkpy::Tuple& args = OBJ_GET(pkpy::Tuple, val);
TUPLE_REF_SET()
}else if(val->is_type(vm->tp_list)){
}else if(is_type(val, vm->tp_list)){
const pkpy::List& args = OBJ_GET(pkpy::List, val);
TUPLE_REF_SET()
}else{
@ -823,7 +854,7 @@ void TupleRef::del(VM* vm, Frame* frame) const{
/***** Frame's Impl *****/
inline void Frame::try_deref(VM* vm, PyVar& v){
if(v->is_type(vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
}
PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{