blueloveTH před 2 měsíci
rodič
revize
2eb84b562e

+ 3 - 0
.gitmodules

@@ -4,3 +4,6 @@
 [submodule "3rd/dmath/dmath"]
 	path = 3rd/dmath/dmath
 	url = https://github.com/pocketpy/dmath
+[submodule "3rd/periphery/c-periphery"]
+	path = 3rd/periphery/c-periphery
+	url = https://github.com/vsergeev/c-periphery.git

+ 1 - 0
3rd/periphery/c-periphery

@@ -0,0 +1 @@
+Subproject commit 76c4edd4b5c43a597fd37c618ed32dbc2a27ec40

+ 1 - 0
include/pocketpy/interpreter/modules.h

@@ -19,6 +19,7 @@ void pk__add_module_base64();
 void pk__add_module_importlib();
 void pk__add_module_unicodedata();
 
+void pk__add_module_stdc();
 void pk__add_module_vmath();
 void pk__add_module_array2d();
 void pk__add_module_colorcvt();

+ 10 - 0
include/pocketpy/pocketpy.h

@@ -876,6 +876,16 @@ enum py_PredefinedType {
     tp_ImportError,
     tp_AssertionError,
     tp_KeyError,
+    /* stdc */
+    tp_stdc_Memory,
+    tp_stdc_Char, tp_stdc_UChar,
+    tp_stdc_Short, tp_stdc_UShort,
+    tp_stdc_Int, tp_stdc_UInt,
+    tp_stdc_Long, tp_stdc_ULong,
+    tp_stdc_LongLong, tp_stdc_ULongLong,
+    tp_stdc_Float, tp_stdc_Double,
+    tp_stdc_Pointer,
+    tp_stdc_Bool,
     /* vmath */
     tp_vec2,
     tp_vec3,

+ 21 - 0
include/typings/picoterm_io.pyi

@@ -0,0 +1,21 @@
+from typing import Literal
+from vmath import vec2, color32
+from cute_png import Image
+
+def read_axis(self) -> vec2: ...
+
+def read_button(self, index: Literal[0, 1, 2, 3, 4, 5], ttl_ms: int = 10) -> bool: ...
+def read_all_buttons(self, out_list: list[bool], ttl_ms: int = 10) -> None: ...
+def clear_button(self, index: Literal[0, 1, 2, 3, 4, 5]) -> None: ...
+def clear_all_buttons(self) -> None: ...
+
+def read_buzzer_freq(self) -> int: ...
+def read_buzzer_volume(self) -> float: ...
+def write_buzzer_freq(self, freq: int) -> None: ...
+def write_buzzer_volume(self, volume: float) -> None: ...
+
+def write_fb0(self, image: Image) -> None: ...
+
+def read_led(self, index: Literal[0, 1, 2, 3]) -> color32: ...
+def write_led(self, index: int, color: color32) -> None: ...
+def write_leds(self, _0: color32 | None, _1: color32 | None, _2: color32 | None, _3: color32 | None) -> None: ...

+ 61 - 0
include/typings/stdc.pyi

@@ -0,0 +1,61 @@
+from typing import overload, Self
+
+intptr = int
+
+def malloc(size: int) -> intptr: ...
+def free(ptr: intptr) -> None: ...
+
+def memcpy(dst: intptr, src: intptr, n: int) -> None: ...
+def memset(s: intptr, c: int, n: int) -> None: ...
+def memcmp(s1: intptr, s2: intptr, n: int) -> int: ...
+
+def addressof(obj: Memory) -> intptr: ...
+def sizeof(obj: type[Memory]) -> int: ...
+
+def read_cstr(p: intptr) -> str: ...
+def read_bytes(p: intptr, n: int) -> bytes: ...
+def write_cstr(p: intptr, data: str) -> None: ...
+def write_bytes(p: intptr, data: bytes) -> None: ...
+
+class Memory: ...
+
+class _BuiltinMemory[T](Memory):
+    value: T
+
+    def __new__(cls, value: T | None = None) -> None: ...
+    @staticmethod
+    def read(p: intptr, offset: int) -> T: ...
+    @staticmethod
+    def write(p: intptr, offset: int, value: T) -> None: ...
+    @staticmethod
+    def array(length: int) -> Self: ...
+
+    @property
+    def size(self) -> int: ...
+
+    def __getitem__(self, index: int) -> T: ...
+    def __setitem__(self, index: int, value: T) -> None: ...
+
+class Char(_BuiltinMemory[int]): ...
+class UChar(_BuiltinMemory[int]): ...
+class Short(_BuiltinMemory[int]): ...
+class UShort(_BuiltinMemory[int]): ...
+class Int(_BuiltinMemory[int]): ...
+class UInt(_BuiltinMemory[int]): ...
+class Long(_BuiltinMemory[int]): ...
+class ULong(_BuiltinMemory[int]): ...
+class LongLong(_BuiltinMemory[int]): ...
+
+class Float(_BuiltinMemory[float]): ...
+class Double(_BuiltinMemory[float]): ...
+class Pointer(_BuiltinMemory[intptr]): ...
+class Bool(_BuiltinMemory[bool]): ...
+
+INT8: _BuiltinMemory[int]
+UINT8: _BuiltinMemory[int]
+INT16: _BuiltinMemory[int]
+UINT16: _BuiltinMemory[int]
+INT32: _BuiltinMemory[int]
+UINT32: _BuiltinMemory[int]
+INT64: _BuiltinMemory[int]
+UINT64: _BuiltinMemory[int]

+ 8 - 1
scripts/c_bind/c_bind/function.py

@@ -2,6 +2,12 @@ from .writer import Writer
 from .converters import get_converter
 from .schema import Function
 
+from keyword import iskeyword
+
+def sanitize_name(name: str):
+    if iskeyword(name):
+        return name + '_'
+    return name
 
 def gen_function(w: Writer, pyi_w: Writer, function: Function):
     name = function.name
@@ -35,10 +41,11 @@ def gen_function(w: Writer, pyi_w: Writer, function: Function):
     # pyi
     py_args = []
     # arg_names = [f'_{i}' for i in range(len(args_cvt))]
-    arg_names = [arg.name for arg in function.params]
+    arg_names = [sanitize_name(arg.name) for arg in function.params]
     for i in range(len(args_cvt)):
         py_args.append(f'{arg_names[i]}: {args_cvt[i].py_T}')
 
+    py_args.append('/')
     pyi_w.write(f'def {name}({", ".join(py_args)}) -> {ret_cvt.py_T}:')
     if function.desc:
         pyi_w.write(f'    """Wraps `{function.signature()}`\n\n    {function.desc}"""')

+ 2 - 2
scripts/c_bind/c_bind/library.py

@@ -191,8 +191,8 @@ class Library:
             self.functions.append(Function(
                 name=function.name,
                 params=[FunctionParam(
-                    type=param,
-                    name=f'_{i}'
+                    type=param[0],
+                    name=param[1] or f'_{i}'
                 ) for i, param in enumerate(function.args)],
                 ret_type=function.ret
             ))

+ 1 - 1
scripts/c_bind/c_bind/meta/parser.py

@@ -129,7 +129,7 @@ class Header:
                 else:
                     T, name = self.build_param(param)
                     if T != 'void':
-                        func.args.append(T)
+                        func.args.append((T, name))
         self.functions.append(func)
 
     def build(self, ast: c_ast.FileAST):

+ 1 - 1
scripts/c_bind/c_bind/meta/schema.py

@@ -32,7 +32,7 @@ class Enum:
 class Function:
     def __init__(self, name: str, ret: str):
         self.name = name
-        self.args = [] # type: list[str]
+        self.args = [] # type: list[tuple[str, str]]
         self.ret = ret
 
     def __repr__(self):

+ 26 - 0
scripts/c_bind/gen_periphery.py

@@ -0,0 +1,26 @@
+import pcpp
+import pycparser
+from c_bind import Library, set_vmath_converter, set_enum_converters
+from c_bind.meta import Header
+import os
+
+file_dir = os.path.dirname(os.path.abspath(__file__))
+
+path = '3rd/periphery/c-periphery/src/gpio.h'
+code = pcpp.CmdPreprocessor([None, path, '-o', 'tmp.h', '-I', os.path.join(file_dir, 'libc_include')])
+
+ast = pycparser.parse_file('tmp.h')
+os.remove('tmp.h')
+
+header = Header()
+header.build(ast)
+
+lib = Library.from_header('periphery', header)
+
+set_enum_converters([enum.name for enum in lib.enums])
+
+lib.build(
+    includes=['c-periphery/gpio.h'],
+    glue_dir='3rd/periphery/src',
+    stub_dir='include/typings'
+)

+ 2 - 0
scripts/c_bind/requirements.txt

@@ -0,0 +1,2 @@
+pcpp
+pycparser

+ 1 - 0
src/interpreter/vm.c

@@ -237,6 +237,7 @@ void VM__ctor(VM* self) {
 
     py_newnotimplemented(py_emplacedict(self->builtins, py_name("NotImplemented")));
 
+    pk__add_module_stdc();
     pk__add_module_vmath();
     pk__add_module_array2d();
     pk__add_module_colorcvt();

+ 275 - 0
src/modules/stdc.c

@@ -0,0 +1,275 @@
+#include "pocketpy/pocketpy.h"
+#include "pocketpy/interpreter/vm.h"
+#include <string.h>
+
+#define DEF_BUILTIN_MEMORY_T(Char_, char_, tp_int_, py_newint_, py_toint_, py_i64_)                \
+    static bool stdc_##Char_##__new__(int argc, py_Ref argv) {                                     \
+        char_* ud = py_newobject(py_retval(), tp_stdc_##Char_, 0, sizeof(char_));                  \
+        if(argc == 2) {                                                                            \
+            PY_CHECK_ARG_TYPE(1, tp_int_);                                                         \
+            *ud = (char_)py_toint_(&argv[1]);                                                      \
+        } else if(argc > 2) {                                                                      \
+            return TypeError("expected 1 or 2 arguments, got %d", argc);                           \
+        }                                                                                          \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__get_value(int argc, py_Ref argv) {                                 \
+        PY_CHECK_ARGC(1);                                                                          \
+        char_* ud = py_touserdata(argv);                                                           \
+        py_newint_(py_retval(), (py_i64_)(*ud));                                                   \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__set_value(int argc, py_Ref argv) {                                 \
+        PY_CHECK_ARGC(2);                                                                          \
+        char_* ud = py_touserdata(argv);                                                           \
+        PY_CHECK_ARG_TYPE(1, tp_int_);                                                             \
+        *ud = (char_)py_toint_(&argv[1]);                                                          \
+        py_newnone(py_retval());                                                                   \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__read_STATIC(int argc, py_Ref argv) {                               \
+        PY_CHECK_ARGC(2);                                                                          \
+        PY_CHECK_ARG_TYPE(0, tp_int);                                                              \
+        PY_CHECK_ARG_TYPE(1, tp_int);                                                              \
+        char_* p = (char_*)(intptr_t)py_toint(&argv[0]);                                           \
+        int offset = py_toint(&argv[1]);                                                           \
+        py_newint_(py_retval(), (py_i64_)(p[offset]));                                             \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__write_STATIC(int argc, py_Ref argv) {                              \
+        PY_CHECK_ARGC(3);                                                                          \
+        PY_CHECK_ARG_TYPE(0, tp_int);                                                              \
+        PY_CHECK_ARG_TYPE(1, tp_int);                                                              \
+        PY_CHECK_ARG_TYPE(2, tp_int_);                                                             \
+        char_* p = (char_*)(intptr_t)py_toint(&argv[0]);                                           \
+        int offset = py_toint(&argv[1]);                                                           \
+        p[offset] = (char_)py_toint_(&argv[2]);                                                    \
+        py_newnone(py_retval());                                                                   \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__array_STATIC(int argc, py_Ref argv) {                              \
+        PY_CHECK_ARGC(1);                                                                          \
+        PY_CHECK_ARG_TYPE(0, tp_int);                                                              \
+        int length = py_toint(argv);                                                               \
+        int size = sizeof(char_) * length;                                                         \
+        py_newobject(py_retval(), tp_stdc_##Char_, 0, size);                                       \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__getitem__(int argc, py_Ref argv) {                                 \
+        PY_CHECK_ARGC(2);                                                                          \
+        char_* ud = py_touserdata(argv);                                                           \
+        PY_CHECK_ARG_TYPE(1, tp_int);                                                              \
+        int index = py_toint(&argv[1]);                                                            \
+        py_newint_(py_retval(), (py_i64_)(ud[index]));                                             \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool stdc_##Char_##__setitem__(int argc, py_Ref argv) {                                 \
+        PY_CHECK_ARGC(3);                                                                          \
+        char_* ud = py_touserdata(argv);                                                           \
+        PY_CHECK_ARG_TYPE(1, tp_int);                                                              \
+        PY_CHECK_ARG_TYPE(2, tp_int_);                                                             \
+        int index = py_toint(&argv[1]);                                                            \
+        ud[index] = (char_)py_toint_(&argv[2]);                                                    \
+        py_newnone(py_retval());                                                                   \
+        return true;                                                                               \
+    }                                                                                              \
+    static void pk__bind_stdc_##Char_(py_Ref mod) {                                                \
+        py_Type type = py_newtype(#Char_, tp_stdc_Memory, mod, NULL);                              \
+        py_tpsetfinal(type);                                                                       \
+        assert(type == tp_stdc_##Char_);                                                           \
+        py_bindmagic(type, __new__, stdc_##Char_##__new__);                                        \
+        py_bindmagic(type, __getitem__, stdc_##Char_##__getitem__);                                \
+        py_bindmagic(type, __setitem__, stdc_##Char_##__setitem__);                                \
+        py_bindproperty(type, "value", stdc_##Char_##__get_value, stdc_##Char_##__set_value);      \
+        py_bindstaticmethod(type, "read", stdc_##Char_##__read_STATIC);                            \
+        py_bindstaticmethod(type, "write", stdc_##Char_##__write_STATIC);                          \
+        py_bindstaticmethod(type, "array", stdc_##Char_##__array_STATIC);                          \
+        py_newint(py_emplacedict(py_tpobject(type), py_name("size")), sizeof(char_));              \
+    }
+
+DEF_BUILTIN_MEMORY_T(Char, char, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(UChar, unsigned char, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(Short, short, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(UShort, unsigned short, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(Int, int, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(UInt, unsigned int, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(Long, long, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(ULong, unsigned long, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(LongLong, long long, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(ULongLong, unsigned long long, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(Float, float, tp_float, py_newfloat, py_tofloat, float)
+DEF_BUILTIN_MEMORY_T(Double, double, tp_float, py_newfloat, py_tofloat, double)
+DEF_BUILTIN_MEMORY_T(Pointer, void*, tp_int, py_newint, py_toint, py_i64)
+DEF_BUILTIN_MEMORY_T(Bool, bool, tp_bool, py_newbool, py_tobool, bool)
+
+#undef DEF_BUILTIN_MEMORY_T
+
+static bool stdc_malloc(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    py_i64 size = py_toint(&argv[0]);
+    void* p = py_malloc(size);
+    py_newint(py_retval(), (py_i64)(intptr_t)p);
+    return true;
+}
+
+static bool stdc_free(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    void* p = (void*)(intptr_t)py_toint(&argv[0]);
+    py_free(p);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool stdc_memcpy(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(3);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_int);
+    PY_CHECK_ARG_TYPE(2, tp_int);
+    void* dst = (void*)(intptr_t)py_toint(&argv[0]);
+    void* src = (void*)(intptr_t)py_toint(&argv[1]);
+    py_i64 n = py_toint(&argv[2]);
+    memcpy(dst, src, (size_t)n);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool stdc_memset(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(3);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_int);
+    PY_CHECK_ARG_TYPE(2, tp_int);
+    void* dst = (void*)(intptr_t)py_toint(&argv[0]);
+    int value = (int)py_toint(&argv[1]);
+    py_i64 n = py_toint(&argv[2]);
+    memset(dst, value, (size_t)n);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool stdc_memcmp(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(3);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_int);
+    PY_CHECK_ARG_TYPE(2, tp_int);
+    void* p1 = (void*)(intptr_t)py_toint(&argv[0]);
+    void* p2 = (void*)(intptr_t)py_toint(&argv[1]);
+    py_i64 n = py_toint(&argv[2]);
+    int res = memcmp(p1, p2, (size_t)n);
+    py_newint(py_retval(), (py_i64)res);
+    return true;
+}
+
+static bool stdc_addressof(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    if(!py_checkinstance(argv, tp_stdc_Memory)) return false;
+    void* ud = py_touserdata(argv);
+    py_newint(py_retval(), (py_i64)(intptr_t)ud);
+    return true;
+}
+
+static bool stdc_sizeof(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    PY_CHECK_ARG_TYPE(0, tp_type);
+    py_Type type = py_totype(&argv[0]);
+    if(!py_issubclass(type, tp_stdc_Memory)) {
+        return TypeError("expected a type derived from stdc.Memory");
+    }
+    py_assign(py_retval(), py_getdict(py_tpobject(type), py_name("size")));
+    return true;
+}
+
+static bool stdc_read_cstr(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    char* p = (char*)(intptr_t)py_toint(&argv[0]);
+    py_newstr(py_retval(), p);
+    return true;
+}
+
+static bool stdc_write_cstr(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(2);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_str);
+    char* p = (char*)(intptr_t)py_toint(&argv[0]);
+    c11_sv sv = py_tosv(&argv[1]);
+    memcpy(p, sv.data, sv.size);
+    p[sv.size] = '\0';
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool stdc_read_bytes(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(2);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_int);
+    unsigned char* p = (unsigned char*)(intptr_t)py_toint(&argv[0]);
+    int size = py_toint(&argv[1]);
+    unsigned char* dst = py_newbytes(py_retval(), size);
+    memcpy(dst, p, size);
+    return true;
+}
+
+static bool stdc_write_bytes(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(2);
+    PY_CHECK_ARG_TYPE(0, tp_int);
+    PY_CHECK_ARG_TYPE(1, tp_bytes);
+    unsigned char* p = (unsigned char*)(intptr_t)py_toint(&argv[0]);
+    int size;
+    unsigned char* src = py_tobytes(&argv[1], &size);
+    memcpy(p, src, size);
+    py_newnone(py_retval());
+    return true;
+}
+
+void pk__add_module_stdc() {
+    py_Ref mod = py_newmodule("stdc");
+
+    py_bindfunc(mod, "malloc", stdc_malloc);
+    py_bindfunc(mod, "free", stdc_free);
+    py_bindfunc(mod, "memcpy", stdc_memcpy);
+    py_bindfunc(mod, "memset", stdc_memset);
+    py_bindfunc(mod, "memcmp", stdc_memcmp);
+
+    py_bindfunc(mod, "addressof", stdc_addressof);
+    py_bindfunc(mod, "sizeof", stdc_sizeof);
+
+    py_bindfunc(mod, "read_cstr", stdc_read_cstr);
+    py_bindfunc(mod, "write_cstr", stdc_write_cstr);
+    py_bindfunc(mod, "read_bytes", stdc_read_bytes);
+    py_bindfunc(mod, "write_bytes", stdc_write_bytes);
+
+    py_Type Memory = py_newtype("Memory", tp_object, mod, NULL);
+    assert(Memory == tp_stdc_Memory);
+
+    pk__bind_stdc_Char(mod);
+    pk__bind_stdc_UChar(mod);
+    pk__bind_stdc_Short(mod);
+    pk__bind_stdc_UShort(mod);
+    pk__bind_stdc_Int(mod);
+    pk__bind_stdc_UInt(mod);
+    pk__bind_stdc_Long(mod);
+    pk__bind_stdc_ULong(mod);
+    pk__bind_stdc_LongLong(mod);
+    pk__bind_stdc_ULongLong(mod);
+
+    for(int size = 1; size <= 8; size *= 2) {
+        for(py_Type t = tp_stdc_Char; t <= tp_stdc_ULongLong; t += 2) {
+            py_Ref size_var = py_getdict(py_tpobject(t), py_name("size"));
+            if(py_toint(size_var) == size) {
+                char buf[16];
+                snprintf(buf, sizeof(buf), "Int%d", size * 8);
+                py_setdict(mod, py_name(buf), py_tpobject(t));
+                snprintf(buf, sizeof(buf), "UInt%d", size * 8);
+                py_setdict(mod, py_name(buf), py_tpobject(t + 1));
+                break;
+            }
+        }
+    }
+
+    pk__bind_stdc_Float(mod);
+    pk__bind_stdc_Double(mod);
+    pk__bind_stdc_Pointer(mod);
+    pk__bind_stdc_Bool(mod);
+}

+ 62 - 0
tests/793_stdc.py

@@ -0,0 +1,62 @@
+from stdc import *
+
+assert sizeof(Int8) == sizeof(UInt8) == 1
+assert sizeof(Int16) == sizeof(UInt16) == 2
+assert sizeof(Int32) == sizeof(UInt32) == 4
+assert sizeof(Int64) == sizeof(UInt64) == 8
+
+assert sizeof(Float) == 4
+assert sizeof(Double) == 8
+
+assert sizeof(Bool) == 1
+assert sizeof(Pointer) in (4, 8)
+
+x = Int32(42)
+assert x.value == 42
+x.value = 100
+assert x.value == 100
+
+Int32.read(addressof(x), 0) == 100
+Int32.write(addressof(x), 0, 200)
+assert x.value == 200
+
+# test array
+arr = Int32.array(3)
+arr[0] = 10
+arr[1] = 20
+arr[2] = 30
+assert arr[0] == 10
+assert arr[1] == 20
+assert arr[2] == 30
+
+# test malloc, memset, memcpy
+p = malloc(3 * sizeof(Int32))
+memset(p, 0, 3 * sizeof(Int32))
+memcpy(p, addressof(arr), 3 * sizeof(Int32))
+for i in range(3):
+    assert arr[i] == Int32.read(p, i)
+
+assert memcmp(p, addressof(arr), 3 * sizeof(Int32)) == 0
+
+# test free
+free(p)
+
+# test float
+y = Double.array(3)
+y[0] = 1.1
+y[1] = 2.2
+y[2] = 3.3
+assert Double.read(addressof(y), 0) == 1.1
+assert Double.read(addressof(y), 1) == 2.2
+assert Double.read(addressof(y), 2) == 3.3
+
+# test read_cstr and write_cstr
+a = Char.array(20)
+write_cstr(addressof(a), "hello")
+assert read_cstr(addressof(a)) == "hello"
+
+a[3] = 0
+assert read_cstr(addressof(a)) == "hel"
+
+# test read_bytes and write_bytes
+assert read_bytes(addressof(a), 5) == b'hel\x00o'