Continue improving defs

& do some testing of mkapi-generated bindings
This commit is contained in:
Jeff Epler 2025-07-25 16:19:08 -05:00
parent 49bb45bad6
commit e188517863
21 changed files with 731 additions and 193 deletions

View file

@ -15,7 +15,7 @@ jobs:
build:
permissions: write-all
runs-on: ubuntu-latest
container: ghcr.io/m68k-micropython/builder
container: ghcr.io/m68k-micropython/builder:latest
steps:
- uses: actions/checkout@v4
- name: Build

View file

@ -75,6 +75,11 @@ static bool is_struct_type(mp_obj_t obj_in) {
return make_new == uctypes_struct_type_make_new;
}
static bool is_struct_instance(mp_obj_t obj_in) {
const mp_obj_type_t *type = mp_obj_get_type(obj_in);
return MP_OBJ_TYPE_GET_SLOT_OR_NULL(type, subscr) == uctypes_struct_subscr;
}
mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 2, 3, false);
mp_obj_t desc = args[1];
@ -346,13 +351,25 @@ static mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) {
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof);
mp_obj_t uctypes_get_struct_desc(mp_obj_t arg) {
if (is_struct_instance(arg)) {
mp_obj_uctypes_struct_t *struct_ = MP_OBJ_TO_PTR(arg);
return struct_->desc;
}
if (is_struct_type(arg)) {
mp_obj_ctypes_struct_type_t *struct_type = MP_OBJ_TO_PTR(arg);
return struct_type->desc;
}
return MP_OBJ_NULL;
}
static mp_obj_t uctypes_struct_desc(mp_obj_t arg) {
if (!is_struct_type(arg)) {
mp_obj_t result = uctypes_get_struct_desc(arg);
if (result == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
mp_obj_ctypes_struct_type_t *struct_type = MP_OBJ_TO_PTR(arg);
return struct_type->desc;
return result;
}
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_desc_obj, uctypes_struct_desc);
static const char type2char[16] = {

View file

@ -47,6 +47,8 @@ mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in);
mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
mp_obj_t uctypes_struct_type_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
// may call on an instance or named struct type
mp_obj_t uctypes_get_struct_desc(const mp_obj_t obj);
#define MP_DECLARE_CTYPES_STRUCT(type_name) \
extern const mp_obj_ctypes_struct_type_t type_name;

14
extmod/multiversal.mk Normal file
View file

@ -0,0 +1,14 @@
MKAPIFORMAT ?=
# $(eval $(call multiversal_module, module name, defs files))
define multiversal_module
$$(BUILD)/mod$(1).c: $(TOP)/tools/mkapi.py $(filter-out -t,$(2)) $$(DEFS)
$$(ECHO) "MKAPI $(1)"
$$(Q)$$(MKDIR) -p $$(BUILD)
$$(Q)$$(PYTHON) $(TOP)/tools/mkapi.py $(MKAPIFORMAT) -o $$@ -m $(1) $$(TDEFS) $(2)
SRC_C += $(BUILD)/mod$(1).c
SRC_QSTR += $(BUILD)/mod$(1).c
mkapi:: $$(BUILD)/mod$(1).c
endef
SRC_C += extmod/multiverse_support.c
SRC_QSTR += extmod/multiverse_support.c

219
extmod/multiverse_support.c Normal file
View file

@ -0,0 +1,219 @@
#include "extmod/multiverse_support.h"
#if __m68k
#define lm_base ((char *)0)
#else
char lm_base[65536];
#endif
MP_DECLARE_CTYPES_STRUCT(Point_obj);
#define DEFINE_PTR_SCALAR(type_c, tag) \
const mp_rom_obj_tuple_t type_c##_ptr_tuple = ROM_TUPLE(MP_ROM_INT(UCTYPE_AGG(PTR)), MP_ROM_INT(UCTYPE_TYPE(tag))); \
MP_DEFINE_CTYPES_STRUCT(type_c##_obj, MP_QSTR_##type_c, MP_ROM_PTR((void *)&type_c##_ptr_tuple), LAYOUT_NATIVE)
DEFINE_PTR_SCALAR(bool, UINT8);
DEFINE_PTR_SCALAR(char, UINT8);
DEFINE_PTR_SCALAR(uint8_t, UINT8);
DEFINE_PTR_SCALAR(uint16_t, UINT16);
DEFINE_PTR_SCALAR(uint32_t, UINT32);
DEFINE_PTR_SCALAR(uint64_t, UINT64);
DEFINE_PTR_SCALAR(int8_t, INT8);
DEFINE_PTR_SCALAR(int16_t, INT16);
DEFINE_PTR_SCALAR(int32_t, INT32);
DEFINE_PTR_SCALAR(int64_t, INT64);
DEFINE_PTR_SCALAR(float, FLOAT32);
DEFINE_PTR_SCALAR(double, FLOAT64);
static mp_uint_t get_agg_type(mp_obj_tuple_t *sub) {
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
return agg_type;
}
static mp_uint_t get_val_type(mp_obj_tuple_t *sub) {
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[1]);
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
return val_type;
}
static bool arg_compatible(const mp_obj_t arg_descr, const mp_obj_t type_descr) {
// types are compatible if their descriptors are equal
if (mp_obj_equal(arg_descr, type_descr)) {
return true;
}
// Otherwise, they are compatible if
// * type is a pointer to T, and
// * arg is a pointer to T or array of T
if (!mp_obj_is_type(type_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *type_sub = MP_OBJ_TO_PTR(type_descr);
if (get_agg_type(type_descr) != PTR) {
return false;
}
if (!mp_obj_is_type(arg_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *arg_sub = MP_OBJ_TO_PTR(arg_descr);
if (arg_sub->len == 2) {
// argument is a pointer-to-scalar or array-of-scalar, compare scalar types
return get_val_type(type_sub) == get_val_type(arg_sub);
} else {
// argument is array-of-struct, compare descriptors
return mp_obj_equal(type_sub->items[1], arg_sub->items[2]);
}
}
static bool deref_compatible(const mp_obj_t arg_descr, const mp_obj_t type_descr) {
if (!mp_obj_is_type(arg_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *arg_sub = MP_OBJ_TO_PTR(arg_descr);
if (get_agg_type(arg_sub) != PTR) {
return false;
}
bool r = mp_obj_equal(type_descr, arg_sub->items[1]);
return r;
}
#define mp_obj_get_type_qstr(o_in) ((qstr)(mp_obj_get_type((o_in))->name))
void *to_struct_helper(mp_obj_t obj, const mp_obj_type_t *struct_type, bool is_const, qstr fieldname) {
if (obj == mp_const_none) {
return NULL;
}
if (struct_type && !mp_obj_is_type(obj, struct_type)) {
mp_obj_t arg_descr = uctypes_get_struct_desc(obj);
mp_obj_t type_descr = uctypes_get_struct_desc(MP_OBJ_FROM_PTR(struct_type));
if (deref_compatible(arg_descr, MP_OBJ_FROM_PTR(struct_type))) {
// Consider the case of
// ```py
// w = WindowMgr.NewWindow(...)
// qd.SetPort(w)
// ```
// which would otherwise say `TypeError: p must be of type GrafPort, not GrafPtr
//
// (currently) mkapi treats the argument to SetPort
// as a GrafPort. But `GrafPtr` is a typedef to `GrafPort*`. It might be
// better to fix this in mkapi, but instead cater here...
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
void *result = *(void **)bufinfo.buf;
return result;
}
if (!arg_compatible(arg_descr, type_descr)) {
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("%q must be of type %q, not %q"), fieldname, (qstr)struct_type->name, mp_obj_get_type_qstr(obj));
}
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
return bufinfo.buf;
}
static const mp_rom_map_elem_t empty_table[] = {};
static MP_DEFINE_CONST_DICT(empty_dict, empty_table);
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *type) {
if (type) {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), MP_OBJ_FROM_PTR(type) };
return uctypes_struct_make_new(type, 2, 0, args);
} else {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), MP_OBJ_FROM_PTR(&empty_dict) };
return uctypes_struct_make_new(&uctypes_struct_type, 2, 0, args);
}
}
void *to_scalar_helper(mp_obj_t obj, size_t objsize, bool is_const) {
if (mp_obj_is_int(obj)) {
return (void *)mp_obj_get_int_truncated(obj);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
if (objsize > 1 && bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
return bufinfo.buf;
}
mp_obj_t from_scalar_helper(void *buf, size_t objsize, bool is_signed_hint) {
return mp_obj_new_int_from_uint(*(unsigned long *)buf);
}
mp_obj_t LMGet_common(long address, size_t objsize, mp_obj_t arg) {
if (arg == mp_const_none) {
return mp_obj_new_bytearray(objsize, (void *)address);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_WRITE);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy(bufinfo.buf, (void *)address, objsize);
return arg;
}
void LMSet_common(long address, size_t objsize, mp_obj_t arg) {
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy((void *)address, bufinfo.buf, objsize);
}
Point Point_to_c(mp_obj_t obj, qstr fieldname) {
Point result;
if (mp_obj_len_maybe(obj) == MP_OBJ_NEW_SMALL_INT(2)) {
result.h = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(0), MP_OBJ_SENTINEL));
result.v = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(1), MP_OBJ_SENTINEL));
} else {
result = *(Point *)to_struct_helper(obj, (const mp_obj_type_t *)&Point_obj, true, fieldname);
}
return result;
}
void *void_ptr_from_py(mp_obj_t arg) {
if (mp_obj_is_int(arg)) {
return (void *)mp_obj_get_int_truncated(arg);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
return bufinfo.buf;
}
#if __m68k
pascal LONGINT GetDblTime(void) {
return LMGetDoubleTime();
}
pascal LONGINT GetCaretTime(void) {
return LMGetCaretTime();
}
typedef struct {
INTEGER count;
Byte data[0];
} patternlist;
pascal void GetIndPattern(Byte *pat, INTEGER patListId, INTEGER index) {
Handle h = (Handle)GetResource('PAT#', patListId);
if (!h) {
return;
}
LoadResource(h);
if (ResError() != noErr) {
return;
}
patternlist *patterns = (patternlist *)*h;
if (index < 0 || index >= patterns->count) {
return;
}
memcpy(pat, patterns->data + 8 * index, 8);
}
#endif

View file

@ -2,15 +2,42 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "extmod/moductypes.h"
#include <Multiverse.h>
#if __m68k__
#include "Multiverse.h"
#else
typedef long LONGINT;
typedef short INTEGER;
typedef unsigned char Byte;
typedef struct { INTEGER h, v;
} Point;
#define pascal /* nothing */
#endif
// Relies on gcc Variadic Macros and Statement Expressions
#define NEW_TUPLE(...) \
({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z); })
#define ROM_TUPLE(...) \
{{&mp_type_tuple}, MP_ARRAY_SIZE(((mp_obj_t[]) {__VA_ARGS__})), {__VA_ARGS__}}
{{&mp_type_tuple}, MP_ARRAY_SIZE(((const mp_obj_t[]) {__VA_ARGS__})), {__VA_ARGS__}}
#define DECLARE_PTR_SCALAR(type_c) \
MP_DECLARE_CTYPES_STRUCT(type_c##_obj)
DECLARE_PTR_SCALAR(bool);
DECLARE_PTR_SCALAR(char);
DECLARE_PTR_SCALAR(uint8_t);
DECLARE_PTR_SCALAR(uint16_t);
DECLARE_PTR_SCALAR(uint32_t);
DECLARE_PTR_SCALAR(uint64_t);
DECLARE_PTR_SCALAR(int8_t);
DECLARE_PTR_SCALAR(int16_t);
DECLARE_PTR_SCALAR(int32_t);
DECLARE_PTR_SCALAR(int64_t);
#define void_obj uint8_t_obj
void *void_ptr_from_py(mp_obj_t obj);
void *to_struct_helper(mp_obj_t obj, const mp_obj_type_t *struct_type, bool is_const, qstr fieldname);
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *type);
void *to_scalar_helper(mp_obj_t obj, size_t objsize, bool is_const);

View file

@ -49,7 +49,6 @@ SRC_C = \
main.c \
vfs_mac.c \
macutil.c \
multiverse_support.c \
SRC_C += \
shared/readline/readline.c \
@ -69,37 +68,28 @@ SRC_S += \
shared/runtime/gchelper_m68k.s \
SRC_QSTR += \
vfs_mac.c \
shared/readline/readline.c \
shared/runtime/pyexec.c \
vfs_mac.c \
.PHONY: mkapi
DEFS = lib/multiversal/defs/MacTypes.yaml etc/MacTypesExtras.yaml
TDEFS = $(patsubst %, -t %, $(DEFS))
# $(eval $(call multiversal_module, module name, defs files))
define multiversal_module
$$(BUILD)/mod$(1).c: tools/mkapi.py $(filter-out -t,$(2)) $$(DEFS)
$$(ECHO) "MKAPI $(1)"
$$(Q)$$(MKDIR) -p $$(BUILD)
$$(Q)$$(PYTHON) tools/mkapi.py -o $$@ -m $(1) $$(TDEFS) $(2)
SRC_C += $(BUILD)/mod$(1).c
SRC_QSTR += $(BUILD)/mod$(1).c
mkapi:: $$(BUILD)/mod$(1).c
endef
include $(TOP)/extmod/multiversal.mk
$(eval $(call multiversal_module,eventmgr,lib/multiversal/defs/EventMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,deskmgr,lib/multiversal/defs/DeskMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,dialogmgr,lib/multiversal/defs/DialogMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t etc/DialogMgrExtras.yaml))
$(eval $(call multiversal_module,deskmgr,lib/multiversal/defs/DeskMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,dialogmgr,lib/multiversal/defs/DialogMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t etc/DialogMgrExtras.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,fontmgr,lib/multiversal/defs/FontMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,mactypes,lib/multiversal/defs/MacTypes.yaml etc/MacTypesExtras.yaml))
$(eval $(call multiversal_module,menumgr,lib/multiversal/defs/MenuMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,qd,lib/multiversal/defs/QuickDraw.yaml etc/QuickDrawExtras.yaml))
$(eval $(call multiversal_module,textedit,lib/multiversal/defs/TextEdit.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,toolboxevent,lib/multiversal/defs/ToolboxEvent.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,toolboxevent,lib/multiversal/defs/ToolboxEvent.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,toolboxutil,lib/multiversal/defs/ToolboxUtil.yaml -t lib/multiversal/defs/EventMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,windowmgr,lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,windowmgr,lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
OBJ += $(PY_CORE_O) $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))

View file

@ -9,8 +9,6 @@ Two methods of building are supported. First, entirely within docker, using the
`.github/workflows/port_m68k.yaml`. Second, building on a standard Linux host machine
(e.g., debian stable) with docker installed:
$ pip install pyyaml click
$ make submodules
$ make docker-build
There's a `make run` target to launch the emulator but it is very specific to

View file

@ -5,6 +5,7 @@ import mactypes
import qd
import uctypes
import windowmgr
import random
scrn = qd.qdGlobals().screenBits
@ -14,23 +15,37 @@ def pstr(s):
b[0] = len(s)
for i in range(len(s)):
b[i + 1] = ord(s[i])
return b
return uctypes.struct(b, mactypes.ConstStringPtr)
ev = eventmgr.EventRecord()
NIL_WINDOW = uctypes.struct(0, qd.GrafPort)
ABOVE_ALL_WINDOWS = uctypes.struct(-1, qd.GrafPort)
NIL_WINDOW = uctypes.struct(0, qd.GrafPtr)
ABOVE_ALL_WINDOWS = uctypes.struct(-1, qd.GrafPtr)
title = pstr("Hello World")
print(f"{ABOVE_ALL_WINDOWS=}")
title = pstr("Hello World 11")
r = mactypes.Rect()
r[:] = scrn.bounds
r.top += 80
qd.InsetRect(r, 25, 25)
w = windowmgr.NewWindow(NIL_WINDOW, r, title, True, 0, ABOVE_ALL_WINDOWS, True, 0)
print(f"{w=}")
print(f"{w.portRect.left=}")
print(f"{w.portRect.right=}")
# print("before setport")
qd.SetPort(w)
# print("33")
# print(type(r))
# print(r)
# print(f"{w}")
# print(f"{w.portRect}")
# print(f"{w.portRect.top}")
# print(f"{w.portRect.left}")
r[:] = w.portRect
print(r.left, r.right)
print(r.top, r.bottom)
g = qd.qdGlobals()
@ -45,6 +60,9 @@ qd.FrameRect(tempRect)
qd.SetRect(tempRect, 80, 20, 90, 50)
qd.FrameOval(tempRect)
qd.CloseRgn(barbell)
qd.FillRgn(barbell, g.black)
qd.DisposeRgn(barbell)
input("hit enter to exit")

View file

@ -1 +1,13 @@
[]
- typedef:
name: ProcPtr
type: void*
- pyverbatim:
typedef_content: |
#define WindowRef_obj GrafPtr_obj
#define WindowPtr_obj GrafPtr_obj
#define DialogPtr_obj GrafPtr_obj
#define INTEGER_obj int16_t_obj
#define Fixed_obj int32_t_obj
#define LONGINT_obj int32_t_obj
#define Byte_obj uint8_t_obj
#define SignedByte_obj int8_t_obj

View file

@ -1,4 +1,3 @@
Using multiversal interfaces
ADBOp
FSOpen
OpenRF
@ -175,3 +174,5 @@ GetDblTime
GetCaretTime
GetIndString
GetIndPattern
R_X2Fix
R_X2Frac

View file

@ -1,108 +0,0 @@
#include "multiverse_support.h"
MP_DECLARE_CTYPES_STRUCT(Point_obj);
#define mp_obj_get_type_qstr(o_in) ((qstr)(mp_obj_get_type((o_in))->name))
void *to_struct_helper(mp_obj_t obj, const mp_obj_type_t *struct_type, bool is_const, qstr fieldname) {
if (obj == mp_const_none) {
return NULL;
}
if (struct_type && !mp_obj_is_type(obj, struct_type)) {
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("%q must be of type %q, not %q"), fieldname, (qstr)struct_type->name, mp_obj_get_type_qstr(obj));
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
return bufinfo.buf;
}
static const mp_rom_map_elem_t empty_table[] = {};
static MP_DEFINE_CONST_DICT(empty_dict, empty_table);
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *type) {
if (type) {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), MP_OBJ_FROM_PTR(type) };
return uctypes_struct_make_new(type, 2, 0, args);
} else {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), &empty_dict };
return uctypes_struct_make_new(&uctypes_struct_type, 2, 0, args);
}
}
void *to_scalar_helper(mp_obj_t obj, size_t objsize, bool is_const) {
if (mp_obj_is_int(obj)) {
return (void *)mp_obj_get_int_truncated(obj);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
if (objsize > 1 && bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
return bufinfo.buf;
}
mp_obj_t from_scalar_helper(void *buf, size_t objsize, bool is_signed_hint) {
return mp_obj_new_int_from_uint(*(unsigned long *)buf);
}
mp_obj_t LMGet_common(long address, size_t objsize, mp_obj_t arg) {
if (arg == mp_const_none) {
return mp_obj_new_bytearray(objsize, (void *)address);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_WRITE);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy(bufinfo.buf, (void *)address, objsize);
return arg;
}
void LMSet_common(long address, size_t objsize, mp_obj_t arg) {
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy((void *)address, bufinfo.buf, objsize);
}
Point Point_to_c(mp_obj_t obj, qstr fieldname) {
Point result;
if (mp_obj_len_maybe(obj) == MP_OBJ_NEW_SMALL_INT(2)) {
result.h = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(0), MP_OBJ_SENTINEL));
result.v = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(1), MP_OBJ_SENTINEL));
} else {
result = *(Point *)to_struct_helper(obj, (const mp_obj_type_t *)&Point_obj, true, fieldname);
}
return result;
}
pascal LONGINT GetDblTime(void) {
return LMGetDoubleTime();
}
pascal LONGINT GetCaretTime(void) {
return LMGetCaretTime();
}
typedef struct {
INTEGER count;
Byte data[0];
} patternlist;
pascal void GetIndPattern(Byte *pat, INTEGER patListId, INTEGER index) {
Handle h = (Handle)GetResource('PAT#', patListId);
if (!h) {
return;
}
LoadResource(h);
if (ResError() != noErr) {
return;
}
patternlist *patterns = (patternlist *)*h;
if (index < 0 || index >= patterns->count) {
return;
}
memcpy(pat, patterns->data + 8 * index, 8);
}

3
ports/unix/makefile Normal file
View file

@ -0,0 +1,3 @@
MAKEFLAGS=-j10
VARIANT ?= coverage
include Makefile

View file

@ -0,0 +1,167 @@
- typedef:
name: Byte
type: uint8_t
- typedef:
name: INTEGER
type: int16_t
- struct:
name: Rect
members:
- name: top
type: INTEGER
- name: left
type: INTEGER
- name: bottom
type: INTEGER
- name: right
type: INTEGER
size: 8
- typedef:
name: Str15
type: Byte[16]
- struct:
name: GrafPort
members:
- name: device
type: INTEGER
- name: portRect
type: Rect
- typedef:
name: GrafPtr
type: GrafPort*
- typedef:
name: WindowPtr
type: GrafPtr
# ####
- struct:
name: Region
members:
- name: rgnSize
type: INTEGER
- name: rgnBBox
type: Rect
size: 10
# ####
- struct:
name: Point
members:
- name: h
type: INTEGER
- name: v
type: INTEGER
- typedef:
name: RegionPtr
type: Region*
- typedef:
name: RgnHandle
type: RegionPtr*
# ####
- pyverbatim:
typedef_content: |
typedef struct {
INTEGER top, left, bottom, right;
} Rect;
typedef struct {
INTEGER rgnSize; Rect rgnBBox;
} Region;
typedef struct {
INTEGER device;
Rect portRect;
} GrafPort;
typedef GrafPort *GrafPtr;
typedef GrafPtr WindowPtr;
#define WindowPtr_obj GrafPtr_obj
typedef Region *RegionPtr;
typedef RegionPtr *RgnHandle;
static void OffsetRgn(RgnHandle rh, INTEGER dh, INTEGER dv) {
Region *region = *rh;
region->rgnBBox.top += dv;
region->rgnBBox.bottom += dv;
region->rgnBBox.left += dh;
region->rgnBBox.right += dh;
}
static RgnHandle NewRgn(void) {
static Region rgn = { 0x505, {100, 200, 300, 400} };
static RegionPtr rp = &rgn;
return &rp;
}
static WindowPtr NewWindow(void) {
static GrafPort result = {0, {0x100, 0x200, 0x300, 0x400} };
return &result;
}
static void PtToAngle(const Rect *r, Point p, INTEGER *angle) {
mp_printf(&mp_plat_print, "PtToAngle(rect@%p, p={%d,%d}, angle@%p\n", r, p.h, p.v, angle);
*angle = 314;
}
static INTEGER GetWinDevice(WindowPtr w) {
return w->device;
}
- function:
name: NewRgn
return: RgnHandle
trap: 0xA8D8
executor: C_
- function:
name: OffsetRgn
args:
- name: rh
type: RgnHandle
- name: dh
type: INTEGER
- name: dv
type: INTEGER
trap: 0xA8E0
executor: C_
- function:
name: PtToAngle
args:
- name: rp
type: const Rect*
- name: p
type: Point
- name: angle
type: INTEGER*
trap: 0xA8C3
executor: C_
- function:
name: NewWindow
return: WindowPtr
- function:
name: GetWinDevice
return: INTEGER
args:
- name: w
type: WindowPtr

View file

@ -12,5 +12,13 @@ LDFLAGS += -fprofile-arcs -ftest-coverage
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
USER_C_MODULES = $(TOP)/examples/usercmodule
# Optionally format the generated files with uncrustify if installed
ifneq ($(shell which uncrustify-apple-macos-gcc),)
MKAPIFORMAT = --format
endif
include $(TOP)/extmod/multiversal.mk
$(eval $(call multiversal_module,mkapitest,variants/coverage/mkapi_test.yaml))
$(info $(call multiversal_module,mkapitest,variants/coverage/mkapi_test.yaml))
SRC_C += coverage.c
SRC_CXX += coveragecpp.cpp

View file

@ -495,6 +495,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
chrs += mp_print_strn(print, str, len, flags, fill, width);
break;
}
case 'r': {
mp_obj_t arg = va_arg(args, mp_obj_t);
mp_obj_print_helper(print, arg, width);
break;
}
case 's': {
const char *str = va_arg(args, const char *);
#ifndef NDEBUG

22
tests/extmod/mkapi.py Normal file
View file

@ -0,0 +1,22 @@
import mkapitest
rh = mkapitest.NewRgn()
r = rh[0]
print(type(rh), type(r))
print(r.rgnBBox.top)
print(r.rgnBBox.left)
print(r.rgnBBox.right)
print(r.rgnBBox.bottom)
mkapitest.OffsetRgn(rh, 3, 5)
print(r.rgnBBox.top)
print(r.rgnBBox.left)
print(r.rgnBBox.right)
print(r.rgnBBox.bottom)
w = mkapitest.NewWindow()
print(type(w))
print(w.portRect.top)
print(w.portRect.left)
print(w.portRect.right)
print(w.portRect.bottom)

14
tests/extmod/mkapi.py.exp Normal file
View file

@ -0,0 +1,14 @@
<class 'RegionPtr'> <class 'Region'>
100
200
400
300
105
203
403
305
<class 'GrafPort'>
256
512
1024
768

View file

@ -57,13 +57,14 @@ cppexample cryptolib deflate errno
example_package ffi framebuf
gc hashlib heapq io
json machine marshal math
os platform random re
select socket struct sys
termios time tls uctypes
vfs websocket
mkapitest os platform random
re select socket struct
sys termios time tls
uctypes vfs websocket
me
micropython machine marshal math
mkapitest
argv atexit byteorder exc_info
executable exit getsizeof implementation

View file

@ -627,6 +627,7 @@ function ci_unix_coverage_setup {
pip3 install setuptools
pip3 install pyelftools
pip3 install ar
pip3 install pyyaml click
ci_gcc_plugin_setup
gcc --version
python3 --version
@ -680,6 +681,7 @@ function ci_unix_32bit_setup {
sudo pip3 install setuptools
sudo pip3 install pyelftools
sudo pip3 install ar
sudo pip3 install --upgrade pyyaml click
gcc --version
python2.7 --version
python3 --version

View file

@ -9,13 +9,34 @@ from functools import singledispatchmethod
from dataclasses import dataclass, Field
from typing import Any, get_args, get_origin, Union
script_dir = pathlib.Path(__file__).parent
if sys.version_info >= (3, 10):
from types import UnionType
else:
UnionType = type(Union[int, float])
with open("etc/needs-glue.txt") as f:
needs_glue = set(f.read().split("\n"))
p = pathlib.Path("etc/needs-glue.txt")
if p.exists():
needs_glue = set(p.read_text().split("\n"))
else:
needs_glue = set()
typecodes = {
'bool': 'B',
'char': 'B',
'uint8_t': 'B',
'uint16_t': 'H',
'uint32_t': 'L',
'uint64_t': 'Q',
'float': 'f',
'double': 'd',
'int8_t': 'b',
'int16_t': 'h',
'int32_t': 'l',
'int64_t': 'q',
}
@dataclass(frozen=True)
@ -260,9 +281,10 @@ class descr_maker_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t", f"ROM_TUPLE(MP_ROM_INT({offset}), MP_ROM_PTR(&{self.tag}_obj))"
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset}), MP_ROM_PTR((void*)&{self.tag}_obj))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -272,10 +294,10 @@ class descr_maker_arr_scalar:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT(UCTYPE_TYPE({self.tag}) | {self.size}))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -285,10 +307,10 @@ class descr_maker_arr_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT({self.size}), MP_ROM_PTR(&{self.tag}_obj))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT({self.size}), MP_ROM_PTR((void*)(&{self.tag}_obj)))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -297,10 +319,10 @@ class descr_maker_ptr_scalar:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_INT(UCTYPE_TYPE({self.tag})))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
class descr_maker_ptr_struct:
@ -309,10 +331,10 @@ class descr_maker_ptr_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_PTR(&{self.tag}_obj))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_PTR((void*)&{self.tag}_obj))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -352,6 +374,7 @@ class ScalarConverter:
@dataclass
class PtrConverter:
emitter: object
fieldname: str
type_c: object
type_obj: object
@ -360,10 +383,28 @@ class PtrConverter:
def emit_to_c(self, name_py, name_c):
is_const = +self.is_const # to get 0/1, not True/False
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {self.type_obj}, {is_const}, MP_QSTR_{self.fieldname});"
resolved_type = self.emitter.parse_type(self.type_c)
if (
isinstance(resolved_type, Ptr)
and self.emitter.parse_type(resolved_type.pointee) not in all_scalar_types
):
type_obj = f"(void*)&{resolved_type.pointee}_obj"
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {type_obj}, {is_const}, MP_QSTR_{self.fieldname}); // 1\n"
else:
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {self.type_obj}, {is_const}, MP_QSTR_{self.fieldname}); // 2\n"
def emit_to_py(self, name_c):
return f"from_struct_helper({name_c}, {self.type_obj});"
resolved_type = self.emitter.parse_type(self.type_c)
if resolved_type in self.emitter.types:
resolved_type = self.emitter.parse_type(self.emitter.types[resolved_type])
print("emit_to_py", self.type_c, resolved_type)
if isinstance(resolved_type, Ptr):
assert self.type_obj and self.type_obj != "null"
type_str = resolved_type.pointee.replace("*", "Ptr")
return f"from_struct_helper({name_c}, (void*)&{type_str}_obj) /* {self.type_c} 3 */"
else:
type_str = self.type_obj.replace("*", "Ptr")
return f"from_struct_helper({name_c}, {self.type_obj}) /* {resolved_type} 4 */"
def emit_call_arg(self, name_c):
if self.deref:
@ -372,12 +413,14 @@ class PtrConverter:
def make_converter(emitter, fieldname, type_c):
print(f"make_converter {type_c=}")
if converter := converters.get(type_c):
return converter(fieldname)
resolved_type = emitter.parse_type(type_c)
print(f"{type_c} -> {resolved_type}")
if resolved_type in signed_integer_types:
return ScalarConverter(resolved_type, "mp_obj_get_int", "mp_obj_new_int")
if resolved_type in emitter.types:
resolved_type = emitter.parse_type(emitter.types[resolved_type])
if resolved_type in emitter.funptrs:
return ScalarConverter(
resolved_type, f"({type_c})mp_obj_get_int_truncated", "mp_obj_new_int_from_ptr"
@ -386,19 +429,48 @@ def make_converter(emitter, fieldname, type_c):
return ScalarConverter(
resolved_type, "mp_obj_get_int_truncated", "mp_obj_new_int_from_uint"
)
if type_c == "void*":
return ScalarConverter(resolved_type, "void_ptr_from_py", "mp_obj_new_int_from_uint")
if isinstance(resolved_type, Ptr):
base_type = resolved_type.pointee
if base_type in emitter.structs:
if base_type in all_scalar_types:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
emitter.info.append(f"confused about {base_type} from {resolved_type} from {type_c}")
return PtrConverter(fieldname, type_c, "NULL", is_const=resolved_type.is_const)
print(f"note: {emitter.funptrs}")
raise ValueError(f"no converter possible for {type_c} ({resolved_type})")
if type in emitter.structs or type_c in emitter.types:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{type_c}_obj",
is_const=resolved_type.is_const,
)
if base_type in emitter.structs:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
elif base_type in emitter.typedef_objs:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
emitter.info.append(f"need to handle typedef obj {base_type}")
elif base_type != 'void':
emitter.info.append(f"confused about {base_type} from {resolved_type} from {type_c}")
return PtrConverter(emitter, fieldname, type_c, "NULL", is_const=resolved_type.is_const)
print(f"note: {emitter.funptrs=}")
raise ValueError(f"no converter possible for {type_c} ({resolved_type=})")
class Processor:
@ -415,7 +487,7 @@ class Processor:
self.structs = {}
self.funptrs = set(("ProcPtr",))
self.decls_dedent("""
#include "multiverse_support.h"
#include "extmod/multiverse_support.h"
""")
self.add_local("__name__", f"MP_ROM_QSTR(MP_QSTR_{self.modname})")
@ -429,6 +501,10 @@ class Processor:
return f"common_{self.definitions[k]}"
def is_array(self, typename):
if isinstance(typename, Array):
return True
if isinstance(typename, Ptr):
return False
if typename.count(']') + ("*" in typename) > 1:
raise ValueError(
f"array-of-array or pointer-to-array or array-of-pointers NYI {typename}"
@ -436,18 +512,30 @@ class Processor:
return typename.endswith("]")
def remove_array(self, typename):
if isinstance(typename, Array):
return typename.pointee
return typename.partition("[")[0]
def remove_ptr(self, typename):
if isinstance(typename, Ptr):
return typename.pointee
return typename.removesuffix("*")
def remove_const(self, typename):
if hasattr(typename, 'is_const'):
return dataclasses.replace(typename, is_const=False)
return typename.removeprefix("const ")
def array_size(self, typename):
if isinstance(typename, Array):
return typename.bound
return int(typename.partition("[")[2].removesuffix("]"))
def is_ptr(self, typename):
if isinstance(typename, Ptr):
return True
if isinstance(typename, Array):
return False
return typename.endswith("*")
def is_scalar(self, typename):
@ -456,6 +544,8 @@ class Processor:
return typename in all_scalar_types
def is_const(self, typename):
if hasattr(typename, 'is_const'):
return typename.is_const
return typename.startswith("const ")
def decls_dedent(self, text):
@ -465,11 +555,8 @@ class Processor:
self.body.append(textwrap.dedent(text.rstrip()))
def parse_type(self, typestr):
print("parse_type", typestr)
if typestr == 'RgnHandle':
print(self.types)
while typestr in self.types:
typestr = self.types[typestr]
if scalar_type := self.types.get(typestr, None):
typestr = scalar_type
is_const = self.is_const(typestr)
base_type = self.remove_const(typestr)
if self.is_array(base_type):
@ -477,8 +564,7 @@ class Processor:
base_type = self.parse_type(self.remove_array(base_type))
return Array(base_type, bound, is_const=is_const)
elif self.is_ptr(base_type):
print(base_type, self.remove_ptr(base_type))
base_type = self.parse_type(self.remove_ptr(base_type))
base_type = self.remove_ptr(base_type)
return Ptr(base_type, is_const=is_const)
else:
if is_const:
@ -492,13 +578,15 @@ class Processor:
d.fulltype = self.parse_type(d.type)
print(f"full type of {d.name} is {d.fulltype}")
self.types[d.name] = d.type
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(
f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // typedef {d.fulltype} is_scalar? {self.is_scalar(d.fulltype)}"
)
if isinstance(d, Struct) and d.members:
self.structs[d.name] = d
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // struct")
if isinstance(d, Union) and d.members:
self.structs[d.name] = d
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // union")
if isinstance(d, PyVerbatim) and d.typedef_content:
self.decls_dedent(d.typedef_content)
if isinstance(d, FunPtr):
@ -506,6 +594,7 @@ class Processor:
def emit(self, defs):
for d in defs:
print("emit", id(d), d)
try:
self.emit_node(d)
except Exception as e:
@ -516,31 +605,53 @@ class Processor:
if type(node) in self.unknowns:
return
self.unknowns.add(type(node))
self.info.append(f"# Unknown {node!r:.68s}...")
raise RuntimeError(f"# Unknown {node!r:.68s}...")
@emit_node.register
def emit_dispatcher(self, dispatcher: Dispatcher):
pass # Nothing to emit
@emit_node.register
def emit_typedef(self, typedef: Typedef):
print("emit_typedef", typedef)
self.body_dedent(f"// typedef {typedef}")
name = typedef.name
type = typedef.type
if type.endswith("*") or type.endswith("]"):
make_descr = self.type_details(typedef.type)
make_descr = self.type_details(typedef.fulltype)
self.body_dedent(f"// {type} {make_descr=}")
if make_descr is None:
self.body_dedent(f"// {typedef}: no make_descr")
return
offset = 0
self.body_dedent(f"""
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, {make_descr(self, offset)}, LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, {make_descr(self, offset)}, LAYOUT_NATIVE); // 1
""")
self.typedef_objs.add(name)
self.add_local(name)
offset = 0
else:
self.body_dedent(f"// no need for {typedef} !?")
def type_details(self, typename):
if typename in self.funptrs:
return None
fulltype = self.parse_type(typename)
is_ptr = isinstance(fulltype, Ptr)
is_array = isinstance(fulltype, Array)
basetypename = fulltype if isinstance(fulltype, str) else fulltype.pointee
if isinstance(typename, Ptr):
is_ptr = True
is_array = False
basetypename = typename.pointee
print(f"{typename=} -- {basetypename=} {basetypename in self.types}")
elif isinstance(typename, Array):
is_ptr = False
is_array = True
fulltype = typename
basetypename = typename.pointee
print(f"{typename=} -- {basetypename=} {basetypename in self.types}")
else:
fulltype = self.parse_type(typename)
is_ptr = isinstance(fulltype, Ptr)
is_array = isinstance(fulltype, Array)
basetypename = fulltype if isinstance(fulltype, str) else fulltype.pointee
if basetypename in all_scalar_types:
u = "U" if basetypename.startswith("u") else ""
@ -569,7 +680,11 @@ class Processor:
descr = descr_maker_scalar(type_str)
else:
if is_ptr:
if basetypename in self.structs:
if typename in self.types:
descr = descr_maker_ptr_struct(typename)
elif basetypename in self.structs:
descr = descr_maker_ptr_struct(basetypename)
elif basetypename in self.types:
descr = descr_maker_ptr_struct(basetypename)
else:
descr = descr_maker_ptr_scalar("UINT8")
@ -607,7 +722,7 @@ class Processor:
{self.union_make_table(e)}
}};
static MP_DEFINE_CONST_DICT({name}_descr_dict, {name}_descr_table);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE); // 2
""")
self.add_local(name)
@ -623,7 +738,7 @@ class Processor:
{self.struct_make_table(e)}
}};
static MP_DEFINE_CONST_DICT({name}_descr_dict, {name}_descr_table);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE); // 3
""")
self.add_local(name)
@ -657,7 +772,7 @@ class Processor:
def add_local(self, name, value=...):
if value is ...:
value = f"MP_ROM_PTR(&{name}_obj)"
value = f"MP_ROM_PTR((void*)&{name}_obj)"
self.locals.append(f"{{ MP_ROM_QSTR(MP_QSTR_{name}), {value} }},")
@emit_node.register
@ -719,7 +834,6 @@ class Processor:
return_type = fun.return_
args = fun.args
argnames = [arg.name or f"arg{i}" for i, arg in enumerate(args)]
print(argnames)
fun_args = ", ".join(argnames)
if fun.inline:
funcall = f"{fun.inline};"
@ -732,9 +846,9 @@ class Processor:
return_type = fun.return_
if return_type:
converter = self.make_converter(0, return_type)
return f" return {converter.emit_to_py('retval')};"
return f" return {converter.emit_to_py('retval')};\n"
else:
return " return mp_const_none;"
return " return mp_const_none;\n"
@emit_node.register
def emit_function(self, node: Function):
@ -746,7 +860,7 @@ class Processor:
if node.api == 'carbon':
return
self.body_dedent(f"""
mp_obj_t {name}_fn(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {{
static mp_obj_t {name}_fn(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {{
{self.fun_parse_args(args)}
{self.fun_convert_args(args)}
{self.fun_call_fun(node)}
@ -795,7 +909,11 @@ class Processor:
"-t", "--typedefs", multiple=True, type=click.Path(path_type=pathlib.Path, exists=True)
)
@click.option("-m", "--modname", type=str)
def main(defs_files, output, modname, typedefs):
@click.option("--format/-no-format", "do_format")
def main(defs_files, output, modname, typedefs, do_format=False):
if modname is None:
modname = defs_files[0].stem
if output is None:
output = pathlib.Path(f"mod{modname}.c")
processor = Processor(modname)
@ -810,8 +928,16 @@ def main(defs_files, output, modname, typedefs):
processor.typedefs(defs)
processor.emit(defs)
with open(output, "w") as f:
processor.make_output(f)
if do_format:
tmpfile = output.with_suffix(".tmp.c")
with open(tmpfile, "w") as f:
processor.make_output(f)
print(f"Formatting {output}: ", [script_dir / "codeformat.py", "-c", tmpfile])
subprocess.check_call([script_dir / "codeformat.py", "-c", tmpfile])
tmpfile.rename(output)
else:
with open(output, "w") as f:
processor.make_output(f)
if __name__ == '__main__':