blueloveTH преди 2 години
родител
ревизия
6062e34a29
променени са 10 файла, в които са добавени 166 реда и са изтрити 354 реда
  1. 10 12
      include/pocketpy/bindings.h
  2. 4 22
      include/pocketpy/cffi.h
  3. 1 1
      include/pocketpy/common.h
  4. 2 1
      include/pocketpy/vm.h
  5. 38 84
      include/typings/c.pyi
  6. 0 27
      python/c.py
  7. 81 122
      src/cffi.cpp
  8. 9 5
      src/vm.cpp
  9. 21 22
      tests/80_c.py
  10. 0 58
      tests/99_cffi_2.py

+ 10 - 12
include/pocketpy/bindings.h

@@ -164,20 +164,18 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
             return VAR(self == other);                                              \
         });                                                                         \
 
-#define PY_POINTER_LIKE(wT) \
-        vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){  \
+#define PY_POINTER_SETGETITEM(wT) \
+        using vT = std::remove_pointer_t<decltype(std::declval<wT>()._())>;         \
+        vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){  \
             wT& self = _CAST(wT&, _0);                                              \
-            if(!vm->isinstance(_1, wT::_type(vm))) return vm->NotImplemented;       \
-            wT& other = _CAST(wT&, _1);                                             \
-            return VAR(self._() == other._());                                      \
+            i64 i = CAST(i64, _1);                                                  \
+            return VAR(self._()[i]);                                                \
         });                                                                         \
-        vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){         \
-            wT& self = _CAST(wT&, obj);                                             \
-            return reinterpret_cast<i64>(self._());                                 \
+        vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1, PyObject* _2){  \
+            wT& self = _CAST(wT&, _0);                                              \
+            i64 i = CAST(i64, _1);                                                  \
+            self._()[i] = CAST(vT, _2);                                             \
+            return vm->None;                                                        \
         });                                                                         \
-        vm->bind_property(type, "_value: int", [](VM* vm, ArgsView args){           \
-            wT& self = _CAST(wT&, args[0]);                                         \
-            return VAR(reinterpret_cast<i64>(self._()));                            \
-        });
 
 }   // namespace pkpy

+ 4 - 22
include/pocketpy/cffi.h

@@ -29,9 +29,6 @@ namespace pkpy {
 
 #define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), __VA_ARGS__)
 
-inline PyObject* py_var(VM* vm, void* p);
-inline PyObject* py_var(VM* vm, char* p);
-
 struct VoidP{
     PY_CLASS(VoidP, c, void_p)
 
@@ -58,6 +55,10 @@ struct VoidP{
     static void _register(VM* vm, PyObject* mod, PyObject* type);
 };
 
+inline PyObject* py_var(VM* vm, void* p){
+    return VAR_T(VoidP, p);
+}
+
 struct C99Struct{
     PY_CLASS(C99Struct, c, struct)
 
@@ -81,33 +82,14 @@ struct C99Struct{
     }
 
     C99Struct(const C99Struct& other): C99Struct(other.p, other.size){}
-
     ~C99Struct(){ if(p!=_inlined) free(p); }
 
     static void _register(VM* vm, PyObject* mod, PyObject* type);
 };
 
-struct ReflType{
-    std::string_view name;
-    size_t size;
-};
-inline static std::map<std::string_view, ReflType> _refl_types;
-
-inline void add_refl_type(std::string_view name, size_t size){
-    ReflType type{name, size};
-    _refl_types[name] = std::move(type);
-}
-
 static_assert(sizeof(Py_<C99Struct>) <= 64);
 static_assert(sizeof(Py_<Tuple>) <= 64);
 
-inline PyObject* py_var(VM* vm, void* p){
-    return VAR_T(VoidP, p);
-}
-
-inline PyObject* py_var(VM* vm, char* p){
-    return VAR_T(VoidP, p);
-}
 /***********************************************/
 template<typename T>
 T to_void_p(VM* vm, PyObject* var){

+ 1 - 1
include/pocketpy/common.h

@@ -22,7 +22,7 @@
 #include <random>
 #include <bitset>
 
-#define PK_VERSION				"1.2.3"
+#define PK_VERSION				"1.2.4"
 
 #include "config.h"
 #include "export.h"

+ 2 - 1
include/pocketpy/vm.h

@@ -167,7 +167,8 @@ public:
     PyObject* py_iter(PyObject* obj);
 
     PyObject* find_name_in_mro(PyObject* cls, StrName name);
-    bool isinstance(PyObject* obj, Type cls_t);
+    bool isinstance(PyObject* obj, Type base);
+    bool issubclass(Type cls, Type base);
     PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr);
     PyObject* exec(Str source);
     PyObject* eval(Str source);

+ 38 - 84
include/typings/c.pyi

@@ -1,64 +1,53 @@
-from typing import overload
+from typing import overload, Generic, TypeVar
 
 def malloc(size: int) -> 'void_p': ...
 def free(ptr: 'void_p') -> None: ...
-def sizeof(type: str) -> int: ...
 def memset(ptr: 'void_p', value: int, size: int) -> None: ...
 def memcpy(dst: 'void_p', src: 'void_p', size: int) -> None: ...
 
+T = TypeVar('T')
+Tp = TypeVar('Tp', bound='void_p')
+
+def p_cast(ptr: 'void_p', cls: type[T]) -> T:
+    """Cast a pointer to a specific type."""
+def p_value(ptr: 'void_p') -> int:
+    """Get the value of a pointer."""
+def pp_deref(ptr: Tp) -> Tp:
+    """Dereference a double pointer."""
+
 class void_p:
     def __init__(self, addr: int): ...
-    def __add__(self, i: int) -> 'void_p': ...
-    def __sub__(self, i: int) -> 'void_p': ...
     def __eq__(self, other: 'void_p') -> bool: ...
     def __ne__(self, other: 'void_p') -> bool: ...
+    def __lt__(self, other: 'void_p') -> bool: ...
+    def __le__(self, other: 'void_p') -> bool: ...
+    def __gt__(self, other: 'void_p') -> bool: ...
+    def __ge__(self, other: 'void_p') -> bool: ...
     def __hash__(self) -> int: ...
-
-    def hex(self) -> str: ...
-
-    @property
-    def _value(self) -> int: ...
-
-    def read_char(self) -> int: ...
-    def read_uchar(self) -> int: ...
-    def read_short(self) -> int: ...
-    def read_ushort(self) -> int: ...
-    def read_int(self) -> int: ...
-    def read_uint(self) -> int: ...
-    def read_long(self) -> int: ...
-    def read_ulong(self) -> int: ...
-    def read_longlong(self) -> int: ...
-    def read_ulonglong(self) -> int: ...
-    def read_float(self) -> float: ...
-    def read_double(self) -> float: ...
-    def read_bool(self) -> bool: ...
-    def read_void_p(self) -> 'void_p': ...
-    def read_bytes(self, size: int) -> bytes: ...
-    def read_struct(self, size: int) -> 'struct': ...
-
-    def write_char(self, value: int) -> None: ...
-    def write_uchar(self, value: int) -> None: ...
-    def write_short(self, value: int) -> None: ...
-    def write_ushort(self, value: int) -> None: ...
-    def write_int(self, value: int) -> None: ...
-    def write_uint(self, value: int) -> None: ...
-    def write_long(self, value: int) -> None: ...
-    def write_ulong(self, value: int) -> None: ...
-    def write_longlong(self, value: int) -> None: ...
-    def write_ulonglong(self, value: int) -> None: ...
-    def write_float(self, value: float) -> None: ...
-    def write_double(self, value: float) -> None: ...
-    def write_bool(self, value: bool) -> None: ...
-    def write_void_p(self, value: 'void_p') -> None: ...
-    def write_bytes(self, value: bytes) -> None: ...
-    def write_struct(self, value: 'struct') -> None: ...
+    def __repr__(self) -> str: ...
+
+class Pointer(Generic[T], void_p):
+    def read(self) -> T: ...
+    def write(self, value: T) -> None: ...
+    def __getitem__(self, index: int) -> T: ...
+    def __setitem__(self, index: int, value: T) -> None: ...
+
+class char_p(Pointer[int]): pass
+class uchar_p(Pointer[int]): pass
+class short_p(Pointer[int]): pass
+class ushort_p(Pointer[int]): pass
+class int_p(Pointer[int]): pass
+class uint_p(Pointer[int]): pass
+class long_p(Pointer[int]): pass
+class ulong_p(Pointer[int]): pass
+class longlong_p(Pointer[int]): pass
+class ulonglong_p(Pointer[int]): pass
+class float_p(Pointer[float]): pass
+class double_p(Pointer[float]): pass
+class bool_p(Pointer[bool]): pass
 
 class struct:
-    @overload
     def __init__(self, size: int): ...
-    @overload
-    def __init__(self, buffer: bytes): ...
-
     def addr(self) -> 'void_p': ...
     def copy(self) -> 'struct': ...
     def sizeof(self) -> int: ...
@@ -79,7 +68,6 @@ class struct:
     def read_double(self, offset=0) -> float: ...
     def read_bool(self, offset=0) -> bool: ...
     def read_void_p(self, offset=0) -> 'void_p': ...
-
     def write_char(self, value: int, offset=0) -> None: ...
     def write_uchar(self, value: int, offset=0) -> None: ...
     def write_short(self, value: int, offset=0) -> None: ...
@@ -109,48 +97,14 @@ def float_(val: float) -> struct: ...
 def double_(val: float) -> struct: ...
 def bool_(val: bool) -> struct: ...
 
-char_p = void_p
-uchar_p = void_p
-short_p = void_p
-ushort_p = void_p
-int_p = void_p
-uint_p = void_p
-long_p = void_p
-ulong_p = void_p
-longlong_p = void_p
-ulonglong_p = void_p
-float_p = void_p
-double_p = void_p
-bool_p = void_p
-
-class array(struct):
-    count: int
-    item_size: int
-
-    def __new__(cls, count: int, item_size: int): ...
-    def __getitem__(self, index: int) -> struct: ...
-    def __setitem__(self, index: int, value: struct) -> None: ...
-    def __len__(self) -> int: ...
-
-from typing import Generic, TypeVar
-
-T = TypeVar('T')
-
 class _StructLike(Generic[T]):
     def to_struct(self) -> struct: ...
     @classmethod
     def from_struct(cls, s: struct) -> T: ...
 
-    def addr(self) -> '_PointerLike[T]': ...
-    def sizeof(self) -> int: ...
+    def addr(self) -> 'Pointer[T]': ...
     def copy(self) -> T: ...
+    def sizeof(self) -> int: ...
     def __eq__(self, other: T) -> bool: ...
     def __ne__(self, other: T) -> bool: ...
 
-class _PointerLike(Generic[T]):
-    def __eq__(self, other) -> bool: ...
-    def __ne__(self, other) -> bool: ...
-    def __hash__(self) -> int: ...
-
-    @property
-    def _value(self) -> int: ...

+ 0 - 27
python/c.py

@@ -1,27 +0,0 @@
-class array(struct):
-    item_count: int
-    item_size: int
-
-    def __new__(cls, item_count: int, item_size: int = 1):
-        obj = struct.__new__(cls, item_count * item_size)
-        obj._enable_instance_dict()
-        obj.item_count = item_count
-        obj.item_size = item_size
-        return obj
-    
-    def __getitem__(self, index: int) -> struct:
-        if index < 0 or index >= self.item_count:
-            raise IndexError("array index out of range")
-        p = self.addr() + self.item_size * index
-        return p.read_struct(self.item_size)
-    
-    def __setitem__(self, index: int, value: struct) -> None:
-        if index < 0 or index >= self.item_count:
-            raise IndexError("array index out of range")
-        if value.sizeof() != self.item_size:
-            raise ValueError(f"array item size mismatch: {value.sizeof()} != {self.item_size}")
-        p = self.addr() + self.item_size * index
-        p.write_struct(value)
-
-    def __len__(self) -> int:
-        return self.item_count

+ 81 - 122
src/cffi.cpp

@@ -1,5 +1,4 @@
 #include "pocketpy/cffi.h"
-#include "pocketpy/str.h"
 
 namespace pkpy{
 
@@ -10,27 +9,20 @@ namespace pkpy{
             return vm->heap.gcnew<VoidP>(cls, reinterpret_cast<void*>(addr));
         });
 
-        vm->bind_method<0>(type, "hex", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            return VAR(self.hex());
+        vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
+            VoidP& self = _CAST(VoidP&, obj);
+            return reinterpret_cast<i64>(self.ptr);
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
             VoidP& self = _CAST(VoidP&, obj);
-            std::stringstream ss;
-            ss << "<void* at " << self.hex() << ">";
-            return VAR(ss.str());
-        });
-
-        vm->bind_property(type, "_value: int", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            return VAR(reinterpret_cast<i64>(self.ptr));
+            return VAR(fmt("<void* at ", self.hex(), ">"));
         });
 
 #define BIND_CMP(name, op)  \
-        vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){       \
-            if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return vm->NotImplemented;       \
-            return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs));                           \
+        vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){        \
+            if(!vm->isinstance(rhs, VoidP::_type(vm))) return vm->NotImplemented;               \
+            return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs));                               \
         });
 
         BIND_CMP(__eq__, ==)
@@ -40,81 +32,14 @@ namespace pkpy{
         BIND_CMP(__ge__, >=)
 
 #undef BIND_CMP
-
-        vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
-            VoidP& self = _CAST(VoidP&, obj);
-            return reinterpret_cast<i64>(self.ptr);
-        });
-
-        vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            VoidP& self = _CAST(VoidP&, lhs);
-            i64 offset = CAST(i64, rhs);
-            return VAR_T(VoidP, (char*)self.ptr + offset);
-        });
-
-        vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            VoidP& self = _CAST(VoidP&, lhs);
-            i64 offset = CAST(i64, rhs);
-            return VAR_T(VoidP, (char*)self.ptr - offset);
-        });
-
-#define BIND_SETGET(T, name) \
-        vm->bind_method<0>(type, "read_" name, [](VM* vm, ArgsView args){   \
-            VoidP& self = _CAST(VoidP&, args[0]);                   \
-            return VAR(*(T*)self.ptr);                              \
-        });                                                         \
-        vm->bind_method<1>(type, "write_" name, [](VM* vm, ArgsView args){   \
-            VoidP& self = _CAST(VoidP&, args[0]);                   \
-            *(T*)self.ptr = CAST(T, args[1]);                       \
-            return vm->None;                                        \
-        });
-
-        BIND_SETGET(char, "char")
-        BIND_SETGET(unsigned char, "uchar")
-        BIND_SETGET(short, "short")
-        BIND_SETGET(unsigned short, "ushort")
-        BIND_SETGET(int, "int")
-        BIND_SETGET(unsigned int, "uint")
-        BIND_SETGET(long, "long")
-        BIND_SETGET(unsigned long, "ulong")
-        BIND_SETGET(long long, "longlong")
-        BIND_SETGET(unsigned long long, "ulonglong")
-        BIND_SETGET(float, "float")
-        BIND_SETGET(double, "double")
-        BIND_SETGET(bool, "bool")
-        BIND_SETGET(void*, "void_p")
-
-        vm->bind_method<1>(type, "read_bytes", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            i64 size = CAST(i64, args[1]);
-            std::vector<char> buffer(size);
-            memcpy(buffer.data(), self.ptr, size);
-            return VAR(Bytes(std::move(buffer)));
-        });
-
-        vm->bind_method<1>(type, "write_bytes", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            Bytes& bytes = CAST(Bytes&, args[1]);
-            memcpy(self.ptr, bytes.data(), bytes.size());
-            return vm->None;
-        });
-
-#undef BIND_SETGET
     }
 
+
     void C99Struct::_register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){
             Type cls = PK_OBJ_GET(Type, args[0]);
-            if(is_int(args[1])){
-                int size = _CAST(int, args[1]);
-                return vm->heap.gcnew<C99Struct>(cls, size);
-            }
-            if(is_non_tagged_type(args[1], vm->tp_bytes)){
-                const Bytes& b = _CAST(Bytes&, args[1]);
-                return vm->heap.gcnew<C99Struct>(cls, (void*)b.data(), b.size());
-            }
-            vm->TypeError("expected int or bytes");
-            return vm->None;
+            int size = CAST(int, args[1]);
+            return vm->heap.gcnew<C99Struct>(cls, size);
         });
 
         vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
@@ -161,7 +86,6 @@ namespace pkpy{
             *(T*)ptr = CAST(T, args[1]);    \
             return vm->None;    \
         });
-
         BIND_SETGET(char, "char")
         BIND_SETGET(unsigned char, "uchar")
         BIND_SETGET(short, "short")
@@ -177,22 +101,6 @@ namespace pkpy{
         BIND_SETGET(bool, "bool")
         BIND_SETGET(void*, "void_p")
 #undef BIND_SETGET
-
-        // patch VoidP
-        type = vm->_t(VoidP::_type(vm));
-
-        vm->bind_method<1>(type, "read_struct", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            int size = CAST(int, args[1]);
-            return VAR_T(C99Struct, self.ptr, size);
-        });
-
-        vm->bind_method<1>(type, "write_struct", [](VM* vm, ArgsView args){
-            VoidP& self = _CAST(VoidP&, args[0]);
-            C99Struct& other = CAST(C99Struct&, args[1]);
-            memcpy(self.ptr, other.p, other.size);
-            return vm->None;
-        });
     }
 
 void add_module_c(VM* vm){
@@ -225,28 +133,81 @@ void add_module_c(VM* vm){
     });
 #endif
 
-    vm->bind_func<1>(mod, "sizeof", [](VM* vm, ArgsView args){
-        const Str& type = CAST(Str&, args[0]);
-        auto it = _refl_types.find(type.sv());
-        if(it != _refl_types.end()) return VAR(it->second.size);
-        vm->ValueError("not a valid c99 type");
-        return vm->None;
-    });
-
     VoidP::register_class(vm, mod);
     C99Struct::register_class(vm, mod);
     mod->attr().set("NULL", VAR_T(VoidP, nullptr));
 
-    add_refl_type("void_p", sizeof(void*));
-    PyObject* void_p_t = mod->attr("void_p");
+    vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args){
+        VoidP& ptr = CAST(VoidP&, args[0]);
+        vm->check_non_tagged_type(args[1], vm->tp_type);
+        Type cls = PK_OBJ_GET(Type, args[1]);
+        if(!vm->issubclass(cls, VoidP::_type(vm))){
+            vm->ValueError("expected a subclass of void_p");
+        }
+        return vm->heap.gcnew<VoidP>(cls, ptr.ptr);
+    });
+
+    vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args){
+        VoidP& ptr = CAST(VoidP&, args[0]);
+        return VAR(reinterpret_cast<i64>(ptr.ptr));
+    });
+
+    vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){
+        VoidP& ptr = CAST(VoidP&, args[0]);
+        void* value = *reinterpret_cast<void**>(ptr.ptr);
+        return vm->heap.gcnew<VoidP>(args[0]->type, value);
+    });
 
-#define BIND_PRIMITIVE(T, name) \
-    vm->bind_func<1>(mod, name "_", [](VM* vm, ArgsView args){      \
-        T val = CAST(T, args[0]);                                   \
-        return VAR_T(C99Struct, &val, sizeof(T));                   \
-    });                                                             \
-    add_refl_type(name, sizeof(T));                                 \
-    mod->attr().set(name "_p", void_p_t);                           \
+    PyObject* type;
+    Type type_t;
+
+#define BIND_PRIMITIVE(T, CNAME) \
+    vm->bind_func<1>(mod, CNAME "_", [](VM* vm, ArgsView args){        \
+        T val = CAST(T, args[0]);                                       \
+        return VAR_T(C99Struct, &val, sizeof(T));                       \
+    });                                                                 \
+    type = vm->new_type_object(mod, CNAME "_p", VoidP::_type(vm));     \
+    type_t = PK_OBJ_GET(Type, type);                                    \
+    vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){         \
+        VoidP& voidp = PK_OBJ_GET(VoidP, args[0]);                      \
+        T* target = (T*)voidp.ptr;                                      \
+        return VAR(*target);                                            \
+    });                                                                 \
+    vm->bind_method<1>(type, "write", [](VM* vm, ArgsView args){        \
+        VoidP& voidp = PK_OBJ_GET(VoidP, args[0]);                      \
+        T val = CAST(T, args[1]);                                       \
+        T* target = (T*)voidp.ptr;                                      \
+        *target = val;                                                  \
+        return vm->None;                                                \
+    });                                                                 \
+    vm->bind__getitem__(type_t, [](VM* vm, PyObject* obj, PyObject* index){  \
+        VoidP& voidp = PK_OBJ_GET(VoidP, obj);                               \
+        i64 offset = CAST(i64, index);                                  \
+        T* target = (T*)voidp.ptr;                                      \
+        return VAR(target[offset]);                                     \
+    });                                                                 \
+    vm->bind__setitem__(type_t, [](VM* vm, PyObject* obj, PyObject* index, PyObject* value){   \
+        VoidP& voidp = PK_OBJ_GET(VoidP, obj);                          \
+        i64 offset = CAST(i64, index);                                  \
+        T* target = (T*)voidp.ptr;                                      \
+        target[offset] = CAST(T, value);                                \
+    });                                                                 \
+    vm->bind__add__(type_t, [](VM* vm, PyObject* lhs, PyObject* rhs){   \
+        VoidP& voidp = PK_OBJ_GET(VoidP, lhs);                          \
+        i64 offset = CAST(i64, rhs);                                    \
+        T* target = (T*)voidp.ptr;                                      \
+        return vm->heap.gcnew<VoidP>(lhs->type, target + offset);       \
+    });                                                                 \
+    vm->bind__sub__(type_t, [](VM* vm, PyObject* lhs, PyObject* rhs){   \
+        VoidP& voidp = PK_OBJ_GET(VoidP, lhs);                          \
+        i64 offset = CAST(i64, rhs);                                    \
+        T* target = (T*)voidp.ptr;                                      \
+        return vm->heap.gcnew<VoidP>(lhs->type, target - offset);       \
+    });                                                                 \
+    vm->bind__repr__(type_t, [](VM* vm, PyObject* obj){                 \
+        VoidP& self = _CAST(VoidP&, obj);                               \
+        return VAR(fmt("<", CNAME, "* at ", self.hex(), ">"));         \
+    });                                                                 \
 
     BIND_PRIMITIVE(char, "char")
     BIND_PRIMITIVE(unsigned char, "uchar")
@@ -262,9 +223,7 @@ void add_module_c(VM* vm){
     BIND_PRIMITIVE(double, "double")
     BIND_PRIMITIVE(bool, "bool")
 
-    // add array type
-    CodeObject_ code = vm->compile(kPythonLibs["c"], "c.py", EXEC_MODE);
-    vm->_exec(code, mod);
+#undef BIND_PRIMITIVE
 }
 
 }   // namespace pkpy

+ 9 - 5
src/vm.cpp

@@ -79,13 +79,17 @@ namespace pkpy{
         return nullptr;
     }
 
-    bool VM::isinstance(PyObject* obj, Type cls_t){
+    bool VM::isinstance(PyObject* obj, Type base){
         Type obj_t = PK_OBJ_GET(Type, _t(obj));
+        return issubclass(obj_t, base);
+    }
+
+    bool VM::issubclass(Type cls, Type base){
         do{
-            if(obj_t == cls_t) return true;
-            Type base = _all_types[obj_t].base;
-            if(base.index == -1) break;
-            obj_t = base;
+            if(cls == base) return true;
+            Type next = _all_types[cls].base;
+            if(next.index == -1) break;
+            cls = next;
         }while(true);
         return false;
     }

+ 21 - 22
tests/80_c.py

@@ -1,33 +1,32 @@
 import c
 
-array = c.malloc(c.sizeof("int") * 10)
+a = c.malloc(100)
+c.free(a)
 
-for i in range(10):
-    off = c.sizeof("int") * i
-    (array+off).write_int(i)
-
-x = c.int_(0)
-for i in range(10):
-    off = c.sizeof("int") * i
-    i = (array+off).read_int()
-    x.write_int(x.read_int() + i)
+a = c.malloc(100)
+c.memset(a, 0, 100)
+b = c.malloc(100)
+b = c.memcpy(b, a, 100)
 
-assert x.read_int() == (0+9)*10//2
+bp = c.p_cast(a, c.int_p)
 
-c.memset(array, 0, c.sizeof("int") * 10)
+assert c.p_value(c.NULL) == 0
+assert c.NULL == c.NULL
+assert c.NULL != a
 
 for i in range(10):
-    off = c.sizeof("int") * i
-    assert (array+off).read_char() == 0
+    bp[i] = i
+    assert bp[i] == i
+    (bp+i).write(i)
+    assert (bp+i).read() == i
 
-array2 = c.malloc(c.sizeof("int") * 10)
-c.memcpy(array2, array, c.sizeof("int") * 10)
-for i in range(10):
-    off = c.sizeof("int") * i
-    assert (array+off).read_char() == 0
+i = c.float_(10)
+assert i.sizeof() == 4
+j = i.copy()
+assert i == j
+assert i is not j
 
-c.free(array)
-c.free(array2)
+####################
 
 class Vec2(c.struct):
     def __new__(cls, x: float, y: float):
@@ -50,4 +49,4 @@ class Vec2(c.struct):
 a = Vec2(1, 2)
 assert isinstance(a, c.struct)
 assert type(a) is Vec2
-assert repr(a) == "Vec2(1.0, 2.0)"
+assert repr(a) == "Vec2(1.0, 2.0)"

+ 0 - 58
tests/99_cffi_2.py

@@ -1,58 +0,0 @@
-import c
-
-assert c.NULL == c.void_p(0)
-# ------------------------------------------------
-# 此处测试并不完全
-c_void_1 = c.malloc(8)
-c_void_1.read_bytes(5)
-c_void_1.write_bytes(c_void_1.read_bytes(5))
-# ------------------------------------------------
-c_void_1 = c.malloc(32)
-my_struct2 = c_void_1.read_struct(32)
-assert my_struct2.sizeof() == 32
-
-data_bytes = bytes([1,2,3])
-my_struct4 = c.struct(data_bytes)
-
-try:
-   c.struct(True)
-   raise Exception('c.struct 的构造方法未能触发 TypeError("expected int or bytes")')
-except TypeError:
-   pass
-
-try:
-   c.struct(1,2,3)
-   raise Exception('c.struct 的构造方法未能触发 TypeError("expected 1 or 2 arguments")')
-except TypeError:
-   pass
-# ------------------------------------------------
-my_struct1 = c.struct(16)
-assert my_struct1.sizeof() == 16
-
-# 对 c.struct 的 copy 方法的测试不完全
-assert my_struct1.copy().sizeof() == 16
-
-data_bytes = bytes([1,2,3])
-my_struct4 = c.struct(data_bytes)
-assert my_struct4.addr().read_bytes(
-    my_struct4.sizeof()
-) == data_bytes
-
-
-# ------------------------------------------------
-# 此处测试并不完全
-c_void_1 = c.malloc(16)
-my_struct1 = c.struct(16)
-c_void_1.write_struct(my_struct1)
-assert c_void_1.read_struct(16) == my_struct1
-
-from c import array, int_, NULL
-
-assert NULL._value == 0
-
-a = array(10, item_size=4)
-assert a.item_count == 10
-assert a.item_size == 4
-
-a[4] = int_(123)
-assert a[4] == int_(123)