diff --git a/src/cffi.h b/src/cffi.h index 94966c6e..593b1cd2 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -5,7 +5,7 @@ namespace pkpy { struct CType{ - PY_CLASS(c, type_) + PY_CLASS(CType, c, type_) const char* name; // must be a literal const int size; @@ -16,7 +16,7 @@ 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->_cast(args[0]); + CType& self = CAST(CType, args[0]); StrStream ss; ss << ""; return VAR(ss.str()); @@ -51,7 +51,7 @@ constexpr int C_TYPE(const char name[]){ #define C_TYPE_T(x) (kCTypes[C_TYPE(x)]) struct Pointer{ - PY_CLASS(c, ptr_) + PY_CLASS(Pointer, c, ptr_) void* ptr; CType ctype; // base type @@ -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->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); StrStream ss; ss << "<" << self.ctype.name << "* at " << (i64)self.ptr << ">"; return VAR(ss.str()); }); vm->bind_method<1>(type, "__add__", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); - return vm->new_object(self + CAST(i64, args[1])); + Pointer& self = CAST(Pointer, args[0]); + return VAR_T(Pointer, self + CAST(i64, args[1])); }); vm->bind_method<1>(type, "__sub__", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); - return vm->new_object(self - CAST_V(i64, args[1])); + Pointer& self = CAST(Pointer, args[0]); + return VAR_T(Pointer, self - CAST_V(i64, args[1])); }); vm->bind_method<1>(type, "__eq__", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); - Pointer& other = vm->_cast(args[1]); + Pointer& self = CAST(Pointer, args[0]); + Pointer& other = CAST(Pointer, args[1]); return VAR(self.ptr == other.ptr); }); vm->bind_method<1>(type, "__ne__", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); - Pointer& other = vm->_cast(args[1]); + Pointer& self = CAST(Pointer, args[0]); + Pointer& other = CAST(Pointer, args[1]); return VAR(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->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); i64 index = CAST_V(i64, args[1]); return (self+index).get(vm); }); vm->bind_method<2>(type, "__setitem__", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); i64 index = CAST_V(i64, args[1]); (self+index).set(vm, args[2]); return vm->None; }); vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); - CType& ctype = vm->_cast(args[1]); - return vm->new_object(self.ptr, ctype); + Pointer& self = CAST(Pointer, args[0]); + CType& ctype = CAST(CType, args[1]); + return VAR_T(Pointer, self.ptr, ctype); }); vm->bind_method<0>(type, "get", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); return self.get(vm); }); vm->bind_method<1>(type, "set", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); self.set(vm, args[1]); return vm->None; }); @@ -155,7 +155,7 @@ struct Pointer{ case C_TYPE("uint16_"): return VAR(ref()); case C_TYPE("uint32_"): return VAR(ref()); case C_TYPE("uint64_"): return VAR(ref()); - case C_TYPE("void_p_"): return vm->new_object(ref(), C_TYPE_T("void_")); + case C_TYPE("void_p_"): return VAR_T(Pointer, ref(), C_TYPE_T("void_")); // use macro here to do extension default: UNREACHABLE(); } @@ -178,7 +178,7 @@ struct Pointer{ case C_TYPE("uint16_"): ref() = CAST_V(i64, val); break; case C_TYPE("uint32_"): ref() = CAST_V(i64, val); break; case C_TYPE("uint64_"): ref() = CAST_V(i64, val); break; - case C_TYPE("void_p_"): ref() = vm->_cast(val).ptr; break; + case C_TYPE("void_p_"): ref() = CAST(Pointer, val).ptr; break; // use macro here to do extension default: UNREACHABLE(); } @@ -209,7 +209,7 @@ static const StructMetaInfo _Point2_info = { }; struct Struct { - PY_CLASS(c, struct_) + PY_CLASS(Struct, c, struct_) const StructMetaInfo* info; int8_t* _data; // store any `struct` @@ -238,11 +238,11 @@ struct Struct { static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind_static_method<-1>(type, "__new__", [](VM* vm, Args& args) { - return vm->new_object(); + return VAR_T(Struct); }); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - Struct& self = vm->_cast(args[0]); + Struct& self = CAST(Struct, args[0]); StrStream ss; ss << self.info->name << "(" << ")"; return VAR(ss.str()); @@ -252,41 +252,41 @@ struct Struct { void add_module_c(VM* vm){ PyVar mod = vm->new_module("c"); - PyVar ptr_t = vm->register_class(mod); - vm->register_class(mod); - vm->register_class(mod); + PyVar ptr_t = Pointer::register_class(vm, mod); + CType::register_class(vm, mod); + Struct::register_class(vm, mod); for(int i=0; isetattr(mod, kCTypes[i].name, vm->new_object(kCTypes[i])); + vm->setattr(mod, kCTypes[i].name, VAR_T(CType, kCTypes[i])); } - vm->setattr(mod, "nullptr", vm->new_object(nullptr, C_TYPE_T("void_"))); + vm->setattr(mod, "nullptr", VAR_T(Pointer, nullptr, C_TYPE_T("void_"))); vm->bind_func<1>(mod, "malloc", [](VM* vm, Args& args) { i64 size = CAST_V(i64, args[0]); - return vm->new_object(malloc(size), C_TYPE_T("void_")); + return VAR_T(Pointer, malloc(size), C_TYPE_T("void_")); }); vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) { - Pointer& self = vm->_cast(args[0]); + Pointer& self = CAST(Pointer, args[0]); free(self.ptr); return vm->None; }); vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) { - CType& ctype = vm->_cast(args[0]); + CType& ctype = CAST(CType, args[0]); return VAR(ctype.size); }); vm->bind_func<3>(mod, "memcpy", [](VM* vm, Args& args) { - Pointer& dst = vm->_cast(args[0]); - Pointer& src = vm->_cast(args[1]); + Pointer& dst = CAST(Pointer, args[0]); + Pointer& src = CAST(Pointer, args[1]); i64 size = CAST_V(i64, args[2]); memcpy(dst.ptr, src.ptr, size); return vm->None; }); vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) { - Pointer& dst = vm->_cast(args[0]); + Pointer& dst = CAST(Pointer, args[0]); i64 val = CAST_V(i64, args[1]); i64 size = CAST_V(i64, args[2]); memset(dst.ptr, (int)val, size); @@ -296,10 +296,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 = CAST(Str, args[0]); - return vm->new_object(strdup(s.c_str()), C_TYPE_T("char_")); + return VAR_T(Pointer, strdup(s.c_str()), C_TYPE_T("char_")); }else if(is_type(args[0], OBJ_GET(Type, ptr_t))){ - Pointer& p = vm->_cast(args[0]); - return vm->new_object(strdup(p.cast()), C_TYPE_T("char_")); + Pointer& p = CAST(Pointer, args[0]); + return VAR_T(Pointer, strdup(p.cast()), C_TYPE_T("char_")); }else{ vm->TypeError("strdup() argument must be 'str' or 'char*'"); return vm->None; @@ -307,13 +307,13 @@ void add_module_c(VM* vm){ }); vm->bind_func<2>(mod, "strcmp", [](VM* vm, Args& args) { - Pointer& p1 = vm->_cast(args[0]); - Pointer& p2 = vm->_cast(args[1]); + Pointer& p1 = CAST(Pointer, args[0]); + Pointer& p2 = CAST(Pointer, args[1]); return VAR(strcmp(p1.cast(), p2.cast())); }); vm->bind_func<1>(mod, "strlen", [](VM* vm, Args& args) { - Pointer& p = vm->_cast(args[0]); + Pointer& p = CAST(Pointer, args[0]); return VAR(strlen(p.cast())); }); } diff --git a/src/obj.h b/src/obj.h index a9c1fcc8..52930f2b 100644 --- a/src/obj.h +++ b/src/obj.h @@ -149,14 +149,19 @@ inline bool is_float(const PyVar& obj) noexcept { return obj.is_tag_10(); } -#define PY_CLASS(mod, name) \ - inline static Type _type(VM* vm) { \ +#define PY_CLASS(T, mod, name) \ + static Type _type(VM* vm) { \ static StrName __x0(#mod); \ static StrName __x1(#name); \ - return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ - } \ - inline static const char* _mod() { return #mod; } \ - inline static const char* _name() { return #name; } + return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ + } \ + static PyVar register_class(VM* vm, PyVar mod) { \ + PyVar type = vm->new_type_object(mod, #name, vm->_t(vm->tp_object));\ + if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \ + T::_register(vm, mod, type); \ + type->attr()._try_perfect_rehash(); \ + return type; \ + } union __8B { i64 _int; @@ -165,16 +170,37 @@ union __8B { __8B(f64 val) : _float(val) {} }; +template struct is_py_class : std::false_type {}; +template struct is_py_class> : std::true_type {}; + template T py_cast_v(VM* vm, const PyVar& var) { UNREACHABLE(); } template T _py_cast_v(VM* vm, const PyVar& var) { UNREACHABLE(); } + template -T& py_cast(VM* vm, const PyVar& var) { UNREACHABLE(); } +void _check_py_class(VM* vm, const PyVar& var); + template -T& _py_cast(VM* vm, const PyVar& var) { UNREACHABLE(); } +T& py_cast(VM* vm, const PyVar& obj) { + if constexpr(is_py_class::value){ + _check_py_class(vm, obj); + return OBJ_GET(T, obj); + }else{ + throw std::runtime_error("bad py_cast() call"); + } +} +template +T& _py_cast(VM* vm, const PyVar& obj) { + if constexpr(is_py_class::value){ + return OBJ_GET(T, obj); + }else{ + throw std::runtime_error("bad py_cast() call"); + } +} #define VAR(x) py_var(vm, x) +#define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__)) #define CAST(T, x) py_cast(vm, x) #define CAST_V(T, x) py_cast_v(vm, x) #define _CAST(T, x) _py_cast(vm, x) diff --git a/src/pocketpy.h b/src/pocketpy.h index 4fc2ab37..a453d489 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -611,7 +611,7 @@ void add_module_dis(VM* vm){ } struct FileIO { - PY_CLASS(io, FileIO) + PY_CLASS(FileIO, io, FileIO) Str file; Str mode; @@ -630,32 +630,32 @@ 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( + return VAR_T(FileIO, vm, CAST(Str, args[0]), CAST(Str, args[1]) ); }); vm->bind_method<0>(type, "read", [](VM* vm, Args& args){ - FileIO& io = vm->_cast(args[0]); + FileIO& io = CAST(FileIO, args[0]); std::string buffer; io._fs >> buffer; return VAR(buffer); }); vm->bind_method<1>(type, "write", [](VM* vm, Args& args){ - FileIO& io = vm->_cast(args[0]); + FileIO& io = CAST(FileIO, args[0]); io._fs << CAST(Str, args[1]); return vm->None; }); vm->bind_method<0>(type, "close", [](VM* vm, Args& args){ - FileIO& io = vm->_cast(args[0]); + FileIO& io = CAST(FileIO, args[0]); io._fs.close(); return vm->None; }); vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){ - FileIO& io = vm->_cast(args[0]); + FileIO& io = CAST(FileIO, args[0]); io._fs.close(); return vm->None; }); @@ -665,7 +665,7 @@ struct FileIO { }; void add_module_io(VM* vm){ PyVar mod = vm->new_module("io"); - PyVar type = vm->register_class(mod); + PyVar type = FileIO::register_class(vm, mod); vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){ return vm->call(type, args); }); @@ -674,7 +674,7 @@ void add_module_io(VM* vm){ void add_module_os(VM* vm){} struct ReMatch { - PY_CLASS(re, Match) + PY_CLASS(ReMatch, re, Match) i64 start; i64 end; @@ -683,16 +683,16 @@ 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(VAR(vm->_cast(args[0]).start))); - vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(vm->_cast(args[0]).end))); + 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, "span", [](VM* vm, Args& args) { - auto& self = vm->_cast(args[0]); + auto& self = CAST(ReMatch, args[0]); return VAR(two_args(VAR(self.start), VAR(self.end))); }); vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { - auto& self = vm->_cast(args[0]); + auto& self = CAST(ReMatch, args[0]); int index = (int)CAST_V(i64, args[1]); index = vm->normalized_index(index, self.m.size()); return VAR(self.m[index].str()); @@ -707,14 +707,14 @@ PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* v if(fromStart && m.position() != 0) return vm->None; i64 start = string._to_u8_index(m.position()); i64 end = string._to_u8_index(m.position() + m.length()); - return vm->new_object(start, end, m); + return VAR_T(ReMatch, start, end, m); } return vm->None; }; void add_module_re(VM* vm){ PyVar mod = vm->new_module("re"); - vm->register_class(mod); + ReMatch::register_class(vm, mod); vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) { const Str& pattern = CAST(Str, args[0]); diff --git a/src/vm.h b/src/vm.h index a6325246..befb73d1 100644 --- a/src/vm.h +++ b/src/vm.h @@ -192,11 +192,6 @@ public: return make_sp>(type, std::move(_value)); } - template - inline PyVar new_object(Args&&... args) { - return new_object(T::_type(this), T(std::forward(args)...)); - } - template void bind_func(Str typeName, Str funcName, NativeFuncRaw fn) { bind_func(_types[typeName], funcName, fn); @@ -290,21 +285,6 @@ public: return _all_types[OBJ_GET(Type, _t(obj->type)).index]; } - template - PyVar register_class(PyVar mod){ - PyVar type = new_type_object(mod, T::_name(), _t(tp_object)); - if(OBJ_NAME(mod) != T::_mod()) UNREACHABLE(); - T::_register(this, mod, type); - type->attr()._try_perfect_rehash(); - return type; - } - - template - inline T& _cast(const PyVar& obj){ - check_type(obj, T::_type(this)); - return OBJ_GET(T, obj); - } - ~VM() { if(!use_stdio){ delete _stdout; @@ -446,6 +426,11 @@ PyVar py_var(VM* vm, const char* val){ return VAR(Str(val)); } +template +void _check_py_class(VM* vm, const PyVar& obj){ + vm->check_type(obj, T::_type(vm)); +} + PyVar VM::num_negated(const PyVar& obj){ if (is_int(obj)){ return VAR(-CAST_V(i64, obj));