Continue improving defs
& do some testing of mkapi-generated bindings
This commit is contained in:
parent
49bb45bad6
commit
e188517863
21 changed files with 731 additions and 193 deletions
2
.github/workflows/ports_m68kmac.yml
vendored
2
.github/workflows/ports_m68kmac.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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] = {
|
||||
|
|
|
|||
|
|
@ -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
14
extmod/multiversal.mk
Normal 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
219
extmod/multiverse_support.c
Normal 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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
Using multiversal interfaces
|
||||
ADBOp
|
||||
FSOpen
|
||||
OpenRF
|
||||
|
|
@ -175,3 +174,5 @@ GetDblTime
|
|||
GetCaretTime
|
||||
GetIndString
|
||||
GetIndPattern
|
||||
R_X2Fix
|
||||
R_X2Frac
|
||||
|
|
|
|||
|
|
@ -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
3
ports/unix/makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
MAKEFLAGS=-j10
|
||||
VARIANT ?= coverage
|
||||
include Makefile
|
||||
167
ports/unix/variants/coverage/mkapi_test.yaml
Normal file
167
ports/unix/variants/coverage/mkapi_test.yaml
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
22
tests/extmod/mkapi.py
Normal 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
14
tests/extmod/mkapi.py.exp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<class 'RegionPtr'> <class 'Region'>
|
||||
100
|
||||
200
|
||||
400
|
||||
300
|
||||
105
|
||||
203
|
||||
403
|
||||
305
|
||||
<class 'GrafPort'>
|
||||
256
|
||||
512
|
||||
1024
|
||||
768
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__':
|
||||
Loading…
Reference in a new issue