mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
object pool impl
This commit is contained in:
parent
01be71f0ef
commit
e816ceee6c
19
src/common.h
19
src/common.h
@ -31,8 +31,23 @@
|
||||
#define UNREACHABLE() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " UNREACHABLE()!");
|
||||
#endif
|
||||
|
||||
#define PK_VERSION "0.8.3"
|
||||
#define PK_VERSION "0.8.4"
|
||||
|
||||
typedef int64_t i64;
|
||||
typedef double f64;
|
||||
#define DUMMY_VAL (i64)0
|
||||
#define DUMMY_VAL (char)1
|
||||
#define DUMMY_VAL_TP char
|
||||
|
||||
template<typename T>
|
||||
void* tid() {
|
||||
static volatile int8_t _x;
|
||||
return (void*)(&_x);
|
||||
}
|
||||
|
||||
// This does not ensure to be unique when the pointer of obj->type is deleted & reused.
|
||||
// But it is good enough for now.
|
||||
template<typename T>
|
||||
void* obj_tid(void* alt){
|
||||
if constexpr(std::is_same_v<T, DUMMY_VAL_TP>) return alt;
|
||||
return tid<T>();
|
||||
}
|
14
src/iter.h
14
src/iter.h
@ -22,16 +22,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class VectorIter : public BaseIter {
|
||||
template <typename T>
|
||||
class ArrayIter : public BaseIter {
|
||||
size_t index = 0;
|
||||
const PyVarList* vec;
|
||||
const T* p;
|
||||
public:
|
||||
VectorIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
|
||||
vec = &OBJ_GET(PyVarList, _ref);
|
||||
}
|
||||
|
||||
bool hasNext(){ return index < vec->size(); }
|
||||
PyVar next(){ return vec->operator[](index++); }
|
||||
ArrayIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
|
||||
bool hasNext(){ return index < p->size(); }
|
||||
PyVar next(){ return p->operator[](index++); }
|
||||
};
|
||||
|
||||
class StringIter : public BaseIter {
|
||||
|
12
src/memory.h
12
src/memory.h
@ -3,17 +3,25 @@
|
||||
#include "common.h"
|
||||
|
||||
namespace pkpy{
|
||||
template<typename T>
|
||||
struct sp_deleter {
|
||||
inline static void call(int* counter){
|
||||
((T*)(counter + 1))->~T();
|
||||
free(counter);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class shared_ptr {
|
||||
int* counter = nullptr;
|
||||
|
||||
#define _t() ((T*)(counter + 1))
|
||||
#define _inc_counter() if(counter) ++(*counter)
|
||||
#define _dec_counter() if(counter && --(*counter) == 0){ _t()->~T(); free(counter); }
|
||||
#define _dec_counter() if(counter && --(*counter) == 0){ pkpy::sp_deleter<T>::call(counter); }
|
||||
|
||||
public:
|
||||
shared_ptr() {}
|
||||
shared_ptr(int* block) : counter(block) {}
|
||||
shared_ptr(int* counter) : counter(counter) {}
|
||||
shared_ptr(const shared_ptr& other) : counter(other.counter) {
|
||||
_inc_counter();
|
||||
}
|
||||
|
28
src/obj.h
28
src/obj.h
@ -78,7 +78,8 @@ struct PyObject {
|
||||
PyVarDict attribs;
|
||||
|
||||
inline bool is_type(const PyVar& type) const noexcept{ return this->type == type; }
|
||||
inline virtual void* value() = 0;
|
||||
virtual void* value() = 0;
|
||||
virtual void* type_id() = 0;
|
||||
|
||||
PyObject(const PyVar& type) : type(type) {}
|
||||
virtual ~PyObject() = default;
|
||||
@ -89,7 +90,8 @@ struct Py_ : PyObject {
|
||||
T _value;
|
||||
|
||||
Py_(const PyVar& type, T val) : PyObject(type), _value(val) {}
|
||||
virtual void* value() override { return &_value; }
|
||||
void* value() override { return &_value; }
|
||||
void* type_id() override { return obj_tid<T>((void*)type.get()); }
|
||||
};
|
||||
|
||||
// Unsafe cast from PyObject to C++ type
|
||||
@ -102,4 +104,24 @@ struct Py_ : PyObject {
|
||||
inline static const char* _mod() { return #mod; } \
|
||||
inline static const char* _name() { return #name; }
|
||||
|
||||
#define PY_BUILTIN_CLASS(name) inline static PyVar _type(VM* vm) { return vm->_tp_##name; }
|
||||
#define PY_BUILTIN_CLASS(name) inline static PyVar _type(VM* vm) { return vm->_tp_##name; }
|
||||
|
||||
|
||||
// memory pool _tp -> [obj1, obj2, ...]
|
||||
static thread_local emhash8::HashMap<void*, std::vector<int*>> _obj_pool;
|
||||
|
||||
namespace pkpy {
|
||||
template<>
|
||||
struct sp_deleter<PyObject> {
|
||||
inline static void call(int* counter) {
|
||||
PyObject* obj = (PyObject*)(counter + 1);
|
||||
std::vector<int*>& pool = _obj_pool[obj->type_id()];
|
||||
if(pool.size() > 100){
|
||||
obj->~PyObject();
|
||||
free(counter);
|
||||
}else{
|
||||
pool.push_back(counter);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -370,20 +370,23 @@ void init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind_method<1>("str", "join", [](VM* vm, const pkpy::Args& args) {
|
||||
const _Str& _self = vm->PyStr_AS_C(args[0]);
|
||||
PyVarList* _list = nullptr;
|
||||
const _Str& self = vm->PyStr_AS_C(args[0]);
|
||||
_StrStream ss;
|
||||
if(args[1]->is_type(vm->_tp_list)){
|
||||
_list = &vm->PyList_AS_C(args[1]);
|
||||
const PyVarList& a = vm->PyList_AS_C(args[1]);
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
if(i > 0) ss << self;
|
||||
ss << vm->PyStr_AS_C(vm->asStr(a[i]));
|
||||
}
|
||||
}else if(args[1]->is_type(vm->_tp_tuple)){
|
||||
_list = &vm->PyTuple_AS_C(args[1]);
|
||||
const _Tuple& a = vm->PyTuple_AS_C(args[1]);
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
if(i > 0) ss << self;
|
||||
ss << vm->PyStr_AS_C(vm->asStr(a[i]));
|
||||
}
|
||||
}else{
|
||||
vm->TypeError("can only join a list or tuple");
|
||||
}
|
||||
_StrStream ss;
|
||||
for(int i = 0; i < _list->size(); i++){
|
||||
if(i > 0) ss << _self;
|
||||
ss << vm->PyStr_AS_C(vm->asStr(_list->operator[](i)));
|
||||
}
|
||||
return vm->PyStr(ss.str());
|
||||
});
|
||||
|
||||
@ -426,25 +429,24 @@ void init_builtins(VM* _vm) {
|
||||
return vm->PyInt(_self.size());
|
||||
});
|
||||
|
||||
_vm->_bind_methods<0>({"list", "tuple"}, "__iter__", [](VM* vm, const pkpy::Args& args) {
|
||||
return vm->PyIter(pkpy::make_shared<BaseIter, VectorIter>(vm, args[0]));
|
||||
_vm->bind_method<0>("list", "__iter__", [](VM* vm, const pkpy::Args& args) {
|
||||
return vm->PyIter(pkpy::make_shared<BaseIter, ArrayIter<PyVarList>>(vm, args[0]));
|
||||
});
|
||||
|
||||
_vm->_bind_methods<1>({"list", "tuple"}, "__getitem__", [](VM* vm, const pkpy::Args& args) {
|
||||
bool list = args[0]->is_type(vm->_tp_list);
|
||||
const PyVarList& _self = list ? vm->PyList_AS_C(args[0]) : vm->PyTuple_AS_C(args[0]);
|
||||
_vm->bind_method<1>("list", "__getitem__", [](VM* vm, const pkpy::Args& args) {
|
||||
const PyVarList& self = vm->PyList_AS_C(args[0]);
|
||||
|
||||
if(args[1]->is_type(vm->_tp_slice)){
|
||||
_Slice s = vm->PySlice_AS_C(args[1]);
|
||||
s.normalize(_self.size());
|
||||
PyVarList _new_list;
|
||||
for(size_t i = s.start; i < s.stop; i++) _new_list.push_back(_self[i]);
|
||||
return list ? vm->PyList(_new_list) : vm->PyTuple(_new_list);
|
||||
s.normalize(self.size());
|
||||
PyVarList new_list;
|
||||
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
|
||||
return vm->PyList(std::move(new_list));
|
||||
}
|
||||
|
||||
int _index = (int)vm->PyInt_AS_C(args[1]);
|
||||
_index = vm->normalized_index(_index, _self.size());
|
||||
return _self[_index];
|
||||
int index = (int)vm->PyInt_AS_C(args[1]);
|
||||
index = vm->normalized_index(index, self.size());
|
||||
return self[index];
|
||||
});
|
||||
|
||||
_vm->bind_method<2>("list", "__setitem__", [](VM* vm, const pkpy::Args& args) {
|
||||
@ -466,12 +468,32 @@ void init_builtins(VM* _vm) {
|
||||
/************ PyTuple ************/
|
||||
_vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, const pkpy::Args& args) {
|
||||
PyVarList _list = vm->PyList_AS_C(vm->call(vm->builtins->attribs["list"], args));
|
||||
return vm->PyTuple(_list);
|
||||
return vm->PyTuple(std::move(_list));
|
||||
});
|
||||
|
||||
_vm->bind_method<0>("tuple", "__iter__", [](VM* vm, const pkpy::Args& args) {
|
||||
return vm->PyIter(pkpy::make_shared<BaseIter, ArrayIter<pkpy::Args>>(vm, args[0]));
|
||||
});
|
||||
|
||||
_vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, const pkpy::Args& args) {
|
||||
const _Tuple& self = vm->PyTuple_AS_C(args[0]);
|
||||
|
||||
if(args[1]->is_type(vm->_tp_slice)){
|
||||
_Slice s = vm->PySlice_AS_C(args[1]);
|
||||
s.normalize(self.size());
|
||||
PyVarList new_list;
|
||||
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
|
||||
return vm->PyTuple(std::move(new_list));
|
||||
}
|
||||
|
||||
int index = (int)vm->PyInt_AS_C(args[1]);
|
||||
index = vm->normalized_index(index, self.size());
|
||||
return self[index];
|
||||
});
|
||||
|
||||
_vm->bind_method<0>("tuple", "__len__", [](VM* vm, const pkpy::Args& args) {
|
||||
const PyVarList& _self = vm->PyTuple_AS_C(args[0]);
|
||||
return vm->PyInt(_self.size());
|
||||
const _Tuple& self = vm->PyTuple_AS_C(args[0]);
|
||||
return vm->PyInt(self.size());
|
||||
});
|
||||
|
||||
/************ PyBool ************/
|
||||
|
15
src/ref.h
15
src/ref.h
@ -17,8 +17,10 @@ enum NameScope {
|
||||
};
|
||||
|
||||
struct NameRef : BaseRef {
|
||||
const std::pair<_Str, NameScope>* pair;
|
||||
NameRef(const std::pair<_Str, NameScope>& pair) : pair(&pair) {}
|
||||
std::pair<_Str, NameScope>* _pair;
|
||||
inline const _Str& name() const { return _pair->first; }
|
||||
inline NameScope scope() const { return _pair->second; }
|
||||
NameRef(std::pair<_Str, NameScope>& pair) : _pair(&pair) {}
|
||||
|
||||
PyVar get(VM* vm, Frame* frame) const;
|
||||
void set(VM* vm, Frame* frame, PyVar val) const;
|
||||
@ -27,8 +29,8 @@ struct NameRef : BaseRef {
|
||||
|
||||
struct AttrRef : BaseRef {
|
||||
mutable PyVar obj;
|
||||
const NameRef attr;
|
||||
AttrRef(PyVar obj, const NameRef attr) : obj(obj), attr(attr) {}
|
||||
NameRef attr;
|
||||
AttrRef(PyVar obj, NameRef attr) : obj(obj), attr(attr) {}
|
||||
|
||||
PyVar get(VM* vm, Frame* frame) const;
|
||||
void set(VM* vm, Frame* frame, PyVar val) const;
|
||||
@ -46,9 +48,8 @@ struct IndexRef : BaseRef {
|
||||
};
|
||||
|
||||
struct TupleRef : BaseRef {
|
||||
PyVarList varRefs;
|
||||
TupleRef(const PyVarList& varRefs) : varRefs(varRefs) {}
|
||||
TupleRef(PyVarList&& varRefs) : varRefs(std::move(varRefs)) {}
|
||||
_Tuple objs;
|
||||
TupleRef(_Tuple&& objs) : objs(std::move(objs)) {}
|
||||
|
||||
PyVar get(VM* vm, Frame* frame) const;
|
||||
void set(VM* vm, Frame* frame, PyVar val) const;
|
||||
|
@ -58,7 +58,7 @@ namespace pkpy {
|
||||
}
|
||||
}
|
||||
|
||||
void _release(){
|
||||
void _free(){
|
||||
if(_size == 0 || _args == nullptr) return;
|
||||
if(_size >= kMaxPoolSize || _args_pool[_size].size() > 32){
|
||||
delete[] _args;
|
||||
@ -76,6 +76,12 @@ namespace pkpy {
|
||||
for(int i=0; i<_size; i++) _args[i] = other._args[i];
|
||||
}
|
||||
|
||||
Args(std::initializer_list<PyVar> a){
|
||||
_alloc(a.size());
|
||||
int i = 0;
|
||||
for(auto& v: a) _args[i++] = v;
|
||||
}
|
||||
|
||||
Args(Args&& other) noexcept {
|
||||
this->_args = other._args;
|
||||
this->_size = other._size;
|
||||
@ -93,7 +99,7 @@ namespace pkpy {
|
||||
const PyVar& operator[](int i) const { return _args[i]; }
|
||||
|
||||
Args& operator=(Args&& other) noexcept {
|
||||
_release();
|
||||
_free();
|
||||
this->_args = other._args;
|
||||
this->_size = other._size;
|
||||
other._args = nullptr;
|
||||
@ -126,7 +132,7 @@ namespace pkpy {
|
||||
}
|
||||
}
|
||||
|
||||
~Args(){ _release(); }
|
||||
~Args(){ _free(); }
|
||||
};
|
||||
|
||||
const Args& no_arg(){
|
||||
@ -148,4 +154,6 @@ namespace pkpy {
|
||||
ret[1] = std::forward<T2>(b);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef pkpy::Args _Tuple;
|
@ -117,8 +117,10 @@ public:
|
||||
|
||||
_Str& operator=(const _Str& s){
|
||||
this->std::string::operator=(s);
|
||||
if(_u8_index != nullptr) delete _u8_index;
|
||||
this->_u8_index = s._u8_index;
|
||||
if(_u8_index != nullptr){
|
||||
delete _u8_index;
|
||||
_u8_index = new std::vector<uint16_t>(*s._u8_index);
|
||||
}
|
||||
this->hash_initialized = s.hash_initialized;
|
||||
this->_hash = s._hash;
|
||||
return *this;
|
||||
@ -128,6 +130,7 @@ public:
|
||||
this->std::string::operator=(std::move(s));
|
||||
if(_u8_index != nullptr) delete _u8_index;
|
||||
this->_u8_index = s._u8_index;
|
||||
s._u8_index = nullptr;
|
||||
this->hash_initialized = s.hash_initialized;
|
||||
this->_hash = s._hash;
|
||||
return *this;
|
||||
|
118
src/vm.h
118
src/vm.h
@ -20,14 +20,14 @@
|
||||
|
||||
|
||||
class VM {
|
||||
std::vector<PyVar> _small_integers; // [-5, 256]
|
||||
// std::vector<PyVar> _small_integers; // [-5, 256]
|
||||
std::stack< std::unique_ptr<Frame> > callstack;
|
||||
PyVar _py_op_call;
|
||||
|
||||
|
||||
PyVar run_frame(Frame* frame){
|
||||
while(frame->has_next_bytecode()){
|
||||
const Bytecode& byte = frame->next_bytecode();
|
||||
// if(frame->_module != builtins){
|
||||
// if(true || frame->_module != builtins){
|
||||
// printf("%d: %s (%d) %s\n", frame->_ip, OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str());
|
||||
// }
|
||||
switch (byte.op)
|
||||
@ -46,11 +46,11 @@ class VM {
|
||||
frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame));
|
||||
} break;
|
||||
case OP_STORE_NAME: {
|
||||
const auto& p = frame->co->names[byte.arg];
|
||||
auto& p = frame->co->names[byte.arg];
|
||||
NameRef(p).set(this, frame, frame->pop_value(this));
|
||||
} break;
|
||||
case OP_BUILD_ATTR_REF: {
|
||||
const auto& attr = frame->co->names[byte.arg];
|
||||
auto& attr = frame->co->names[byte.arg];
|
||||
PyVar obj = frame->pop_value(this);
|
||||
frame->push(PyRef(AttrRef(obj, NameRef(attr))));
|
||||
} break;
|
||||
@ -75,14 +75,13 @@ class VM {
|
||||
for(int i=0; i<items.size(); i++){
|
||||
if(!items[i]->is_type(_tp_ref)) {
|
||||
done = true;
|
||||
PyVarList values = items.to_list();
|
||||
for(int j=i; j<values.size(); j++) frame->try_deref(this, values[j]);
|
||||
frame->push(PyTuple(values));
|
||||
for(int j=i; j<items.size(); j++) frame->try_deref(this, items[j]);
|
||||
frame->push(PyTuple(std::move(items)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(done) break;
|
||||
frame->push(PyRef(TupleRef(items.to_list())));
|
||||
frame->push(PyRef(TupleRef(std::move(items))));
|
||||
} break;
|
||||
case OP_BUILD_STRING:
|
||||
{
|
||||
@ -364,10 +363,9 @@ public:
|
||||
this->_stdout = new _StrStream();
|
||||
this->_stderr = new _StrStream();
|
||||
}
|
||||
initializeBuiltinClasses();
|
||||
|
||||
_small_integers.reserve(270);
|
||||
for(i64 i=-5; i<=256; i++) _small_integers.push_back(new_object(_tp_int, i));
|
||||
init_builtin_types();
|
||||
// for(i64 i=-5; i<=256; i++) _small_integers.push_back(new_object(_tp_int, i));
|
||||
}
|
||||
|
||||
PyVar asStr(const PyVar& obj){
|
||||
@ -473,8 +471,7 @@ public:
|
||||
|
||||
std::vector<_Str> positional_overrided_keys;
|
||||
if(!fn->starredArg.empty()){
|
||||
// handle *args
|
||||
PyVarList vargs;
|
||||
PyVarList vargs; // handle *args
|
||||
while(i < args.size()) vargs.push_back(args[i++]);
|
||||
locals.emplace(fn->starredArg, PyTuple(std::move(vargs)));
|
||||
}else{
|
||||
@ -608,7 +605,14 @@ public:
|
||||
template<typename T>
|
||||
inline PyVar new_object(PyVar type, T _value) {
|
||||
if(!type->is_type(_tp_type)) UNREACHABLE();
|
||||
return pkpy::make_shared<PyObject, Py_<T>>(type, _value);
|
||||
std::vector<int*>& pool = _obj_pool[obj_tid<T>((void*)type.get())];
|
||||
if(pool.empty()) return pkpy::make_shared<PyObject, Py_<T>>(type, _value);
|
||||
int* counter = pool.back(); pool.pop_back();
|
||||
*counter = 1;
|
||||
Py_<T>* obj = (Py_<T>*)(counter + 1);
|
||||
obj->_value = std::move(_value);
|
||||
obj->attribs.clear();
|
||||
return PyVar(counter);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
@ -810,16 +814,11 @@ public:
|
||||
return (const BaseRef*)(obj->value());
|
||||
}
|
||||
|
||||
__DEF_PY_AS_C(Int, i64, _tp_int)
|
||||
inline PyVar PyInt(i64 value) {
|
||||
if(value >= -5 && value <= 256) return _small_integers[value + 5];
|
||||
return new_object(_tp_int, value);
|
||||
}
|
||||
|
||||
DEF_NATIVE(Int, i64, _tp_int)
|
||||
DEF_NATIVE(Float, f64, _tp_float)
|
||||
DEF_NATIVE(Str, _Str, _tp_str)
|
||||
DEF_NATIVE(List, PyVarList, _tp_list)
|
||||
DEF_NATIVE(Tuple, PyVarList, _tp_tuple)
|
||||
DEF_NATIVE(Tuple, _Tuple, _tp_tuple)
|
||||
DEF_NATIVE(Function, _Func, _tp_function)
|
||||
DEF_NATIVE(NativeFunction, _CppFunc, _tp_native_function)
|
||||
DEF_NATIVE(Iter, pkpy::shared_ptr<BaseIter>, _tp_native_iterator)
|
||||
@ -832,7 +831,7 @@ public:
|
||||
inline bool PyBool_AS_C(const PyVar& obj){return obj == True;}
|
||||
inline const PyVar& PyBool(bool value){return value ? True : False;}
|
||||
|
||||
void initializeBuiltinClasses(){
|
||||
void init_builtin_types(){
|
||||
_tp_object = pkpy::make_shared<PyObject, Py_<i64>>(nullptr, DUMMY_VAL);
|
||||
_tp_type = pkpy::make_shared<PyObject, Py_<i64>>(nullptr, DUMMY_VAL);
|
||||
_types["object"] = _tp_object;
|
||||
@ -890,8 +889,9 @@ public:
|
||||
if (obj->is_type(_tp_type)) return (i64)obj.get();
|
||||
if (obj->is_type(_tp_tuple)) {
|
||||
i64 x = 1000003;
|
||||
for (const auto& item : PyTuple_AS_C(obj)) {
|
||||
i64 y = hash(item);
|
||||
const _Tuple& items = PyTuple_AS_C(obj);
|
||||
for (int i=0; i<items.size(); i++) {
|
||||
i64 y = hash(items[i]);
|
||||
x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); // recommended by Github Copilot
|
||||
}
|
||||
return x;
|
||||
@ -964,26 +964,26 @@ public:
|
||||
/***** Pointers' Impl *****/
|
||||
PyVar NameRef::get(VM* vm, Frame* frame) const{
|
||||
PyVar* val;
|
||||
val = frame->f_locals().try_get(pair->first);
|
||||
val = frame->f_locals().try_get(name());
|
||||
if(val) return *val;
|
||||
val = frame->f_globals().try_get(pair->first);
|
||||
val = frame->f_globals().try_get(name());
|
||||
if(val) return *val;
|
||||
val = vm->builtins->attribs.try_get(pair->first);
|
||||
val = vm->builtins->attribs.try_get(name());
|
||||
if(val) return *val;
|
||||
vm->NameError(pair->first);
|
||||
vm->NameError(name());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
|
||||
switch(pair->second) {
|
||||
case NAME_LOCAL: frame->f_locals()[pair->first] = std::move(val); break;
|
||||
switch(scope()) {
|
||||
case NAME_LOCAL: frame->f_locals()[name()] = std::move(val); break;
|
||||
case NAME_GLOBAL:
|
||||
{
|
||||
PyVar* existing = frame->f_locals().try_get(pair->first);
|
||||
PyVar* existing = frame->f_locals().try_get(name());
|
||||
if(existing != nullptr){
|
||||
*existing = std::move(val);
|
||||
}else{
|
||||
frame->f_globals()[pair->first] = std::move(val);
|
||||
frame->f_globals()[name()] = std::move(val);
|
||||
}
|
||||
} break;
|
||||
default: UNREACHABLE();
|
||||
@ -991,23 +991,23 @@ void NameRef::set(VM* vm, Frame* frame, PyVar val) const{
|
||||
}
|
||||
|
||||
void NameRef::del(VM* vm, Frame* frame) const{
|
||||
switch(pair->second) {
|
||||
switch(scope()) {
|
||||
case NAME_LOCAL: {
|
||||
if(frame->f_locals().contains(pair->first)){
|
||||
frame->f_locals().erase(pair->first);
|
||||
if(frame->f_locals().contains(name())){
|
||||
frame->f_locals().erase(name());
|
||||
}else{
|
||||
vm->NameError(pair->first);
|
||||
vm->NameError(name());
|
||||
}
|
||||
} break;
|
||||
case NAME_GLOBAL:
|
||||
{
|
||||
if(frame->f_locals().contains(pair->first)){
|
||||
frame->f_locals().erase(pair->first);
|
||||
if(frame->f_locals().contains(name())){
|
||||
frame->f_locals().erase(name());
|
||||
}else{
|
||||
if(frame->f_globals().contains(pair->first)){
|
||||
frame->f_globals().erase(pair->first);
|
||||
if(frame->f_globals().contains(name())){
|
||||
frame->f_globals().erase(name());
|
||||
}else{
|
||||
vm->NameError(pair->first);
|
||||
vm->NameError(name());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@ -1016,11 +1016,11 @@ void NameRef::del(VM* vm, Frame* frame) const{
|
||||
}
|
||||
|
||||
PyVar AttrRef::get(VM* vm, Frame* frame) const{
|
||||
return vm->getattr(obj, attr.pair->first);
|
||||
return vm->getattr(obj, attr.name());
|
||||
}
|
||||
|
||||
void AttrRef::set(VM* vm, Frame* frame, PyVar val) const{
|
||||
vm->setattr(obj, attr.pair->first, val);
|
||||
vm->setattr(obj, attr.name(), val);
|
||||
}
|
||||
|
||||
void AttrRef::del(VM* vm, Frame* frame) const{
|
||||
@ -1040,27 +1040,33 @@ void IndexRef::del(VM* vm, Frame* frame) const{
|
||||
}
|
||||
|
||||
PyVar TupleRef::get(VM* vm, Frame* frame) const{
|
||||
PyVarList args(varRefs.size());
|
||||
for (int i = 0; i < varRefs.size(); i++) {
|
||||
args[i] = vm->PyRef_AS_C(varRefs[i])->get(vm, frame);
|
||||
_Tuple args(objs.size());
|
||||
for (int i = 0; i < objs.size(); i++) {
|
||||
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
|
||||
}
|
||||
return vm->PyTuple(args);
|
||||
return vm->PyTuple(std::move(args));
|
||||
}
|
||||
|
||||
void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
|
||||
if(!val->is_type(vm->_tp_tuple) && !val->is_type(vm->_tp_list)){
|
||||
#define TUPLE_REF_SET() \
|
||||
if(args.size() > objs.size()) vm->ValueError("too many values to unpack"); \
|
||||
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)){
|
||||
const _Tuple& args = OBJ_GET(_Tuple, val);
|
||||
TUPLE_REF_SET()
|
||||
}else if(val->is_type(vm->_tp_list)){
|
||||
const PyVarList& args = OBJ_GET(PyVarList, val);
|
||||
TUPLE_REF_SET()
|
||||
}else{
|
||||
vm->TypeError("only tuple or list can be unpacked");
|
||||
}
|
||||
const PyVarList& args = OBJ_GET(PyVarList, val);
|
||||
if(args.size() > varRefs.size()) vm->ValueError("too many values to unpack");
|
||||
if(args.size() < varRefs.size()) vm->ValueError("not enough values to unpack");
|
||||
for (int i = 0; i < varRefs.size(); i++) {
|
||||
vm->PyRef_AS_C(varRefs[i])->set(vm, frame, args[i]);
|
||||
}
|
||||
#undef TUPLE_REF_SET
|
||||
}
|
||||
|
||||
void TupleRef::del(VM* vm, Frame* frame) const{
|
||||
for (auto& r : varRefs) vm->PyRef_AS_C(r)->del(vm, frame);
|
||||
for(int i=0; i<objs.size(); i++) vm->PyRef_AS_C(objs[i])->del(vm, frame);
|
||||
}
|
||||
|
||||
/***** Frame's Impl *****/
|
||||
|
Loading…
x
Reference in New Issue
Block a user