diff --git a/build_cpp.sh b/build_cpp.sh index 3a241834..974a6df7 100644 --- a/build_cpp.sh +++ b/build_cpp.sh @@ -1 +1 @@ -g++ -o pocketpy src/main.cpp --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti \ No newline at end of file +g++ -o pocketpy src/main.cpp -Wfatal-errors --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti \ No newline at end of file diff --git a/src/ceval.h b/src/ceval.h index 3167306b..9b50a9e8 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -18,12 +18,12 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue; case OP_LOAD_FUNCTION: { const PyVar obj = frame->co->consts[byte.arg]; - Function f = PyFunction_AS_C(obj); // copy + Function f = py_cast_v(this, obj); // copy f._module = frame->_module; - frame->push(PyFunction(f)); + frame->push(py_object(this, f)); } continue; case OP_SETUP_CLOSURE: { - Function& f = PyFunction_AS_C(frame->top()); // reference + Function& f = py_cast(this, frame->top()); // reference f._closure = frame->_locals; } continue; case OP_LOAD_NAME_REF: { @@ -70,7 +70,7 @@ PyVar VM::run_frame(Frame* frame){ continue; case OP_BUILD_TUPLE: { Args items = frame->pop_n_values_reversed(this, byte.arg); - frame->push(PyTuple(std::move(items))); + frame->push(py_object(this, std::move(items))); } continue; case OP_BUILD_TUPLE_REF: { Args items = frame->pop_n_reversed(byte.arg); @@ -79,13 +79,13 @@ PyVar VM::run_frame(Frame* frame){ case OP_BUILD_STRING: { Args items = frame->pop_n_values_reversed(this, byte.arg); StrStream ss; - for(int i=0; ipush(PyStr(ss.str())); + for(int i=0; i(this, asStr(items[i])); + frame->push(py_object(this, ss.str())); } continue; case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue; case OP_LIST_APPEND: { PyVar obj = frame->pop_value(this); - List& list = PyList_AS_C(frame->top_1()); + List& list = py_cast(this, frame->top_1()); list.push_back(std::move(obj)); } continue; case OP_BEGIN_CLASS: { @@ -109,7 +109,7 @@ PyVar VM::run_frame(Frame* frame){ case OP_RETURN_VALUE: return frame->pop_value(this); case OP_PRINT_EXPR: { const PyVar expr = frame->top_value(this); - if(expr != None) *_stdout << PyStr_AS_C(asRepr(expr)) << '\n'; + if(expr != None) *_stdout << py_cast(this, asRepr(expr)) << '\n'; } continue; case OP_POP_TOP: frame->_pop(); continue; case OP_BINARY_OP: { @@ -175,7 +175,7 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue; case OP_ASSERT: { PyVar _msg = frame->pop_value(this); - Str msg = PyStr_AS_C(asStr(_msg)); + Str msg = py_cast(this, asStr(_msg)); PyVar expr = frame->pop_value(this); if(asBool(expr) != True) _error("AssertionError", msg); } continue; @@ -186,13 +186,13 @@ PyVar VM::run_frame(Frame* frame){ } continue; case OP_RAISE: { PyVar obj = frame->pop_value(this); - Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj)); + Str msg = obj == None ? "" : py_cast(this, asStr(obj)); StrName type = frame->co->names[byte.arg].first; _error(type, msg); } continue; case OP_RE_RAISE: _raise(); continue; case OP_BUILD_LIST: - frame->push(PyList(frame->pop_n_values_reversed(this, byte.arg).move_to_list())); + frame->push(py_object(this, frame->pop_n_values_reversed(this, byte.arg).move_to_list())); continue; case OP_BUILD_MAP: { Args items = frame->pop_n_values_reversed(this, byte.arg*2); @@ -203,7 +203,7 @@ PyVar VM::run_frame(Frame* frame){ frame->push(obj); } continue; case OP_BUILD_SET: { - PyVar list = PyList( + PyVar list = py_object(this, frame->pop_n_values_reversed(this, byte.arg).move_to_list() ); PyVar obj = call(builtins->attr("set"), one_arg(list)); diff --git a/src/cffi.h b/src/cffi.h index 6d3e2847..6d3ed055 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -16,10 +16,10 @@ struct CType{ vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - CType& self = vm->py_cast(args[0]); + CType& self = vm->_cast(args[0]); StrStream ss; ss << ""; - return vm->PyStr(ss.str()); + return py_object(vm, ss.str()); }); } }; @@ -70,61 +70,61 @@ struct Pointer{ vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); StrStream ss; ss << "<" << self.ctype.name << "* at " << (i64)self.ptr << ">"; - return vm->PyStr(ss.str()); + return py_object(vm, ss.str()); }); vm->bind_method<1>(type, "__add__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); return vm->new_object(self + py_cast(vm, args[1])); }); vm->bind_method<1>(type, "__sub__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); return vm->new_object(self - py_cast_v(vm, args[1])); }); vm->bind_method<1>(type, "__eq__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); - Pointer& other = vm->py_cast(args[1]); + Pointer& self = vm->_cast(args[0]); + Pointer& other = vm->_cast(args[1]); return vm->PyBool(self.ptr == other.ptr); }); vm->bind_method<1>(type, "__ne__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); - Pointer& other = vm->py_cast(args[1]); + Pointer& self = vm->_cast(args[0]); + Pointer& other = vm->_cast(args[1]); return vm->PyBool(self.ptr != other.ptr); }); // https://docs.python.org/zh-cn/3/library/ctypes.html vm->bind_method<1>(type, "__getitem__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); i64 index = py_cast_v(vm, args[1]); return (self+index).get(vm); }); vm->bind_method<2>(type, "__setitem__", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); i64 index = py_cast_v(vm, args[1]); (self+index).set(vm, args[2]); return vm->None; }); vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); - CType& ctype = vm->py_cast(args[1]); + Pointer& self = vm->_cast(args[0]); + CType& ctype = vm->_cast(args[1]); return vm->new_object(self.ptr, ctype); }); vm->bind_method<0>(type, "get", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); return self.get(vm); }); vm->bind_method<1>(type, "set", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); self.set(vm, args[1]); return vm->None; }); @@ -178,7 +178,7 @@ struct Pointer{ case C_TYPE("uint16_"): ref() = py_cast_v(vm, val); break; case C_TYPE("uint32_"): ref() = py_cast_v(vm, val); break; case C_TYPE("uint64_"): ref() = py_cast_v(vm, val); break; - case C_TYPE("void_p_"): ref() = vm->py_cast(val).ptr; break; + case C_TYPE("void_p_"): ref() = vm->_cast(val).ptr; break; // use macro here to do extension default: UNREACHABLE(); } @@ -242,10 +242,10 @@ struct Struct { }); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - Struct& self = vm->py_cast(args[0]); + Struct& self = vm->_cast(args[0]); StrStream ss; ss << self.info->name << "(" << ")"; - return vm->PyStr(ss.str()); + return py_object(vm, ss.str()); }); } }; @@ -267,26 +267,26 @@ void add_module_c(VM* vm){ }); vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) { - Pointer& self = vm->py_cast(args[0]); + Pointer& self = vm->_cast(args[0]); free(self.ptr); return vm->None; }); vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) { - CType& ctype = vm->py_cast(args[0]); + CType& ctype = vm->_cast(args[0]); return py_object(vm, ctype.size); }); vm->bind_func<3>(mod, "memcpy", [](VM* vm, Args& args) { - Pointer& dst = vm->py_cast(args[0]); - Pointer& src = vm->py_cast(args[1]); + Pointer& dst = vm->_cast(args[0]); + Pointer& src = vm->_cast(args[1]); i64 size = py_cast_v(vm, args[2]); memcpy(dst.ptr, src.ptr, size); return vm->None; }); vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) { - Pointer& dst = vm->py_cast(args[0]); + Pointer& dst = vm->_cast(args[0]); i64 val = py_cast_v(vm, args[1]); i64 size = py_cast_v(vm, args[2]); memset(dst.ptr, (int)val, size); @@ -295,10 +295,10 @@ void add_module_c(VM* vm){ vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, Args& args) { if(is_type(args[0], vm->tp_str)){ - const Str& s = vm->PyStr_AS_C(args[0]); + const Str& s = py_cast(vm, args[0]); return vm->new_object(strdup(s.c_str()), C_TYPE_T("char_")); }else if(is_type(args[0], OBJ_GET(Type, ptr_t))){ - Pointer& p = vm->py_cast(args[0]); + Pointer& p = vm->_cast(args[0]); return vm->new_object(strdup(p.cast()), C_TYPE_T("char_")); }else{ vm->TypeError("strdup() argument must be 'str' or 'char*'"); @@ -307,13 +307,13 @@ void add_module_c(VM* vm){ }); vm->bind_func<2>(mod, "strcmp", [](VM* vm, Args& args) { - Pointer& p1 = vm->py_cast(args[0]); - Pointer& p2 = vm->py_cast(args[1]); + Pointer& p1 = vm->_cast(args[0]); + Pointer& p2 = vm->_cast(args[1]); return py_object(vm, strcmp(p1.cast(), p2.cast())); }); vm->bind_func<1>(mod, "strlen", [](VM* vm, Args& args) { - Pointer& p = vm->py_cast(args[0]); + Pointer& p = vm->_cast(args[0]); return py_object(vm, strlen(p.cast())); }); } diff --git a/src/compiler.h b/src/compiler.h index ec0ac260..6a8436c5 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -147,9 +147,9 @@ private: void eat_string(char quote, StringType type) { Str s = eat_string_until(quote, type == RAW_STRING); if(type == F_STRING){ - parser->set_next_token(TK("@fstr"), vm->PyStr(s)); + parser->set_next_token(TK("@fstr"), py_object(vm, s)); }else{ - parser->set_next_token(TK("@str"), vm->PyStr(s)); + parser->set_next_token(TK("@str"), py_object(vm, s)); } } @@ -360,7 +360,7 @@ private: void exprFString() { static const std::regex pattern(R"(\{(.*?)\})"); PyVar value = parser->prev.value; - Str s = vm->PyStr_AS_C(value); + Str s = py_cast(vm, value); std::sregex_iterator begin(s.begin(), s.end(), pattern); std::sregex_iterator end; int size = 0; @@ -369,18 +369,18 @@ private: std::smatch m = *it; if (i < m.position()) { std::string literal = s.substr(i, m.position() - i); - emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(literal))); + emit(OP_LOAD_CONST, co()->add_const(py_object(vm, literal))); size++; } emit(OP_LOAD_EVAL_FN); - emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(m[1].str()))); + emit(OP_LOAD_CONST, co()->add_const(py_object(vm, m[1].str()))); emit(OP_CALL, 1); size++; i = (int)(m.position() + m.length()); } if (i < s.size()) { std::string literal = s.substr(i, s.size() - i); - emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(literal))); + emit(OP_LOAD_CONST, co()->add_const(py_object(vm, literal))); size++; } emit(OP_BUILD_STRING, size); @@ -399,7 +399,7 @@ private: emit(OP_RETURN_VALUE); func.code->optimize(vm); this->codes.pop(); - emit(OP_LOAD_FUNCTION, co()->add_const(vm->PyFunction(func))); + emit(OP_LOAD_FUNCTION, co()->add_const(py_object(vm, func))); if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE); } @@ -613,7 +613,7 @@ __LISTCOMP: if(peek() == TK("@id") && peek_next() == TK("=")) { consume(TK("@id")); const Str& key = parser->prev.str(); - emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(key))); + emit(OP_LOAD_CONST, co()->add_const(py_object(vm, key))); consume(TK("=")); co()->_rvalue += 1; EXPR(); co()->_rvalue -= 1; KWARGC++; @@ -929,7 +929,7 @@ __LISTCOMP: co()->_rvalue += 1; EXPR(); if (match(TK(","))) EXPR(); - else emit(OP_LOAD_CONST, co()->add_const(vm->PyStr(""))); + else emit(OP_LOAD_CONST, co()->add_const(py_object(vm, ""))); co()->_rvalue -= 1; emit(OP_ASSERT); consume_end_stmt(); @@ -1073,7 +1073,7 @@ __LISTCOMP: compile_block_body(); func.code->optimize(vm); this->codes.pop(); - emit(OP_LOAD_FUNCTION, co()->add_const(vm->PyFunction(func))); + emit(OP_LOAD_FUNCTION, co()->add_const(py_object(vm, func))); if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE); if(!co()->_is_compiling_class){ if(obj_name.empty()){ diff --git a/src/iter.h b/src/iter.h index 21580ff8..547c522f 100644 --- a/src/iter.h +++ b/src/iter.h @@ -46,7 +46,7 @@ public: PyVar next() { if(index == str->u8_length()) return nullptr; - return vm->PyStr(str->u8_getitem(index++)); + return py_object(vm, str->u8_getitem(index++)); } }; diff --git a/src/main.cpp b/src/main.cpp index 5d143a69..4d9dfb56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ int main(int argc, char** argv){ vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::Args& args){ static std::string line; std::getline(std::cin, line); - return vm->PyStr(line); + return py_object(vm, line); }); if(argc == 1){ pkpy::REPL* repl = pkpy_new_repl(vm); diff --git a/src/pocketpy.h b/src/pocketpy.h index 1a6d92c2..d8d8d795 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -56,7 +56,7 @@ void init_builtins(VM* _vm) { #undef BIND_NUM_LOGICAL_OPT _vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, Args& args) { - (*vm->_stdout) << vm->PyStr_AS_C(args[0]); + (*vm->_stdout) << py_cast(vm, args[0]); return vm->None; }); @@ -78,12 +78,12 @@ void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { - CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "", EVAL_MODE); + CodeObject_ code = vm->compile(py_cast(vm, args[0]), "", EVAL_MODE); return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); }); _vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) { - CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "", EXEC_MODE); + CodeObject_ code = vm->compile(py_cast(vm, args[0]), "", EXEC_MODE); vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); return vm->None; }); @@ -107,33 +107,33 @@ void init_builtins(VM* _vm) { _vm->bind_builtin_func<1>("chr", [](VM* vm, Args& args) { i64 i = py_cast_v(vm, args[0]); if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)"); - return vm->PyStr(std::string(1, (char)i)); + return py_object(vm, std::string(1, (char)i)); }); _vm->bind_builtin_func<1>("ord", [](VM* vm, Args& args) { - Str s = vm->PyStr_AS_C(args[0]); + Str s = py_cast(vm, args[0]); if (s.size() != 1) vm->TypeError("ord() expected an ASCII character"); return py_object(vm, (i64)(s.c_str()[0])); }); _vm->bind_builtin_func<2>("hasattr", [](VM* vm, Args& args) { - return vm->PyBool(vm->getattr(args[0], vm->PyStr_AS_C(args[1]), false) != nullptr); + return vm->PyBool(vm->getattr(args[0], py_cast(vm, args[1]), false) != nullptr); }); _vm->bind_builtin_func<3>("setattr", [](VM* vm, Args& args) { - vm->setattr(args[0], vm->PyStr_AS_C(args[1]), args[2]); + vm->setattr(args[0], py_cast(vm, args[1]), args[2]); return vm->None; }); _vm->bind_builtin_func<2>("getattr", [](VM* vm, Args& args) { - Str name = vm->PyStr_AS_C(args[1]); + Str name = py_cast(vm, args[1]); return vm->getattr(args[0], name); }); _vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) { std::stringstream ss; ss << std::hex << py_cast_v(vm, args[0]); - return vm->PyStr("0x" + ss.str()); + return py_object(vm, "0x" + ss.str()); }); _vm->bind_builtin_func<1>("dir", [](VM* vm, Args& args) { @@ -146,8 +146,8 @@ void init_builtins(VM* _vm) { std::vector keys = t_attr.keys(); names.insert(keys.begin(), keys.end()); List ret; - for (StrName name : names) ret.push_back(vm->PyStr(name.str())); - return vm->PyList(std::move(ret)); + for (StrName name : names) ret.push_back(py_object(vm, name.str())); + return py_object(vm, std::move(ret)); }); _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) { @@ -156,7 +156,7 @@ void init_builtins(VM* _vm) { StrStream ss; ss << std::hex << addr; Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">"; - return vm->PyStr(s); + return py_object(vm, s); }); _vm->bind_method<1>("object", "__eq__", CPP_LAMBDA(vm->PyBool(args[0] == args[1]))); @@ -179,8 +179,8 @@ void init_builtins(VM* _vm) { vm->PyIter(RangeIter(vm, args[0])) )); - _vm->bind_method<0>("NoneType", "__repr__", CPP_LAMBDA(vm->PyStr("None"))); - _vm->bind_method<0>("NoneType", "__json__", CPP_LAMBDA(vm->PyStr("null"))); + _vm->bind_method<0>("NoneType", "__repr__", CPP_LAMBDA(py_object(vm, "None"))); + _vm->bind_method<0>("NoneType", "__json__", CPP_LAMBDA(py_object(vm, "null"))); _vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, Args& args) { f64 rhs = vm->num_to_float(args[1]); @@ -213,7 +213,7 @@ void init_builtins(VM* _vm) { if (is_type(args[0], vm->tp_float)) return py_object(vm, (i64)py_cast_v(vm, args[0])); if (is_type(args[0], vm->tp_bool)) return py_object(vm, vm->_PyBool_AS_C(args[0]) ? 1 : 0); if (is_type(args[0], vm->tp_str)) { - const Str& s = vm->PyStr_AS_C(args[0]); + const Str& s = py_cast(vm, args[0]); try{ size_t parsed = 0; i64 val = S_TO_INT(s, &parsed, 10); @@ -239,8 +239,8 @@ void init_builtins(VM* _vm) { return py_object(vm, py_cast_v(vm, args[0]) % rhs); }); - _vm->bind_method<0>("int", "__repr__", CPP_LAMBDA(vm->PyStr(std::to_string(py_cast_v(vm, args[0]))))); - _vm->bind_method<0>("int", "__json__", CPP_LAMBDA(vm->PyStr(std::to_string(py_cast_v(vm, args[0]))))); + _vm->bind_method<0>("int", "__repr__", CPP_LAMBDA(py_object(vm, std::to_string(py_cast_v(vm, args[0]))))); + _vm->bind_method<0>("int", "__json__", CPP_LAMBDA(py_object(vm, std::to_string(py_cast_v(vm, args[0]))))); #define INT_BITWISE_OP(name,op) \ _vm->bind_method<1>("int", #name, CPP_LAMBDA(py_object(vm, py_cast_v(vm, args[0]) op py_cast_v(vm, args[1])))); @@ -259,7 +259,7 @@ void init_builtins(VM* _vm) { if (is_type(args[0], vm->tp_float)) return args[0]; if (is_type(args[0], vm->tp_bool)) return py_object(vm, vm->_PyBool_AS_C(args[0]) ? 1.0 : 0.0); if (is_type(args[0], vm->tp_str)) { - const Str& s = vm->PyStr_AS_C(args[0]); + const Str& s = py_cast(vm, args[0]); if(s == "inf") return py_object(vm, INFINITY); if(s == "-inf") return py_object(vm, -INFINITY); try{ @@ -275,37 +275,37 @@ void init_builtins(VM* _vm) { _vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) { f64 val = py_cast_v(vm, args[0]); - if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val)); + if(std::isinf(val) || std::isnan(val)) return py_object(vm, std::to_string(val)); StrStream ss; ss << std::setprecision(std::numeric_limits::max_digits10-1-2) << val; std::string s = ss.str(); if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0"; - return vm->PyStr(s); + return py_object(vm, s); }); _vm->bind_method<0>("float", "__json__", [](VM* vm, Args& args) { f64 val = py_cast_v(vm, args[0]); if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'"); - return vm->PyStr(std::to_string(val)); + return py_object(vm, std::to_string(val)); }); /************ PyString ************/ _vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0]))); _vm->bind_method<1>("str", "__add__", [](VM* vm, Args& args) { - const Str& lhs = vm->PyStr_AS_C(args[0]); - const Str& rhs = vm->PyStr_AS_C(args[1]); - return vm->PyStr(lhs + rhs); + const Str& lhs = py_cast(vm, args[0]); + const Str& rhs = py_cast(vm, args[1]); + return py_object(vm, lhs + rhs); }); _vm->bind_method<0>("str", "__len__", [](VM* vm, Args& args) { - const Str& self = vm->PyStr_AS_C(args[0]); + const Str& self = py_cast(vm, args[0]); return py_object(vm, self.u8_length()); }); _vm->bind_method<1>("str", "__contains__", [](VM* vm, Args& args) { - const Str& self = vm->PyStr_AS_C(args[0]); - const Str& other = vm->PyStr_AS_C(args[1]); + const Str& self = py_cast(vm, args[0]); + const Str& other = py_cast(vm, args[1]); return vm->PyBool(self.find(other) != Str::npos); }); @@ -313,57 +313,57 @@ void init_builtins(VM* _vm) { _vm->bind_method<0>("str", "__iter__", CPP_LAMBDA(vm->PyIter(StringIter(vm, args[0])))); _vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) { - const Str& _self = vm->PyStr_AS_C(args[0]); - return vm->PyStr(_self.escape(true)); + const Str& _self = py_cast(vm, args[0]); + return py_object(vm, _self.escape(true)); }); _vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) { - const Str& _self = vm->PyStr_AS_C(args[0]); - return vm->PyStr(_self.escape(false)); + const Str& _self = py_cast(vm, args[0]); + return py_object(vm, _self.escape(false)); }); _vm->bind_method<1>("str", "__eq__", [](VM* vm, Args& args) { if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) - return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1])); + return vm->PyBool(py_cast(vm, args[0]) == py_cast(vm, args[1])); return vm->PyBool(args[0] == args[1]); }); _vm->bind_method<1>("str", "__ne__", [](VM* vm, Args& args) { if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) - return vm->PyBool(vm->PyStr_AS_C(args[0]) != vm->PyStr_AS_C(args[1])); + return vm->PyBool(py_cast(vm, args[0]) != py_cast(vm, args[1])); return vm->PyBool(args[0] != args[1]); }); _vm->bind_method<1>("str", "__getitem__", [](VM* vm, Args& args) { - const Str& self (vm->PyStr_AS_C(args[0])); + const Str& self (py_cast(vm, args[0])); if(is_type(args[1], vm->tp_slice)){ Slice s = vm->PySlice_AS_C(args[1]); s.normalize(self.u8_length()); - return vm->PyStr(self.u8_substr(s.start, s.stop)); + return py_object(vm, self.u8_substr(s.start, s.stop)); } int index = (int)py_cast_v(vm, args[1]); index = vm->normalized_index(index, self.u8_length()); - return vm->PyStr(self.u8_getitem(index)); + return py_object(vm, self.u8_getitem(index)); }); _vm->bind_method<1>("str", "__gt__", [](VM* vm, Args& args) { - const Str& self (vm->PyStr_AS_C(args[0])); - const Str& obj (vm->PyStr_AS_C(args[1])); + const Str& self (py_cast(vm, args[0])); + const Str& obj (py_cast(vm, args[1])); return vm->PyBool(self > obj); }); _vm->bind_method<1>("str", "__lt__", [](VM* vm, Args& args) { - const Str& self (vm->PyStr_AS_C(args[0])); - const Str& obj (vm->PyStr_AS_C(args[1])); + const Str& self (py_cast(vm, args[0])); + const Str& obj (py_cast(vm, args[1])); return vm->PyBool(self < obj); }); _vm->bind_method<2>("str", "replace", [](VM* vm, Args& args) { - const Str& _self = vm->PyStr_AS_C(args[0]); - const Str& _old = vm->PyStr_AS_C(args[1]); - const Str& _new = vm->PyStr_AS_C(args[2]); + const Str& _self = py_cast(vm, args[0]); + const Str& _old = py_cast(vm, args[1]); + const Str& _new = py_cast(vm, args[2]); Str _copy = _self; // replace all occurences of _old with _new in _copy size_t pos = 0; @@ -371,82 +371,82 @@ void init_builtins(VM* _vm) { _copy.replace(pos, _old.length(), _new); pos += _new.length(); } - return vm->PyStr(_copy); + return py_object(vm, _copy); }); _vm->bind_method<1>("str", "startswith", [](VM* vm, Args& args) { - const Str& _self = vm->PyStr_AS_C(args[0]); - const Str& _prefix = vm->PyStr_AS_C(args[1]); + const Str& _self = py_cast(vm, args[0]); + const Str& _prefix = py_cast(vm, args[1]); return vm->PyBool(_self.find(_prefix) == 0); }); _vm->bind_method<1>("str", "endswith", [](VM* vm, Args& args) { - const Str& _self = vm->PyStr_AS_C(args[0]); - const Str& _suffix = vm->PyStr_AS_C(args[1]); + const Str& _self = py_cast(vm, args[0]); + const Str& _suffix = py_cast(vm, args[1]); return vm->PyBool(_self.rfind(_suffix) == _self.length() - _suffix.length()); }); _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) { - const Str& self = vm->PyStr_AS_C(args[0]); + const Str& self = py_cast(vm, args[0]); StrStream ss; PyVar obj = vm->asList(args[1]); - const List& list = vm->PyList_AS_C(obj); + const List& list = py_cast(vm, obj); for (int i = 0; i < list.size(); ++i) { if (i > 0) ss << self; - ss << vm->PyStr_AS_C(list[i]); + ss << py_cast(vm, list[i]); } - return vm->PyStr(ss.str()); + return py_object(vm, ss.str()); }); /************ PyList ************/ _vm->bind_method<1>("list", "append", [](VM* vm, Args& args) { - List& self = vm->PyList_AS_C(args[0]); + List& self = py_cast(vm, args[0]); self.push_back(args[1]); return vm->None; }); _vm->bind_method<0>("list", "reverse", [](VM* vm, Args& args) { - List& self = vm->PyList_AS_C(args[0]); + List& self = py_cast(vm, args[0]); std::reverse(self.begin(), self.end()); return vm->None; }); _vm->bind_method<1>("list", "__mul__", [](VM* vm, Args& args) { - const List& self = vm->PyList_AS_C(args[0]); + const List& self = py_cast(vm, args[0]); int n = (int)py_cast_v(vm, args[1]); List result; result.reserve(self.size() * n); for(int i = 0; i < n; i++) result.insert(result.end(), self.begin(), self.end()); - return vm->PyList(std::move(result)); + return py_object(vm, std::move(result)); }); _vm->bind_method<2>("list", "insert", [](VM* vm, Args& args) { - List& _self = vm->PyList_AS_C(args[0]); + List& self = py_cast(vm, args[0]); int index = (int)py_cast_v(vm, args[1]); - if(index < 0) index += _self.size(); + if(index < 0) index += self.size(); if(index < 0) index = 0; - if(index > _self.size()) index = _self.size(); - _self.insert(_self.begin() + index, args[2]); + if(index > self.size()) index = self.size(); + self.insert(self.begin() + index, args[2]); return vm->None; }); _vm->bind_method<0>("list", "clear", [](VM* vm, Args& args) { - vm->PyList_AS_C(args[0]).clear(); + py_cast(vm, args[0]).clear(); return vm->None; }); - _vm->bind_method<0>("list", "copy", CPP_LAMBDA(vm->PyList(vm->PyList_AS_C(args[0])))); + _vm->bind_method<0>("list", "copy", CPP_LAMBDA(py_object(vm, py_cast(vm, args[0])))); _vm->bind_method<1>("list", "__add__", [](VM* vm, Args& args) { - const List& self = vm->PyList_AS_C(args[0]); - const List& obj = vm->PyList_AS_C(args[1]); + const List& self = py_cast(vm, args[0]); + const List& obj = py_cast(vm, args[1]); List new_list = self; new_list.insert(new_list.end(), obj.begin(), obj.end()); - return vm->PyList(new_list); + return py_object(vm, new_list); }); _vm->bind_method<0>("list", "__len__", [](VM* vm, Args& args) { - const List& self = vm->PyList_AS_C(args[0]); + const List& self = py_cast(vm, args[0]); return py_object(vm, self.size()); }); @@ -455,14 +455,14 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("list", "__getitem__", [](VM* vm, Args& args) { - const List& self = vm->PyList_AS_C(args[0]); + const List& self = py_cast(vm, args[0]); if(is_type(args[1], vm->tp_slice)){ Slice s = vm->PySlice_AS_C(args[1]); s.normalize(self.size()); List new_list; for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]); - return vm->PyList(std::move(new_list)); + return py_object(vm, std::move(new_list)); } int index = (int)py_cast_v(vm, args[1]); @@ -471,7 +471,7 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<2>("list", "__setitem__", [](VM* vm, Args& args) { - List& self = vm->PyList_AS_C(args[0]); + List& self = py_cast(vm, args[0]); int index = (int)py_cast_v(vm, args[1]); index = vm->normalized_index(index, self.size()); self[index] = args[2]; @@ -479,7 +479,7 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("list", "__delitem__", [](VM* vm, Args& args) { - List& self = vm->PyList_AS_C(args[0]); + List& self = py_cast(vm, args[0]); int index = (int)py_cast_v(vm, args[1]); index = vm->normalized_index(index, self.size()); self.erase(self.begin() + index); @@ -488,8 +488,8 @@ void init_builtins(VM* _vm) { /************ PyTuple ************/ _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, Args& args) { - List list = vm->PyList_AS_C(vm->asList(args[0])); - return vm->PyTuple(std::move(list)); + List list = py_cast(vm, vm->asList(args[0])); + return py_object(vm, std::move(list)); }); _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, Args& args) { @@ -497,14 +497,14 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, Args& args) { - const Tuple& self = vm->PyTuple_AS_C(args[0]); + const Tuple& self = py_cast(vm, args[0]); if(is_type(args[1], vm->tp_slice)){ Slice s = vm->PySlice_AS_C(args[1]); s.normalize(self.size()); List new_list; for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]); - return vm->PyTuple(std::move(new_list)); + return py_object(vm, std::move(new_list)); } int index = (int)py_cast_v(vm, args[1]); @@ -513,7 +513,7 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<0>("tuple", "__len__", [](VM* vm, Args& args) { - const Tuple& self = vm->PyTuple_AS_C(args[0]); + const Tuple& self = py_cast(vm, args[0]); return py_object(vm, self.size()); }); @@ -522,12 +522,12 @@ void init_builtins(VM* _vm) { _vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) { bool val = vm->PyBool_AS_C(args[0]); - return vm->PyStr(val ? "True" : "False"); + return py_object(vm, val ? "True" : "False"); }); _vm->bind_method<0>("bool", "__json__", [](VM* vm, Args& args) { bool val = vm->PyBool_AS_C(args[0]); - return vm->PyStr(val ? "true" : "false"); + return py_object(vm, val ? "true" : "false"); }); _vm->bind_method<1>("bool", "__xor__", [](VM* vm, Args& args) { @@ -536,7 +536,7 @@ void init_builtins(VM* _vm) { return vm->PyBool(self ^ other); }); - _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(vm->PyStr("Ellipsis"))); + _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(py_object(vm, "Ellipsis"))); } #include "builtins.h" @@ -563,7 +563,7 @@ void add_module_time(VM* vm){ void add_module_sys(VM* vm){ PyVar mod = vm->new_module("sys"); - vm->setattr(mod, "version", vm->PyStr(PK_VERSION)); + vm->setattr(mod, "version", py_object(vm, PK_VERSION)); vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(py_object(vm, args[0].use_count()))); vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(py_object(vm, vm->recursionlimit))); @@ -577,7 +577,7 @@ void add_module_sys(VM* vm){ void add_module_json(VM* vm){ PyVar mod = vm->new_module("json"); vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) { - const Str& expr = vm->PyStr_AS_C(args[0]); + const Str& expr = py_cast(vm, args[0]); CodeObject_ code = vm->compile(expr, "", JSON_MODE); return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); }); @@ -609,7 +609,7 @@ void add_module_dis(VM* vm){ vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) { PyVar f = args[0]; if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method; - CodeObject_ code = vm->PyFunction_AS_C(f).code; + CodeObject_ code = py_cast(vm, f).code; (*vm->_stdout) << vm->disassemble(code); return vm->None; }); @@ -636,31 +636,31 @@ struct FileIO { static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){ return vm->new_object( - vm, vm->PyStr_AS_C(args[0]), vm->PyStr_AS_C(args[1]) + vm, py_cast(vm, args[0]), py_cast(vm, args[1]) ); }); vm->bind_method<0>(type, "read", [](VM* vm, Args& args){ - FileIO& io = vm->py_cast(args[0]); + FileIO& io = vm->_cast(args[0]); std::string buffer; io._fs >> buffer; - return vm->PyStr(buffer); + return py_object(vm, buffer); }); vm->bind_method<1>(type, "write", [](VM* vm, Args& args){ - FileIO& io = vm->py_cast(args[0]); - io._fs << vm->PyStr_AS_C(args[1]); + FileIO& io = vm->_cast(args[0]); + io._fs << py_cast(vm, args[1]); return vm->None; }); vm->bind_method<0>(type, "close", [](VM* vm, Args& args){ - FileIO& io = vm->py_cast(args[0]); + FileIO& io = vm->_cast(args[0]); io._fs.close(); return vm->None; }); vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){ - FileIO& io = vm->py_cast(args[0]); + FileIO& io = vm->_cast(args[0]); io._fs.close(); return vm->None; }); @@ -688,19 +688,19 @@ struct ReMatch { static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); - vm->bind_method<0>(type, "start", CPP_LAMBDA(py_object(vm, vm->py_cast(args[0]).start))); - vm->bind_method<0>(type, "end", CPP_LAMBDA(py_object(vm, vm->py_cast(args[0]).end))); + vm->bind_method<0>(type, "start", CPP_LAMBDA(py_object(vm, vm->_cast(args[0]).start))); + vm->bind_method<0>(type, "end", CPP_LAMBDA(py_object(vm, vm->_cast(args[0]).end))); vm->bind_method<0>(type, "span", [](VM* vm, Args& args) { - auto& self = vm->py_cast(args[0]); - return vm->PyTuple({ py_object(vm, self.start), py_object(vm, self.end) }); + auto& self = vm->_cast(args[0]); + return py_object(vm, pkpy::Args({ py_object(vm, self.start), py_object(vm, self.end) })); }); vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { - auto& self = vm->py_cast(args[0]); + auto& self = vm->_cast(args[0]); int index = (int)py_cast_v(vm, args[1]); index = vm->normalized_index(index, self.m.size()); - return vm->PyStr(self.m[index].str()); + return py_object(vm, self.m[index].str()); }); } }; @@ -722,36 +722,36 @@ void add_module_re(VM* vm){ vm->register_class(mod); vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) { - const Str& pattern = vm->PyStr_AS_C(args[0]); - const Str& string = vm->PyStr_AS_C(args[1]); + const Str& pattern = py_cast(vm, args[0]); + const Str& string = py_cast(vm, args[1]); return _regex_search(pattern, string, true, vm); }); vm->bind_func<2>(mod, "search", [](VM* vm, Args& args) { - const Str& pattern = vm->PyStr_AS_C(args[0]); - const Str& string = vm->PyStr_AS_C(args[1]); + const Str& pattern = py_cast(vm, args[0]); + const Str& string = py_cast(vm, args[1]); return _regex_search(pattern, string, false, vm); }); vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) { - const Str& pattern = vm->PyStr_AS_C(args[0]); - const Str& repl = vm->PyStr_AS_C(args[1]); - const Str& string = vm->PyStr_AS_C(args[2]); + const Str& pattern = py_cast(vm, args[0]); + const Str& repl = py_cast(vm, args[1]); + const Str& string = py_cast(vm, args[2]); std::regex re(pattern); - return vm->PyStr(std::regex_replace(string, re, repl)); + return py_object(vm, std::regex_replace(string, re, repl)); }); vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) { - const Str& pattern = vm->PyStr_AS_C(args[0]); - const Str& string = vm->PyStr_AS_C(args[1]); + const Str& pattern = py_cast(vm, args[0]); + const Str& string = py_cast(vm, args[1]); std::regex re(pattern); std::sregex_token_iterator it(string.begin(), string.end(), re, -1); std::sregex_token_iterator end; List vec; for(; it != end; ++it){ - vec.push_back(vm->PyStr(it->str())); + vec.push_back(py_object(vm, it->str())); } - return vm->PyList(vec); + return py_object(vm, vec); }); } @@ -868,7 +868,7 @@ extern "C" { pkpy::PyVar* val = vm->_main->attr().try_get(name); if(val == nullptr) return nullptr; try{ - pkpy::Str _repr = vm->PyStr_AS_C(vm->asRepr(*val)); + pkpy::Str& _repr = pkpy::py_cast(vm, vm->asRepr(*val)); return strdup(_repr.c_str()); }catch(...){ return nullptr; @@ -884,7 +884,7 @@ extern "C" { pkpy::PyVarOrNull ret = vm->exec(source, "", pkpy::EVAL_MODE); if(ret == nullptr) return nullptr; try{ - pkpy::Str _repr = vm->PyStr_AS_C(vm->asRepr(ret)); + pkpy::Str& _repr = pkpy::py_cast(vm, vm->asRepr(ret)); return strdup(_repr.c_str()); }catch(...){ return nullptr; @@ -971,7 +971,7 @@ extern "C" { for(int i=0; icall(args[i], pkpy::__json__); - ss << vm->PyStr_AS_C(x); + ss << pkpy::py_cast(vm, x); } char* packet = strdup(ss.str().c_str()); switch(ret_code){ @@ -981,7 +981,7 @@ extern "C" { case 's': { char* p = f_str(packet); if(p == nullptr) return vm->None; - return vm->PyStr(p); // no need to free(p) + return py_object(vm, p); // no need to free(p) } case 'N': f_None(packet); return vm->None; } diff --git a/src/ref.h b/src/ref.h index 5e7e8e5f..aa16f640 100644 --- a/src/ref.h +++ b/src/ref.h @@ -118,7 +118,7 @@ struct TupleRef : BaseRef { for (int i = 0; i < objs.size(); i++) { args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame); } - return vm->PyTuple(std::move(args)); + return py_object(vm, std::move(args)); } void set(VM* vm, Frame* frame, PyVar val) const{ @@ -133,7 +133,7 @@ struct TupleRef : BaseRef { auto ref = vm->PyRef_AS_C(star.obj); List list; while((x = iter->next()) != nullptr) list.push_back(x); - ref->set(vm, frame, vm->PyList(std::move(list))); + ref->set(vm, frame, py_object(vm, std::move(list))); return; }else{ x = iter->next(); diff --git a/src/tuplelist.h b/src/tuplelist.h index f7589173..9cf1c4f9 100644 --- a/src/tuplelist.h +++ b/src/tuplelist.h @@ -39,11 +39,12 @@ namespace pkpy { other._size = 0; } - Args(List&& other) noexcept { - _alloc(other.size()); - memcpy((void*)_args, (void*)other.data(), sizeof(PyVar)*_size); - memset((void*)other.data(), 0, sizeof(PyVar)*_size); + static pkpy::Args from_list(List&& other) noexcept { + Args ret(other.size()); + memcpy((void*)ret._args, (void*)other.data(), sizeof(PyVar)*ret.size()); + memset((void*)other.data(), 0, sizeof(PyVar)*ret.size()); other.clear(); + return ret; } PyVar& operator[](int i){ return _args[i]; } diff --git a/src/vm.h b/src/vm.h index e1eaa4b6..f06f4551 100644 --- a/src/vm.h +++ b/src/vm.h @@ -21,6 +21,13 @@ namespace pkpy{ template<> ctype& _py_cast(VM* vm, const PyVar& obj) { \ return OBJ_GET(ctype, obj); \ } \ + template<> ctype py_cast_v(VM* vm, const PyVar& obj) { \ + vm->check_type(obj, vm->ptype); \ + return OBJ_GET(ctype, obj); \ + } \ + template<> ctype _py_cast_v(VM* vm, const PyVar& obj) { \ + return OBJ_GET(ctype, obj); \ + } \ PyVar py_object(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ PyVar py_object(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));} @@ -84,11 +91,6 @@ public: return callstack.top().get(); } - PyVar asRepr(const PyVar& obj){ - if(is_type(obj, tp_type)) return PyStr("attr(__name__)) + "'>"); - return call(obj, __repr__); - } - PyVar asIter(const PyVar& obj){ if(is_type(obj, tp_native_iterator)) return obj; PyVarOrNull iter_f = getattr(obj, __iter__, false); @@ -133,82 +135,6 @@ public: return call(getattr(obj, name), no_arg(), no_arg(), false); } - PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){ - if(is_type(_callable, tp_type)){ - PyVar* new_f = _callable->attr().try_get(__new__); - PyVar obj; - if(new_f != nullptr){ - obj = call(*new_f, std::move(args), kwargs, false); - }else{ - obj = new_object(_callable, DummyInstance()); - PyVarOrNull init_f = getattr(obj, __init__, false); - if (init_f != nullptr) call(init_f, std::move(args), kwargs, false); - } - return obj; - } - - const PyVar* callable = &_callable; - if(is_type(*callable, tp_bound_method)){ - auto& bm = PyBoundMethod_AS_C((*callable)); - callable = &bm.method; // get unbound method - args.extend_self(bm.obj); - } - - if(is_type(*callable, tp_native_function)){ - const auto& f = OBJ_GET(NativeFunc, *callable); - if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); - return f(this, args); - } else if(is_type(*callable, tp_function)){ - const Function& fn = PyFunction_AS_C(*callable); - NameDict_ locals = make_sp( - fn.code->perfect_locals_capacity, - kLocalsLoadFactor, - fn.code->perfect_hash_seed - ); - - int i = 0; - for(StrName name : fn.args){ - if(i < args.size()){ - locals->set(name, std::move(args[i++])); - continue; - } - TypeError("missing positional argument " + name.str().escape(true)); - } - - locals->update(fn.kwargs); - - if(!fn.starred_arg.empty()){ - List vargs; // handle *args - while(i < args.size()) vargs.push_back(std::move(args[i++])); - locals->set(fn.starred_arg, PyTuple(std::move(vargs))); - }else{ - for(StrName key : fn.kwargs_order){ - if(i < args.size()){ - locals->set(key, std::move(args[i++])); - }else{ - break; - } - } - if(i < args.size()) TypeError("too many arguments"); - } - - for(int i=0; iset(key, kwargs[i+1]); - } - const PyVar& _module = fn._module != nullptr ? fn._module : top_frame()->_module; - auto _frame = _new_frame(fn.code, _module, locals, fn._closure); - if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame))); - callstack.push(std::move(_frame)); - if(opCall) return _py_op_call; - return _exec(); - } - TypeError(OBJ_NAME(_t(*callable)).escape(true) + " object is not callable"); - return None; - } // repl mode is only for setting `frame->id` to 0 PyVarOrNull exec(Str source, Str filename, CompileMode mode, PyVar _module=nullptr){ @@ -282,18 +208,6 @@ public: } } - PyVar new_type_object(PyVar mod, StrName name, PyVar base){ - if(!is_type(base, tp_type)) UNREACHABLE(); - PyVar obj = make_sp>(tp_type, _all_types.size()); - setattr(obj, __base__, base); - Str fullName = name.str(); - if(mod != builtins) fullName = OBJ_NAME(mod) + "." + name.str(); - setattr(obj, __name__, PyStr(fullName)); - setattr(mod, name, obj); - _all_types.push_back(obj); - return obj; - } - Type _new_type_object(StrName name, Type base=0) { PyVar obj = make_sp>(tp_type, _all_types.size()); setattr(obj, __base__, _t(base)); @@ -331,13 +245,6 @@ public: return new_object(T::_type(this), T(std::forward(args)...)); } - PyVar new_module(StrName name) { - PyVar obj = new_object(tp_module, DummyModule()); - setattr(obj, __name__, PyStr(name.str())); - _modules.set(name, obj); - return obj; - } - PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true) { PyVar* val; PyObject* cls; @@ -435,75 +342,6 @@ public: return index; } - Str disassemble(CodeObject_ co){ - std::vector jumpTargets; - for(auto byte : co->codes){ - if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_SAFE_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){ - jumpTargets.push_back(byte.arg); - } - } - StrStream ss; - ss << std::string(54, '-') << '\n'; - ss << co->name << ":\n"; - int prev_line = -1; - for(int i=0; icodes.size(); i++){ - const Bytecode& byte = co->codes[i]; - if(byte.op == OP_NO_OP) continue; - Str line = std::to_string(byte.line); - if(byte.line == prev_line) line = ""; - else{ - if(prev_line != -1) ss << "\n"; - prev_line = byte.line; - } - - std::string pointer; - if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){ - pointer = "-> "; - }else{ - pointer = " "; - } - ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); - ss << " " << pad(OP_NAMES[byte.op], 20) << " "; - // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5); - std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); - if(byte.op == OP_LOAD_CONST){ - argStr += " (" + PyStr_AS_C(asRepr(co->consts[byte.arg])) + ")"; - } - if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE || byte.op == OP_STORE_NAME){ - argStr += " (" + co->names[byte.arg].first.str().escape(true) + ")"; - } - if(byte.op == OP_FAST_INDEX || byte.op == OP_FAST_INDEX_REF){ - auto& a = co->names[byte.arg & 0xFFFF]; - auto& x = co->names[(byte.arg >> 16) & 0xFFFF]; - argStr += " (" + a.first.str() + '[' + x.first.str() + "])"; - } - ss << pad(argStr, 20); // may overflow - ss << co->blocks[byte.block].to_string(); - if(i != co->codes.size() - 1) ss << '\n'; - } - StrStream consts; - consts << "co_consts: "; - consts << PyStr_AS_C(asRepr(PyList(co->consts))); - - StrStream names; - names << "co_names: "; - List list; - for(int i=0; inames.size(); i++){ - list.push_back(PyStr(co->names[i].first.str())); - } - names << PyStr_AS_C(asRepr(PyList(list))); - ss << '\n' << consts.str() << '\n' << names.str() << '\n'; - - for(int i=0; iconsts.size(); i++){ - PyVar obj = co->consts[i]; - if(is_type(obj, tp_function)){ - const auto& f = PyFunction_AS_C(obj); - ss << disassemble(f.code); - } - } - return Str(ss.str()); - } - // for quick access Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str; Type tp_list, tp_tuple; @@ -523,10 +361,6 @@ public: return static_cast(obj->value()); } - DEF_NATIVE(Str, Str, tp_str) - DEF_NATIVE(List, List, tp_list) - DEF_NATIVE(Tuple, Tuple, tp_tuple) - DEF_NATIVE(Function, Function, tp_function) DEF_NATIVE(NativeFunc, NativeFunc, tp_native_function) DEF_NATIVE(BoundMethod, BoundMethod, tp_bound_method) DEF_NATIVE(Range, Range, tp_range) @@ -542,63 +376,6 @@ public: inline bool _PyBool_AS_C(const PyVar& obj){ return obj == True; } inline const PyVar& PyBool(bool value){return value ? True : False;} - void init_builtin_types(){ - PyVar _tp_object = make_sp>(1, 0); - PyVar _tp_type = make_sp>(1, 1); - _all_types.push_back(_tp_object); - _all_types.push_back(_tp_type); - tp_object = 0; tp_type = 1; - - _types.set("object", _tp_object); - _types.set("type", _tp_type); - - tp_int = _new_type_object("int"); - tp_float = _new_type_object("float"); - if(tp_int.index != kTpIntIndex || tp_float.index != kTpFloatIndex) UNREACHABLE(); - - tp_bool = _new_type_object("bool"); - tp_str = _new_type_object("str"); - tp_list = _new_type_object("list"); - tp_tuple = _new_type_object("tuple"); - tp_slice = _new_type_object("slice"); - tp_range = _new_type_object("range"); - tp_module = _new_type_object("module"); - tp_ref = _new_type_object("_ref"); - tp_star_wrapper = _new_type_object("_star_wrapper"); - - tp_function = _new_type_object("function"); - tp_native_function = _new_type_object("native_function"); - tp_native_iterator = _new_type_object("native_iterator"); - tp_bound_method = _new_type_object("bound_method"); - tp_super = _new_type_object("super"); - tp_exception = _new_type_object("Exception"); - - this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL); - this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL); - this->True = new_object(tp_bool, true); - this->False = new_object(tp_bool, false); - this->builtins = new_module("builtins"); - this->_main = new_module("__main__"); - this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL); - this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL); - - setattr(_t(tp_type), __base__, _t(tp_object)); - setattr(_t(tp_object), __base__, None); - - for(auto [k, v]: _types.items()){ - setattr(v, __name__, PyStr(k.str())); - } - - std::vector pb_types = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; - for (auto& name : pb_types) { - setattr(builtins, name, _types[name]); - } - - post_init(); - for(auto [k, v]: _types.items()) v->attr()._try_perfect_rehash(); - for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); - } - /***** Error Reporter *****/ void _error(StrName name, const Str& msg){ _error(Exception(name, msg)); @@ -659,27 +436,11 @@ public: } template - inline T& py_cast(const PyVar& obj){ + inline T& _cast(const PyVar& obj){ check_type(obj, T::_type(this)); return OBJ_GET(T, obj); } - void unpack_args(Args& args){ - List unpacked; - for(int i=0; i PyVarRef PyRef(P&& value); @@ -740,8 +508,19 @@ void CodeObject::optimize(VM* vm){ } } +DEF_NATIVE_2(Str, tp_str) +DEF_NATIVE_2(List, tp_list) +DEF_NATIVE_2(Tuple, tp_tuple) +DEF_NATIVE_2(Function, tp_function) +DEF_NATIVE_2(NativeFunc, tp_native_function) +DEF_NATIVE_2(BoundMethod, tp_bound_method) +DEF_NATIVE_2(Range, tp_range) +DEF_NATIVE_2(Slice, tp_slice) +DEF_NATIVE_2(Exception, tp_exception) +DEF_NATIVE_2(StarWrapper, tp_star_wrapper) + template -std::enable_if_t, PyVar> py_object(VM* vm, T _val){ +std::enable_if_t && !std::is_same_v, PyVar> py_object(VM* vm, T _val){ i64 val = static_cast(_val); if(((val << 2) >> 2) != val){ vm->_error("OverflowError", std::to_string(val) + " is out of range"); @@ -786,17 +565,9 @@ template<> bool _py_cast_v(VM* vm, const PyVar& obj){ return obj == vm->True; } -DEF_NATIVE_2(Str, tp_str) -DEF_NATIVE_2(List, tp_list) -DEF_NATIVE_2(Tuple, tp_tuple) -DEF_NATIVE_2(Function, tp_function) -DEF_NATIVE_2(NativeFunc, tp_native_function) -DEF_NATIVE_2(BoundMethod, tp_bound_method) -DEF_NATIVE_2(Range, tp_range) -DEF_NATIVE_2(Slice, tp_slice) -DEF_NATIVE_2(Exception, tp_exception) -DEF_NATIVE_2(StarWrapper, tp_star_wrapper) - +PyVar py_object(VM* vm, const char* val){ + return py_object(vm, Str(val)); +} PyVar VM::num_negated(const PyVar& obj){ if (is_int(obj)){ @@ -832,11 +603,11 @@ const PyVar& VM::asBool(const PyVar& obj){ } i64 VM::hash(const PyVar& obj){ - if (is_type(obj, tp_str)) return PyStr_AS_C(obj).hash(); + if (is_type(obj, tp_str)) return py_cast(this, obj).hash(); if (is_int(obj)) return py_cast_v(this, obj); if (is_type(obj, tp_tuple)) { i64 x = 1000003; - const Tuple& items = PyTuple_AS_C(obj); + const Tuple& items = py_cast(this, obj); for (int i=0; i> 2)); // recommended by Github Copilot @@ -853,4 +624,247 @@ i64 VM::hash(const PyVar& obj){ return 0; } +PyVar VM::asRepr(const PyVar& obj){ + if(is_type(obj, tp_type)) return py_object(this, "attr(__name__)) + "'>"); + return call(obj, __repr__); +} + +PyVar VM::new_type_object(PyVar mod, StrName name, PyVar base){ + if(!is_type(base, tp_type)) UNREACHABLE(); + PyVar obj = make_sp>(tp_type, _all_types.size()); + setattr(obj, __base__, base); + Str fullName = name.str(); + if(mod != builtins) fullName = OBJ_NAME(mod) + "." + name.str(); + setattr(obj, __name__, py_object(this, fullName)); + setattr(mod, name, obj); + _all_types.push_back(obj); + return obj; +} + +PyVar VM::new_module(StrName name) { + PyVar obj = new_object(tp_module, DummyModule()); + setattr(obj, __name__, py_object(this, name.str())); + _modules.set(name, obj); + return obj; +} + +Str VM::disassemble(CodeObject_ co){ + std::vector jumpTargets; + for(auto byte : co->codes){ + if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_SAFE_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){ + jumpTargets.push_back(byte.arg); + } + } + StrStream ss; + ss << std::string(54, '-') << '\n'; + ss << co->name << ":\n"; + int prev_line = -1; + for(int i=0; icodes.size(); i++){ + const Bytecode& byte = co->codes[i]; + if(byte.op == OP_NO_OP) continue; + Str line = std::to_string(byte.line); + if(byte.line == prev_line) line = ""; + else{ + if(prev_line != -1) ss << "\n"; + prev_line = byte.line; + } + + std::string pointer; + if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){ + pointer = "-> "; + }else{ + pointer = " "; + } + ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); + ss << " " << pad(OP_NAMES[byte.op], 20) << " "; + // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5); + std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); + if(byte.op == OP_LOAD_CONST){ + argStr += " (" + py_cast(this, asRepr(co->consts[byte.arg])) + ")"; + } + if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE || byte.op == OP_STORE_NAME){ + argStr += " (" + co->names[byte.arg].first.str().escape(true) + ")"; + } + if(byte.op == OP_FAST_INDEX || byte.op == OP_FAST_INDEX_REF){ + auto& a = co->names[byte.arg & 0xFFFF]; + auto& x = co->names[(byte.arg >> 16) & 0xFFFF]; + argStr += " (" + a.first.str() + '[' + x.first.str() + "])"; + } + ss << pad(argStr, 20); // may overflow + ss << co->blocks[byte.block].to_string(); + if(i != co->codes.size() - 1) ss << '\n'; + } + StrStream consts; + consts << "co_consts: "; + consts << py_cast(this, asRepr(py_object(this, co->consts))); + + StrStream names; + names << "co_names: "; + List list; + for(int i=0; inames.size(); i++){ + list.push_back(py_object(this, co->names[i].first.str())); + } + names << py_cast(this, asRepr(py_object(this, list))); + ss << '\n' << consts.str() << '\n' << names.str() << '\n'; + + for(int i=0; iconsts.size(); i++){ + PyVar obj = co->consts[i]; + if(is_type(obj, tp_function)){ + const auto& f = py_cast(this, obj); + ss << disassemble(f.code); + } + } + return Str(ss.str()); +} + +void VM::init_builtin_types(){ + PyVar _tp_object = make_sp>(1, 0); + PyVar _tp_type = make_sp>(1, 1); + _all_types.push_back(_tp_object); + _all_types.push_back(_tp_type); + tp_object = 0; tp_type = 1; + + _types.set("object", _tp_object); + _types.set("type", _tp_type); + + tp_int = _new_type_object("int"); + tp_float = _new_type_object("float"); + if(tp_int.index != kTpIntIndex || tp_float.index != kTpFloatIndex) UNREACHABLE(); + + tp_bool = _new_type_object("bool"); + tp_str = _new_type_object("str"); + tp_list = _new_type_object("list"); + tp_tuple = _new_type_object("tuple"); + tp_slice = _new_type_object("slice"); + tp_range = _new_type_object("range"); + tp_module = _new_type_object("module"); + tp_ref = _new_type_object("_ref"); + tp_star_wrapper = _new_type_object("_star_wrapper"); + + tp_function = _new_type_object("function"); + tp_native_function = _new_type_object("native_function"); + tp_native_iterator = _new_type_object("native_iterator"); + tp_bound_method = _new_type_object("bound_method"); + tp_super = _new_type_object("super"); + tp_exception = _new_type_object("Exception"); + + this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL); + this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL); + this->True = new_object(tp_bool, true); + this->False = new_object(tp_bool, false); + this->builtins = new_module("builtins"); + this->_main = new_module("__main__"); + this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL); + this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL); + + setattr(_t(tp_type), __base__, _t(tp_object)); + setattr(_t(tp_object), __base__, None); + + for(auto [k, v]: _types.items()){ + setattr(v, __name__, py_object(this, k.str())); + } + + std::vector pb_types = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; + for (auto& name : pb_types) { + setattr(builtins, name, _types[name]); + } + + post_init(); + for(auto [k, v]: _types.items()) v->attr()._try_perfect_rehash(); + for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); +} + +PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){ + if(is_type(_callable, tp_type)){ + PyVar* new_f = _callable->attr().try_get(__new__); + PyVar obj; + if(new_f != nullptr){ + obj = call(*new_f, std::move(args), kwargs, false); + }else{ + obj = new_object(_callable, DummyInstance()); + PyVarOrNull init_f = getattr(obj, __init__, false); + if (init_f != nullptr) call(init_f, std::move(args), kwargs, false); + } + return obj; + } + + const PyVar* callable = &_callable; + if(is_type(*callable, tp_bound_method)){ + auto& bm = PyBoundMethod_AS_C((*callable)); + callable = &bm.method; // get unbound method + args.extend_self(bm.obj); + } + + if(is_type(*callable, tp_native_function)){ + const auto& f = OBJ_GET(NativeFunc, *callable); + if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); + return f(this, args); + } else if(is_type(*callable, tp_function)){ + const Function& fn = py_cast(this, *callable); + NameDict_ locals = make_sp( + fn.code->perfect_locals_capacity, + kLocalsLoadFactor, + fn.code->perfect_hash_seed + ); + + int i = 0; + for(StrName name : fn.args){ + if(i < args.size()){ + locals->set(name, std::move(args[i++])); + continue; + } + TypeError("missing positional argument " + name.str().escape(true)); + } + + locals->update(fn.kwargs); + + if(!fn.starred_arg.empty()){ + List vargs; // handle *args + while(i < args.size()) vargs.push_back(std::move(args[i++])); + locals->set(fn.starred_arg, py_object(this, Tuple::from_list(std::move(vargs)))); + }else{ + for(StrName key : fn.kwargs_order){ + if(i < args.size()){ + locals->set(key, std::move(args[i++])); + }else{ + break; + } + } + if(i < args.size()) TypeError("too many arguments"); + } + + for(int i=0; i(this, kwargs[i]); + if(!fn.kwargs.contains(key)){ + TypeError(key.escape(true) + " is an invalid keyword argument for " + fn.name.str() + "()"); + } + locals->set(key, kwargs[i+1]); + } + const PyVar& _module = fn._module != nullptr ? fn._module : top_frame()->_module; + auto _frame = _new_frame(fn.code, _module, locals, fn._closure); + if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame))); + callstack.push(std::move(_frame)); + if(opCall) return _py_op_call; + return _exec(); + } + TypeError(OBJ_NAME(_t(*callable)).escape(true) + " object is not callable"); + return None; +} + +void VM::unpack_args(Args& args){ + List unpacked; + for(int i=0; i(this, list); + unpacked.insert(unpacked.end(), list_c.begin(), list_c.end()); + }else{ + unpacked.push_back(args[i]); + } + } + args = Args::from_list(std::move(unpacked)); +} + } // namespace pkpy \ No newline at end of file