mirror of
https://github.com/pocketpy/pocketpy
synced 2026-02-04 14:40:16 +00:00
Compare commits
2 Commits
0eabbda7d4
...
64ec1ed313
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ec1ed313 | ||
|
|
2eb84b562e |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
3rd/periphery/c-periphery
Submodule
1
3rd/periphery/c-periphery
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 76c4edd4b5c43a597fd37c618ed32dbc2a27ec40
|
||||
@ -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();
|
||||
|
||||
@ -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
include/typings/picoterm_io.pyi
Normal file
21
include/typings/picoterm_io.pyi
Normal file
@ -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: ...
|
||||
60
include/typings/stdc.pyi
Normal file
60
include/typings/stdc.pyi
Normal file
@ -0,0 +1,60 @@
|
||||
from typing import Self, ClassVar
|
||||
|
||||
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 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:
|
||||
size: ClassVar[int]
|
||||
|
||||
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: ...
|
||||
@classmethod
|
||||
def array(cls, length: int) -> Self: ...
|
||||
|
||||
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] = ...
|
||||
|
||||
def addressof(obj: Memory) -> intptr: ...
|
||||
def sizeof(obj: type[Memory]) -> int: ...
|
||||
|
||||
@ -28,6 +28,8 @@ Type = _PLACEHOLDER
|
||||
TypeAlias = _PLACEHOLDER
|
||||
NewType = _PLACEHOLDER
|
||||
|
||||
ClassVar = _PLACEHOLDER
|
||||
|
||||
Literal = _PLACEHOLDER
|
||||
LiteralString = _PLACEHOLDER
|
||||
|
||||
|
||||
@ -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}"""')
|
||||
|
||||
@ -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
|
||||
))
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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
scripts/c_bind/gen_periphery.py
Normal file
26
scripts/c_bind/gen_periphery.py
Normal file
@ -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
scripts/c_bind/requirements.txt
Normal file
2
scripts/c_bind/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pcpp
|
||||
pycparser
|
||||
@ -11,7 +11,7 @@ const char kPythonLibs_functools[] = "class cache:\n def __init__(self, f):\n
|
||||
const char kPythonLibs_heapq[] = "# Heap queue algorithm (a.k.a. priority queue)\ndef heappush(heap, item):\n \"\"\"Push item onto heap, maintaining the heap invariant.\"\"\"\n heap.append(item)\n _siftdown(heap, 0, len(heap)-1)\n\ndef heappop(heap):\n \"\"\"Pop the smallest item off the heap, maintaining the heap invariant.\"\"\"\n lastelt = heap.pop() # raises appropriate IndexError if heap is empty\n if heap:\n returnitem = heap[0]\n heap[0] = lastelt\n _siftup(heap, 0)\n return returnitem\n return lastelt\n\ndef heapreplace(heap, item):\n \"\"\"Pop and return the current smallest value, and add the new item.\n\n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed-size heap. Note that the value\n returned may be larger than item! That constrains reasonable uses of\n this routine unless written as part of a conditional replacement:\n\n if item > heap[0]:\n item = heapreplace(heap, item)\n \"\"\"\n returnitem = heap[0] # raises appropriate IndexError if heap is empty\n heap[0] = item\n _siftup(heap, 0)\n return returnitem\n\ndef heappushpop(heap, item):\n \"\"\"Fast version of a heappush followed by a heappop.\"\"\"\n if heap and heap[0] < item:\n item, heap[0] = heap[0], item\n _siftup(heap, 0)\n return item\n\ndef heapify(x):\n \"\"\"Transform list into a heap, in-place, in O(len(x)) time.\"\"\"\n n = len(x)\n # Transform bottom-up. The largest index there's any point to looking at\n # is the largest with a child index in-range, so must have 2*i + 1 < n,\n # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so\n # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is\n # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.\n for i in reversed(range(n//2)):\n _siftup(x, i)\n\n# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos\n# is the index of a leaf with a possibly out-of-order value. Restore the\n# heap invariant.\ndef _siftdown(heap, startpos, pos):\n newitem = heap[pos]\n # Follow the path to the root, moving parents down until finding a place\n # newitem fits.\n while pos > startpos:\n parentpos = (pos - 1) >> 1\n parent = heap[parentpos]\n if newitem < parent:\n heap[pos] = parent\n pos = parentpos\n continue\n break\n heap[pos] = newitem\n\ndef _siftup(heap, pos):\n endpos = len(heap)\n startpos = pos\n newitem = heap[pos]\n # Bubble up the smaller child until hitting a leaf.\n childpos = 2*pos + 1 # leftmost child position\n while childpos < endpos:\n # Set childpos to index of smaller child.\n rightpos = childpos + 1\n if rightpos < endpos and not heap[childpos] < heap[rightpos]:\n childpos = rightpos\n # Move the smaller child up.\n heap[pos] = heap[childpos]\n pos = childpos\n childpos = 2*pos + 1\n # The leaf at pos is empty now. Put newitem there, and bubble it up\n # to its final resting place (by sifting its parents down).\n heap[pos] = newitem\n _siftdown(heap, startpos, pos)";
|
||||
const char kPythonLibs_linalg[] = "from vmath import *";
|
||||
const char kPythonLibs_operator[] = "# https://docs.python.org/3/library/operator.html#mapping-operators-to-functions\n\ndef le(a, b): return a <= b\ndef lt(a, b): return a < b\ndef ge(a, b): return a >= b\ndef gt(a, b): return a > b\ndef eq(a, b): return a == b\ndef ne(a, b): return a != b\n\ndef and_(a, b): return a & b\ndef or_(a, b): return a | b\ndef xor(a, b): return a ^ b\ndef invert(a): return ~a\ndef lshift(a, b): return a << b\ndef rshift(a, b): return a >> b\n\ndef is_(a, b): return a is b\ndef is_not(a, b): return a is not b\ndef not_(a): return not a\ndef truth(a): return bool(a)\ndef contains(a, b): return b in a\n\ndef add(a, b): return a + b\ndef sub(a, b): return a - b\ndef mul(a, b): return a * b\ndef truediv(a, b): return a / b\ndef floordiv(a, b): return a // b\ndef mod(a, b): return a % b\ndef pow(a, b): return a ** b\ndef neg(a): return -a\ndef matmul(a, b): return a @ b\n\ndef getitem(a, b): return a[b]\ndef setitem(a, b, c): a[b] = c\ndef delitem(a, b): del a[b]\n\ndef iadd(a, b): a += b; return a\ndef isub(a, b): a -= b; return a\ndef imul(a, b): a *= b; return a\ndef itruediv(a, b): a /= b; return a\ndef ifloordiv(a, b): a //= b; return a\ndef imod(a, b): a %= b; return a\n# def ipow(a, b): a **= b; return a\n# def imatmul(a, b): a @= b; return a\ndef iand(a, b): a &= b; return a\ndef ior(a, b): a |= b; return a\ndef ixor(a, b): a ^= b; return a\ndef ilshift(a, b): a <<= b; return a\ndef irshift(a, b): a >>= b; return a\n";
|
||||
const char kPythonLibs_typing[] = "class _Placeholder:\n def __init__(self, *args, **kwargs):\n pass\n def __getitem__(self, *args):\n return self\n def __call__(self, *args, **kwargs):\n return self\n def __and__(self, other):\n return self\n def __or__(self, other):\n return self\n def __xor__(self, other):\n return self\n\n\n_PLACEHOLDER = _Placeholder()\n\nSequence = _PLACEHOLDER\nList = _PLACEHOLDER\nDict = _PLACEHOLDER\nTuple = _PLACEHOLDER\nSet = _PLACEHOLDER\nAny = _PLACEHOLDER\nUnion = _PLACEHOLDER\nOptional = _PLACEHOLDER\nCallable = _PLACEHOLDER\nType = _PLACEHOLDER\nTypeAlias = _PLACEHOLDER\nNewType = _PLACEHOLDER\n\nLiteral = _PLACEHOLDER\nLiteralString = _PLACEHOLDER\n\nIterable = _PLACEHOLDER\nGenerator = _PLACEHOLDER\nIterator = _PLACEHOLDER\n\nHashable = _PLACEHOLDER\n\nTypeVar = _PLACEHOLDER\nSelf = _PLACEHOLDER\n\nProtocol = object\nGeneric = object\nNever = object\n\nTYPE_CHECKING = False\n\n# decorators\noverload = lambda x: x\nfinal = lambda x: x\n\n# exhaustiveness checking\nassert_never = lambda x: x\n\nTypedDict = dict\nNotRequired = _PLACEHOLDER\n";
|
||||
const char kPythonLibs_typing[] = "class _Placeholder:\n def __init__(self, *args, **kwargs):\n pass\n def __getitem__(self, *args):\n return self\n def __call__(self, *args, **kwargs):\n return self\n def __and__(self, other):\n return self\n def __or__(self, other):\n return self\n def __xor__(self, other):\n return self\n\n\n_PLACEHOLDER = _Placeholder()\n\nSequence = _PLACEHOLDER\nList = _PLACEHOLDER\nDict = _PLACEHOLDER\nTuple = _PLACEHOLDER\nSet = _PLACEHOLDER\nAny = _PLACEHOLDER\nUnion = _PLACEHOLDER\nOptional = _PLACEHOLDER\nCallable = _PLACEHOLDER\nType = _PLACEHOLDER\nTypeAlias = _PLACEHOLDER\nNewType = _PLACEHOLDER\n\nClassVar = _PLACEHOLDER\n\nLiteral = _PLACEHOLDER\nLiteralString = _PLACEHOLDER\n\nIterable = _PLACEHOLDER\nGenerator = _PLACEHOLDER\nIterator = _PLACEHOLDER\n\nHashable = _PLACEHOLDER\n\nTypeVar = _PLACEHOLDER\nSelf = _PLACEHOLDER\n\nProtocol = object\nGeneric = object\nNever = object\n\nTYPE_CHECKING = False\n\n# decorators\noverload = lambda x: x\nfinal = lambda x: x\n\n# exhaustiveness checking\nassert_never = lambda x: x\n\nTypedDict = dict\nNotRequired = _PLACEHOLDER\n";
|
||||
|
||||
const char* load_kPythonLib(const char* name) {
|
||||
if (strchr(name, '.') != NULL) return NULL;
|
||||
|
||||
@ -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
src/modules/stdc.c
Normal file
275
src/modules/stdc.c
Normal file
@ -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
tests/793_stdc.py
Normal file
62
tests/793_stdc.py
Normal file
@ -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'
|
||||
Loading…
x
Reference in New Issue
Block a user