mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
update gc
This commit is contained in:
parent
c2ef720d90
commit
f57fa16ee2
91
src/ceval.h
91
src/ceval.h
@ -7,7 +7,7 @@ namespace pkpy{
|
|||||||
|
|
||||||
Str _read_file_cwd(const Str& name, bool* ok);
|
Str _read_file_cwd(const Str& name, bool* ok);
|
||||||
|
|
||||||
PyVar VM::run_frame(Frame* frame){
|
PyObject* VM::run_frame(Frame* frame){
|
||||||
while(frame->has_next_bytecode()){
|
while(frame->has_next_bytecode()){
|
||||||
const Bytecode& byte = frame->next_bytecode();
|
const Bytecode& byte = frame->next_bytecode();
|
||||||
switch (byte.op)
|
switch (byte.op)
|
||||||
@ -16,7 +16,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
case OP_SETUP_DECORATOR: continue;
|
case OP_SETUP_DECORATOR: continue;
|
||||||
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
|
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
|
||||||
case OP_LOAD_FUNCTION: {
|
case OP_LOAD_FUNCTION: {
|
||||||
const PyVar obj = frame->co->consts[byte.arg];
|
PyObject* obj = frame->co->consts[byte.arg];
|
||||||
Function f = CAST(Function, obj); // copy
|
Function f = CAST(Function, obj); // copy
|
||||||
f._module = frame->_module;
|
f._module = frame->_module;
|
||||||
frame->push(VAR(f));
|
frame->push(VAR(f));
|
||||||
@ -37,13 +37,13 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: {
|
case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: {
|
||||||
auto& attr = frame->co->names[byte.arg];
|
auto& attr = frame->co->names[byte.arg];
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
AttrRef ref = AttrRef(obj, NameRef(attr));
|
AttrRef ref = AttrRef(obj, NameRef(attr));
|
||||||
if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame));
|
if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame));
|
||||||
else frame->push(PyRef(ref));
|
else frame->push(PyRef(ref));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_INDEX: {
|
case OP_BUILD_INDEX: {
|
||||||
PyVar index = frame->pop_value(this);
|
PyObject* index = frame->pop_value(this);
|
||||||
auto ref = IndexRef(frame->pop_value(this), index);
|
auto ref = IndexRef(frame->pop_value(this), index);
|
||||||
if(byte.arg > 0) frame->push(ref.get(this, frame));
|
if(byte.arg > 0) frame->push(ref.get(this, frame));
|
||||||
else frame->push(PyRef(ref));
|
else frame->push(PyRef(ref));
|
||||||
@ -57,9 +57,6 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
} continue;
|
} continue;
|
||||||
case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue;
|
case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue;
|
||||||
case OP_STORE_REF: {
|
case OP_STORE_REF: {
|
||||||
// PyVar obj = frame->pop_value(this);
|
|
||||||
// PyVarRef r = frame->pop();
|
|
||||||
// PyRef_AS_C(r)->set(this, frame, std::move(obj));
|
|
||||||
PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this));
|
PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this));
|
||||||
frame->_pop(); frame->_pop();
|
frame->_pop(); frame->_pop();
|
||||||
} continue;
|
} continue;
|
||||||
@ -84,25 +81,25 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
|
case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
|
||||||
case OP_BEGIN_CLASS: {
|
case OP_BEGIN_CLASS: {
|
||||||
auto& name = frame->co->names[byte.arg];
|
auto& name = frame->co->names[byte.arg];
|
||||||
PyVar clsBase = frame->pop_value(this);
|
PyObject* clsBase = frame->pop_value(this);
|
||||||
if(clsBase == None) clsBase = _t(tp_object);
|
if(clsBase == None) clsBase = _t(tp_object);
|
||||||
check_type(clsBase, tp_type);
|
check_type(clsBase, tp_type);
|
||||||
PyVar cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase));
|
PyObject* cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase));
|
||||||
frame->push(cls);
|
frame->push(cls);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_END_CLASS: {
|
case OP_END_CLASS: {
|
||||||
PyVar cls = frame->pop();
|
PyObject* cls = frame->pop();
|
||||||
cls->attr()._try_perfect_rehash();
|
cls->attr()._try_perfect_rehash();
|
||||||
}; continue;
|
}; continue;
|
||||||
case OP_STORE_CLASS_ATTR: {
|
case OP_STORE_CLASS_ATTR: {
|
||||||
auto& name = frame->co->names[byte.arg];
|
auto& name = frame->co->names[byte.arg];
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
PyVar& cls = frame->top();
|
PyObject* cls = frame->top();
|
||||||
cls->attr().set(name.first, std::move(obj));
|
cls->attr().set(name.first, std::move(obj));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_RETURN_VALUE: return frame->pop_value(this);
|
case OP_RETURN_VALUE: return frame->pop_value(this);
|
||||||
case OP_PRINT_EXPR: {
|
case OP_PRINT_EXPR: {
|
||||||
const PyVar expr = frame->top_value(this);
|
PyObject* expr = frame->top_value(this);
|
||||||
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
|
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
|
||||||
} continue;
|
} continue;
|
||||||
case OP_POP_TOP: frame->_pop(); continue;
|
case OP_POP_TOP: frame->_pop(); continue;
|
||||||
@ -122,7 +119,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
Args args(2);
|
Args args(2);
|
||||||
args[1] = frame->pop();
|
args[1] = frame->pop();
|
||||||
args[0] = frame->top_value(this);
|
args[0] = frame->top_value(this);
|
||||||
PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
|
PyObject* ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
|
||||||
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
|
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
|
||||||
frame->_pop();
|
frame->_pop();
|
||||||
} continue;
|
} continue;
|
||||||
@ -130,7 +127,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
Args args(2);
|
Args args(2);
|
||||||
args[1] = frame->pop_value(this);
|
args[1] = frame->pop_value(this);
|
||||||
args[0] = frame->top_value(this);
|
args[0] = frame->top_value(this);
|
||||||
PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
|
PyObject* ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
|
||||||
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
|
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
|
||||||
frame->_pop();
|
frame->_pop();
|
||||||
} continue;
|
} continue;
|
||||||
@ -141,14 +138,14 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
|
frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_IS_OP: {
|
case OP_IS_OP: {
|
||||||
PyVar rhs = frame->pop_value(this);
|
PyObject* rhs = frame->pop_value(this);
|
||||||
bool ret_c = rhs == frame->top_value(this);
|
bool ret_c = rhs == frame->top_value(this);
|
||||||
if(byte.arg == 1) ret_c = !ret_c;
|
if(byte.arg == 1) ret_c = !ret_c;
|
||||||
frame->top() = VAR(ret_c);
|
frame->top() = VAR(ret_c);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_CONTAINS_OP: {
|
case OP_CONTAINS_OP: {
|
||||||
PyVar rhs = frame->pop_value(this);
|
PyObject* rhs = frame->pop_value(this);
|
||||||
bool ret_c = CAST(bool, call(rhs, __contains__, one_arg(frame->pop_value(this))));
|
bool ret_c = CAST(bool, call(rhs, __contains__, Args{frame->pop_value(this)}));
|
||||||
if(byte.arg == 1) ret_c = !ret_c;
|
if(byte.arg == 1) ret_c = !ret_c;
|
||||||
frame->push(VAR(ret_c));
|
frame->push(VAR(ret_c));
|
||||||
} continue;
|
} continue;
|
||||||
@ -156,8 +153,8 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
frame->top() = num_negated(frame->top_value(this));
|
frame->top() = num_negated(frame->top_value(this));
|
||||||
continue;
|
continue;
|
||||||
case OP_UNARY_NOT: {
|
case OP_UNARY_NOT: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
const PyVar& obj_bool = asBool(obj);
|
PyObject* obj_bool = asBool(obj);
|
||||||
frame->push(VAR(!_CAST(bool, obj_bool)));
|
frame->push(VAR(!_CAST(bool, obj_bool)));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_POP_JUMP_IF_FALSE:
|
case OP_POP_JUMP_IF_FALSE:
|
||||||
@ -168,9 +165,9 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
case OP_LOAD_FALSE: frame->push(False); continue;
|
case OP_LOAD_FALSE: frame->push(False); continue;
|
||||||
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
|
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
|
||||||
case OP_ASSERT: {
|
case OP_ASSERT: {
|
||||||
PyVar _msg = frame->pop_value(this);
|
PyObject* _msg = frame->pop_value(this);
|
||||||
Str msg = CAST(Str, asStr(_msg));
|
Str msg = CAST(Str, asStr(_msg));
|
||||||
PyVar expr = frame->pop_value(this);
|
PyObject* expr = frame->pop_value(this);
|
||||||
if(asBool(expr) != True) _error("AssertionError", msg);
|
if(asBool(expr) != True) _error("AssertionError", msg);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_EXCEPTION_MATCH: {
|
case OP_EXCEPTION_MATCH: {
|
||||||
@ -179,7 +176,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
frame->push(VAR(e.match_type(name)));
|
frame->push(VAR(e.match_type(name)));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_RAISE: {
|
case OP_RAISE: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
Str msg = obj == None ? "" : CAST(Str, asStr(obj));
|
Str msg = obj == None ? "" : CAST(Str, asStr(obj));
|
||||||
StrName type = frame->co->names[byte.arg].first;
|
StrName type = frame->co->names[byte.arg].first;
|
||||||
_error(type, msg);
|
_error(type, msg);
|
||||||
@ -190,32 +187,32 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
continue;
|
continue;
|
||||||
case OP_BUILD_MAP: {
|
case OP_BUILD_MAP: {
|
||||||
Args items = frame->pop_n_values_reversed(this, byte.arg*2);
|
Args items = frame->pop_n_values_reversed(this, byte.arg*2);
|
||||||
PyVar obj = call(builtins->attr("dict"));
|
PyObject* obj = call(builtins->attr("dict"));
|
||||||
for(int i=0; i<items.size(); i+=2){
|
for(int i=0; i<items.size(); i+=2){
|
||||||
call(obj, __setitem__, two_args(items[i], items[i+1]));
|
call(obj, __setitem__, Args{items[i], items[i+1]});
|
||||||
}
|
}
|
||||||
frame->push(obj);
|
frame->push(obj);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_SET: {
|
case OP_BUILD_SET: {
|
||||||
PyVar list = VAR(
|
PyObject* list = VAR(
|
||||||
frame->pop_n_values_reversed(this, byte.arg).move_to_list()
|
frame->pop_n_values_reversed(this, byte.arg).move_to_list()
|
||||||
);
|
);
|
||||||
PyVar obj = call(builtins->attr("set"), one_arg(list));
|
PyObject* obj = call(builtins->attr("set"), Args{list});
|
||||||
frame->push(obj);
|
frame->push(obj);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_LIST_APPEND: {
|
case OP_LIST_APPEND: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
List& list = CAST(List&, frame->top_1());
|
List& list = CAST(List&, frame->top_1());
|
||||||
list.push_back(std::move(obj));
|
list.push_back(std::move(obj));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_MAP_ADD: {
|
case OP_MAP_ADD: {
|
||||||
PyVar value = frame->pop_value(this);
|
PyObject* value = frame->pop_value(this);
|
||||||
PyVar key = frame->pop_value(this);
|
PyObject* key = frame->pop_value(this);
|
||||||
call(frame->top_1(), __setitem__, two_args(key, value));
|
call(frame->top_1(), __setitem__, Args{key, value});
|
||||||
} continue;
|
} continue;
|
||||||
case OP_SET_ADD: {
|
case OP_SET_ADD: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
call(frame->top_1(), "add", one_arg(obj));
|
call(frame->top_1(), "add", Args{obj});
|
||||||
} continue;
|
} continue;
|
||||||
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
|
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
|
||||||
case OP_UNARY_STAR: {
|
case OP_UNARY_STAR: {
|
||||||
@ -232,16 +229,16 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
|
Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
|
||||||
Args args = frame->pop_n_values_reversed(this, ARGC);
|
Args args = frame->pop_n_values_reversed(this, ARGC);
|
||||||
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
|
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
|
||||||
PyVar callable = frame->pop_value(this);
|
PyObject* callable = frame->pop_value(this);
|
||||||
PyVar ret = call(callable, std::move(args), kwargs, true);
|
PyObject* ret = call(callable, std::move(args), kwargs, true);
|
||||||
if(ret == _py_op_call) return ret;
|
if(ret == _py_op_call) return ret;
|
||||||
frame->push(std::move(ret));
|
frame->push(std::move(ret));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_CALL_UNPACK: case OP_CALL: {
|
case OP_CALL_UNPACK: case OP_CALL: {
|
||||||
Args args = frame->pop_n_values_reversed(this, byte.arg);
|
Args args = frame->pop_n_values_reversed(this, byte.arg);
|
||||||
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
|
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
|
||||||
PyVar callable = frame->pop_value(this);
|
PyObject* callable = frame->pop_value(this);
|
||||||
PyVar ret = call(callable, std::move(args), no_arg(), true);
|
PyObject* ret = call(callable, std::move(args), no_arg(), true);
|
||||||
if(ret == _py_op_call) return ret;
|
if(ret == _py_op_call) return ret;
|
||||||
frame->push(std::move(ret));
|
frame->push(std::move(ret));
|
||||||
} continue;
|
} continue;
|
||||||
@ -254,15 +251,15 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
frame->jump_abs_safe(it->second);
|
frame->jump_abs_safe(it->second);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_GET_ITER: {
|
case OP_GET_ITER: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
PyVar iter = asIter(obj);
|
PyObject* iter = asIter(obj);
|
||||||
check_type(frame->top(), tp_ref);
|
check_type(frame->top(), tp_ref);
|
||||||
PyIter_AS_C(iter)->loop_var = frame->pop();
|
PyIter_AS_C(iter)->loop_var = frame->pop();
|
||||||
frame->push(std::move(iter));
|
frame->push(std::move(iter));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_FOR_ITER: {
|
case OP_FOR_ITER: {
|
||||||
BaseIter* it = PyIter_AS_C(frame->top());
|
BaseIter* it = PyIter_AS_C(frame->top());
|
||||||
PyVar obj = it->next();
|
PyObject* obj = it->next();
|
||||||
if(obj != nullptr){
|
if(obj != nullptr){
|
||||||
PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj));
|
PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj));
|
||||||
}else{
|
}else{
|
||||||
@ -279,18 +276,18 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
frame->jump_abs_safe(blockEnd);
|
frame->jump_abs_safe(blockEnd);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_JUMP_IF_FALSE_OR_POP: {
|
case OP_JUMP_IF_FALSE_OR_POP: {
|
||||||
const PyVar expr = frame->top_value(this);
|
PyObject* expr = frame->top_value(this);
|
||||||
if(asBool(expr)==False) frame->jump_abs(byte.arg);
|
if(asBool(expr)==False) frame->jump_abs(byte.arg);
|
||||||
else frame->pop_value(this);
|
else frame->pop_value(this);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_JUMP_IF_TRUE_OR_POP: {
|
case OP_JUMP_IF_TRUE_OR_POP: {
|
||||||
const PyVar expr = frame->top_value(this);
|
PyObject* expr = frame->top_value(this);
|
||||||
if(asBool(expr)==True) frame->jump_abs(byte.arg);
|
if(asBool(expr)==True) frame->jump_abs(byte.arg);
|
||||||
else frame->pop_value(this);
|
else frame->pop_value(this);
|
||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_SLICE: {
|
case OP_BUILD_SLICE: {
|
||||||
PyVar stop = frame->pop_value(this);
|
PyObject* stop = frame->pop_value(this);
|
||||||
PyVar start = frame->pop_value(this);
|
PyObject* start = frame->pop_value(this);
|
||||||
Slice s;
|
Slice s;
|
||||||
if(start != None) { s.start = CAST(int, start);}
|
if(start != None) { s.start = CAST(int, start);}
|
||||||
if(stop != None) { s.stop = CAST(int, stop);}
|
if(stop != None) { s.stop = CAST(int, stop);}
|
||||||
@ -298,7 +295,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
} continue;
|
} continue;
|
||||||
case OP_IMPORT_NAME: {
|
case OP_IMPORT_NAME: {
|
||||||
StrName name = frame->co->names[byte.arg].first;
|
StrName name = frame->co->names[byte.arg].first;
|
||||||
PyVar* ext_mod = _modules.try_get(name);
|
PyObject** ext_mod = _modules.try_get(name);
|
||||||
if(ext_mod == nullptr){
|
if(ext_mod == nullptr){
|
||||||
Str source;
|
Str source;
|
||||||
auto it2 = _lazy_modules.find(name);
|
auto it2 = _lazy_modules.find(name);
|
||||||
@ -311,7 +308,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
_lazy_modules.erase(it2);
|
_lazy_modules.erase(it2);
|
||||||
}
|
}
|
||||||
CodeObject_ code = compile(source, name.str(), EXEC_MODE);
|
CodeObject_ code = compile(source, name.str(), EXEC_MODE);
|
||||||
PyVar new_mod = new_module(name);
|
PyObject* new_mod = new_module(name);
|
||||||
_exec(code, new_mod);
|
_exec(code, new_mod);
|
||||||
frame->push(new_mod);
|
frame->push(new_mod);
|
||||||
new_mod->attr()._try_perfect_rehash();
|
new_mod->attr()._try_perfect_rehash();
|
||||||
@ -320,7 +317,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
}
|
}
|
||||||
} continue;
|
} continue;
|
||||||
case OP_STORE_ALL_NAMES: {
|
case OP_STORE_ALL_NAMES: {
|
||||||
PyVar obj = frame->pop_value(this);
|
PyObject* obj = frame->pop_value(this);
|
||||||
for(auto& [name, value]: obj->attr().items()){
|
for(auto& [name, value]: obj->attr().items()){
|
||||||
Str s = name.str();
|
Str s = name.str();
|
||||||
if(s.empty() || s[0] == '_') continue;
|
if(s.empty() || s[0] == '_') continue;
|
||||||
|
40
src/cffi.h
40
src/cffi.h
@ -14,7 +14,7 @@ struct NativeProxyFunc {
|
|||||||
_Fp func;
|
_Fp func;
|
||||||
NativeProxyFunc(_Fp func) : func(func) {}
|
NativeProxyFunc(_Fp func) : func(func) {}
|
||||||
|
|
||||||
PyVar operator()(VM* vm, Args& args) {
|
PyObject* operator()(VM* vm, Args& args) {
|
||||||
if (args.size() != N) {
|
if (args.size() != N) {
|
||||||
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size()));
|
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size()));
|
||||||
}
|
}
|
||||||
@ -22,13 +22,13 @@ struct NativeProxyFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template<typename __Ret, size_t... Is>
|
||||||
std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
||||||
func(py_cast<Params>(vm, args[Is])...);
|
func(py_cast<Params>(vm, args[Is])...);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template<typename __Ret, size_t... Is>
|
||||||
std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
||||||
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ struct NativeProxyMethod {
|
|||||||
_Fp func;
|
_Fp func;
|
||||||
NativeProxyMethod(_Fp func) : func(func) {}
|
NativeProxyMethod(_Fp func) : func(func) {}
|
||||||
|
|
||||||
PyVar operator()(VM* vm, Args& args) {
|
PyObject* operator()(VM* vm, Args& args) {
|
||||||
int actual_size = args.size() - 1;
|
int actual_size = args.size() - 1;
|
||||||
if (actual_size != N) {
|
if (actual_size != N) {
|
||||||
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
|
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
|
||||||
@ -50,14 +50,14 @@ struct NativeProxyMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template<typename __Ret, size_t... Is>
|
||||||
std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
||||||
T& self = py_cast<T&>(vm, args[0]);
|
T& self = py_cast<T&>(vm, args[0]);
|
||||||
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template<typename __Ret, size_t... Is>
|
||||||
std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
|
||||||
T& self = py_cast<T&>(vm, args[0]);
|
T& self = py_cast<T&>(vm, args[0]);
|
||||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
@ -200,7 +200,7 @@ struct Pointer{
|
|||||||
return Pointer(ctype, level, ptr-offset*unit_size());
|
return Pointer(ctype, level, ptr-offset*unit_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
|
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
|
||||||
|
|
||||||
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
|
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
|
||||||
@ -268,7 +268,7 @@ struct Pointer{
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
|
inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
|
||||||
|
|
||||||
PyVar get(VM* vm){
|
PyObject* get(VM* vm){
|
||||||
if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
|
if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
|
||||||
switch(ctype->index){
|
switch(ctype->index){
|
||||||
#define CASE(T) case type_index<T>(): return VAR(ref<T>())
|
#define CASE(T) case type_index<T>(): return VAR(ref<T>())
|
||||||
@ -291,7 +291,7 @@ struct Pointer{
|
|||||||
return VAR_T(Pointer, *this);
|
return VAR_T(Pointer, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(VM* vm, const PyVar& val){
|
void set(VM* vm, PyObject* val){
|
||||||
if(level > 1) {
|
if(level > 1) {
|
||||||
Pointer& p = CAST(Pointer&, val);
|
Pointer& p = CAST(Pointer&, val);
|
||||||
ref<char*>() = p.ptr; // We don't check the type, just copy the underlying address
|
ref<char*>() = p.ptr; // We don't check the type, just copy the underlying address
|
||||||
@ -359,7 +359,7 @@ struct Value {
|
|||||||
Value& operator=(const Value& other) = delete;
|
Value& operator=(const Value& other) = delete;
|
||||||
Value(const Value& other) = delete;
|
Value(const Value& other) = delete;
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
|
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
|
||||||
|
|
||||||
vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) {
|
vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) {
|
||||||
@ -388,7 +388,7 @@ struct CType{
|
|||||||
CType() : type(_type_db.get<void>()) {}
|
CType() : type(_type_db.get<void>()) {}
|
||||||
CType(const TypeInfo* type) : type(type) {}
|
CType(const TypeInfo* type) : type(type) {}
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) {
|
vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) {
|
||||||
const Str& name = CAST(Str&, args[0]);
|
const Str& name = CAST(Str&, args[0]);
|
||||||
const TypeInfo* type = _type_db.get(name);
|
const TypeInfo* type = _type_db.get(name);
|
||||||
@ -404,8 +404,8 @@ struct CType{
|
|||||||
};
|
};
|
||||||
|
|
||||||
void add_module_c(VM* vm){
|
void add_module_c(VM* vm){
|
||||||
PyVar mod = vm->new_module("c");
|
PyObject* mod = vm->new_module("c");
|
||||||
PyVar ptr_t = Pointer::register_class(vm, mod);
|
PyObject* ptr_t = Pointer::register_class(vm, mod);
|
||||||
Value::register_class(vm, mod);
|
Value::register_class(vm, mod);
|
||||||
CType::register_class(vm, mod);
|
CType::register_class(vm, mod);
|
||||||
|
|
||||||
@ -462,11 +462,11 @@ void add_module_c(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar py_var(VM* vm, void* p){
|
PyObject* py_var(VM* vm, void* p){
|
||||||
return VAR_T(Pointer, _type_db.get<void>(), (char*)p);
|
return VAR_T(Pointer, _type_db.get<void>(), (char*)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar py_var(VM* vm, char* p){
|
PyObject* py_var(VM* vm, char* p){
|
||||||
return VAR_T(Pointer, _type_db.get<char>(), (char*)p);
|
return VAR_T(Pointer, _type_db.get<char>(), (char*)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +491,7 @@ struct pointer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T py_pointer_cast(VM* vm, const PyVar& var){
|
T py_pointer_cast(VM* vm, PyObject* var){
|
||||||
static_assert(std::is_pointer_v<T>);
|
static_assert(std::is_pointer_v<T>);
|
||||||
Pointer& p = CAST(Pointer&, var);
|
Pointer& p = CAST(Pointer&, var);
|
||||||
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
|
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
|
||||||
@ -503,14 +503,14 @@ T py_pointer_cast(VM* vm, const PyVar& var){
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T py_value_cast(VM* vm, const PyVar& var){
|
T py_value_cast(VM* vm, PyObject* var){
|
||||||
static_assert(std::is_pod_v<T>);
|
static_assert(std::is_pod_v<T>);
|
||||||
Value& v = CAST(Value&, var);
|
Value& v = CAST(Value&, var);
|
||||||
return *reinterpret_cast<T*>(v.data);
|
return *reinterpret_cast<T*>(v.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyVar>
|
std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyObject*>
|
||||||
py_var(VM* vm, T p){
|
py_var(VM* vm, T p){
|
||||||
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
|
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
|
||||||
if(type == nullptr) type = _type_db.get<void>();
|
if(type == nullptr) type = _type_db.get<void>();
|
||||||
@ -518,9 +518,9 @@ py_var(VM* vm, T p){
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyVar>
|
std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyObject*>
|
||||||
py_var(VM* vm, T p){
|
py_var(VM* vm, T p){
|
||||||
if constexpr(std::is_same_v<T, PyVar>) return p;
|
if constexpr(std::is_same_v<T, PyObject*>) return p;
|
||||||
const TypeInfo* type = _type_db.get<T>();
|
const TypeInfo* type = _type_db.get<T>();
|
||||||
return VAR_T(Value, type, &p);
|
return VAR_T(Value, type, &p);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ struct CodeObject {
|
|||||||
return names.size() - 1;
|
return names.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_const(PyVar v){
|
int add_const(PyObject* v){
|
||||||
consts.push_back(v);
|
consts.push_back(v);
|
||||||
return consts.size() - 1;
|
return consts.size() - 1;
|
||||||
}
|
}
|
||||||
|
21
src/common.h
21
src/common.h
@ -57,7 +57,6 @@ namespace std = ::std;
|
|||||||
struct Dummy { };
|
struct Dummy { };
|
||||||
struct DummyInstance { };
|
struct DummyInstance { };
|
||||||
struct DummyModule { };
|
struct DummyModule { };
|
||||||
#define DUMMY_VAL Dummy()
|
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
int index;
|
int index;
|
||||||
@ -85,4 +84,24 @@ struct Type {
|
|||||||
const float kLocalsLoadFactor = 0.67f;
|
const float kLocalsLoadFactor = 0.67f;
|
||||||
const float kInstAttrLoadFactor = 0.67f;
|
const float kInstAttrLoadFactor = 0.67f;
|
||||||
const float kTypeAttrLoadFactor = 0.5f;
|
const float kTypeAttrLoadFactor = 0.5f;
|
||||||
|
|
||||||
|
static_assert(sizeof(i64) == sizeof(int*));
|
||||||
|
static_assert(sizeof(f64) == sizeof(int*));
|
||||||
|
static_assert(std::numeric_limits<float>::is_iec559);
|
||||||
|
static_assert(std::numeric_limits<double>::is_iec559);
|
||||||
|
|
||||||
|
struct PyObject;
|
||||||
|
#define BITS(p) (reinterpret_cast<i64>(p))
|
||||||
|
inline bool is_tagged(PyObject* p) noexcept { return (BITS(p) & 0b11) != 0b00; }
|
||||||
|
inline bool is_int(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b01; }
|
||||||
|
inline bool is_float(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b10; }
|
||||||
|
|
||||||
|
inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept {
|
||||||
|
return is_tagged(a) && is_tagged(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
|
||||||
|
return is_int(a) && is_int(b);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -353,14 +353,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exprLiteral() {
|
void exprLiteral() {
|
||||||
PyVar value = parser->prev.value;
|
PyObject* value = parser->prev.value;
|
||||||
int index = co()->add_const(value);
|
int index = co()->add_const(value);
|
||||||
emit(OP_LOAD_CONST, index);
|
emit(OP_LOAD_CONST, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exprFString() {
|
void exprFString() {
|
||||||
static const std::regex pattern(R"(\{(.*?)\})");
|
static const std::regex pattern(R"(\{(.*?)\})");
|
||||||
PyVar value = parser->prev.value;
|
PyObject* value = parser->prev.value;
|
||||||
Str s = CAST(Str, value);
|
Str s = CAST(Str, value);
|
||||||
std::sregex_iterator begin(s.begin(), s.end(), pattern);
|
std::sregex_iterator begin(s.begin(), s.end(), pattern);
|
||||||
std::sregex_iterator end;
|
std::sregex_iterator end;
|
||||||
@ -1059,7 +1059,7 @@ private:
|
|||||||
case 1: func.starred_arg = name; state+=1; break;
|
case 1: func.starred_arg = name; state+=1; break;
|
||||||
case 2: {
|
case 2: {
|
||||||
consume(TK("="));
|
consume(TK("="));
|
||||||
PyVarOrNull value = read_literal();
|
PyObject* value = read_literal();
|
||||||
if(value == nullptr){
|
if(value == nullptr){
|
||||||
SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type));
|
SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type));
|
||||||
}
|
}
|
||||||
@ -1115,10 +1115,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVarOrNull read_literal(){
|
PyObject* read_literal(){
|
||||||
if(match(TK("-"))){
|
if(match(TK("-"))){
|
||||||
consume(TK("@num"));
|
consume(TK("@num"));
|
||||||
PyVar val = parser->prev.value;
|
PyObject* val = parser->prev.value;
|
||||||
return vm->num_negated(val);
|
return vm->num_negated(val);
|
||||||
}
|
}
|
||||||
if(match(TK("@num"))) return parser->prev.value;
|
if(match(TK("@num"))) return parser->prev.value;
|
||||||
@ -1166,7 +1166,7 @@ public:
|
|||||||
code->optimize(vm);
|
code->optimize(vm);
|
||||||
return code;
|
return code;
|
||||||
}else if(mode()==JSON_MODE){
|
}else if(mode()==JSON_MODE){
|
||||||
PyVarOrNull value = read_literal();
|
PyObject* value = read_literal();
|
||||||
if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
|
if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
|
||||||
else if(match(TK("{"))) exprMap();
|
else if(match(TK("{"))) exprMap();
|
||||||
else if(match(TK("["))) exprList();
|
else if(match(TK("["))) exprList();
|
||||||
|
30
src/frame.h
30
src/frame.h
@ -7,27 +7,27 @@ namespace pkpy{
|
|||||||
static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
|
static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
std::vector<PyVar> _data;
|
std::vector<PyObject*> _data;
|
||||||
int _ip = -1;
|
int _ip = -1;
|
||||||
int _next_ip = 0;
|
int _next_ip = 0;
|
||||||
|
|
||||||
const CodeObject* co;
|
const CodeObject* co;
|
||||||
PyVar _module;
|
PyObject* _module;
|
||||||
NameDict_ _locals;
|
NameDict_ _locals;
|
||||||
NameDict_ _closure;
|
NameDict_ _closure;
|
||||||
const uint64_t id;
|
const uint64_t id;
|
||||||
std::vector<std::pair<int, std::vector<PyVar>>> s_try_block;
|
std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
|
||||||
|
|
||||||
inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
|
inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
|
||||||
inline NameDict& f_globals() noexcept { return _module->attr(); }
|
inline NameDict& f_globals() noexcept { return _module->attr(); }
|
||||||
|
|
||||||
inline PyVar* f_closure_try_get(StrName name) noexcept {
|
inline PyObject** f_closure_try_get(StrName name) noexcept {
|
||||||
if(_closure == nullptr) return nullptr;
|
if(_closure == nullptr) return nullptr;
|
||||||
return _closure->try_get(name);
|
return _closure->try_get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame(const CodeObject_& co,
|
Frame(const CodeObject_& co,
|
||||||
const PyVar& _module,
|
PyObject* _module,
|
||||||
const NameDict_& _locals=nullptr,
|
const NameDict_& _locals=nullptr,
|
||||||
const NameDict_& _closure=nullptr)
|
const NameDict_& _closure=nullptr)
|
||||||
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
|
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
|
||||||
@ -57,11 +57,11 @@ struct Frame {
|
|||||||
return _next_ip < co->codes.size();
|
return _next_ip < co->codes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar pop(){
|
inline PyObject* pop(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
PyVar v = std::move(_data.back());
|
PyObject* v = _data.back();
|
||||||
_data.pop_back();
|
_data.pop_back();
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -73,28 +73,28 @@ struct Frame {
|
|||||||
_data.pop_back();
|
_data.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void try_deref(VM*, PyVar&);
|
inline void try_deref(VM*, PyObject*&);
|
||||||
|
|
||||||
inline PyVar pop_value(VM* vm){
|
inline PyObject* pop_value(VM* vm){
|
||||||
PyVar value = pop();
|
PyObject* value = pop();
|
||||||
try_deref(vm, value);
|
try_deref(vm, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar top_value(VM* vm){
|
inline PyObject* top_value(VM* vm){
|
||||||
PyVar value = top();
|
PyObject* value = top();
|
||||||
try_deref(vm, value);
|
try_deref(vm, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar& top(){
|
inline PyObject*& top(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
return _data.back();
|
return _data.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar& top_1(){
|
inline PyObject*& top_1(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
||||||
#endif
|
#endif
|
||||||
@ -117,7 +117,7 @@ struct Frame {
|
|||||||
|
|
||||||
bool jump_to_exception_handler(){
|
bool jump_to_exception_handler(){
|
||||||
if(s_try_block.empty()) return false;
|
if(s_try_block.empty()) return false;
|
||||||
PyVar obj = pop();
|
PyObject* obj = pop();
|
||||||
auto& p = s_try_block.back();
|
auto& p = s_try_block.back();
|
||||||
_data = std::move(p.second);
|
_data = std::move(p.second);
|
||||||
_data.push_back(obj);
|
_data.push_back(obj);
|
||||||
|
59
src/gc.h
59
src/gc.h
@ -3,49 +3,38 @@
|
|||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
using PyVar0 = PyObject*;
|
struct ManagedHeap{
|
||||||
|
std::vector<PyObject*> heap;
|
||||||
|
|
||||||
// a generational mark and sweep garbage collector
|
template<typename T>
|
||||||
struct GC{
|
PyObject* gcnew(Type type, T&& val){
|
||||||
using Generation = std::vector<PyVar0>;
|
PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
|
||||||
static const int kTotalGen = 3;
|
obj->gc.enabled = true;
|
||||||
Generation gen[kTotalGen];
|
heap.push_back(obj);
|
||||||
|
return obj;
|
||||||
void add(PyVar0 obj){
|
|
||||||
if(!obj->need_gc) return;
|
|
||||||
gen[0].push_back(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sweep(int index){
|
void sweep(){
|
||||||
Generation& g = gen[index];
|
std::vector<PyObject*> alive;
|
||||||
if(index < kTotalGen-1){
|
for(PyObject* obj: heap){
|
||||||
for(int i=0; i<g.size(); i++){
|
if(obj->gc.marked){
|
||||||
if(g[i]->marked){
|
obj->gc.marked = false;
|
||||||
g[i]->marked = false;
|
alive.push_back(obj);
|
||||||
gen[index+1].push_back(g[i]);
|
}else{
|
||||||
}else{
|
delete obj;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
heap.clear();
|
||||||
|
heap.swap(alive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect(int index){
|
void collect(VM* vm){
|
||||||
sweep(index);
|
std::vector<PyObject*> roots = get_roots(vm);
|
||||||
|
for(PyObject* obj: roots) obj->mark();
|
||||||
|
sweep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PyObject*> get_roots(VM* vm);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
8
src/io.h
8
src/io.h
@ -42,7 +42,7 @@ struct FileIO {
|
|||||||
if(!_fs.is_open()) vm->IOError(strerror(errno));
|
if(!_fs.is_open()) vm->IOError(strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
|
vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
|
||||||
return VAR_T(FileIO,
|
return VAR_T(FileIO,
|
||||||
vm, CAST(Str, args[0]), CAST(Str, args[1])
|
vm, CAST(Str, args[0]), CAST(Str, args[1])
|
||||||
@ -79,15 +79,15 @@ struct FileIO {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void add_module_io(VM* vm){
|
void add_module_io(VM* vm){
|
||||||
PyVar mod = vm->new_module("io");
|
PyObject* mod = vm->new_module("io");
|
||||||
PyVar type = FileIO::register_class(vm, mod);
|
PyObject* type = FileIO::register_class(vm, mod);
|
||||||
vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
|
vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
|
||||||
return vm->call(type, args);
|
return vm->call(type, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_os(VM* vm){
|
void add_module_os(VM* vm){
|
||||||
PyVar mod = vm->new_module("os");
|
PyObject* mod = vm->new_module("os");
|
||||||
// Working directory is shared by all VMs!!
|
// Working directory is shared by all VMs!!
|
||||||
vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
|
vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
|
||||||
return VAR(std::filesystem::current_path().string());
|
return VAR(std::filesystem::current_path().string());
|
||||||
|
16
src/iter.h
16
src/iter.h
@ -8,7 +8,7 @@ class RangeIter : public BaseIter {
|
|||||||
i64 current;
|
i64 current;
|
||||||
Range r;
|
Range r;
|
||||||
public:
|
public:
|
||||||
RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
|
RangeIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
|
||||||
this->r = OBJ_GET(Range, _ref);
|
this->r = OBJ_GET(Range, _ref);
|
||||||
this->current = r.start;
|
this->current = r.start;
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ public:
|
|||||||
return r.step > 0 ? current < r.stop : current > r.stop;
|
return r.step > 0 ? current < r.stop : current > r.stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar next(){
|
PyObject* next(){
|
||||||
if(!_has_next()) return nullptr;
|
if(!_has_next()) return nullptr;
|
||||||
current += r.step;
|
current += r.step;
|
||||||
return VAR(current-r.step);
|
return VAR(current-r.step);
|
||||||
@ -29,8 +29,8 @@ class ArrayIter : public BaseIter {
|
|||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
const T* p;
|
const T* p;
|
||||||
public:
|
public:
|
||||||
ArrayIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
|
ArrayIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
|
||||||
PyVar next(){
|
PyObject* next(){
|
||||||
if(index == p->size()) return nullptr;
|
if(index == p->size()) return nullptr;
|
||||||
return p->operator[](index++);
|
return p->operator[](index++);
|
||||||
}
|
}
|
||||||
@ -40,20 +40,20 @@ class StringIter : public BaseIter {
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
Str* str;
|
Str* str;
|
||||||
public:
|
public:
|
||||||
StringIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
|
StringIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
|
||||||
str = &OBJ_GET(Str, _ref);
|
str = &OBJ_GET(Str, _ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar next() {
|
PyObject* next() {
|
||||||
if(index == str->u8_length()) return nullptr;
|
if(index == str->u8_length()) return nullptr;
|
||||||
return VAR(str->u8_getitem(index++));
|
return VAR(str->u8_getitem(index++));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PyVar Generator::next(){
|
PyObject* Generator::next(){
|
||||||
if(state == 2) return nullptr;
|
if(state == 2) return nullptr;
|
||||||
vm->callstack.push(std::move(frame));
|
vm->callstack.push(std::move(frame));
|
||||||
PyVar ret = vm->_exec();
|
PyObject* ret = vm->_exec();
|
||||||
if(ret == vm->_py_op_yield){
|
if(ret == vm->_py_op_yield){
|
||||||
frame = std::move(vm->callstack.top());
|
frame = std::move(vm->callstack.top());
|
||||||
vm->callstack.pop();
|
vm->callstack.pop();
|
||||||
|
@ -75,7 +75,7 @@ int main(int argc, char** argv){
|
|||||||
// set parent path as cwd
|
// set parent path as cwd
|
||||||
std::filesystem::current_path(filepath.parent_path());
|
std::filesystem::current_path(filepath.parent_path());
|
||||||
|
|
||||||
pkpy::PyVarOrNull ret = nullptr;
|
pkpy::PyObject* ret = nullptr;
|
||||||
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
|
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
|
||||||
pkpy_delete(vm);
|
pkpy_delete(vm);
|
||||||
return ret != nullptr ? 0 : 1;
|
return ret != nullptr ? 0 : 1;
|
||||||
|
60
src/memory.h
60
src/memory.h
@ -4,31 +4,12 @@
|
|||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
struct PyObject;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct SpAllocator {
|
|
||||||
template<typename U>
|
|
||||||
inline static int* alloc(){
|
|
||||||
return (int*)malloc(sizeof(int) + sizeof(U));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void dealloc(int* counter){
|
|
||||||
((T*)(counter + 1))->~T();
|
|
||||||
free(counter);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct shared_ptr {
|
struct shared_ptr {
|
||||||
union {
|
int* counter;
|
||||||
int* counter;
|
|
||||||
i64 bits;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define _t() (T*)(counter + 1)
|
#define _t() (T*)(counter + 1)
|
||||||
#define _inc_counter() if(!is_tagged() && counter) ++(*counter)
|
#define _inc_counter() if(counter) ++(*counter)
|
||||||
#define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter)
|
#define _dec_counter() if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); free(counter);}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_ptr() : counter(nullptr) {}
|
shared_ptr() : counter(nullptr) {}
|
||||||
@ -69,7 +50,6 @@ public:
|
|||||||
T* get() const { return _t(); }
|
T* get() const { return _t(); }
|
||||||
|
|
||||||
int use_count() const {
|
int use_count() const {
|
||||||
if(is_tagged()) return 0;
|
|
||||||
return counter ? *counter : 0;
|
return counter ? *counter : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,44 +57,20 @@ public:
|
|||||||
_dec_counter();
|
_dec_counter();
|
||||||
counter = nullptr;
|
counter = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is_tagged() const {
|
|
||||||
if constexpr(!std::is_same_v<T, PyObject>) return false;
|
|
||||||
return (bits & 0b11) != 0b00;
|
|
||||||
}
|
|
||||||
inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
|
|
||||||
inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
|
|
||||||
inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
|
|
||||||
inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef _t
|
#undef _t
|
||||||
#undef _inc_counter
|
#undef _inc_counter
|
||||||
#undef _dec_counter
|
#undef _dec_counter
|
||||||
|
|
||||||
template <typename T, typename U, typename... Args>
|
|
||||||
shared_ptr<T> make_sp(Args&&... args) {
|
|
||||||
static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
|
|
||||||
static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
|
|
||||||
static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
|
|
||||||
int* p = SpAllocator<T>::template alloc<U>(); *p = 1;
|
|
||||||
new(p+1) U(std::forward<Args>(args)...);
|
|
||||||
return shared_ptr<T>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
shared_ptr<T> make_sp(Args&&... args) {
|
shared_ptr<T> make_sp(Args&&... args) {
|
||||||
int* p = SpAllocator<T>::template alloc<T>(); *p = 1;
|
int* p = (int*)malloc(sizeof(int) + sizeof(T));
|
||||||
|
*p = 1;
|
||||||
new(p+1) T(std::forward<Args>(args)...);
|
new(p+1) T(std::forward<Args>(args)...);
|
||||||
return shared_ptr<T>(p);
|
return shared_ptr<T>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(sizeof(i64) == sizeof(int*));
|
|
||||||
static_assert(sizeof(f64) == sizeof(int*));
|
|
||||||
static_assert(sizeof(shared_ptr<PyObject>) == sizeof(int*));
|
|
||||||
static_assert(std::numeric_limits<float>::is_iec559);
|
|
||||||
static_assert(std::numeric_limits<double>::is_iec559);
|
|
||||||
|
|
||||||
template<typename T, int __Bucket, int __BucketSize=32>
|
template<typename T, int __Bucket, int __BucketSize=32>
|
||||||
struct SmallArrayPool {
|
struct SmallArrayPool {
|
||||||
std::vector<T*> buckets[__Bucket+1];
|
std::vector<T*> buckets[__Bucket+1];
|
||||||
@ -145,10 +101,4 @@ struct SmallArrayPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef shared_ptr<PyObject> PyVar;
|
|
||||||
typedef PyVar PyVarOrNull;
|
|
||||||
typedef PyVar PyVarRef;
|
|
||||||
|
|
||||||
}; // namespace pkpy
|
}; // namespace pkpy
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar);
|
const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyObject*);
|
||||||
|
|
||||||
template<int __Bucket, int __BucketSize=32>
|
template<int __Bucket, int __BucketSize=32>
|
||||||
struct DictArrayPool {
|
struct DictArrayPool {
|
||||||
@ -26,9 +26,7 @@ struct DictArrayPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dealloc(StrName* head, uint16_t n){
|
void dealloc(StrName* head, uint16_t n){
|
||||||
PyVar* _values = (PyVar*)(head + n);
|
|
||||||
if(n > __Bucket || buckets[n].size() >= __BucketSize){
|
if(n > __Bucket || buckets[n].size() >= __BucketSize){
|
||||||
for(int i=0; i<n; i++) _values[i].~PyVar();
|
|
||||||
free(head);
|
free(head);
|
||||||
}else{
|
}else{
|
||||||
buckets[n].push_back(head);
|
buckets[n].push_back(head);
|
||||||
@ -75,12 +73,12 @@ struct NameDict {
|
|||||||
uint16_t _mask;
|
uint16_t _mask;
|
||||||
StrName* _keys;
|
StrName* _keys;
|
||||||
|
|
||||||
inline PyVar& value(uint16_t i){
|
inline PyObject*& value(uint16_t i){
|
||||||
return reinterpret_cast<PyVar*>(_keys + _capacity)[i];
|
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const PyVar& value(uint16_t i) const {
|
inline PyObject* value(uint16_t i) const {
|
||||||
return reinterpret_cast<const PyVar*>(_keys + _capacity)[i];
|
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
|
NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
|
||||||
@ -123,19 +121,19 @@ while(!_keys[i].empty()) { \
|
|||||||
i = (i + 1) & _mask; \
|
i = (i + 1) & _mask; \
|
||||||
}
|
}
|
||||||
|
|
||||||
const PyVar& operator[](StrName key) const {
|
PyObject* operator[](StrName key) const {
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
||||||
return value(i);
|
return value(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar& get(StrName key){
|
// PyObject*& get(StrName key){
|
||||||
bool ok; uint16_t i;
|
// bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
// HASH_PROBE(key, ok, i);
|
||||||
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
// if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
|
||||||
return value(i);
|
// return value(i);
|
||||||
}
|
// }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set(StrName key, T&& val){
|
void set(StrName key, T&& val){
|
||||||
@ -154,7 +152,7 @@ while(!_keys[i].empty()) { \
|
|||||||
|
|
||||||
void _rehash(bool resize){
|
void _rehash(bool resize){
|
||||||
StrName* old_keys = _keys;
|
StrName* old_keys = _keys;
|
||||||
PyVar* old_values = &value(0);
|
PyObject** old_values = &value(0);
|
||||||
uint16_t old_capacity = _capacity;
|
uint16_t old_capacity = _capacity;
|
||||||
if(resize){
|
if(resize){
|
||||||
_capacity = find_next_capacity(_capacity * 2);
|
_capacity = find_next_capacity(_capacity * 2);
|
||||||
@ -177,18 +175,18 @@ while(!_keys[i].empty()) { \
|
|||||||
_rehash(false); // do not resize
|
_rehash(false); // do not resize
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar* try_get(StrName key){
|
inline PyObject** try_get(StrName key){
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
if(!ok) return nullptr;
|
if(!ok) return nullptr;
|
||||||
return &value(i);
|
return &value(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool try_set(StrName key, PyVar&& val){
|
inline bool try_set(StrName key, PyObject* val){
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
if(!ok) return false;
|
if(!ok) return false;
|
||||||
value(i) = std::move(val);
|
value(i) = val;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,8 +211,8 @@ while(!_keys[i].empty()) { \
|
|||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<StrName, PyVar>> items() const {
|
std::vector<std::pair<StrName, PyObject*>> items() const {
|
||||||
std::vector<std::pair<StrName, PyVar>> v;
|
std::vector<std::pair<StrName, PyObject*>> v;
|
||||||
for(uint16_t i=0; i<_capacity; i++){
|
for(uint16_t i=0; i<_capacity; i++){
|
||||||
if(_keys[i].empty()) continue;
|
if(_keys[i].empty()) continue;
|
||||||
v.push_back(std::make_pair(_keys[i], value(i)));
|
v.push_back(std::make_pair(_keys[i], value(i)));
|
||||||
@ -231,7 +229,7 @@ while(!_keys[i].empty()) { \
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_v(void(*f)(PyVar)) {
|
void apply_v(void(*f)(PyObject*)) {
|
||||||
for(uint16_t i=0; i<_capacity; i++){
|
for(uint16_t i=0; i<_capacity; i++){
|
||||||
if(_keys[i].empty()) continue;
|
if(_keys[i].empty()) continue;
|
||||||
f(value(i));
|
f(value(i));
|
||||||
|
88
src/obj.h
88
src/obj.h
@ -12,7 +12,7 @@ struct Frame;
|
|||||||
struct BaseRef;
|
struct BaseRef;
|
||||||
class VM;
|
class VM;
|
||||||
|
|
||||||
typedef std::function<PyVar(VM*, Args&)> NativeFuncRaw;
|
typedef std::function<PyObject*(VM*, Args&)> NativeFuncRaw;
|
||||||
typedef shared_ptr<CodeObject> CodeObject_;
|
typedef shared_ptr<CodeObject> CodeObject_;
|
||||||
typedef shared_ptr<NameDict> NameDict_;
|
typedef shared_ptr<NameDict> NameDict_;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ struct NativeFunc {
|
|||||||
bool method;
|
bool method;
|
||||||
|
|
||||||
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
|
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
|
||||||
inline PyVar operator()(VM* vm, Args& args) const;
|
inline PyObject* operator()(VM* vm, Args& args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
@ -34,7 +34,7 @@ struct Function {
|
|||||||
std::vector<StrName> kwargs_order;
|
std::vector<StrName> kwargs_order;
|
||||||
|
|
||||||
// runtime settings
|
// runtime settings
|
||||||
PyVar _module = nullptr;
|
PyObject* _module = nullptr;
|
||||||
NameDict_ _closure = nullptr;
|
NameDict_ _closure = nullptr;
|
||||||
|
|
||||||
bool has_name(StrName val) const {
|
bool has_name(StrName val) const {
|
||||||
@ -46,9 +46,9 @@ struct Function {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BoundMethod {
|
struct BoundMethod {
|
||||||
PyVar obj;
|
PyObject* obj;
|
||||||
PyVar method;
|
PyObject* method;
|
||||||
BoundMethod(const PyVar& obj, const PyVar& method) : obj(obj), method(method) {}
|
BoundMethod(PyObject* obj, PyObject* method) : obj(obj), method(method) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Range {
|
struct Range {
|
||||||
@ -58,9 +58,9 @@ struct Range {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct StarWrapper {
|
struct StarWrapper {
|
||||||
PyVar obj;
|
PyObject* obj;
|
||||||
bool rvalue;
|
bool rvalue;
|
||||||
StarWrapper(const PyVar& obj, bool rvalue): obj(obj), rvalue(rvalue) {}
|
StarWrapper(PyObject* obj, bool rvalue): obj(obj), rvalue(rvalue) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Slice {
|
struct Slice {
|
||||||
@ -79,30 +79,34 @@ struct Slice {
|
|||||||
class BaseIter {
|
class BaseIter {
|
||||||
protected:
|
protected:
|
||||||
VM* vm;
|
VM* vm;
|
||||||
PyVar _ref; // keep a reference to the object so it will not be deleted while iterating
|
PyObject* _ref; // keep a reference to the object so it will not be deleted while iterating
|
||||||
public:
|
public:
|
||||||
virtual PyVar next() = 0;
|
virtual PyObject* next() = 0;
|
||||||
PyVarRef loop_var;
|
PyObject* loop_var;
|
||||||
BaseIter(VM* vm, PyVar _ref) : vm(vm), _ref(_ref) {}
|
BaseIter(VM* vm, PyObject* _ref) : vm(vm), _ref(_ref) {}
|
||||||
virtual ~BaseIter() = default;
|
virtual ~BaseIter() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GCHeader {
|
||||||
|
bool enabled; // whether this object is managed by GC
|
||||||
|
bool marked; // whether this object is marked
|
||||||
|
GCHeader() : enabled(false), marked(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct PyObject {
|
struct PyObject {
|
||||||
bool need_gc;
|
GCHeader gc;
|
||||||
bool marked;
|
|
||||||
/**********/
|
|
||||||
Type type;
|
Type type;
|
||||||
NameDict* _attr;
|
NameDict* _attr;
|
||||||
|
|
||||||
inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||||
inline NameDict& attr() noexcept { return *_attr; }
|
inline NameDict& attr() noexcept { return *_attr; }
|
||||||
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
|
inline PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; }
|
||||||
virtual void* value() = 0;
|
virtual void* value() = 0;
|
||||||
|
|
||||||
virtual void mark() {
|
virtual void mark() {
|
||||||
if(!need_gc || marked) return;
|
if(!gc.enabled || gc.marked) return;
|
||||||
marked = true;
|
gc.marked = true;
|
||||||
if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); });
|
if(is_attr_valid()) attr().apply_v([](PyObject* v){ v->mark(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject(Type type) : type(type) {}
|
PyObject(Type type) : type(type) {}
|
||||||
@ -141,67 +145,51 @@ struct Py_ : PyObject {
|
|||||||
const int kTpIntIndex = 2;
|
const int kTpIntIndex = 2;
|
||||||
const int kTpFloatIndex = 3;
|
const int kTpFloatIndex = 3;
|
||||||
|
|
||||||
inline bool is_type(const PyVar& obj, Type type) noexcept {
|
inline bool is_type(PyObject* obj, Type type) noexcept {
|
||||||
switch(type.index){
|
switch(type.index){
|
||||||
case kTpIntIndex: return obj.is_tag_01();
|
case kTpIntIndex: return is_tag_01(obj);
|
||||||
case kTpFloatIndex: return obj.is_tag_10();
|
case kTpFloatIndex: return is_tag_10(obj);
|
||||||
default: return !obj.is_tagged() && obj->type == type;
|
default: return !is_tagged(obj) && obj->type == type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_both_int_or_float(const PyVar& a, const PyVar& b) noexcept {
|
|
||||||
return a.is_tagged() && b.is_tagged();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_both_int(const PyVar& a, const PyVar& b) noexcept {
|
|
||||||
return (a.bits & b.bits & 0b11) == 0b01;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(T, mod, name) \
|
#define PY_CLASS(T, mod, name) \
|
||||||
static Type _type(VM* vm) { \
|
static Type _type(VM* vm) { \
|
||||||
static const StrName __x0(#mod); \
|
static const StrName __x0(#mod); \
|
||||||
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 PyVar register_class(VM* vm, PyVar mod) { \
|
static PyObject* register_class(VM* vm, PyObject* mod) { \
|
||||||
PyVar type = vm->new_type_object(mod, #name, vm->tp_object); \
|
PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \
|
||||||
if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \
|
if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \
|
||||||
T::_register(vm, mod, type); \
|
T::_register(vm, mod, type); \
|
||||||
type->attr()._try_perfect_rehash(); \
|
type->attr()._try_perfect_rehash(); \
|
||||||
return type; \
|
return type; \
|
||||||
}
|
}
|
||||||
|
|
||||||
union __8B {
|
union BitsCvt {
|
||||||
i64 _int;
|
i64 _int;
|
||||||
f64 _float;
|
f64 _float;
|
||||||
__8B(i64 val) : _int(val) {}
|
BitsCvt(i64 val) : _int(val) {}
|
||||||
__8B(f64 val) : _float(val) {}
|
BitsCvt(f64 val) : _float(val) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename, typename = void> struct is_py_class : std::false_type {};
|
template <typename, typename = void> struct is_py_class : std::false_type {};
|
||||||
template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
|
template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void _check_py_class(VM* vm, const PyVar& var);
|
void _check_py_class(VM* vm, PyObject* var);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T py_pointer_cast(VM* vm, const PyVar& var);
|
T py_pointer_cast(VM* vm, PyObject* var);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T py_value_cast(VM* vm, const PyVar& var);
|
T py_value_cast(VM* vm, PyObject* var);
|
||||||
|
|
||||||
struct Discarded {};
|
struct Discarded {};
|
||||||
|
|
||||||
template<typename __T>
|
template<typename __T>
|
||||||
__T py_cast(VM* vm, const PyVar& obj) {
|
__T py_cast(VM* vm, PyObject* obj) {
|
||||||
using T = std::decay_t<__T>;
|
using T = std::decay_t<__T>;
|
||||||
if constexpr(std::is_pointer_v<T>){
|
if constexpr(std::is_pointer_v<T>){
|
||||||
return py_pointer_cast<T>(vm, obj);
|
return py_pointer_cast<T>(vm, obj);
|
||||||
@ -216,7 +204,7 @@ __T py_cast(VM* vm, const PyVar& obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename __T>
|
template<typename __T>
|
||||||
__T _py_cast(VM* vm, const PyVar& obj) {
|
__T _py_cast(VM* vm, PyObject* obj) {
|
||||||
using T = std::decay_t<__T>;
|
using T = std::decay_t<__T>;
|
||||||
if constexpr(std::is_pointer_v<__T>){
|
if constexpr(std::is_pointer_v<__T>){
|
||||||
return py_pointer_cast<__T>(vm, obj);
|
return py_pointer_cast<__T>(vm, obj);
|
||||||
@ -228,7 +216,7 @@ __T _py_cast(VM* vm, const PyVar& obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define VAR(x) py_var(vm, x)
|
#define VAR(x) py_var(vm, x)
|
||||||
#define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__))
|
#define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
|
||||||
#define CAST(T, x) py_cast<T>(vm, x)
|
#define CAST(T, x) py_cast<T>(vm, x)
|
||||||
#define _CAST(T, x) _py_cast<T>(vm, x)
|
#define _CAST(T, x) _py_cast<T>(vm, x)
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ struct Token{
|
|||||||
const char* start;
|
const char* start;
|
||||||
int length;
|
int length;
|
||||||
int line;
|
int line;
|
||||||
PyVar value;
|
PyObject* value;
|
||||||
|
|
||||||
Str str() const { return Str(start, length);}
|
Str str() const { return Str(start, length);}
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ struct Parser {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_next_token(TokenIndex type, PyVar value=nullptr) {
|
void set_next_token(TokenIndex type, PyObject* value=nullptr) {
|
||||||
switch(type){
|
switch(type){
|
||||||
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
|
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
|
||||||
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;
|
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;
|
||||||
|
@ -69,7 +69,7 @@ void init_builtins(VM* _vm) {
|
|||||||
vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
|
vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
|
||||||
}
|
}
|
||||||
Type base = vm->_all_types[type.index].base;
|
Type base = vm->_all_types[type.index].base;
|
||||||
return vm->new_object(vm->tp_super, Super(args[1], base));
|
return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) {
|
_vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) {
|
||||||
@ -79,16 +79,16 @@ void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
|
_vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
|
||||||
const PyVar& obj = args[0];
|
PyObject* obj = args[0];
|
||||||
if(obj.is_tagged()) return VAR((i64)0);
|
if(is_tagged(obj)) return VAR((i64)0);
|
||||||
return VAR(obj.bits);
|
return VAR(BITS(obj));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) {
|
_vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) {
|
||||||
i64 lhs = CAST(i64, args[0]);
|
i64 lhs = CAST(i64, args[0]);
|
||||||
i64 rhs = CAST(i64, args[1]);
|
i64 rhs = CAST(i64, args[1]);
|
||||||
if(rhs == 0) vm->ZeroDivisionError();
|
if(rhs == 0) vm->ZeroDivisionError();
|
||||||
return VAR(two_args(VAR(lhs/rhs), VAR(lhs%rhs)));
|
return VAR(Tuple{VAR(lhs/rhs), VAR(lhs%rhs)});
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
|
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
|
||||||
@ -169,8 +169,8 @@ void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
|
_vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
|
||||||
PyVar self = args[0];
|
PyObject* self = args[0];
|
||||||
std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get();
|
std::uintptr_t addr = is_tagged(self) ? 0 : (uintptr_t)self;
|
||||||
StrStream ss;
|
StrStream ss;
|
||||||
ss << std::hex << addr;
|
ss << std::hex << addr;
|
||||||
Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">";
|
Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">";
|
||||||
@ -405,7 +405,7 @@ void init_builtins(VM* _vm) {
|
|||||||
_vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
|
_vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
|
||||||
const Str& self = CAST(Str&, args[0]);
|
const Str& self = CAST(Str&, args[0]);
|
||||||
StrStream ss;
|
StrStream ss;
|
||||||
PyVar obj = vm->asList(args[1]);
|
PyObject* obj = vm->asList(args[1]);
|
||||||
const List& list = CAST(List&, obj);
|
const List& list = CAST(List&, obj);
|
||||||
for (int i = 0; i < list.size(); ++i) {
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
if (i > 0) ss << self;
|
if (i > 0) ss << self;
|
||||||
@ -423,7 +423,7 @@ void init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) {
|
_vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) {
|
||||||
List& self = CAST(List&, args[0]);
|
List& self = CAST(List&, args[0]);
|
||||||
PyVar obj = vm->asList(args[1]);
|
PyObject* obj = vm->asList(args[1]);
|
||||||
const List& list = CAST(List&, obj);
|
const List& list = CAST(List&, obj);
|
||||||
self.insert(self.end(), list.begin(), list.end());
|
self.insert(self.end(), list.begin(), list.end());
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -575,7 +575,7 @@ void init_builtins(VM* _vm) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void add_module_time(VM* vm){
|
void add_module_time(VM* vm){
|
||||||
PyVar mod = vm->new_module("time");
|
PyObject* mod = vm->new_module("time");
|
||||||
vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
|
vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
|
return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
|
||||||
@ -583,7 +583,7 @@ void add_module_time(VM* vm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add_module_sys(VM* vm){
|
void add_module_sys(VM* vm){
|
||||||
PyVar mod = vm->new_module("sys");
|
PyObject* mod = vm->new_module("sys");
|
||||||
vm->setattr(mod, "version", VAR(PK_VERSION));
|
vm->setattr(mod, "version", VAR(PK_VERSION));
|
||||||
|
|
||||||
vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count())));
|
vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count())));
|
||||||
@ -596,7 +596,7 @@ void add_module_sys(VM* vm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add_module_json(VM* vm){
|
void add_module_json(VM* vm){
|
||||||
PyVar mod = vm->new_module("json");
|
PyObject* mod = vm->new_module("json");
|
||||||
vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
|
vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
|
||||||
const Str& expr = CAST(Str&, args[0]);
|
const Str& expr = CAST(Str&, args[0]);
|
||||||
CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
|
CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
|
||||||
@ -607,7 +607,7 @@ void add_module_json(VM* vm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add_module_math(VM* vm){
|
void add_module_math(VM* vm){
|
||||||
PyVar mod = vm->new_module("math");
|
PyObject* mod = vm->new_module("math");
|
||||||
vm->setattr(mod, "pi", VAR(3.1415926535897932384));
|
vm->setattr(mod, "pi", VAR(3.1415926535897932384));
|
||||||
vm->setattr(mod, "e" , VAR(2.7182818284590452354));
|
vm->setattr(mod, "e" , VAR(2.7182818284590452354));
|
||||||
|
|
||||||
@ -626,9 +626,9 @@ void add_module_math(VM* vm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add_module_dis(VM* vm){
|
void add_module_dis(VM* vm){
|
||||||
PyVar mod = vm->new_module("dis");
|
PyObject* mod = vm->new_module("dis");
|
||||||
vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
|
vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
|
||||||
PyVar f = args[0];
|
PyObject* f = args[0];
|
||||||
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method;
|
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method;
|
||||||
CodeObject_ code = CAST(Function, f).code;
|
CodeObject_ code = CAST(Function, f).code;
|
||||||
(*vm->_stdout) << vm->disassemble(code);
|
(*vm->_stdout) << vm->disassemble(code);
|
||||||
@ -644,14 +644,14 @@ struct ReMatch {
|
|||||||
std::smatch m;
|
std::smatch m;
|
||||||
ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {}
|
ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {}
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED());
|
vm->bind_method<-1>(type, "__init__", 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)));
|
||||||
|
|
||||||
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
|
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
|
||||||
auto& self = CAST(ReMatch&, args[0]);
|
auto& self = CAST(ReMatch&, args[0]);
|
||||||
return VAR(two_args(VAR(self.start), VAR(self.end)));
|
return VAR(Tuple{VAR(self.start), VAR(self.end)});
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
|
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
|
||||||
@ -663,7 +663,7 @@ struct ReMatch {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){
|
PyObject* _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){
|
||||||
std::regex re(pattern);
|
std::regex re(pattern);
|
||||||
std::smatch m;
|
std::smatch m;
|
||||||
if(std::regex_search(string, m, re)){
|
if(std::regex_search(string, m, re)){
|
||||||
@ -676,7 +676,7 @@ PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* v
|
|||||||
};
|
};
|
||||||
|
|
||||||
void add_module_re(VM* vm){
|
void add_module_re(VM* vm){
|
||||||
PyVar mod = vm->new_module("re");
|
PyObject* mod = vm->new_module("re");
|
||||||
ReMatch::register_class(vm, mod);
|
ReMatch::register_class(vm, mod);
|
||||||
|
|
||||||
vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
|
vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
|
||||||
@ -740,7 +740,7 @@ struct Random{
|
|||||||
gen.seed(seed);
|
gen.seed(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
|
vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
|
||||||
vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed));
|
vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed));
|
||||||
vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint));
|
vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint));
|
||||||
@ -750,7 +750,7 @@ struct Random{
|
|||||||
};
|
};
|
||||||
|
|
||||||
void add_module_random(VM* vm){
|
void add_module_random(VM* vm){
|
||||||
PyVar mod = vm->new_module("random");
|
PyObject* mod = vm->new_module("random");
|
||||||
Random::register_class(vm, mod);
|
Random::register_class(vm, mod);
|
||||||
CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
|
CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
|
||||||
vm->_exec(code, mod);
|
vm->_exec(code, mod);
|
||||||
@ -851,7 +851,7 @@ extern "C" {
|
|||||||
/// Return `__repr__` of the result.
|
/// Return `__repr__` of the result.
|
||||||
/// If the variable is not found, return `nullptr`.
|
/// If the variable is not found, return `nullptr`.
|
||||||
char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){
|
char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){
|
||||||
pkpy::PyVar* val = vm->_main->attr().try_get(name);
|
pkpy::PyObject** val = vm->_main->attr().try_get(name);
|
||||||
if(val == nullptr) return nullptr;
|
if(val == nullptr) return nullptr;
|
||||||
try{
|
try{
|
||||||
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val));
|
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val));
|
||||||
@ -867,7 +867,7 @@ extern "C" {
|
|||||||
/// Return `__repr__` of the result.
|
/// Return `__repr__` of the result.
|
||||||
/// If there is any error, return `nullptr`.
|
/// If there is any error, return `nullptr`.
|
||||||
char* pkpy_vm_eval(pkpy::VM* vm, const char* source){
|
char* pkpy_vm_eval(pkpy::VM* vm, const char* source){
|
||||||
pkpy::PyVarOrNull ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
|
pkpy::PyObject* ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
|
||||||
if(ret == nullptr) return nullptr;
|
if(ret == nullptr) return nullptr;
|
||||||
try{
|
try{
|
||||||
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret));
|
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret));
|
||||||
@ -950,13 +950,13 @@ extern "C" {
|
|||||||
for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr;
|
for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr;
|
||||||
for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
|
for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
|
||||||
std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
|
std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
|
||||||
pkpy::PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
|
pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
|
||||||
vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){
|
vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){
|
||||||
pkpy::StrStream ss;
|
pkpy::StrStream ss;
|
||||||
ss << f_header;
|
ss << f_header;
|
||||||
for(int i=0; i<args.size(); i++){
|
for(int i=0; i<args.size(); i++){
|
||||||
ss << ' ';
|
ss << ' ';
|
||||||
pkpy::PyVar x = vm->call(args[i], pkpy::__json__);
|
pkpy::PyObject* x = vm->call(args[i], pkpy::__json__);
|
||||||
ss << pkpy::CAST(pkpy::Str&, x);
|
ss << pkpy::CAST(pkpy::Str&, x);
|
||||||
}
|
}
|
||||||
char* packet = strdup(ss.str().c_str());
|
char* packet = strdup(ss.str().c_str());
|
||||||
|
54
src/ref.h
54
src/ref.h
@ -6,8 +6,8 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
struct BaseRef {
|
struct BaseRef {
|
||||||
virtual PyVar get(VM*, Frame*) const = 0;
|
virtual PyObject* get(VM*, Frame*) const = 0;
|
||||||
virtual void set(VM*, Frame*, PyVar) const = 0;
|
virtual void set(VM*, Frame*, PyObject*) const = 0;
|
||||||
virtual void del(VM*, Frame*) const = 0;
|
virtual void del(VM*, Frame*) const = 0;
|
||||||
virtual ~BaseRef() = default;
|
virtual ~BaseRef() = default;
|
||||||
};
|
};
|
||||||
@ -18,8 +18,8 @@ struct NameRef : BaseRef {
|
|||||||
inline NameScope scope() const { return pair.second; }
|
inline NameScope scope() const { return pair.second; }
|
||||||
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
|
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
|
||||||
|
|
||||||
PyVar get(VM* vm, Frame* frame) const{
|
PyObject* get(VM* vm, Frame* frame) const{
|
||||||
PyVar* val;
|
PyObject** val;
|
||||||
val = frame->f_locals().try_get(name());
|
val = frame->f_locals().try_get(name());
|
||||||
if(val != nullptr) return *val;
|
if(val != nullptr) return *val;
|
||||||
val = frame->f_closure_try_get(name());
|
val = frame->f_closure_try_get(name());
|
||||||
@ -32,12 +32,12 @@ struct NameRef : BaseRef {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyVar val) const{
|
void set(VM* vm, Frame* frame, PyObject* val) const{
|
||||||
switch(scope()) {
|
switch(scope()) {
|
||||||
case NAME_LOCAL: frame->f_locals().set(name(), std::move(val)); break;
|
case NAME_LOCAL: frame->f_locals().set(name(), val); break;
|
||||||
case NAME_GLOBAL:
|
case NAME_GLOBAL:
|
||||||
if(frame->f_locals().try_set(name(), std::move(val))) return;
|
if(frame->f_locals().try_set(name(), val)) return;
|
||||||
frame->f_globals().set(name(), std::move(val));
|
frame->f_globals().set(name(), val);
|
||||||
break;
|
break;
|
||||||
default: UNREACHABLE();
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -70,15 +70,15 @@ struct NameRef : BaseRef {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AttrRef : BaseRef {
|
struct AttrRef : BaseRef {
|
||||||
mutable PyVar obj;
|
mutable PyObject* obj;
|
||||||
NameRef attr;
|
NameRef attr;
|
||||||
AttrRef(PyVar obj, NameRef attr) : obj(obj), attr(attr) {}
|
AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {}
|
||||||
|
|
||||||
PyVar get(VM* vm, Frame* frame) const{
|
PyObject* get(VM* vm, Frame* frame) const{
|
||||||
return vm->getattr(obj, attr.name());
|
return vm->getattr(obj, attr.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyVar val) const{
|
void set(VM* vm, Frame* frame, PyObject* val) const{
|
||||||
vm->setattr(obj, attr.name(), std::move(val));
|
vm->setattr(obj, attr.name(), std::move(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,22 +90,22 @@ struct AttrRef : BaseRef {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct IndexRef : BaseRef {
|
struct IndexRef : BaseRef {
|
||||||
mutable PyVar obj;
|
mutable PyObject* obj;
|
||||||
PyVar index;
|
PyObject* index;
|
||||||
IndexRef(PyVar obj, PyVar index) : obj(obj), index(index) {}
|
IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {}
|
||||||
|
|
||||||
PyVar get(VM* vm, Frame* frame) const{
|
PyObject* get(VM* vm, Frame* frame) const{
|
||||||
return vm->fast_call(__getitem__, two_args(obj, index));
|
return vm->fast_call(__getitem__, Args{obj, index});
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyVar val) const{
|
void set(VM* vm, Frame* frame, PyObject* val) const{
|
||||||
Args args(3);
|
Args args(3);
|
||||||
args[0] = obj; args[1] = index; args[2] = std::move(val);
|
args[0] = obj; args[1] = index; args[2] = std::move(val);
|
||||||
vm->fast_call(__setitem__, std::move(args));
|
vm->fast_call(__setitem__, std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
void del(VM* vm, Frame* frame) const{
|
void del(VM* vm, Frame* frame) const{
|
||||||
vm->fast_call(__delitem__, two_args(obj, index));
|
vm->fast_call(__delitem__, Args{obj, index});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ struct TupleRef : BaseRef {
|
|||||||
Tuple objs;
|
Tuple objs;
|
||||||
TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
|
TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
|
||||||
|
|
||||||
PyVar get(VM* vm, Frame* frame) const{
|
PyObject* get(VM* vm, Frame* frame) const{
|
||||||
Tuple args(objs.size());
|
Tuple args(objs.size());
|
||||||
for (int i = 0; i < objs.size(); i++) {
|
for (int i = 0; i < objs.size(); i++) {
|
||||||
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
|
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
|
||||||
@ -121,11 +121,11 @@ struct TupleRef : BaseRef {
|
|||||||
return VAR(std::move(args));
|
return VAR(std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(VM* vm, Frame* frame, PyVar val) const{
|
void set(VM* vm, Frame* frame, PyObject* val) const{
|
||||||
val = vm->asIter(val);
|
val = vm->asIter(val);
|
||||||
BaseIter* iter = vm->PyIter_AS_C(val);
|
BaseIter* iter = vm->PyIter_AS_C(val);
|
||||||
for(int i=0; i<objs.size(); i++){
|
for(int i=0; i<objs.size(); i++){
|
||||||
PyVarOrNull x;
|
PyObject* x;
|
||||||
if(is_type(objs[i], vm->tp_star_wrapper)){
|
if(is_type(objs[i], vm->tp_star_wrapper)){
|
||||||
auto& star = _CAST(StarWrapper&, objs[i]);
|
auto& star = _CAST(StarWrapper&, objs[i]);
|
||||||
if(star.rvalue) vm->ValueError("can't use starred expression here");
|
if(star.rvalue) vm->ValueError("can't use starred expression here");
|
||||||
@ -141,7 +141,7 @@ struct TupleRef : BaseRef {
|
|||||||
vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
|
vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyVarOrNull x = iter->next();
|
PyObject* x = iter->next();
|
||||||
if(x != nullptr) vm->ValueError("too many values to unpack");
|
if(x != nullptr) vm->ValueError("too many values to unpack");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,19 +152,19 @@ struct TupleRef : BaseRef {
|
|||||||
|
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
PyVarRef VM::PyRef(P&& value) {
|
PyObject* VM::PyRef(P&& value) {
|
||||||
static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
|
static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
|
||||||
return new_object(tp_ref, std::forward<P>(value));
|
return heap.gcnew<P>(tp_ref, std::forward<P>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseRef* VM::PyRef_AS_C(const PyVar& obj)
|
const BaseRef* VM::PyRef_AS_C(PyObject* obj)
|
||||||
{
|
{
|
||||||
if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
|
if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
|
||||||
return static_cast<const BaseRef*>(obj->value());
|
return static_cast<const BaseRef*>(obj->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Frame's Impl *****/
|
/***** Frame's Impl *****/
|
||||||
inline void Frame::try_deref(VM* vm, PyVar& v){
|
inline void Frame::try_deref(VM* vm, PyObject*& v){
|
||||||
if(is_type(v, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
using List = std::vector<PyObject*>;
|
using List = std::vector<PyObject*>;
|
||||||
@ -33,6 +34,11 @@ namespace pkpy {
|
|||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Args(std::initializer_list<PyObject*> list) : Args(list.size()){
|
||||||
|
int i=0;
|
||||||
|
for(auto& p : list) _args[i++] = p;
|
||||||
|
}
|
||||||
|
|
||||||
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(PyObject*)*ret.size());
|
memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size());
|
||||||
@ -82,30 +88,6 @@ namespace pkpy {
|
|||||||
return _zero;
|
return _zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Args one_arg(T&& a) {
|
|
||||||
Args ret(1);
|
|
||||||
ret[0] = std::forward<T>(a);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
Args two_args(T1&& a, T2&& b) {
|
|
||||||
Args ret(2);
|
|
||||||
ret[0] = std::forward<T1>(a);
|
|
||||||
ret[1] = std::forward<T2>(b);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T1, typename T2, typename T3>
|
|
||||||
Args three_args(T1&& a, T2&& b, T3&& c) {
|
|
||||||
Args ret(3);
|
|
||||||
ret[0] = std::forward<T1>(a);
|
|
||||||
ret[1] = std::forward<T2>(b);
|
|
||||||
ret[2] = std::forward<T3>(c);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef Args Tuple;
|
typedef Args Tuple;
|
||||||
THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
|
THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
131
src/vm.h
131
src/vm.h
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -20,8 +22,8 @@ namespace pkpy{
|
|||||||
template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \
|
template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \
|
||||||
return OBJ_GET(ctype, obj); \
|
return OBJ_GET(ctype, obj); \
|
||||||
} \
|
} \
|
||||||
PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \
|
PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \
|
||||||
PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));}
|
PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));}
|
||||||
|
|
||||||
class Generator: public BaseIter {
|
class Generator: public BaseIter {
|
||||||
std::unique_ptr<Frame> frame;
|
std::unique_ptr<Frame> frame;
|
||||||
@ -41,6 +43,7 @@ struct PyTypeInfo{
|
|||||||
|
|
||||||
class VM {
|
class VM {
|
||||||
VM* vm; // self reference for simplify code
|
VM* vm; // self reference for simplify code
|
||||||
|
ManagedHeap heap;
|
||||||
public:
|
public:
|
||||||
std::stack< std::unique_ptr<Frame> > callstack;
|
std::stack< std::unique_ptr<Frame> > callstack;
|
||||||
std::vector<PyTypeInfo> _all_types;
|
std::vector<PyTypeInfo> _all_types;
|
||||||
@ -78,11 +81,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
init_builtin_types();
|
init_builtin_types();
|
||||||
// for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* asStr(PyObject* obj){
|
PyObject* asStr(PyObject* obj){
|
||||||
PyVarOrNull f = getattr(obj, __str__, false, true);
|
PyObject* f = getattr(obj, __str__, false, true);
|
||||||
if(f != nullptr) return call(f);
|
if(f != nullptr) return call(f);
|
||||||
return asRepr(obj);
|
return asRepr(obj);
|
||||||
}
|
}
|
||||||
@ -95,8 +97,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject* asIter(PyObject* obj){
|
PyObject* asIter(PyObject* obj){
|
||||||
if(is_type(obj, tp_native_iterator)) return obj;
|
if(is_type(obj, tp_iterator)) return obj;
|
||||||
PyVarOrNull iter_f = getattr(obj, __iter__, false, true);
|
PyObject* iter_f = getattr(obj, __iter__, false, true);
|
||||||
if(iter_f != nullptr) return call(iter_f);
|
if(iter_f != nullptr) return call(iter_f);
|
||||||
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
|
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -104,7 +106,7 @@ public:
|
|||||||
|
|
||||||
PyObject* asList(PyObject* 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), Args{iterable});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject** find_name_in_mro(PyObject* cls, StrName name){
|
PyObject** find_name_in_mro(PyObject* cls, StrName name){
|
||||||
@ -191,13 +193,13 @@ public:
|
|||||||
|
|
||||||
PyObject* property(NativeFuncRaw fget){
|
PyObject* property(NativeFuncRaw fget){
|
||||||
PyObject* p = builtins->attr("property");
|
PyObject* p = builtins->attr("property");
|
||||||
PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false));
|
PyObject* method = heap.gcnew(tp_native_function, NativeFunc(fget, 1, false));
|
||||||
return call(p, one_arg(method));
|
return call(p, Args{method});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* new_type_object(PyObject* mod, StrName name, Type base){
|
PyObject* new_type_object(PyObject* mod, StrName name, Type base){
|
||||||
// use gcnew
|
// use gcnew
|
||||||
PyObject* obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
|
PyObject* obj = new Py_<Type>(tp_type, _all_types.size());
|
||||||
PyTypeInfo info{
|
PyTypeInfo info{
|
||||||
.obj = obj,
|
.obj = obj,
|
||||||
.base = base,
|
.base = base,
|
||||||
@ -213,30 +215,6 @@ public:
|
|||||||
return OBJ_GET(Type, obj);
|
return OBJ_GET(Type, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline PyObject* new_object(PyObject* type, const T& _value) {
|
|
||||||
#if PK_EXTRA_CHECK
|
|
||||||
if(!is_type(type, tp_type)) UNREACHABLE();
|
|
||||||
#endif
|
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
inline PyObject* new_object(PyObject* type, T&& _value) {
|
|
||||||
#if PK_EXTRA_CHECK
|
|
||||||
if(!is_type(type, tp_type)) UNREACHABLE();
|
|
||||||
#endif
|
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), std::move(_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline PyObject* new_object(Type type, const T& _value) {
|
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
inline PyObject* new_object(Type type, T&& _value) {
|
|
||||||
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* _find_type(const Str& type){
|
PyObject* _find_type(const Str& type){
|
||||||
PyObject** obj = builtins->attr().try_get(type);
|
PyObject** obj = builtins->attr().try_get(type);
|
||||||
if(!obj){
|
if(!obj){
|
||||||
@ -282,19 +260,19 @@ public:
|
|||||||
// for quick access
|
// for quick access
|
||||||
Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
|
Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
|
||||||
Type tp_list, tp_tuple;
|
Type tp_list, tp_tuple;
|
||||||
Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method;
|
Type tp_function, tp_native_function, tp_iterator, tp_bound_method;
|
||||||
Type tp_slice, tp_range, tp_module, tp_ref;
|
Type tp_slice, tp_range, tp_module, tp_ref;
|
||||||
Type tp_super, tp_exception, tp_star_wrapper;
|
Type tp_super, tp_exception, tp_star_wrapper;
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
inline PyObject* 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 heap.gcnew<P>(tp_iterator, std::forward<P>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BaseIter* PyIter_AS_C(PyObject* obj)
|
inline BaseIter* PyIter_AS_C(PyObject* obj)
|
||||||
{
|
{
|
||||||
check_type(obj, tp_native_iterator);
|
check_type(obj, tp_iterator);
|
||||||
return static_cast<BaseIter*>(obj->value());
|
return static_cast<BaseIter*>(obj->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +347,7 @@ public:
|
|||||||
PyObject* _exec();
|
PyObject* _exec();
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
PyVarRef PyRef(P&& value);
|
PyObject* PyRef(P&& value);
|
||||||
const BaseRef* PyRef_AS_C(PyObject* obj);
|
const BaseRef* PyRef_AS_C(PyObject* obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -458,23 +436,23 @@ 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 BitsCvt(bits)._float;
|
||||||
}
|
}
|
||||||
template<> float _py_cast<float>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
|
||||||
}
|
}
|
||||||
template<> double py_cast<double>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
|
||||||
}
|
}
|
||||||
template<> double _py_cast<double>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -502,7 +480,7 @@ PY_VAR_INT(unsigned long long)
|
|||||||
#define PY_VAR_FLOAT(T) \
|
#define PY_VAR_FLOAT(T) \
|
||||||
PyObject* 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 = BitsCvt(val)._int; \
|
||||||
bits = (bits >> 2) << 2; \
|
bits = (bits >> 2) << 2; \
|
||||||
bits |= 0b10; \
|
bits |= 0b10; \
|
||||||
return reinterpret_cast<PyObject*>(bits); \
|
return reinterpret_cast<PyObject*>(bits); \
|
||||||
@ -561,7 +539,7 @@ PyObject* VM::asBool(PyObject* 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);
|
PyObject* len_fn = getattr(obj, __len__, false, true);
|
||||||
if(len_fn != nullptr){
|
if(len_fn != nullptr){
|
||||||
PyObject* ret = call(len_fn);
|
PyObject* ret = call(len_fn);
|
||||||
return VAR(CAST(i64, ret) > 0);
|
return VAR(CAST(i64, ret) > 0);
|
||||||
@ -596,8 +574,11 @@ PyObject* VM::asRepr(PyObject* obj){
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::new_module(StrName name) {
|
PyObject* VM::new_module(StrName name) {
|
||||||
PyObject* obj = new_object(tp_module, DummyModule());
|
PyObject* obj = new Py_<DummyModule>(tp_module, DummyModule());
|
||||||
obj->attr().set(__name__, VAR(name.str()));
|
obj->attr().set(__name__, VAR(name.str()));
|
||||||
|
// we do not allow override in order to avoid memory leak
|
||||||
|
// it is because Module objects are not garbage collected
|
||||||
|
if(_modules.contains(name)) UNREACHABLE();
|
||||||
_modules.set(name, obj);
|
_modules.set(name, obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -672,9 +653,11 @@ Str VM::disassemble(CodeObject_ co){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VM::init_builtin_types(){
|
void VM::init_builtin_types(){
|
||||||
// Py_(Type type, T&& val)
|
PyObject* _tp_object = new Py_<Type>(Type(1), Type(0));
|
||||||
PyVar _tp_object = make_sp<PyObject, Py_<Type>>(Type(1), Type(0));
|
PyObject* _tp_type = new Py_<Type>(Type(1), Type(1));
|
||||||
PyVar _tp_type = make_sp<PyObject, Py_<Type>>(Type(1), Type(1));
|
// PyTypeObject is managed by _all_types
|
||||||
|
// PyModuleObject is managed by _modules
|
||||||
|
// They are not managed by GC, so we use a simple "new"
|
||||||
_all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"});
|
_all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"});
|
||||||
_all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"});
|
_all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"});
|
||||||
tp_object = 0; tp_type = 1;
|
tp_object = 0; tp_type = 1;
|
||||||
@ -695,17 +678,17 @@ void VM::init_builtin_types(){
|
|||||||
|
|
||||||
tp_function = _new_type_object("function");
|
tp_function = _new_type_object("function");
|
||||||
tp_native_function = _new_type_object("native_function");
|
tp_native_function = _new_type_object("native_function");
|
||||||
tp_native_iterator = _new_type_object("native_iterator");
|
tp_iterator = _new_type_object("iterator");
|
||||||
tp_bound_method = _new_type_object("bound_method");
|
tp_bound_method = _new_type_object("bound_method");
|
||||||
tp_super = _new_type_object("super");
|
tp_super = _new_type_object("super");
|
||||||
tp_exception = _new_type_object("Exception");
|
tp_exception = _new_type_object("Exception");
|
||||||
|
|
||||||
this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL);
|
this->None = new Py_<Dummy>(_new_type_object("NoneType"), {});
|
||||||
this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL);
|
this->Ellipsis = new Py_<Dummy>(_new_type_object("ellipsis"), {});
|
||||||
this->True = new_object(tp_bool, true);
|
this->True = new Py_<Dummy>(tp_bool, {});
|
||||||
this->False = new_object(tp_bool, false);
|
this->False = new Py_<Dummy>(tp_bool, {});
|
||||||
this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL);
|
this->_py_op_call = new Py_<Dummy>(_new_type_object("_py_op_call"), {});
|
||||||
this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL);
|
this->_py_op_yield = new Py_<Dummy>(_new_type_object("_py_op_yield"), {});
|
||||||
this->builtins = new_module("builtins");
|
this->builtins = new_module("builtins");
|
||||||
this->_main = new_module("__main__");
|
this->_main = new_module("__main__");
|
||||||
|
|
||||||
@ -735,8 +718,8 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
|
|||||||
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{
|
||||||
obj = new_object(_callable, DummyInstance());
|
obj = heap.gcnew<DummyInstance>(_callable, {});
|
||||||
PyVarOrNull init_f = getattr(obj, __init__, false, true);
|
PyObject* init_f = getattr(obj, __init__, false, true);
|
||||||
if (init_f != nullptr) call(init_f, std::move(args), kwargs, false);
|
if (init_f != nullptr) call(init_f, std::move(args), kwargs, false);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
@ -801,7 +784,7 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
|
|||||||
return _exec();
|
return _exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVarOrNull call_f = getattr(_callable, __call__, false, true);
|
PyObject* call_f = getattr(_callable, __call__, false, true);
|
||||||
if(call_f != nullptr){
|
if(call_f != nullptr){
|
||||||
return call(call_f, std::move(args), kwargs, false);
|
return call(call_f, std::move(args), kwargs, false);
|
||||||
}
|
}
|
||||||
@ -829,42 +812,44 @@ 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
|
||||||
PyObject* VM::getattr(PyObject* 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);
|
||||||
if(is_type(*obj, tp_super)){
|
// handle super() proxy
|
||||||
const Super& super = OBJ_GET(Super, *obj);
|
if(is_type(obj, tp_super)){
|
||||||
obj = &super.first;
|
const Super& super = OBJ_GET(Super, obj);
|
||||||
objtype = _t(super.second).get();
|
obj = super.first;
|
||||||
|
objtype = _t(super.second);
|
||||||
}
|
}
|
||||||
PyObject** 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
|
||||||
PyObject** 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, Args{*cls_var, obj});
|
||||||
}
|
}
|
||||||
// handle instance __dict__
|
// handle instance __dict__
|
||||||
if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){
|
if(!class_only && !is_tagged(obj) && obj->is_attr_valid()){
|
||||||
PyObject** 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){
|
||||||
// bound method is non-data descriptor
|
// bound method is non-data descriptor
|
||||||
if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){
|
if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){
|
||||||
return VAR(BoundMethod(*obj, *cls_var));
|
return VAR(BoundMethod(obj, *cls_var));
|
||||||
}
|
}
|
||||||
return *cls_var;
|
return *cls_var;
|
||||||
}
|
}
|
||||||
if(throw_err) AttributeError(*obj, name);
|
if(throw_err) AttributeError(obj, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void VM::setattr(PyObject* 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>, PyObject*>);
|
||||||
PyObject* objtype = _t(obj).get();
|
PyObject* objtype = _t(obj);
|
||||||
|
// handle super() proxy
|
||||||
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);
|
||||||
}
|
}
|
||||||
PyObject** 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){
|
||||||
@ -873,7 +858,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
|
|||||||
if(cls_var_t->attr().contains(__get__)){
|
if(cls_var_t->attr().contains(__get__)){
|
||||||
PyObject** 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, Args{*cls_var, obj, std::forward<T>(value)});
|
||||||
}else{
|
}else{
|
||||||
TypeError("readonly attribute: " + name.str().escape(true));
|
TypeError("readonly attribute: " + name.str().escape(true));
|
||||||
}
|
}
|
||||||
@ -881,7 +866,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// handle instance __dict__
|
// handle instance __dict__
|
||||||
if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute");
|
if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute");
|
||||||
obj->attr().set(name, std::forward<T>(value));
|
obj->attr().set(name, std::forward<T>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user