mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 04:50:17 +00:00
update gc
This commit is contained in:
parent
06d486d2a2
commit
c2ef720d90
51
src/gc.h
Normal file
51
src/gc.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "obj.h"
|
||||||
|
|
||||||
|
namespace pkpy {
|
||||||
|
using PyVar0 = PyObject*;
|
||||||
|
|
||||||
|
// a generational mark and sweep garbage collector
|
||||||
|
struct GC{
|
||||||
|
using Generation = std::vector<PyVar0>;
|
||||||
|
static const int kTotalGen = 3;
|
||||||
|
Generation gen[kTotalGen];
|
||||||
|
|
||||||
|
void add(PyVar0 obj){
|
||||||
|
if(!obj->need_gc) return;
|
||||||
|
gen[0].push_back(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sweep(int index){
|
||||||
|
Generation& g = gen[index];
|
||||||
|
if(index < kTotalGen-1){
|
||||||
|
for(int i=0; i<g.size(); i++){
|
||||||
|
if(g[i]->marked){
|
||||||
|
g[i]->marked = false;
|
||||||
|
gen[index+1].push_back(g[i]);
|
||||||
|
}else{
|
||||||
|
delete g[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.clear();
|
||||||
|
}else{
|
||||||
|
Generation alive;
|
||||||
|
// the oldest generation
|
||||||
|
for(int i=0; i<g.size(); i++){
|
||||||
|
if(g[i]->marked){
|
||||||
|
g[i]->marked = false;
|
||||||
|
alive.push_back(g[i]);
|
||||||
|
}else{
|
||||||
|
delete g[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g = std::move(alive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect(int index){
|
||||||
|
sweep(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pkpy
|
@ -230,6 +230,13 @@ while(!_keys[i].empty()) { \
|
|||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply_v(void(*f)(PyVar)) {
|
||||||
|
for(uint16_t i=0; i<_capacity; i++){
|
||||||
|
if(_keys[i].empty()) continue;
|
||||||
|
f(value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
#undef HASH_PROBE
|
#undef HASH_PROBE
|
||||||
#undef _hash
|
#undef _hash
|
||||||
};
|
};
|
||||||
|
16
src/obj.h
16
src/obj.h
@ -88,6 +88,9 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PyObject {
|
struct PyObject {
|
||||||
|
bool need_gc;
|
||||||
|
bool marked;
|
||||||
|
/**********/
|
||||||
Type type;
|
Type type;
|
||||||
NameDict* _attr;
|
NameDict* _attr;
|
||||||
|
|
||||||
@ -96,6 +99,12 @@ struct PyObject {
|
|||||||
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
|
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
|
||||||
virtual void* value() = 0;
|
virtual void* value() = 0;
|
||||||
|
|
||||||
|
virtual void mark() {
|
||||||
|
if(!need_gc || marked) return;
|
||||||
|
marked = true;
|
||||||
|
if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); });
|
||||||
|
}
|
||||||
|
|
||||||
PyObject(Type type) : type(type) {}
|
PyObject(Type type) : type(type) {}
|
||||||
virtual ~PyObject() { delete _attr; }
|
virtual ~PyObject() { delete _attr; }
|
||||||
};
|
};
|
||||||
@ -119,9 +128,14 @@ struct Py_ : PyObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void* value() override { return &_value; }
|
void* value() override { return &_value; }
|
||||||
|
|
||||||
|
void mark() override {
|
||||||
|
PyObject::mark();
|
||||||
|
// extra mark for `T`
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OBJ_GET(T, obj) (((Py_<T>*)((obj).get()))->_value)
|
#define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
|
||||||
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__))
|
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__))
|
||||||
|
|
||||||
const int kTpIntIndex = 2;
|
const int kTpIntIndex = 2;
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
using List = std::vector<PyVar>;
|
using List = std::vector<PyObject*>;
|
||||||
|
|
||||||
class Args {
|
class Args {
|
||||||
static THREAD_LOCAL SmallArrayPool<PyVar, 10> _pool;
|
static THREAD_LOCAL SmallArrayPool<PyObject*, 10> _pool;
|
||||||
|
|
||||||
PyVar* _args;
|
PyObject** _args;
|
||||||
int _size;
|
int _size;
|
||||||
|
|
||||||
inline void _alloc(int n){
|
inline void _alloc(int n){
|
||||||
@ -35,14 +35,14 @@ namespace pkpy {
|
|||||||
|
|
||||||
static pkpy::Args from_list(List&& other) noexcept {
|
static pkpy::Args from_list(List&& other) noexcept {
|
||||||
Args ret(other.size());
|
Args ret(other.size());
|
||||||
memcpy((void*)ret._args, (void*)other.data(), sizeof(PyVar)*ret.size());
|
memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size());
|
||||||
memset((void*)other.data(), 0, sizeof(PyVar)*ret.size());
|
memset((void*)other.data(), 0, sizeof(PyObject*)*ret.size());
|
||||||
other.clear();
|
other.clear();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar& operator[](int i){ return _args[i]; }
|
PyObject*& operator[](int i){ return _args[i]; }
|
||||||
const PyVar& operator[](int i) const { return _args[i]; }
|
PyObject* operator[](int i) const { return _args[i]; }
|
||||||
|
|
||||||
Args& operator=(Args&& other) noexcept {
|
Args& operator=(Args&& other) noexcept {
|
||||||
_pool.dealloc(_args, _size);
|
_pool.dealloc(_args, _size);
|
||||||
@ -57,29 +57,30 @@ namespace pkpy {
|
|||||||
|
|
||||||
List move_to_list() noexcept {
|
List move_to_list() noexcept {
|
||||||
List ret(_size);
|
List ret(_size);
|
||||||
memcpy((void*)ret.data(), (void*)_args, sizeof(PyVar)*_size);
|
memcpy((void*)ret.data(), (void*)_args, sizeof(PyObject*)*_size);
|
||||||
memset((void*)_args, 0, sizeof(PyVar)*_size);
|
memset((void*)_args, 0, sizeof(PyObject*)*_size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void extend_self(const PyVar& self){
|
void extend_self(PyObject* self){
|
||||||
static_assert(std::is_standard_layout_v<PyVar>);
|
PyObject** old_args = _args;
|
||||||
PyVar* old_args = _args;
|
|
||||||
int old_size = _size;
|
int old_size = _size;
|
||||||
_alloc(old_size+1);
|
_alloc(old_size+1);
|
||||||
_args[0] = self;
|
_args[0] = self;
|
||||||
if(old_size == 0) return;
|
if(old_size == 0) return;
|
||||||
|
|
||||||
memcpy((void*)(_args+1), (void*)old_args, sizeof(PyVar)*old_size);
|
memcpy((void*)(_args+1), (void*)old_args, sizeof(PyObject*)*old_size);
|
||||||
memset((void*)old_args, 0, sizeof(PyVar)*old_size);
|
memset((void*)old_args, 0, sizeof(PyObject*)*old_size);
|
||||||
_pool.dealloc(old_args, old_size);
|
_pool.dealloc(old_args, old_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Args(){ _pool.dealloc(_args, _size); }
|
~Args(){ _pool.dealloc(_args, _size); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Args _zero(0);
|
inline const Args& no_arg() {
|
||||||
inline const Args& no_arg() { return _zero; }
|
static const Args _zero(0);
|
||||||
|
return _zero;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Args one_arg(T&& a) {
|
Args one_arg(T&& a) {
|
||||||
@ -106,5 +107,5 @@ namespace pkpy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef Args Tuple;
|
typedef Args Tuple;
|
||||||
THREAD_LOCAL SmallArrayPool<PyVar, 10> Args::_pool;
|
THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
276
src/vm.h
276
src/vm.h
@ -6,22 +6,22 @@
|
|||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
#define DEF_NATIVE_2(ctype, ptype) \
|
#define DEF_NATIVE_2(ctype, ptype) \
|
||||||
template<> ctype py_cast<ctype>(VM* vm, const PyVar& obj) { \
|
template<> ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
|
||||||
vm->check_type(obj, vm->ptype); \
|
vm->check_type(obj, vm->ptype); \
|
||||||
return OBJ_GET(ctype, obj); \
|
return OBJ_GET(ctype, obj); \
|
||||||
} \
|
} \
|
||||||
template<> ctype _py_cast<ctype>(VM* vm, const PyVar& obj) { \
|
template<> ctype _py_cast<ctype>(VM* vm, PyObject* obj) { \
|
||||||
return OBJ_GET(ctype, obj); \
|
return OBJ_GET(ctype, obj); \
|
||||||
} \
|
} \
|
||||||
template<> ctype& py_cast<ctype&>(VM* vm, const PyVar& obj) { \
|
template<> ctype& py_cast<ctype&>(VM* vm, PyObject* obj) { \
|
||||||
vm->check_type(obj, vm->ptype); \
|
vm->check_type(obj, vm->ptype); \
|
||||||
return OBJ_GET(ctype, obj); \
|
return OBJ_GET(ctype, obj); \
|
||||||
} \
|
} \
|
||||||
template<> ctype& _py_cast<ctype&>(VM* vm, const PyVar& obj) { \
|
template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \
|
||||||
return OBJ_GET(ctype, obj); \
|
return OBJ_GET(ctype, obj); \
|
||||||
} \
|
} \
|
||||||
PyVar py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \
|
PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \
|
||||||
PyVar py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));}
|
PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));}
|
||||||
|
|
||||||
class Generator: public BaseIter {
|
class Generator: public BaseIter {
|
||||||
std::unique_ptr<Frame> frame;
|
std::unique_ptr<Frame> frame;
|
||||||
@ -30,11 +30,11 @@ public:
|
|||||||
Generator(VM* vm, std::unique_ptr<Frame>&& frame)
|
Generator(VM* vm, std::unique_ptr<Frame>&& frame)
|
||||||
: BaseIter(vm, nullptr), frame(std::move(frame)), state(0) {}
|
: BaseIter(vm, nullptr), frame(std::move(frame)), state(0) {}
|
||||||
|
|
||||||
PyVar next();
|
PyObject* next();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PyTypeInfo{
|
struct PyTypeInfo{
|
||||||
PyVar obj;
|
PyObject* obj;
|
||||||
Type base;
|
Type base;
|
||||||
Str name;
|
Str name;
|
||||||
};
|
};
|
||||||
@ -43,23 +43,27 @@ class VM {
|
|||||||
VM* vm; // self reference for simplify code
|
VM* vm; // self reference for simplify code
|
||||||
public:
|
public:
|
||||||
std::stack< std::unique_ptr<Frame> > callstack;
|
std::stack< std::unique_ptr<Frame> > callstack;
|
||||||
PyVar _py_op_call;
|
|
||||||
PyVar _py_op_yield;
|
|
||||||
std::vector<PyTypeInfo> _all_types;
|
std::vector<PyTypeInfo> _all_types;
|
||||||
|
|
||||||
PyVar run_frame(Frame* frame);
|
PyObject* run_frame(Frame* frame);
|
||||||
|
|
||||||
NameDict _modules; // loaded modules
|
NameDict _modules; // loaded modules
|
||||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||||
PyVar None, True, False, Ellipsis;
|
|
||||||
|
// singleton objects, need_gc=false
|
||||||
|
PyObject* _py_op_call;
|
||||||
|
PyObject* _py_op_yield;
|
||||||
|
PyObject* None;
|
||||||
|
PyObject* True;
|
||||||
|
PyObject* False;
|
||||||
|
PyObject* Ellipsis;
|
||||||
|
|
||||||
|
PyObject* builtins; // builtins module
|
||||||
|
PyObject* _main; // __main__ module
|
||||||
|
|
||||||
bool use_stdio;
|
bool use_stdio;
|
||||||
std::ostream* _stdout;
|
std::ostream* _stdout;
|
||||||
std::ostream* _stderr;
|
std::ostream* _stderr;
|
||||||
|
|
||||||
PyVar builtins; // builtins module
|
|
||||||
PyVar _main; // __main__ module
|
|
||||||
|
|
||||||
int recursionlimit = 1000;
|
int recursionlimit = 1000;
|
||||||
|
|
||||||
VM(bool use_stdio){
|
VM(bool use_stdio){
|
||||||
@ -77,7 +81,7 @@ public:
|
|||||||
// for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
|
// for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar asStr(const PyVar& obj){
|
PyObject* asStr(PyObject* obj){
|
||||||
PyVarOrNull f = getattr(obj, __str__, false, true);
|
PyVarOrNull f = getattr(obj, __str__, false, true);
|
||||||
if(f != nullptr) return call(f);
|
if(f != nullptr) return call(f);
|
||||||
return asRepr(obj);
|
return asRepr(obj);
|
||||||
@ -90,7 +94,7 @@ public:
|
|||||||
return callstack.top().get();
|
return callstack.top().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar asIter(const PyVar& obj){
|
PyObject* asIter(PyObject* obj){
|
||||||
if(is_type(obj, tp_native_iterator)) return obj;
|
if(is_type(obj, tp_native_iterator)) return obj;
|
||||||
PyVarOrNull iter_f = getattr(obj, __iter__, false, true);
|
PyVarOrNull iter_f = getattr(obj, __iter__, false, true);
|
||||||
if(iter_f != nullptr) return call(iter_f);
|
if(iter_f != nullptr) return call(iter_f);
|
||||||
@ -98,25 +102,25 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar asList(const PyVar& iterable){
|
PyObject* asList(PyObject* iterable){
|
||||||
if(is_type(iterable, tp_list)) return iterable;
|
if(is_type(iterable, tp_list)) return iterable;
|
||||||
return call(_t(tp_list), one_arg(iterable));
|
return call(_t(tp_list), one_arg(iterable));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar* find_name_in_mro(PyObject* cls, StrName name){
|
PyObject** find_name_in_mro(PyObject* cls, StrName name){
|
||||||
PyVar* val;
|
PyObject** val;
|
||||||
do{
|
do{
|
||||||
val = cls->attr().try_get(name);
|
val = cls->attr().try_get(name);
|
||||||
if(val != nullptr) return val;
|
if(val != nullptr) return val;
|
||||||
Type cls_t = static_cast<Py_<Type>*>(cls)->_value;
|
Type cls_t = static_cast<Py_<Type>*>(cls)->_value;
|
||||||
Type base = _all_types[cls_t.index].base;
|
Type base = _all_types[cls_t.index].base;
|
||||||
if(base.index == -1) break;
|
if(base.index == -1) break;
|
||||||
cls = _all_types[base.index].obj.get();
|
cls = _all_types[base.index].obj;
|
||||||
}while(true);
|
}while(true);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isinstance(const PyVar& obj, Type cls_t){
|
bool isinstance(PyObject* obj, Type cls_t){
|
||||||
Type obj_t = OBJ_GET(Type, _t(obj));
|
Type obj_t = OBJ_GET(Type, _t(obj));
|
||||||
do{
|
do{
|
||||||
if(obj_t == cls_t) return true;
|
if(obj_t == cls_t) return true;
|
||||||
@ -127,36 +131,36 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar fast_call(StrName name, Args&& args){
|
PyObject* fast_call(StrName name, Args&& args){
|
||||||
PyVar* val = find_name_in_mro(_t(args[0]).get(), name);
|
PyObject** val = find_name_in_mro(_t(args[0]).get(), name);
|
||||||
if(val != nullptr) return call(*val, std::move(args));
|
if(val != nullptr) return call(*val, std::move(args));
|
||||||
AttributeError(args[0], name);
|
AttributeError(args[0], name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar call(const PyVar& _callable){
|
inline PyObject* call(PyObject* _callable){
|
||||||
return call(_callable, no_arg(), no_arg(), false);
|
return call(_callable, no_arg(), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ArgT>
|
template<typename ArgT>
|
||||||
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyVar>
|
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
||||||
call(const PyVar& _callable, ArgT&& args){
|
call(PyObject* _callable, ArgT&& args){
|
||||||
return call(_callable, std::forward<ArgT>(args), no_arg(), false);
|
return call(_callable, std::forward<ArgT>(args), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ArgT>
|
template<typename ArgT>
|
||||||
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyVar>
|
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
||||||
call(const PyVar& obj, const StrName name, ArgT&& args){
|
call(PyObject* obj, const StrName name, ArgT&& args){
|
||||||
return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false);
|
return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar call(const PyVar& obj, StrName name){
|
inline PyObject* call(PyObject* obj, StrName name){
|
||||||
return call(getattr(obj, name, true, true), no_arg(), no_arg(), false);
|
return call(getattr(obj, name, true, true), no_arg(), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// repl mode is only for setting `frame->id` to 0
|
// repl mode is only for setting `frame->id` to 0
|
||||||
PyVarOrNull exec(Str source, Str filename, CompileMode mode, PyVar _module=nullptr){
|
PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){
|
||||||
if(_module == nullptr) _module = _main;
|
if(_module == nullptr) _module = _main;
|
||||||
try {
|
try {
|
||||||
CodeObject_ code = compile(source, filename, mode);
|
CodeObject_ code = compile(source, filename, mode);
|
||||||
@ -180,19 +184,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
inline PyVar _exec(Args&&... args){
|
inline PyObject* _exec(Args&&... args){
|
||||||
callstack.push(_new_frame(std::forward<Args>(args)...));
|
callstack.push(_new_frame(std::forward<Args>(args)...));
|
||||||
return _exec();
|
return _exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar property(NativeFuncRaw fget){
|
PyObject* property(NativeFuncRaw fget){
|
||||||
PyVar p = builtins->attr("property");
|
PyObject* p = builtins->attr("property");
|
||||||
PyVar method = new_object(tp_native_function, NativeFunc(fget, 1, false));
|
PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false));
|
||||||
return call(p, one_arg(method));
|
return call(p, one_arg(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar new_type_object(PyVar mod, StrName name, Type base){
|
PyObject* new_type_object(PyObject* mod, StrName name, Type base){
|
||||||
PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
|
// use gcnew
|
||||||
|
PyObject* obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
|
||||||
PyTypeInfo info{
|
PyTypeInfo info{
|
||||||
.obj = obj,
|
.obj = obj,
|
||||||
.base = base,
|
.base = base,
|
||||||
@ -204,19 +209,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type _new_type_object(StrName name, Type base=0) {
|
Type _new_type_object(StrName name, Type base=0) {
|
||||||
PyVar obj = new_type_object(nullptr, name, base);
|
PyObject* obj = new_type_object(nullptr, name, base);
|
||||||
return OBJ_GET(Type, obj);
|
return OBJ_GET(Type, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline PyVar new_object(const PyVar& type, const T& _value) {
|
inline PyObject* new_object(PyObject* type, const T& _value) {
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(!is_type(type, tp_type)) UNREACHABLE();
|
if(!is_type(type, tp_type)) UNREACHABLE();
|
||||||
#endif
|
#endif
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
|
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline PyVar new_object(const PyVar& type, T&& _value) {
|
inline PyObject* new_object(PyObject* type, T&& _value) {
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(!is_type(type, tp_type)) UNREACHABLE();
|
if(!is_type(type, tp_type)) UNREACHABLE();
|
||||||
#endif
|
#endif
|
||||||
@ -224,16 +229,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline PyVar new_object(Type type, const T& _value) {
|
inline PyObject* new_object(Type type, const T& _value) {
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
|
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline PyVar new_object(Type type, T&& _value) {
|
inline PyObject* new_object(Type type, T&& _value) {
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
|
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar _find_type(const Str& type){
|
PyObject* _find_type(const Str& type){
|
||||||
PyVar* obj = builtins->attr().try_get(type);
|
PyObject** obj = builtins->attr().try_get(type);
|
||||||
if(!obj){
|
if(!obj){
|
||||||
for(auto& t: _all_types) if(t.name == type) return t.obj;
|
for(auto& t: _all_types) if(t.name == type) return t.obj;
|
||||||
throw std::runtime_error("type not found: " + type);
|
throw std::runtime_error("type not found: " + type);
|
||||||
@ -282,12 +287,12 @@ public:
|
|||||||
Type tp_super, tp_exception, tp_star_wrapper;
|
Type tp_super, tp_exception, tp_star_wrapper;
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
inline PyVar PyIter(P&& value) {
|
inline PyObject* PyIter(P&& value) {
|
||||||
static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
|
static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
|
||||||
return new_object(tp_native_iterator, std::forward<P>(value));
|
return new_object(tp_native_iterator, std::forward<P>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BaseIter* PyIter_AS_C(const PyVar& obj)
|
inline BaseIter* PyIter_AS_C(PyObject* obj)
|
||||||
{
|
{
|
||||||
check_type(obj, tp_native_iterator);
|
check_type(obj, tp_native_iterator);
|
||||||
return static_cast<BaseIter*>(obj->value());
|
return static_cast<BaseIter*>(obj->value());
|
||||||
@ -313,22 +318,22 @@ public:
|
|||||||
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
||||||
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
|
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
|
||||||
|
|
||||||
void AttributeError(PyVar obj, StrName name){
|
void AttributeError(PyObject* obj, StrName name){
|
||||||
_error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true));
|
_error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
||||||
|
|
||||||
inline void check_type(const PyVar& obj, Type type){
|
inline void check_type(PyObject* obj, Type type){
|
||||||
if(is_type(obj, type)) return;
|
if(is_type(obj, type)) return;
|
||||||
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
|
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar& _t(Type t){
|
inline PyObject* _t(Type t){
|
||||||
return _all_types[t.index].obj;
|
return _all_types[t.index].obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar& _t(const PyVar& obj){
|
inline PyObject* _t(PyObject* obj){
|
||||||
if(is_int(obj)) return _t(tp_int);
|
if(is_int(obj)) return _t(tp_int);
|
||||||
if(is_float(obj)) return _t(tp_float);
|
if(is_float(obj)) return _t(tp_float);
|
||||||
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
|
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
|
||||||
@ -341,42 +346,34 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true, bool class_only=false){
|
|
||||||
return getattr(&obj, name, throw_err, class_only);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
inline void setattr(PyVar& obj, StrName name, T&& value){
|
|
||||||
setattr(&obj, name, std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeObject_ compile(Str source, Str filename, CompileMode mode);
|
CodeObject_ compile(Str source, Str filename, CompileMode mode);
|
||||||
void post_init();
|
void post_init();
|
||||||
PyVar num_negated(const PyVar& obj);
|
PyObject* num_negated(PyObject* obj);
|
||||||
f64 num_to_float(const PyVar& obj);
|
f64 num_to_float(PyObject* obj);
|
||||||
const PyVar& asBool(const PyVar& obj);
|
PyObject* asBool(PyObject* obj);
|
||||||
i64 hash(const PyVar& obj);
|
i64 hash(PyObject* obj);
|
||||||
PyVar asRepr(const PyVar& obj);
|
PyObject* asRepr(PyObject* obj);
|
||||||
PyVar new_module(StrName name);
|
PyObject* new_module(StrName name);
|
||||||
Str disassemble(CodeObject_ co);
|
Str disassemble(CodeObject_ co);
|
||||||
void init_builtin_types();
|
void init_builtin_types();
|
||||||
PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall);
|
PyObject* call(PyObject* _callable, Args args, const Args& kwargs, bool opCall);
|
||||||
void unpack_args(Args& args);
|
void unpack_args(Args& args);
|
||||||
PyVarOrNull getattr(const PyVar* obj, StrName name, bool throw_err=true, bool class_only=false);
|
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void setattr(PyVar* obj, StrName name, T&& value);
|
void setattr(PyObject* obj, StrName name, T&& value);
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn);
|
void bind_method(PyObject* obj, Str funcName, NativeFuncRaw fn);
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn);
|
void bind_func(PyObject* obj, Str funcName, NativeFuncRaw fn);
|
||||||
void _error(Exception e);
|
void _error(Exception e);
|
||||||
PyVar _exec();
|
PyObject* _exec();
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
PyVarRef PyRef(P&& value);
|
PyVarRef PyRef(P&& value);
|
||||||
const BaseRef* PyRef_AS_C(const PyVar& obj);
|
const BaseRef* PyRef_AS_C(PyObject* obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
PyVar NativeFunc::operator()(VM* vm, Args& args) const{
|
PyObject* NativeFunc::operator()(VM* vm, Args& args) const{
|
||||||
int args_size = args.size() - (int)method; // remove self
|
int args_size = args.size() - (int)method; // remove self
|
||||||
if(argc != -1 && args_size != argc) {
|
if(argc != -1 && args_size != argc) {
|
||||||
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
|
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
|
||||||
@ -437,11 +434,11 @@ DEF_NATIVE_2(Exception, tp_exception)
|
|||||||
DEF_NATIVE_2(StarWrapper, tp_star_wrapper)
|
DEF_NATIVE_2(StarWrapper, tp_star_wrapper)
|
||||||
|
|
||||||
#define PY_CAST_INT(T) \
|
#define PY_CAST_INT(T) \
|
||||||
template<> T py_cast<T>(VM* vm, const PyVar& obj){ \
|
template<> T py_cast<T>(VM* vm, PyObject* obj){ \
|
||||||
vm->check_type(obj, vm->tp_int); \
|
vm->check_type(obj, vm->tp_int); \
|
||||||
return (T)(obj.bits >> 2); \
|
return (T)(obj.bits >> 2); \
|
||||||
} \
|
} \
|
||||||
template<> T _py_cast<T>(VM* vm, const PyVar& obj){ \
|
template<> T _py_cast<T>(VM* vm, PyObject* obj){ \
|
||||||
return (T)(obj.bits >> 2); \
|
return (T)(obj.bits >> 2); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,38 +454,38 @@ PY_CAST_INT(unsigned long)
|
|||||||
PY_CAST_INT(unsigned long long)
|
PY_CAST_INT(unsigned long long)
|
||||||
|
|
||||||
|
|
||||||
template<> float py_cast<float>(VM* vm, const PyVar& obj){
|
template<> float py_cast<float>(VM* vm, PyObject* obj){
|
||||||
vm->check_type(obj, vm->tp_float);
|
vm->check_type(obj, vm->tp_float);
|
||||||
i64 bits = obj.bits;
|
i64 bits = obj.bits;
|
||||||
bits = (bits >> 2) << 2;
|
bits = (bits >> 2) << 2;
|
||||||
return __8B(bits)._float;
|
return __8B(bits)._float;
|
||||||
}
|
}
|
||||||
template<> float _py_cast<float>(VM* vm, const PyVar& obj){
|
template<> float _py_cast<float>(VM* vm, PyObject* obj){
|
||||||
i64 bits = obj.bits;
|
i64 bits = obj.bits;
|
||||||
bits = (bits >> 2) << 2;
|
bits = (bits >> 2) << 2;
|
||||||
return __8B(bits)._float;
|
return __8B(bits)._float;
|
||||||
}
|
}
|
||||||
template<> double py_cast<double>(VM* vm, const PyVar& obj){
|
template<> double py_cast<double>(VM* vm, PyObject* obj){
|
||||||
vm->check_type(obj, vm->tp_float);
|
vm->check_type(obj, vm->tp_float);
|
||||||
i64 bits = obj.bits;
|
i64 bits = obj.bits;
|
||||||
bits = (bits >> 2) << 2;
|
bits = (bits >> 2) << 2;
|
||||||
return __8B(bits)._float;
|
return __8B(bits)._float;
|
||||||
}
|
}
|
||||||
template<> double _py_cast<double>(VM* vm, const PyVar& obj){
|
template<> double _py_cast<double>(VM* vm, PyObject* obj){
|
||||||
i64 bits = obj.bits;
|
i64 bits = obj.bits;
|
||||||
bits = (bits >> 2) << 2;
|
bits = (bits >> 2) << 2;
|
||||||
return __8B(bits)._float;
|
return __8B(bits)._float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define PY_VAR_INT(T) \
|
#define PY_VAR_INT(T) \
|
||||||
PyVar py_var(VM* vm, T _val){ \
|
PyObject* py_var(VM* vm, T _val){ \
|
||||||
i64 val = static_cast<i64>(_val); \
|
i64 val = static_cast<i64>(_val); \
|
||||||
if(((val << 2) >> 2) != val){ \
|
if(((val << 2) >> 2) != val){ \
|
||||||
vm->_error("OverflowError", std::to_string(val) + " is out of range"); \
|
vm->_error("OverflowError", std::to_string(val) + " is out of range"); \
|
||||||
} \
|
} \
|
||||||
val = (val << 2) | 0b01; \
|
val = (val << 2) | 0b01; \
|
||||||
return PyVar(reinterpret_cast<int*>(val)); \
|
return reinterpret_cast<PyObject*>(val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
PY_VAR_INT(char)
|
PY_VAR_INT(char)
|
||||||
@ -502,44 +499,44 @@ PY_VAR_INT(unsigned int)
|
|||||||
PY_VAR_INT(unsigned long)
|
PY_VAR_INT(unsigned long)
|
||||||
PY_VAR_INT(unsigned long long)
|
PY_VAR_INT(unsigned long long)
|
||||||
|
|
||||||
#define PY_VAR_FLOAT(T) \
|
#define PY_VAR_FLOAT(T) \
|
||||||
PyVar py_var(VM* vm, T _val){ \
|
PyObject* py_var(VM* vm, T _val){ \
|
||||||
f64 val = static_cast<f64>(_val); \
|
f64 val = static_cast<f64>(_val); \
|
||||||
i64 bits = __8B(val)._int; \
|
i64 bits = __8B(val)._int; \
|
||||||
bits = (bits >> 2) << 2; \
|
bits = (bits >> 2) << 2; \
|
||||||
bits |= 0b10; \
|
bits |= 0b10; \
|
||||||
return PyVar(reinterpret_cast<int*>(bits)); \
|
return reinterpret_cast<PyObject*>(bits); \
|
||||||
}
|
}
|
||||||
|
|
||||||
PY_VAR_FLOAT(float)
|
PY_VAR_FLOAT(float)
|
||||||
PY_VAR_FLOAT(double)
|
PY_VAR_FLOAT(double)
|
||||||
|
|
||||||
const PyVar& py_var(VM* vm, bool val){
|
PyObject* py_var(VM* vm, bool val){
|
||||||
return val ? vm->True : vm->False;
|
return val ? vm->True : vm->False;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> bool py_cast<bool>(VM* vm, const PyVar& obj){
|
template<> bool py_cast<bool>(VM* vm, PyObject* obj){
|
||||||
vm->check_type(obj, vm->tp_bool);
|
vm->check_type(obj, vm->tp_bool);
|
||||||
return obj == vm->True;
|
return obj == vm->True;
|
||||||
}
|
}
|
||||||
template<> bool _py_cast<bool>(VM* vm, const PyVar& obj){
|
template<> bool _py_cast<bool>(VM* vm, PyObject* obj){
|
||||||
return obj == vm->True;
|
return obj == vm->True;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar py_var(VM* vm, const char val[]){
|
PyObject* py_var(VM* vm, const char val[]){
|
||||||
return VAR(Str(val));
|
return VAR(Str(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar py_var(VM* vm, std::string val){
|
PyObject* py_var(VM* vm, std::string val){
|
||||||
return VAR(Str(std::move(val)));
|
return VAR(Str(std::move(val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void _check_py_class(VM* vm, const PyVar& obj){
|
void _check_py_class(VM* vm, PyObject* obj){
|
||||||
vm->check_type(obj, T::_type(vm));
|
vm->check_type(obj, T::_type(vm));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::num_negated(const PyVar& obj){
|
PyObject* VM::num_negated(PyObject* obj){
|
||||||
if (is_int(obj)){
|
if (is_int(obj)){
|
||||||
return VAR(-CAST(i64, obj));
|
return VAR(-CAST(i64, obj));
|
||||||
}else if(is_float(obj)){
|
}else if(is_float(obj)){
|
||||||
@ -549,7 +546,7 @@ PyVar VM::num_negated(const PyVar& obj){
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
f64 VM::num_to_float(const PyVar& obj){
|
f64 VM::num_to_float(PyObject* obj){
|
||||||
if(is_float(obj)){
|
if(is_float(obj)){
|
||||||
return CAST(f64, obj);
|
return CAST(f64, obj);
|
||||||
} else if (is_int(obj)){
|
} else if (is_int(obj)){
|
||||||
@ -559,20 +556,20 @@ f64 VM::num_to_float(const PyVar& obj){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PyVar& VM::asBool(const PyVar& obj){
|
PyObject* VM::asBool(PyObject* obj){
|
||||||
if(is_type(obj, tp_bool)) return obj;
|
if(is_type(obj, tp_bool)) return obj;
|
||||||
if(obj == None) return False;
|
if(obj == None) return False;
|
||||||
if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0);
|
if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0);
|
||||||
if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0);
|
if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0);
|
||||||
PyVarOrNull len_fn = getattr(obj, __len__, false, true);
|
PyVarOrNull len_fn = getattr(obj, __len__, false, true);
|
||||||
if(len_fn != nullptr){
|
if(len_fn != nullptr){
|
||||||
PyVar ret = call(len_fn);
|
PyObject* ret = call(len_fn);
|
||||||
return VAR(CAST(i64, ret) > 0);
|
return VAR(CAST(i64, ret) > 0);
|
||||||
}
|
}
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 VM::hash(const PyVar& obj){
|
i64 VM::hash(PyObject* obj){
|
||||||
if (is_type(obj, tp_str)) return CAST(Str&, obj).hash();
|
if (is_type(obj, tp_str)) return CAST(Str&, obj).hash();
|
||||||
if (is_int(obj)) return CAST(i64, obj);
|
if (is_int(obj)) return CAST(i64, obj);
|
||||||
if (is_type(obj, tp_tuple)) {
|
if (is_type(obj, tp_tuple)) {
|
||||||
@ -594,12 +591,12 @@ i64 VM::hash(const PyVar& obj){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::asRepr(const PyVar& obj){
|
PyObject* VM::asRepr(PyObject* obj){
|
||||||
return call(obj, __repr__);
|
return call(obj, __repr__);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::new_module(StrName name) {
|
PyObject* VM::new_module(StrName name) {
|
||||||
PyVar obj = new_object(tp_module, DummyModule());
|
PyObject* obj = new_object(tp_module, DummyModule());
|
||||||
obj->attr().set(__name__, VAR(name.str()));
|
obj->attr().set(__name__, VAR(name.str()));
|
||||||
_modules.set(name, obj);
|
_modules.set(name, obj);
|
||||||
return obj;
|
return obj;
|
||||||
@ -665,7 +662,7 @@ Str VM::disassemble(CodeObject_ co){
|
|||||||
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
|
||||||
|
|
||||||
for(int i=0; i<co->consts.size(); i++){
|
for(int i=0; i<co->consts.size(); i++){
|
||||||
PyVar obj = co->consts[i];
|
PyObject* obj = co->consts[i];
|
||||||
if(is_type(obj, tp_function)){
|
if(is_type(obj, tp_function)){
|
||||||
const auto& f = CAST(Function&, obj);
|
const auto& f = CAST(Function&, obj);
|
||||||
ss << disassemble(f.code);
|
ss << disassemble(f.code);
|
||||||
@ -731,10 +728,10 @@ void VM::init_builtin_types(){
|
|||||||
for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash();
|
for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){
|
PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCall){
|
||||||
if(is_type(_callable, tp_type)){
|
if(is_type(callable, tp_type)){
|
||||||
PyVar* new_f = _callable->attr().try_get(__new__);
|
PyObject** new_f = callable->attr().try_get(__new__);
|
||||||
PyVar obj;
|
PyObject* obj;
|
||||||
if(new_f != nullptr){
|
if(new_f != nullptr){
|
||||||
obj = call(*new_f, std::move(args), kwargs, false);
|
obj = call(*new_f, std::move(args), kwargs, false);
|
||||||
}else{
|
}else{
|
||||||
@ -745,19 +742,18 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PyVar* callable = &_callable;
|
if(is_type(callable, tp_bound_method)){
|
||||||
if(is_type(*callable, tp_bound_method)){
|
auto& bm = CAST(BoundMethod&, callable);
|
||||||
auto& bm = CAST(BoundMethod&, *callable);
|
callable = bm.method; // get unbound method
|
||||||
callable = &bm.method; // get unbound method
|
|
||||||
args.extend_self(bm.obj);
|
args.extend_self(bm.obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_type(*callable, tp_native_function)){
|
if(is_type(callable, tp_native_function)){
|
||||||
const auto& f = OBJ_GET(NativeFunc, *callable);
|
const auto& f = OBJ_GET(NativeFunc, callable);
|
||||||
if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
|
if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
|
||||||
return f(this, args);
|
return f(this, args);
|
||||||
} else if(is_type(*callable, tp_function)){
|
} else if(is_type(callable, tp_function)){
|
||||||
const Function& fn = CAST(Function&, *callable);
|
const Function& fn = CAST(Function&, callable);
|
||||||
NameDict_ locals = make_sp<NameDict>(
|
NameDict_ locals = make_sp<NameDict>(
|
||||||
fn.code->perfect_locals_capacity,
|
fn.code->perfect_locals_capacity,
|
||||||
kLocalsLoadFactor,
|
kLocalsLoadFactor,
|
||||||
@ -797,7 +793,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal
|
|||||||
}
|
}
|
||||||
locals->set(key, kwargs[i+1]);
|
locals->set(key, kwargs[i+1]);
|
||||||
}
|
}
|
||||||
const PyVar& _module = fn._module != nullptr ? fn._module : top_frame()->_module;
|
PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module;
|
||||||
auto _frame = _new_frame(fn.code, _module, locals, fn._closure);
|
auto _frame = _new_frame(fn.code, _module, locals, fn._closure);
|
||||||
if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame)));
|
if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame)));
|
||||||
callstack.push(std::move(_frame));
|
callstack.push(std::move(_frame));
|
||||||
@ -819,7 +815,7 @@ void VM::unpack_args(Args& args){
|
|||||||
if(is_type(args[i], tp_star_wrapper)){
|
if(is_type(args[i], tp_star_wrapper)){
|
||||||
auto& star = _CAST(StarWrapper&, args[i]);
|
auto& star = _CAST(StarWrapper&, args[i]);
|
||||||
if(!star.rvalue) UNREACHABLE();
|
if(!star.rvalue) UNREACHABLE();
|
||||||
PyVar list = asList(star.obj);
|
PyObject* list = asList(star.obj);
|
||||||
List& list_c = CAST(List&, list);
|
List& list_c = CAST(List&, list);
|
||||||
unpacked.insert(unpacked.end(), list_c.begin(), list_c.end());
|
unpacked.insert(unpacked.end(), list_c.begin(), list_c.end());
|
||||||
}else{
|
}else{
|
||||||
@ -829,25 +825,25 @@ void VM::unpack_args(Args& args){
|
|||||||
args = Args::from_list(std::move(unpacked));
|
args = Args::from_list(std::move(unpacked));
|
||||||
}
|
}
|
||||||
|
|
||||||
using Super = std::pair<PyVar, Type>;
|
using Super = std::pair<PyObject*, Type>;
|
||||||
|
|
||||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||||
PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool class_only){
|
PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
|
||||||
PyObject* objtype = _t(*obj).get();
|
PyObject* objtype = _t(*obj).get();
|
||||||
if(is_type(*obj, tp_super)){
|
if(is_type(*obj, tp_super)){
|
||||||
const Super& super = OBJ_GET(Super, *obj);
|
const Super& super = OBJ_GET(Super, *obj);
|
||||||
obj = &super.first;
|
obj = &super.first;
|
||||||
objtype = _t(super.second).get();
|
objtype = _t(super.second).get();
|
||||||
}
|
}
|
||||||
PyVar* cls_var = find_name_in_mro(objtype, name);
|
PyObject** cls_var = find_name_in_mro(objtype, name);
|
||||||
if(cls_var != nullptr){
|
if(cls_var != nullptr){
|
||||||
// handle descriptor
|
// handle descriptor
|
||||||
PyVar* descr_get = _t(*cls_var)->attr().try_get(__get__);
|
PyObject** descr_get = _t(*cls_var)->attr().try_get(__get__);
|
||||||
if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj));
|
if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj));
|
||||||
}
|
}
|
||||||
// handle instance __dict__
|
// handle instance __dict__
|
||||||
if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){
|
if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){
|
||||||
PyVar* val = (*obj)->attr().try_get(name);
|
PyObject** val = (*obj)->attr().try_get(name);
|
||||||
if(val != nullptr) return *val;
|
if(val != nullptr) return *val;
|
||||||
}
|
}
|
||||||
if(cls_var != nullptr){
|
if(cls_var != nullptr){
|
||||||
@ -862,22 +858,22 @@ PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool cla
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void VM::setattr(PyVar* obj, StrName name, T&& value){
|
void VM::setattr(PyObject* obj, StrName name, T&& value){
|
||||||
static_assert(std::is_same_v<std::decay_t<T>, PyVar>);
|
static_assert(std::is_same_v<std::decay_t<T>, PyVar>);
|
||||||
PyObject* objtype = _t(*obj).get();
|
PyObject* objtype = _t(obj).get();
|
||||||
if(is_type(*obj, tp_super)){
|
if(is_type(obj, tp_super)){
|
||||||
Super& super = OBJ_GET(Super, *obj);
|
Super& super = OBJ_GET(Super, *obj);
|
||||||
obj = &super.first;
|
obj = super.first;
|
||||||
objtype = _t(super.second).get();
|
objtype = _t(super.second).get();
|
||||||
}
|
}
|
||||||
PyVar* cls_var = find_name_in_mro(objtype, name);
|
PyObject** cls_var = find_name_in_mro(objtype, name);
|
||||||
if(cls_var != nullptr){
|
if(cls_var != nullptr){
|
||||||
// handle descriptor
|
// handle descriptor
|
||||||
const PyVar& cls_var_t = _t(*cls_var);
|
PyObject* cls_var_t = _t(*cls_var);
|
||||||
if(cls_var_t->attr().contains(__get__)){
|
if(cls_var_t->attr().contains(__get__)){
|
||||||
PyVar* descr_set = cls_var_t->attr().try_get(__set__);
|
PyObject** descr_set = cls_var_t->attr().try_get(__set__);
|
||||||
if(descr_set != nullptr){
|
if(descr_set != nullptr){
|
||||||
call(*descr_set, three_args(*cls_var, *obj, std::forward<T>(value)));
|
call(*descr_set, three_args(*cls_var, obj, std::forward<T>(value)));
|
||||||
}else{
|
}else{
|
||||||
TypeError("readonly attribute: " + name.str().escape(true));
|
TypeError("readonly attribute: " + name.str().escape(true));
|
||||||
}
|
}
|
||||||
@ -885,18 +881,18 @@ void VM::setattr(PyVar* obj, StrName name, T&& value){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// handle instance __dict__
|
// handle instance __dict__
|
||||||
if((*obj).is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute");
|
if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute");
|
||||||
(*obj)->attr().set(name, std::forward<T>(value));
|
obj->attr().set(name, std::forward<T>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
void VM::bind_method(PyVar obj, Str name, NativeFuncRaw fn) {
|
void VM::bind_method(PyObject* obj, Str name, NativeFuncRaw fn) {
|
||||||
check_type(obj, tp_type);
|
check_type(obj, tp_type);
|
||||||
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true)));
|
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
void VM::bind_func(PyVar obj, Str name, NativeFuncRaw fn) {
|
void VM::bind_func(PyObject* obj, Str name, NativeFuncRaw fn) {
|
||||||
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false)));
|
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,10 +905,10 @@ void VM::_error(Exception e){
|
|||||||
_raise();
|
_raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::_exec(){
|
PyObject* VM::_exec(){
|
||||||
Frame* frame = top_frame();
|
Frame* frame = top_frame();
|
||||||
i64 base_id = frame->id;
|
i64 base_id = frame->id;
|
||||||
PyVar ret = nullptr;
|
PyObject* ret = nullptr;
|
||||||
bool need_raise = false;
|
bool need_raise = false;
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
@ -936,7 +932,7 @@ PyVar VM::_exec(){
|
|||||||
}catch(HandledException& e){
|
}catch(HandledException& e){
|
||||||
continue;
|
continue;
|
||||||
}catch(UnhandledException& e){
|
}catch(UnhandledException& e){
|
||||||
PyVar obj = frame->pop();
|
PyObject* obj = frame->pop();
|
||||||
Exception& _e = CAST(Exception&, obj);
|
Exception& _e = CAST(Exception&, obj);
|
||||||
_e.st_push(frame->snapshot());
|
_e.st_push(frame->snapshot());
|
||||||
callstack.pop();
|
callstack.pop();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user