This commit is contained in:
blueloveTH 2023-02-26 16:26:24 +08:00
parent f3ab008f6a
commit c13bdb55b0
4 changed files with 158 additions and 49 deletions

View File

@ -2,8 +2,18 @@
#include "vm.h"
// struct Point2{
// int x;
// int y;
// };
// std::map<std::string_view, int> _Point2_members = {
// {"x", offsetof(Point2, x)},
// {"y", offsetof(Point2, y)},
// };
struct CType{
PY_CLASS(c, _type)
PY_CLASS(c, type_)
const char* name; // must be a literal
const int size;
@ -48,13 +58,21 @@ constexpr int ctype(const char name[]){
#define ctype_t(x) (kCTypes[ctype(x)])
struct Pointer{
PY_CLASS(c, _ptr)
PY_CLASS(c, ptr_)
void* ptr;
CType _ctype; // base type
Pointer(void* ptr, CType _ctype) : ptr(ptr), _ctype(_ctype) {}
Pointer operator+(i64 offset) const {
return Pointer((int8_t*)ptr + offset * _ctype.size, _ctype);
}
Pointer operator-(i64 offset) const {
return Pointer((int8_t*)ptr - offset * _ctype.size, _ctype);
}
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
@ -67,16 +85,12 @@ struct Pointer{
vm->bind_method<1>(type, "__add__", [](VM* vm, pkpy::Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 offset = vm->PyInt_AS_C(args[1]);
int8_t* new_ptr = (int8_t*)self.ptr + offset * self._ctype.size;
return vm->new_object<Pointer>((void*)new_ptr, self._ctype);
return vm->new_object<Pointer>(self + vm->PyInt_AS_C(args[1]));
});
vm->bind_method<1>(type, "__sub__", [](VM* vm, pkpy::Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 offset = vm->PyInt_AS_C(args[1]);
int8_t* new_ptr = (int8_t*)self.ptr - offset * self._ctype.size;
return vm->new_object<Pointer>((void*)new_ptr, self._ctype);
return vm->new_object<Pointer>(self - vm->PyInt_AS_C(args[1]));
});
vm->bind_method<1>(type, "__eq__", [](VM* vm, pkpy::Args& args) {
@ -95,48 +109,13 @@ struct Pointer{
vm->bind_method<1>(type, "__getitem__", [](VM* vm, pkpy::Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 index = vm->PyInt_AS_C(args[1]);
switch(self._ctype.index){
case ctype("char_"): return vm->PyInt(((char*)self.ptr)[index]);
case ctype("int_"): return vm->PyInt(((int*)self.ptr)[index]);
case ctype("float_"): return vm->PyFloat(((float*)self.ptr)[index]);
case ctype("double_"): return vm->PyFloat(((double*)self.ptr)[index]);
case ctype("bool_"): return vm->PyBool(((bool*)self.ptr)[index]);
case ctype("void_"): vm->TypeError("cannot index void*"); break;
case ctype("int8_"): return vm->PyInt(((int8_t*)self.ptr)[index]);
case ctype("int16_"): return vm->PyInt(((int16_t*)self.ptr)[index]);
case ctype("int32_"): return vm->PyInt(((int32_t*)self.ptr)[index]);
case ctype("int64_"): return vm->PyInt(((int64_t*)self.ptr)[index]);
case ctype("uint8_"): return vm->PyInt(((uint8_t*)self.ptr)[index]);
case ctype("uint16_"): return vm->PyInt(((uint16_t*)self.ptr)[index]);
case ctype("uint32_"): return vm->PyInt(((uint32_t*)self.ptr)[index]);
case ctype("uint64_"): return vm->PyInt(((uint64_t*)self.ptr)[index]);
// use macro here to do extension
default: UNREACHABLE();
}
return vm->None;
return (self+index).get(vm);
});
vm->bind_method<2>(type, "__setitem__", [](VM* vm, pkpy::Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 index = vm->PyInt_AS_C(args[1]);
switch(self._ctype.index){
case ctype("char_"): ((char*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("int_"): ((int*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("float_"): ((float*)self.ptr)[index] = vm->PyFloat_AS_C(args[2]); break;
case ctype("double_"): ((double*)self.ptr)[index] = vm->PyFloat_AS_C(args[2]); break;
case ctype("bool_"): ((bool*)self.ptr)[index] = vm->PyBool_AS_C(args[2]); break;
case ctype("void_"): vm->TypeError("cannot index void*"); break;
case ctype("int8_"): ((int8_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("int16_"): ((int16_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("int32_"): ((int32_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("int64_"): ((int64_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("uint8_"): ((uint8_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("uint16_"): ((uint16_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("uint32_"): ((uint32_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
case ctype("uint64_"): ((uint64_t*)self.ptr)[index] = vm->PyInt_AS_C(args[2]); break;
// use macro here to do extension
default: UNREACHABLE();
}
(self+index).set(vm, args[2]);
return vm->None;
});
@ -147,14 +126,125 @@ struct Pointer{
});
}
template<class T>
inline T cast() noexcept { return reinterpret_cast<T>(ptr); }
template<typename T>
inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
template<typename TP>
inline TP cast() noexcept {
static_assert(std::is_pointer_v<TP>);
return reinterpret_cast<TP>(ptr);
}
PyVar get(VM* vm){
switch(_ctype.index){
case ctype("char_"): return vm->PyInt(ref<char>());
case ctype("int_"): return vm->PyInt(ref<int>());
case ctype("float_"): return vm->PyFloat(ref<float>());
case ctype("double_"): return vm->PyFloat(ref<double>());
case ctype("bool_"): return vm->PyBool(ref<bool>());
case ctype("void_"): vm->ValueError("cannot get void*"); break;
case ctype("int8_"): return vm->PyInt(ref<int8_t>());
case ctype("int16_"): return vm->PyInt(ref<int16_t>());
case ctype("int32_"): return vm->PyInt(ref<int32_t>());
case ctype("int64_"): return vm->PyInt(ref<int64_t>());
case ctype("uint8_"): return vm->PyInt(ref<uint8_t>());
case ctype("uint16_"): return vm->PyInt(ref<uint16_t>());
case ctype("uint32_"): return vm->PyInt(ref<uint32_t>());
case ctype("uint64_"): return vm->PyInt(ref<uint64_t>());
// use macro here to do extension
default: UNREACHABLE();
}
return vm->None;
}
void set(VM* vm, const PyVar& val){
switch(_ctype.index){
case ctype("char_"): ref<char>() = vm->PyInt_AS_C(val); break;
case ctype("int_"): ref<int>() = vm->PyInt_AS_C(val); break;
case ctype("float_"): ref<float>() = vm->PyFloat_AS_C(val); break;
case ctype("double_"): ref<double>() = vm->PyFloat_AS_C(val); break;
case ctype("bool_"): ref<bool>() = vm->PyBool_AS_C(val); break;
case ctype("void_"): vm->ValueError("cannot set void*"); break;
case ctype("int8_"): ref<int8_t>() = vm->PyInt_AS_C(val); break;
case ctype("int16_"): ref<int16_t>() = vm->PyInt_AS_C(val); break;
case ctype("int32_"): ref<int32_t>() = vm->PyInt_AS_C(val); break;
case ctype("int64_"): ref<int64_t>() = vm->PyInt_AS_C(val); break;
case ctype("uint8_"): ref<uint8_t>() = vm->PyInt_AS_C(val); break;
case ctype("uint16_"): ref<uint16_t>() = vm->PyInt_AS_C(val); break;
case ctype("uint32_"): ref<uint32_t>() = vm->PyInt_AS_C(val); break;
case ctype("uint64_"): ref<uint64_t>() = vm->PyInt_AS_C(val); break;
// use macro here to do extension
default: UNREACHABLE();
}
}
};
struct StructMemberInfo {
int offset;
CType type;
};
struct StructMetaInfo {
Str name;
std::map<std::string_view, StructMemberInfo> members;
};
struct Struct {
PY_CLASS(c, struct_)
const StructMetaInfo* info;
int8_t* _data; // store any `struct`
Struct(const StructMetaInfo* info, int8_t* data) : info(info), _data(data) {}
~Struct(){ delete[] _data; }
int8_t* address(std::string_view name){
auto it = info->members.find(name);
if(it == info->members.end()) return nullptr;
return _data + it->second.offset;
}
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
Struct& self = vm->py_cast<Struct>(args[0]);
StrStream ss;
ss << "<c._struct '" << self.info->name << "'>";
return vm->PyStr(ss.str());
});
#define MEMBER_LOOKUP() \
Struct& self = vm->py_cast<Struct>(args[0]); \
std::string_view name = vm->PyStr_AS_C(args[1]); \
auto it = self.info->members.find(name); \
if(it == self.info->members.end()){ \
vm->AttributeError(args[0], name.data()); \
return vm->None; \
} \
const StructMemberInfo& info = it->second; \
Pointer p = Pointer(self._data+info.offset, info.type); \
vm->bind_method<1>(type, "__getattr__", [](VM* vm, pkpy::Args& args) {
MEMBER_LOOKUP()
return p.get(vm);
});
vm->bind_method<2>(type, "__setattr__", [](VM* vm, pkpy::Args& args) {
MEMBER_LOOKUP()
p.set(vm, args[2]);
return vm->None;
});
#undef MEMBER_LOOKUP
}
};
void add_module_c(VM* vm){
PyVar mod = vm->new_module("c");
PyVar ptr_t = vm->register_class<Pointer>(mod);
vm->register_class<CType>(mod);
vm->register_class<Struct>(mod);
for(int i=0; i<kCTypeCount; i++){
vm->setattr(mod, kCTypes[i].name, vm->new_object<CType>(kCTypes[i]));

View File

@ -51,6 +51,7 @@ typedef double f64;
struct Dummy { };
struct DummyInstance { };
struct DummyProperty { };
struct DummyModule { };
#define DUMMY_VAL Dummy()

View File

@ -109,7 +109,7 @@ struct Py_ : PyObject {
_attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
}else if constexpr(std::is_same_v<T, DummyInstance>){
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc>){
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc> || std::is_same_v<T, DummyProperty>){
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
}else{
_attr = nullptr;

View File

@ -361,6 +361,7 @@ public:
while(cls != None.get()) {
val = cls->attr().try_get(name);
if(val != nullptr){
if(is_type(*val, tp_property)) return call((*val)->attr("__get__"), pkpy::one_arg(obj));
if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
return PyBoundMethod({obj, *val});
}else{
@ -378,10 +379,26 @@ public:
if(obj.is_tagged()) TypeError("cannot set attribute");
PyObject* p = obj.get();
while(p->type == tp_super) p = static_cast<PyVar*>(p->value())->get();
// handle property
PyVar* prop = _t(obj)->attr().try_get(name);
if(prop != nullptr && is_type(*prop, tp_property)){
call((*prop)->attr("__set__"), pkpy::two_args(obj, std::forward<T>(value)));
return;
}
if(!p->is_attr_valid()) TypeError("cannot set attribute");
p->attr().set(name, std::forward<T>(value));
}
void bind_property(PyVar obj, Str field, NativeFuncRaw getter, NativeFuncRaw setter){
check_type(obj, tp_type);
PyVar prop = new_object(tp_property, DummyProperty());
prop->attr().set("__get__", PyNativeFunc(pkpy::NativeFunc(getter, 0, true)));
prop->attr().set("__set__", PyNativeFunc(pkpy::NativeFunc(setter, 1, true)));
setattr(obj, field, prop);
}
template<int ARGC>
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
check_type(obj, tp_type);
@ -520,7 +537,7 @@ public:
Type tp_list, tp_tuple;
Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method;
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, tp_property;
template<typename P>
inline PyVarRef PyRef(P&& value) {
@ -637,6 +654,7 @@ public:
tp_module = _new_type_object("module");
tp_ref = _new_type_object("_ref");
tp_star_wrapper = _new_type_object("_star_wrapper");
tp_property = _new_type_object("property");
tp_function = _new_type_object("function");
tp_native_function = _new_type_object("native_function");