Merge remote-tracking branch 'origin/main' into main
This commit is contained in:
commit
c0b28c4510
@ -1,3 +1,6 @@
|
||||
# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
|
||||
0f78c36c5aa458a954eed39a46942209107a553e
|
||||
|
||||
# tests/run-tests.py: Reformat with Black.
|
||||
2a38d7103672580882fb621a5b76e8d26805d593
|
||||
|
||||
|
@ -182,10 +182,6 @@ Exceptions
|
||||
|
||||
.. exception:: OSError
|
||||
|
||||
|see_cpython| :py:class:`cpython:OSError`. CircuitPython doesn't implement the ``errno``
|
||||
attribute, instead use the standard way to access exception arguments:
|
||||
``exc.args[0]``.
|
||||
|
||||
.. exception:: RuntimeError
|
||||
|
||||
.. exception:: ReloadException
|
||||
|
@ -214,6 +214,14 @@ TCP stream connections
|
||||
|
||||
This is a coroutine.
|
||||
|
||||
.. method:: Stream.readinto(buf)
|
||||
|
||||
Read up to n bytes into *buf* with n being equal to the length of *buf*.
|
||||
|
||||
Return the number of bytes read into *buf*.
|
||||
|
||||
This is a coroutine, and a MicroPython extension.
|
||||
|
||||
.. method:: Stream.readline()
|
||||
|
||||
Read a line and return it.
|
||||
|
@ -247,7 +247,7 @@ Module contents
|
||||
|
||||
.. data:: VOID
|
||||
|
||||
``VOID`` is an alias for ``UINT8``, and is provided to conviniently define
|
||||
``VOID`` is an alias for ``UINT8``, and is provided to conveniently define
|
||||
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
|
||||
|
||||
.. data:: PTR
|
||||
|
@ -8,9 +8,11 @@
|
||||
|
||||
|see_cpython_module| :mod:`cpython:heapq`.
|
||||
|
||||
This module implements the heap queue algorithm.
|
||||
This module implements the
|
||||
`min heap queue algorithm <https://en.wikipedia.org/wiki/Heap_%28data_structure%29>`_.
|
||||
|
||||
A heap queue is simply a list that has its elements stored in a certain way.
|
||||
A heap queue is essentially a list that has its elements stored in such a way
|
||||
that the first item of the list is always the smallest.
|
||||
|
||||
Functions
|
||||
---------
|
||||
@ -21,8 +23,10 @@ Functions
|
||||
|
||||
.. function:: heappop(heap)
|
||||
|
||||
Pop the first item from the ``heap``, and return it. Raises IndexError if
|
||||
heap is empty.
|
||||
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
|
||||
``heap`` is empty.
|
||||
|
||||
The returned item will be the smallest item in the ``heap``.
|
||||
|
||||
.. function:: heapify(x)
|
||||
|
||||
|
@ -89,11 +89,11 @@ Methods
|
||||
``callee-owned tuples``. This function provides efficient, allocation-free
|
||||
way to poll on streams.
|
||||
|
||||
If *flags* is 1, one-shot behavior for events is employed: streams for
|
||||
If *flags* is 1, one-shot behaviour for events is employed: streams for
|
||||
which events happened will have their event masks automatically reset
|
||||
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
|
||||
won't be processed until new mask is set with `poll.modify()`. This
|
||||
behavior is useful for asynchronous I/O schedulers.
|
||||
behaviour is useful for asynchronous I/O schedulers.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
@ -31,12 +31,19 @@
|
||||
|
||||
#if MICROPY_PY_UASYNCIO
|
||||
|
||||
#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
|
||||
#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
|
||||
#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
|
||||
|
||||
#define TASK_IS_DONE(task) ( \
|
||||
(task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
|
||||
|| (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
|
||||
|
||||
typedef struct _mp_obj_task_t {
|
||||
mp_pairheap_t pairheap;
|
||||
mp_obj_t coro;
|
||||
mp_obj_t data;
|
||||
mp_obj_t waiting;
|
||||
|
||||
mp_obj_t state;
|
||||
mp_obj_t ph_key;
|
||||
} mp_obj_task_t;
|
||||
|
||||
@ -146,9 +153,6 @@ STATIC const mp_obj_type_t task_queue_type = {
|
||||
/******************************************************************************/
|
||||
// Task class
|
||||
|
||||
// For efficiency, the task object is stored to the coro entry when the task is done.
|
||||
#define TASK_IS_DONE(task) ((task)->coro == MP_OBJ_FROM_PTR(task))
|
||||
|
||||
// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
|
||||
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
|
||||
|
||||
@ -159,7 +163,7 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, const mp
|
||||
mp_pairheap_init_node(task_lt, &self->pairheap);
|
||||
self->coro = args[0];
|
||||
self->data = mp_const_none;
|
||||
self->waiting = mp_const_none;
|
||||
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
|
||||
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
|
||||
if (n_args == 2) {
|
||||
uasyncio_context = args[1];
|
||||
@ -218,24 +222,6 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
|
||||
|
||||
STATIC mp_obj_t task_throw(mp_obj_t self_in, mp_obj_t value_in) {
|
||||
// This task raised an exception which was uncaught; handle that now.
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
// Set the data because it was cleared by the main scheduling loop.
|
||||
self->data = value_in;
|
||||
if (self->waiting == mp_const_none) {
|
||||
// Nothing await'ed on the task so call the exception handler.
|
||||
mp_obj_t _exc_context = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__exc_context));
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_exception), value_in);
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_future), self_in);
|
||||
mp_obj_t Loop = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_Loop));
|
||||
mp_obj_t call_exception_handler = mp_load_attr(Loop, MP_QSTR_call_exception_handler);
|
||||
mp_call_function_1(call_exception_handler, _exc_context);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_throw_obj, task_throw);
|
||||
|
||||
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
@ -244,32 +230,24 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
dest[0] = self->coro;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
dest[0] = self->data;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
if (self->waiting != mp_const_none && self->waiting != mp_const_false) {
|
||||
dest[0] = self->waiting;
|
||||
}
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
dest[0] = self->state;
|
||||
} else if (attr == MP_QSTR_done) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_cancel) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_throw) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_throw_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_ph_key) {
|
||||
dest[0] = self->ph_key;
|
||||
}
|
||||
} else if (dest[1] != MP_OBJ_NULL) {
|
||||
// Store
|
||||
if (attr == MP_QSTR_coro) {
|
||||
self->coro = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
if (attr == MP_QSTR_data) {
|
||||
self->data = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
self->waiting = dest[1];
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
self->state = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
@ -278,15 +256,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
(void)iter_buf;
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->waiting == mp_const_none) {
|
||||
// The is the first access of the "waiting" entry.
|
||||
if (TASK_IS_DONE(self)) {
|
||||
// Signal that the completed-task has been await'ed on.
|
||||
self->waiting = mp_const_false;
|
||||
} else {
|
||||
// Lazily allocate the waiting queue.
|
||||
self->waiting = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
if (TASK_IS_DONE(self)) {
|
||||
// Signal that the completed-task has been await'ed on.
|
||||
self->state = TASK_STATE_DONE_WAS_WAITED_ON;
|
||||
} else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
|
||||
// Allocate the waiting queue.
|
||||
self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
return self_in;
|
||||
}
|
||||
@ -299,7 +274,7 @@ STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
|
||||
} else {
|
||||
// Put calling task on waiting queue.
|
||||
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t args[2] = { self->waiting, cur_task };
|
||||
mp_obj_t args[2] = { self->state, cur_task };
|
||||
task_queue_push_sorted(2, args);
|
||||
// Set calling task's data to this task that it waits on, to double-link it.
|
||||
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
|
||||
|
@ -15,38 +15,10 @@
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// The module also provides convenience functions to access memory buffers
|
||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
||||
/// \constant UINT8_1 - uint8_t value type
|
||||
|
||||
/// \class struct - C-like structure
|
||||
///
|
||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
||||
/// any methods, only attribute access (for structure fields) and
|
||||
/// indexing (for pointer and array fields).
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// # Define layout of a structure with 2 fields
|
||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
||||
/// # they are logically ORed with field type
|
||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
||||
///
|
||||
/// # Example memory buffer to access (contained in bytes object)
|
||||
/// buf = b"\x64\0\0\0\0x14"
|
||||
///
|
||||
/// # Create structure object referring to address of
|
||||
/// # the data in the buffer above
|
||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
||||
///
|
||||
/// # Access fields
|
||||
/// print(s.a, s.b)
|
||||
/// # Result:
|
||||
/// # 100, 20
|
||||
// The uctypes module allows defining the layout of a raw data structure (using
|
||||
// terms of the C language), and then access memory buffers using this definition.
|
||||
// The module also provides convenience functions to access memory buffers
|
||||
// contained in Python objects or wrap memory buffers in Python objects.
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
@ -56,6 +28,7 @@
|
||||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#define OFFSET_BITS 17
|
||||
#define LEN_BITS (OFFSET_BITS + BITF_OFF_BITS)
|
||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||
#error Invalid encoding field length
|
||||
#endif
|
||||
@ -172,7 +145,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
// Elements of array are scalar
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
item_s = uctypes_struct_scalar_size(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
@ -400,10 +373,8 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
// printf("scalar type=%d offset=%x\n", val_type, offset);
|
||||
|
||||
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_aligned(val_type, self->addr + offset, 0);
|
||||
@ -420,9 +391,9 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
}
|
||||
}
|
||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
uint bit_offset = (offset >> OFFSET_BITS) & 31;
|
||||
uint bit_len = (offset >> LEN_BITS) & 31;
|
||||
offset &= (1 << OFFSET_BITS) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||
@ -470,7 +441,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
// printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
@ -495,7 +465,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
o->desc = MP_OBJ_FROM_PTR(sub);
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
// printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
}
|
||||
@ -553,7 +522,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
|
||||
return value; // just !MP_OBJ_NULL
|
||||
}
|
||||
} else {
|
||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
||||
byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
@ -628,9 +597,8 @@ STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
// addressof()
|
||||
// Return address of object's data (applies to objects providing the buffer interface).
|
||||
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
@ -638,25 +606,20 @@ STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
// bytearray_at()
|
||||
// Capture memory at given address of given size as bytearray.
|
||||
STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
// bytes_at()
|
||||
// Capture memory at given address of given size as bytes.
|
||||
STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_struct,
|
||||
@ -676,81 +639,63 @@ STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
|
||||
|
||||
/// \moduleref uctypes
|
||||
|
||||
/// \constant NATIVE - Native structure layout - native endianness,
|
||||
/// platform-specific field alignment
|
||||
{ MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
|
||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
|
||||
|
||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
||||
{ MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \constant UINT32 - uint32_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
/// \constant INT32 - int32_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
/// \constant UINT64 - uint64_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
/// \constant INT64 - int64_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||
// C native type aliases. These depend on GCC-compatible predefined
|
||||
// preprocessor macros.
|
||||
#if __SIZEOF_SHORT__ == 2
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_INT__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
|
@ -42,9 +42,16 @@
|
||||
|
||||
typedef struct _mp_obj_hash_t {
|
||||
mp_obj_base_t base;
|
||||
char state[0];
|
||||
bool final; // if set, update and digest raise an exception
|
||||
uintptr_t state[0]; // must be aligned to a machine word
|
||||
} mp_obj_hash_t;
|
||||
|
||||
static void uhashlib_ensure_not_final(mp_obj_hash_t *self) {
|
||||
if (self->final) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_UHASHLIB_SHA256
|
||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
|
||||
|
||||
@ -60,6 +67,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
||||
if (n_args == 1) {
|
||||
@ -70,6 +78,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -78,6 +87,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 32);
|
||||
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
|
||||
@ -102,6 +113,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
||||
mp_arg_check_num(n_args, kw_args, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
@ -112,6 +124,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
check_not_unicode(arg);
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -120,6 +133,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
|
||||
@ -153,6 +168,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
mp_arg_check_num(n_args, kw_args, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
SHA1_Init((SHA1_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
@ -163,6 +179,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
check_not_unicode(arg);
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -171,6 +188,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA1_SIZE);
|
||||
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
|
||||
@ -190,6 +209,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
||||
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
@ -200,6 +220,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -208,6 +229,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 20);
|
||||
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
|
||||
@ -241,6 +264,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
MD5_Init((MD5_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
@ -250,6 +274,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
|
||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -258,6 +283,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, MD5_SIZE);
|
||||
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
|
||||
@ -277,6 +304,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
||||
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
@ -287,6 +315,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
|
||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
@ -295,6 +324,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 16);
|
||||
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
|
||||
|
@ -66,8 +66,11 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) {
|
||||
|
||||
STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
|
||||
int n = mp_obj_get_int(num_in);
|
||||
if (n > 32 || n == 0) {
|
||||
mp_raise_ValueError(NULL);
|
||||
if (n > 32 || n < 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
|
||||
}
|
||||
if (n == 0) {
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
}
|
||||
uint32_t mask = ~0;
|
||||
// Beware of C undefined behavior when shifting by >= than bit size
|
||||
|
@ -20,10 +20,6 @@
|
||||
// Flags for poll()
|
||||
#define FLAG_ONESHOT (1)
|
||||
|
||||
/// \module select - Provides select function to wait for events on a stream
|
||||
///
|
||||
/// This module provides the select function.
|
||||
|
||||
typedef struct _poll_obj_t {
|
||||
mp_obj_t obj;
|
||||
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||
@ -91,7 +87,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
||||
return n_ready;
|
||||
}
|
||||
|
||||
/// \function select(rlist, wlist, xlist[, timeout])
|
||||
// select(rlist, wlist, xlist[, timeout])
|
||||
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||
// get array data from tuple/list arguments
|
||||
size_t rwx_len[3];
|
||||
@ -158,8 +154,6 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
||||
|
||||
/// \class Poll - poll class
|
||||
|
||||
typedef struct _mp_obj_poll_t {
|
||||
mp_obj_base_t base;
|
||||
mp_map_t poll_map;
|
||||
@ -170,7 +164,7 @@ typedef struct _mp_obj_poll_t {
|
||||
mp_obj_t ret_tuple;
|
||||
} mp_obj_poll_t;
|
||||
|
||||
/// \method register(obj[, eventmask])
|
||||
// register(obj[, eventmask])
|
||||
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_uint_t flags;
|
||||
@ -184,7 +178,7 @@ STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
||||
|
||||
/// \method unregister(obj)
|
||||
// unregister(obj)
|
||||
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
||||
@ -193,7 +187,7 @@ STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
|
||||
|
||||
/// \method modify(obj, eventmask)
|
||||
// modify(obj, eventmask)
|
||||
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
||||
@ -328,7 +322,7 @@ STATIC const mp_obj_type_t mp_type_poll = {
|
||||
.locals_dict = (void *)&poll_locals_dict,
|
||||
};
|
||||
|
||||
/// \function poll()
|
||||
// poll()
|
||||
STATIC mp_obj_t select_poll(void) {
|
||||
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
|
||||
poll->base.type = &mp_type_poll;
|
||||
|
@ -175,6 +175,10 @@ def run_until_complete(main_task=None):
|
||||
if not exc:
|
||||
t.coro.send(None)
|
||||
else:
|
||||
# If the task is finished and on the run queue and gets here, then it
|
||||
# had an exception and was not await'ed on. Throwing into it now will
|
||||
# raise StopIteration and the code below will catch this and run the
|
||||
# call_exception_handler function.
|
||||
t.data = None
|
||||
t.coro.throw(exc)
|
||||
except excs_all as er:
|
||||
@ -185,22 +189,32 @@ def run_until_complete(main_task=None):
|
||||
if isinstance(er, StopIteration):
|
||||
return er.value
|
||||
raise er
|
||||
# Schedule any other tasks waiting on the completion of this task
|
||||
waiting = False
|
||||
if hasattr(t, "waiting"):
|
||||
while t.waiting.peek():
|
||||
_task_queue.push_head(t.waiting.pop_head())
|
||||
waiting = True
|
||||
t.waiting = None # Free waiting queue head
|
||||
if not waiting and not isinstance(er, excs_stop):
|
||||
# An exception ended this detached task, so queue it for later
|
||||
# execution to handle the uncaught exception if no other task retrieves
|
||||
# the exception in the meantime (this is handled by Task.throw).
|
||||
_task_queue.push_head(t)
|
||||
# Indicate task is done by setting coro to the task object itself
|
||||
t.coro = t
|
||||
# Save return value of coro to pass up to caller
|
||||
t.data = er
|
||||
if t.state:
|
||||
# Task was running but is now finished.
|
||||
waiting = False
|
||||
if t.state is True:
|
||||
# "None" indicates that the task is complete and not await'ed on (yet).
|
||||
t.state = None
|
||||
else:
|
||||
# Schedule any other tasks waiting on the completion of this task.
|
||||
while t.state.peek():
|
||||
_task_queue.push_head(t.state.pop_head())
|
||||
waiting = True
|
||||
# "False" indicates that the task is complete and has been await'ed on.
|
||||
t.state = False
|
||||
if not waiting and not isinstance(er, excs_stop):
|
||||
# An exception ended this detached task, so queue it for later
|
||||
# execution to handle the uncaught exception if no other task retrieves
|
||||
# the exception in the meantime (this is handled by Task.throw).
|
||||
_task_queue.push_head(t)
|
||||
# Save return value of coro to pass up to caller.
|
||||
t.data = er
|
||||
elif t.state is None:
|
||||
# Task is already finished and nothing await'ed on the task,
|
||||
# so call the exception handler.
|
||||
_exc_context["exception"] = exc
|
||||
_exc_context["future"] = t
|
||||
Loop.call_exception_handler(_exc_context)
|
||||
|
||||
|
||||
# Create a new task from a coroutine and run it until it finishes
|
||||
|
@ -30,6 +30,10 @@ class Stream:
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.read(n)
|
||||
|
||||
async def readinto(self, buf):
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.readinto(buf)
|
||||
|
||||
async def readexactly(self, n):
|
||||
r = b""
|
||||
while n:
|
||||
@ -82,7 +86,7 @@ async def open_connection(host, port):
|
||||
try:
|
||||
s.connect(ai[-1])
|
||||
except OSError as er:
|
||||
if er.args[0] != EINPROGRESS:
|
||||
if er.errno != EINPROGRESS:
|
||||
raise er
|
||||
yield core._io_queue.queue_write(s)
|
||||
return ss, ss
|
||||
@ -112,7 +116,6 @@ class Server:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(ai[-1])
|
||||
s.listen(backlog)
|
||||
self.task = core.cur_task
|
||||
# Accept incoming connections
|
||||
while True:
|
||||
try:
|
||||
@ -135,7 +138,7 @@ class Server:
|
||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||
async def start_server(cb, host, port, backlog=5):
|
||||
s = Server()
|
||||
core.create_task(s._serve(cb, host, port, backlog))
|
||||
s.task = core.create_task(s._serve(cb, host, port, backlog))
|
||||
return s
|
||||
|
||||
|
||||
|
@ -123,6 +123,7 @@ class Task:
|
||||
def __init__(self, coro, globals=None):
|
||||
self.coro = coro # Coroutine of this Task
|
||||
self.data = None # General data for queue it is waiting on
|
||||
self.state = True # None, False, True or a TaskQueue instance
|
||||
self.ph_key = 0 # Pairing heap
|
||||
self.ph_child = None # Paring heap
|
||||
self.ph_child_last = None # Paring heap
|
||||
@ -130,30 +131,30 @@ class Task:
|
||||
self.ph_rightmost_parent = None # Paring heap
|
||||
|
||||
def __iter__(self):
|
||||
if self.coro is self:
|
||||
# Signal that the completed-task has been await'ed on.
|
||||
self.waiting = None
|
||||
elif not hasattr(self, "waiting"):
|
||||
# Lazily allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.waiting = TaskQueue()
|
||||
if not self.state:
|
||||
# Task finished, signal that is has been await'ed on.
|
||||
self.state = False
|
||||
elif self.state is True:
|
||||
# Allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.state = TaskQueue()
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
# Task finished, raise return value to caller so it can continue.
|
||||
raise self.data
|
||||
else:
|
||||
# Put calling task on waiting queue.
|
||||
self.waiting.push_head(core.cur_task)
|
||||
self.state.push_head(core.cur_task)
|
||||
# Set calling task's data to this task that it waits on, to double-link it.
|
||||
core.cur_task.data = self
|
||||
|
||||
def done(self):
|
||||
return self.coro is self
|
||||
return not self.state
|
||||
|
||||
def cancel(self):
|
||||
# Check if task is already finished.
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
return False
|
||||
# Can't cancel self (not supported yet).
|
||||
if self is core.cur_task:
|
||||
@ -172,13 +173,3 @@ class Task:
|
||||
core._task_queue.push_head(self)
|
||||
self.data = core.CancelledError
|
||||
return True
|
||||
|
||||
def throw(self, value):
|
||||
# This task raised an exception which was uncaught; handle that now.
|
||||
# Set the data because it was cleared by the main scheduling loop.
|
||||
self.data = value
|
||||
if not hasattr(self, "waiting"):
|
||||
# Nothing await'ed on the task so call the exception handler.
|
||||
core._exc_context["exception"] = value
|
||||
core._exc_context["future"] = self
|
||||
core.Loop.call_exception_handler(core._exc_context)
|
||||
|
@ -264,7 +264,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
|
||||
|
||||
/// Change current directory.
|
||||
// Change current directory.
|
||||
STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
const char *path;
|
||||
@ -280,7 +280,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
|
||||
|
||||
/// Get the current directory.
|
||||
// Get the current directory.
|
||||
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
@ -292,8 +292,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
|
||||
|
||||
/// \function stat(path)
|
||||
/// Get the status of a file or directory.
|
||||
// Get the status of a file or directory.
|
||||
STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
@ -622,8 +622,8 @@ friendly_repl_reset:
|
||||
|
||||
// If the GC is locked at this point there is no way out except a reset,
|
||||
// so force the GC to be unlocked to help the user debug what went wrong.
|
||||
if (MP_STATE_MEM(gc_lock_depth) != 0) {
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
if (MP_STATE_THREAD(gc_lock_depth) != 0) {
|
||||
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||
}
|
||||
|
||||
vstr_reset(&line);
|
||||
|
@ -47,9 +47,8 @@ extern pyexec_mode_kind_t pyexec_mode_kind;
|
||||
extern int pyexec_system_exit;
|
||||
|
||||
#define PYEXEC_FORCED_EXIT (0x100)
|
||||
#define PYEXEC_SWITCH_MODE (0x200)
|
||||
#define PYEXEC_EXCEPTION (0x400)
|
||||
#define PYEXEC_DEEP_SLEEP (0x800)
|
||||
#define PYEXEC_EXCEPTION (0x200)
|
||||
#define PYEXEC_DEEP_SLEEP (0x400)
|
||||
|
||||
int pyexec_raw_repl(void);
|
||||
int pyexec_friendly_repl(void);
|
||||
|
132
lib/utils/semihosting.c
Normal file
132
lib/utils/semihosting.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Ayke van Laethem
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "semihosting.h"
|
||||
|
||||
// Resources:
|
||||
// http://embed.rs/articles/2016/semi-hosting-rust/
|
||||
// https://wiki.dlang.org/Minimal_semihosted_ARM_Cortex-M_%22Hello_World%22
|
||||
// https://github.com/arduino/OpenOCD/blob/master/src/target/arm_semihosting.c
|
||||
|
||||
#define SYS_OPEN 0x01
|
||||
#define SYS_WRITEC 0x03
|
||||
#define SYS_WRITE 0x05
|
||||
#define SYS_READC 0x07
|
||||
|
||||
// Constants:
|
||||
#define OPEN_MODE_READ (0) // mode "r"
|
||||
#define OPEN_MODE_WRITE (4) // mode "w"
|
||||
|
||||
#ifndef __thumb__
|
||||
#error Semihosting is only implemented for ARM microcontrollers.
|
||||
#endif
|
||||
|
||||
static int mp_semihosting_stdout;
|
||||
|
||||
static uint32_t mp_semihosting_call(uint32_t num, const void *arg) {
|
||||
// A semihosting call works as follows, similar to a SVCall:
|
||||
// * the call is invoked by a special breakpoint: 0xAB
|
||||
// * the command is placed in r0
|
||||
// * a pointer to the arguments is placed in r1
|
||||
// * the return value is placed in r0
|
||||
// Note that because it uses the breakpoint instruction, applications
|
||||
// will hang if they're not connected to a debugger. And they'll be
|
||||
// stuck in a breakpoint if semihosting is not specifically enabled in
|
||||
// the debugger.
|
||||
// Also note that semihosting is extremely slow (sometimes >100ms per
|
||||
// call).
|
||||
register uint32_t num_reg __asm__ ("r0") = num;
|
||||
register const void *args_reg __asm__ ("r1") = arg;
|
||||
__asm__ __volatile__ (
|
||||
"bkpt 0xAB\n" // invoke semihosting call
|
||||
: "+r" (num_reg) // call number and result
|
||||
: "r" (args_reg) // arguments
|
||||
: "memory"); // make sure args aren't optimized away
|
||||
return num_reg; // r0, which became the result
|
||||
}
|
||||
|
||||
static int mp_semihosting_open_console(uint32_t mode) {
|
||||
struct {
|
||||
char *name;
|
||||
uint32_t mode;
|
||||
uint32_t name_len;
|
||||
} args = {
|
||||
.name = ":tt", // magic path to console
|
||||
.mode = mode, // e.g. "r", "w" (see OPEN_MODE_* constants)
|
||||
.name_len = 3, // strlen(":tt")
|
||||
};
|
||||
return mp_semihosting_call(SYS_OPEN, &args);
|
||||
}
|
||||
|
||||
void mp_semihosting_init() {
|
||||
mp_semihosting_stdout = mp_semihosting_open_console(OPEN_MODE_WRITE);
|
||||
}
|
||||
|
||||
int mp_semihosting_rx_char() {
|
||||
return mp_semihosting_call(SYS_READC, NULL);
|
||||
}
|
||||
|
||||
static void mp_semihosting_tx_char(char c) {
|
||||
mp_semihosting_call(SYS_WRITEC, &c);
|
||||
}
|
||||
|
||||
uint32_t mp_semihosting_tx_strn(const char *str, size_t len) {
|
||||
if (len == 0) {
|
||||
return 0; // nothing to do
|
||||
}
|
||||
if (len == 1) {
|
||||
mp_semihosting_tx_char(*str); // maybe faster?
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t fd;
|
||||
const char *str;
|
||||
uint32_t len;
|
||||
} args = {
|
||||
.fd = mp_semihosting_stdout,
|
||||
.str = str,
|
||||
.len = len,
|
||||
};
|
||||
return mp_semihosting_call(SYS_WRITE, &args);
|
||||
}
|
||||
|
||||
uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len) {
|
||||
// Write chunks of data until (excluding) the first '\n' character,
|
||||
// insert a '\r' character, and then continue with the next chunk
|
||||
// (starting with '\n').
|
||||
// Doing byte-by-byte writes would be easier to implement but is far
|
||||
// too slow.
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
mp_semihosting_tx_strn(str + start, i - start);
|
||||
mp_semihosting_tx_char('\r');
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
return mp_semihosting_tx_strn(str + start, len - start);
|
||||
}
|
@ -2547,6 +2547,10 @@ msgstr ""
|
||||
msgid "binary op %q not implemented"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/modurandom.c
|
||||
msgid "bits must be 32 or less"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/busio/UART.c
|
||||
msgid "bits must be in range 5 to 9"
|
||||
msgstr ""
|
||||
@ -3158,6 +3162,10 @@ msgstr ""
|
||||
msgid "graphic must be 2048 bytes long"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/moduhashlib.c
|
||||
msgid "hash is final"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/moduheapq.c
|
||||
msgid "heap must be a list"
|
||||
msgstr ""
|
||||
|
@ -120,7 +120,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
|
||||
// Compare mp_interrupt_char with wanted_char and ignore if not matched
|
||||
if (mp_interrupt_char == wanted_char) {
|
||||
tud_cdc_read_flush(); // flush read fifo
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
// CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB.
|
||||
// So, we must notify the other task when a CTRL-C is received.
|
||||
xTaskNotifyGive(circuitpython_task);
|
||||
|
@ -81,7 +81,7 @@ STATIC void on_ble_evt(ble_evt_t *ble_evt, void *param) {
|
||||
for (size_t i = 0; i < write->len; ++i) {
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
if (write->data[i] == mp_interrupt_char) {
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -355,7 +355,7 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *handle) {
|
||||
if (context->sigint_enabled) {
|
||||
if (context->rx_char == CHAR_CTRL_C) {
|
||||
common_hal_busio_uart_clear_rx_buffer(context);
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,13 @@ STATIC mp_obj_t extra_coverage(void) {
|
||||
size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
|
||||
len = mp_repl_autocomplete("i", 1, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
mp_repl_autocomplete("import ", 7, &mp_plat_print, &str);
|
||||
len = mp_repl_autocomplete("import ut", 9, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
mp_repl_autocomplete("import utime", 12, &mp_plat_print, &str);
|
||||
|
||||
mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)));
|
||||
mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str);
|
||||
len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str);
|
||||
@ -485,7 +492,7 @@ STATIC mp_obj_t extra_coverage(void) {
|
||||
}
|
||||
|
||||
// setting the keyboard interrupt and raising it during mp_handle_pending
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_handle_pending(true);
|
||||
@ -495,13 +502,13 @@ STATIC mp_obj_t extra_coverage(void) {
|
||||
}
|
||||
|
||||
// setting the keyboard interrupt (twice) and cancelling it during mp_handle_pending
|
||||
mp_keyboard_interrupt();
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
mp_handle_pending(false);
|
||||
|
||||
// setting keyboard interrupt and a pending event (intr should be handled first)
|
||||
mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(10));
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_handle_pending(true);
|
||||
nlr_pop();
|
||||
|
@ -450,7 +450,13 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
mp_stack_set_limit(40000 * (sizeof(void *) / 4));
|
||||
// Define a reasonable stack limit to detect stack overflow.
|
||||
mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
|
||||
#if defined(__arm__) && !defined(__thumb2__)
|
||||
// ARM (non-Thumb) architectures require more stack.
|
||||
stack_limit *= 2;
|
||||
#endif
|
||||
mp_stack_set_limit(stack_limit);
|
||||
|
||||
pre_process_options(argc, argv);
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/objint.h"
|
||||
|
||||
#include "supervisor/shared/translate.h"
|
||||
|
||||
@ -58,6 +59,18 @@
|
||||
* but may be later.
|
||||
*/
|
||||
|
||||
// This union is large enough to hold any supported argument/return value.
|
||||
typedef union _ffi_union_t {
|
||||
ffi_arg ffi;
|
||||
unsigned char B;
|
||||
unsigned short int H;
|
||||
unsigned int I;
|
||||
unsigned long int L;
|
||||
unsigned long long int Q;
|
||||
float flt;
|
||||
double dbl;
|
||||
} ffi_union_t;
|
||||
|
||||
typedef struct _mp_obj_opaque_t {
|
||||
mp_obj_base_t base;
|
||||
void *val;
|
||||
@ -153,10 +166,10 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unknown type"));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
|
||||
STATIC mp_obj_t return_ffi_value(ffi_union_t *val, char type) {
|
||||
switch (type) {
|
||||
case 's': {
|
||||
const char *s = (const char *)(intptr_t)val;
|
||||
const char *s = (const char *)(intptr_t)val->ffi;
|
||||
if (!s) {
|
||||
return mp_const_none;
|
||||
}
|
||||
@ -166,20 +179,30 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
|
||||
return mp_const_none;
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f': {
|
||||
union { ffi_arg ffi;
|
||||
float flt;
|
||||
} val_union = { .ffi = val };
|
||||
return mp_obj_new_float_from_f(val_union.flt);
|
||||
return mp_obj_new_float_from_f(val->flt);
|
||||
}
|
||||
case 'd': {
|
||||
double *p = (double *)&val;
|
||||
return mp_obj_new_float_from_d(*p);
|
||||
return mp_obj_new_float_from_d(val->dbl);
|
||||
}
|
||||
#endif
|
||||
case 'b':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'l':
|
||||
return mp_obj_new_int((signed)val->ffi);
|
||||
case 'B':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'L':
|
||||
return mp_obj_new_int_from_uint(val->ffi);
|
||||
case 'q':
|
||||
return mp_obj_new_int_from_ll(val->Q);
|
||||
case 'Q':
|
||||
return mp_obj_new_int_from_ull(val->Q);
|
||||
case 'O':
|
||||
return (mp_obj_t)(intptr_t)val;
|
||||
return (mp_obj_t)(intptr_t)val->ffi;
|
||||
default:
|
||||
return mp_obj_new_int(val);
|
||||
return mp_obj_new_int(val->ffi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,34 +387,74 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
|
||||
mp_printf(print, "<ffifunc %p>", self->func);
|
||||
}
|
||||
|
||||
STATIC unsigned long long ffi_get_int_value(mp_obj_t o) {
|
||||
if (mp_obj_is_small_int(o)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(o);
|
||||
} else {
|
||||
unsigned long long res;
|
||||
mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
|
||||
ffi_union_t ret;
|
||||
if ((argtype | 0x20) == 'q') {
|
||||
ret.Q = ffi_get_int_value(o);
|
||||
return ret;
|
||||
} else {
|
||||
mp_uint_t val = mp_obj_int_get_truncated(o);
|
||||
switch (argtype) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
ret.B = val;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
ret.H = val;
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
ret.I = val;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
ret.L = val;
|
||||
break;
|
||||
default:
|
||||
ret.ffi = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
(void)n_kw;
|
||||
mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
assert(n_kw == 0);
|
||||
assert(n_args == self->cif.nargs);
|
||||
|
||||
ffi_arg values[n_args];
|
||||
ffi_union_t values[n_args];
|
||||
void *valueptrs[n_args];
|
||||
const char *argtype = self->argtypes;
|
||||
for (uint i = 0; i < n_args; i++, argtype++) {
|
||||
mp_obj_t a = args[i];
|
||||
if (*argtype == 'O') {
|
||||
values[i] = (ffi_arg)(intptr_t)a;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)a;
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (*argtype == 'f') {
|
||||
float *p = (float *)&values[i];
|
||||
*p = mp_obj_get_float_to_f(a);
|
||||
values[i].flt = mp_obj_get_float_to_f(a);
|
||||
} else if (*argtype == 'd') {
|
||||
double *p = (double *)&values[i];
|
||||
*p = mp_obj_get_float_to_d(a);
|
||||
values[i].dbl = mp_obj_get_float_to_d(a);
|
||||
#endif
|
||||
} else if (a == mp_const_none) {
|
||||
values[i] = 0;
|
||||
values[i].ffi = 0;
|
||||
} else if (mp_obj_is_int(a)) {
|
||||
values[i] = mp_obj_int_get_truncated(a);
|
||||
values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
|
||||
} else if (mp_obj_is_str(a)) {
|
||||
const char *s = mp_obj_str_get_str(a);
|
||||
values[i] = (ffi_arg)(intptr_t)s;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)s;
|
||||
} else if (((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) {
|
||||
mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a);
|
||||
mp_buffer_info_t bufinfo;
|
||||
@ -399,32 +462,19 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
||||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
values[i] = (ffi_arg)(intptr_t)bufinfo.buf;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)bufinfo.buf;
|
||||
} else if (mp_obj_is_type(a, &fficallback_type)) {
|
||||
mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);
|
||||
values[i] = (ffi_arg)(intptr_t)p->func;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)p->func;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
valueptrs[i] = &values[i];
|
||||
}
|
||||
|
||||
// If ffi_arg is not big enough to hold a double, then we must pass along a
|
||||
// pointer to a memory location of the correct size.
|
||||
// TODO check if this needs to be done for other types which don't fit into
|
||||
// ffi_arg.
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
if (sizeof(ffi_arg) == 4 && self->rettype == 'd') {
|
||||
double retval;
|
||||
ffi_call(&self->cif, self->func, &retval, valueptrs);
|
||||
return mp_obj_new_float_from_d(retval);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ffi_arg retval;
|
||||
ffi_call(&self->cif, self->func, &retval, valueptrs);
|
||||
return return_ffi_value(retval, self->rettype);
|
||||
}
|
||||
ffi_union_t retval;
|
||||
ffi_call(&self->cif, self->func, &retval, valueptrs);
|
||||
return return_ffi_value(&retval, self->rettype);
|
||||
|
||||
error:
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("Don't know how to pass object to native function"));
|
||||
|
@ -126,7 +126,7 @@ void mp_thread_init(void) {
|
||||
thread->next = NULL;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%d", (int)thread->id);
|
||||
snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%ld", (long)thread->id);
|
||||
thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0);
|
||||
#else
|
||||
sem_init(&thread_signal_done, 0, 0);
|
||||
|
@ -57,7 +57,7 @@ STATIC void sighandler(int signum) {
|
||||
// this is the second time we are called, so die straight away
|
||||
exit(1);
|
||||
}
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
size_t n_args_max = (sig >> 1) & 0xffff;
|
||||
|
||||
if (n_kw && !takes_kw) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("function doesn't take keyword arguments"));
|
||||
@ -49,7 +49,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
|
||||
if (n_args_min == n_args_max) {
|
||||
if (n_args != n_args_min) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("function takes %d positional arguments but %d were given"),
|
||||
@ -58,7 +58,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
}
|
||||
} else {
|
||||
if (n_args < n_args_min) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -66,7 +66,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
n_args_min - n_args);
|
||||
#endif
|
||||
} else if (n_args > n_args_max) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -106,7 +106,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
||||
}
|
||||
if (kw == NULL) {
|
||||
if (allowed[i].flags & MP_ARG_REQUIRED) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst);
|
||||
@ -130,7 +130,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
||||
}
|
||||
if (pos_found < n_pos) {
|
||||
extra_positional:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
// TODO better error message
|
||||
@ -138,7 +138,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
||||
#endif
|
||||
}
|
||||
if (kws != NULL && kws_found < kws->used) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
// TODO better error message
|
||||
|
19
py/asmarm.c
19
py/asmarm.c
@ -38,25 +38,6 @@
|
||||
|
||||
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as) {
|
||||
if (as->base.pass == MP_ASM_PASS_EMIT) {
|
||||
#if defined(__linux__) && defined(__GNUC__)
|
||||
char *start = mp_asm_base_get_code(&as->base);
|
||||
char *end = start + mp_asm_base_get_code_size(&as->base);
|
||||
__builtin___clear_cache(start, end);
|
||||
#elif defined(__arm__)
|
||||
// flush I- and D-cache
|
||||
asm volatile (
|
||||
"0:"
|
||||
"mrc p15, 0, r15, c7, c10, 3\n"
|
||||
"bne 0b\n"
|
||||
"mov r0, #0\n"
|
||||
"mcr p15, 0, r0, c7, c7, 0\n"
|
||||
: : : "r0", "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Insert word into instruction flow
|
||||
STATIC void emit(asm_arm_t *as, uint op) {
|
||||
uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
|
||||
|
@ -72,7 +72,9 @@ typedef struct _asm_arm_t {
|
||||
uint stack_adjust;
|
||||
} asm_arm_t;
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as);
|
||||
static inline void asm_arm_end_pass(asm_arm_t *as) {
|
||||
(void)as;
|
||||
}
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals);
|
||||
void asm_arm_exit(asm_arm_t *as);
|
||||
|
@ -35,7 +35,6 @@
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/persistentcode.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/asmthumb.h"
|
||||
|
||||
#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32)
|
||||
@ -62,20 +61,6 @@ static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
|
||||
return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
|
||||
}
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
(void)as;
|
||||
// could check labels are resolved...
|
||||
|
||||
#if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1
|
||||
if (as->base.pass == MP_ASM_PASS_EMIT) {
|
||||
// flush D-cache, so the code emitted is stored in memory
|
||||
MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size);
|
||||
// invalidate I-cache
|
||||
SCB_InvalidateICache();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {
|
||||
byte *c = asm_thumb_get_cur_to_write_bytes(as, 1);
|
||||
|
@ -70,7 +70,9 @@ typedef struct _asm_thumb_t {
|
||||
uint32_t stack_adjust;
|
||||
} asm_thumb_t;
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as);
|
||||
static inline void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
(void)as;
|
||||
}
|
||||
|
||||
void asm_thumb_entry(asm_thumb_t *as, int num_locals);
|
||||
void asm_thumb_exit(asm_thumb_t *as);
|
||||
|
15
py/asmx64.c
15
py/asmx64.c
@ -285,31 +285,28 @@ void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_TO_R64);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
4
py/bc.c
4
py/bc.c
@ -77,7 +77,7 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
|
||||
#endif
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
// generic message, used also for other argument issues
|
||||
(void)f;
|
||||
(void)expected;
|
||||
@ -221,7 +221,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
}
|
||||
// Didn't find name match with positional args
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -332,7 +332,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
// We must have some component left over to import from
|
||||
if (p == this_name) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("cannot perform relative import"));
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("cannot perform relative import"));
|
||||
}
|
||||
|
||||
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
|
||||
@ -421,7 +421,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
mp_module_call_init(mod_name, module_obj);
|
||||
} else {
|
||||
// couldn't find the file, so fail
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError,
|
||||
@ -533,7 +533,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
#endif
|
||||
|
||||
// Couldn't find the module, so fail
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr);
|
||||
|
45
py/compile.c
45
py/compile.c
@ -1795,16 +1795,6 @@ STATIC void compile_yield_from(compiler_t *comp) {
|
||||
}
|
||||
|
||||
#if MICROPY_PY_ASYNC_AWAIT
|
||||
STATIC bool compile_require_async_context(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
int scope_flags = comp->scope_cur->scope_flags;
|
||||
if ((scope_flags & MP_SCOPE_FLAG_ASYNC) != 0) {
|
||||
return true;
|
||||
}
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns,
|
||||
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
|
||||
EMIT_ARG(load_method, method, false);
|
||||
EMIT_ARG(call_method, 0, 0, 0);
|
||||
@ -1813,11 +1803,6 @@ STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
|
||||
|
||||
STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||
|
||||
if (!compile_require_async_context(comp, pns)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
|
||||
uint while_else_label = comp_next_label(comp);
|
||||
uint try_exception_label = comp_next_label(comp);
|
||||
@ -1980,9 +1965,6 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_
|
||||
}
|
||||
|
||||
STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (!compile_require_async_context(comp, pns)) {
|
||||
return;
|
||||
}
|
||||
// get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
|
||||
mp_parse_node_t *nodes;
|
||||
size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
|
||||
@ -2000,13 +1982,23 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
compile_funcdef(comp, pns0);
|
||||
scope_t *fscope = (scope_t *)pns0->nodes[4];
|
||||
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC;
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
|
||||
// async for
|
||||
compile_async_for_stmt(comp, pns0);
|
||||
} else {
|
||||
// async with
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);
|
||||
compile_async_with_stmt(comp, pns0);
|
||||
// async for/with; first verify the scope is a generator
|
||||
int scope_flags = comp->scope_cur->scope_flags;
|
||||
if (!(scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns0,
|
||||
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
|
||||
// async for
|
||||
compile_async_for_stmt(comp, pns0);
|
||||
} else {
|
||||
// async with
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);
|
||||
compile_async_with_stmt(comp, pns0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2627,7 +2619,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
|
||||
compile_node(comp, pn_i);
|
||||
if (is_dict) {
|
||||
if (!is_key_value) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
|
||||
#else
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting key:value for dict"));
|
||||
@ -2637,7 +2629,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
|
||||
EMIT(store_map);
|
||||
} else {
|
||||
if (is_key_value) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
|
||||
#else
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting just a value for set"));
|
||||
@ -2799,7 +2791,6 @@ STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pn
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("'await' outside function"));
|
||||
return;
|
||||
}
|
||||
compile_require_async_context(comp, pns);
|
||||
compile_atom_expr_normal(comp, pns);
|
||||
|
||||
// If it's an awaitable thing, need to reach for the __await__ method for the coroutine.
|
||||
|
@ -81,6 +81,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
|
||||
|
||||
#define mp_type_type (*mp_fun_table.type_type)
|
||||
#define mp_type_str (*mp_fun_table.type_str)
|
||||
#define mp_type_tuple (*((mp_obj_base_t *)mp_const_empty_tuple)->type)
|
||||
#define mp_type_list (*mp_fun_table.type_list)
|
||||
#define mp_type_EOFError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))
|
||||
#define mp_type_IndexError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))
|
||||
@ -121,6 +122,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
|
||||
|
||||
#define mp_obj_len(o) (mp_obj_len_dyn(o))
|
||||
#define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val)))
|
||||
#define mp_obj_get_array(o, len, items) (mp_obj_get_array_dyn((o), (len), (items)))
|
||||
#define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item)))
|
||||
|
||||
#define mp_obj_assert_native_inited(o) (mp_fun_table.assert_native_inited((o)))
|
||||
@ -264,4 +266,23 @@ static inline void mp_raise_OSError_dyn(int er) {
|
||||
#define mp_obj_get_float(o) (mp_obj_get_float_to_d((o)))
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
// Inline function definitions.
|
||||
|
||||
// *items may point inside a GC block
|
||||
static inline void mp_obj_get_array_dyn(mp_obj_t o, size_t *len, mp_obj_t **items) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(o);
|
||||
if (type == &mp_type_tuple) {
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(o);
|
||||
*len = t->len;
|
||||
*items = &t->items[0];
|
||||
} else if (type == &mp_type_list) {
|
||||
mp_obj_list_t *l = MP_OBJ_TO_PTR(o);
|
||||
*len = l->len;
|
||||
*items = l->items;
|
||||
} else {
|
||||
mp_raise_TypeError("expected tuple/list");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H
|
||||
|
@ -108,6 +108,31 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
|
||||
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
|
||||
|
||||
// Some architectures require flushing/invalidation of the I/D caches,
|
||||
// so that the generated native code which was created in data RAM will
|
||||
// be available for execution from instruction RAM.
|
||||
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
|
||||
#if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1
|
||||
// Flush D-cache, so the code emitted is stored in RAM.
|
||||
MP_HAL_CLEAN_DCACHE(fun_data, fun_len);
|
||||
// Invalidate I-cache, so the newly-created code is reloaded from RAM.
|
||||
SCB_InvalidateICache();
|
||||
#endif
|
||||
#elif MICROPY_EMIT_ARM
|
||||
#if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
|
||||
__builtin___clear_cache(fun_data, (uint8_t *)fun_data + fun_len);
|
||||
#elif defined(__arm__)
|
||||
// Flush I-cache and D-cache.
|
||||
asm volatile (
|
||||
"0:"
|
||||
"mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
|
||||
"bne 0b\n"
|
||||
"mov r0, #0\n"
|
||||
"mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
|
||||
: : : "r0", "cc");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
|
@ -1797,7 +1797,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
int reg_index = REG_ARG_2;
|
||||
int reg_value = REG_ARG_3;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_value);
|
||||
#if N_X86
|
||||
#if N_X64 || N_X86
|
||||
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
|
||||
emit_pre_pop_reg(emit, &vtype_value, reg_value);
|
||||
#else
|
||||
@ -1884,7 +1884,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
|
||||
MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index));
|
||||
}
|
||||
#if N_X86
|
||||
#if N_X64 || N_X86
|
||||
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
|
||||
emit_pre_pop_reg(emit, &vtype_value, reg_value);
|
||||
#else
|
||||
|
61
py/gc.c
61
py/gc.c
@ -167,7 +167,7 @@ void gc_init(void *start, void *end) {
|
||||
MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void *)PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB));
|
||||
|
||||
// unlock the GC
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||
|
||||
// allow auto collection
|
||||
MP_STATE_MEM(gc_auto_collect_enabled) = true;
|
||||
@ -200,19 +200,20 @@ void gc_deinit(void) {
|
||||
}
|
||||
|
||||
void gc_lock(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
GC_EXIT();
|
||||
// This does not need to be atomic or have the GC mutex because:
|
||||
// - each thread has its own gc_lock_depth so there are no races between threads;
|
||||
// - a hard interrupt will only change gc_lock_depth during its execution, and
|
||||
// upon return will restore the value of gc_lock_depth.
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
}
|
||||
|
||||
void gc_unlock(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)--;
|
||||
GC_EXIT();
|
||||
// This does not need to be atomic, See comment above in gc_lock.
|
||||
MP_STATE_THREAD(gc_lock_depth)--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return MP_STATE_MEM(gc_lock_depth) != 0;
|
||||
return MP_STATE_THREAD(gc_lock_depth) != 0;
|
||||
}
|
||||
|
||||
#ifndef TRACE_MARK
|
||||
@ -356,7 +357,7 @@ STATIC void gc_mark(void *ptr) {
|
||||
|
||||
void gc_collect_start(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
#if MICROPY_GC_ALLOC_THRESHOLD
|
||||
MP_STATE_MEM(gc_alloc_amount) = 0;
|
||||
#endif
|
||||
@ -383,9 +384,19 @@ void gc_collect_ptr(void *ptr) {
|
||||
gc_mark(ptr);
|
||||
}
|
||||
|
||||
// Address sanitizer needs to know that the access to ptrs[i] must always be
|
||||
// considered OK, even if it's a load from an address that would normally be
|
||||
// prohibited (due to being undefined, in a red zone, etc).
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
__attribute__((no_sanitize_address))
|
||||
#endif
|
||||
static void *gc_get_ptr(void **ptrs, int i) {
|
||||
return ptrs[i];
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
void *ptr = ptrs[i];
|
||||
void *ptr = gc_get_ptr(ptrs, i);
|
||||
gc_mark(ptr);
|
||||
}
|
||||
}
|
||||
@ -397,13 +408,13 @@ void gc_collect_end(void) {
|
||||
MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
|
||||
}
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
|
||||
MP_STATE_MEM(gc_lock_depth)--;
|
||||
MP_STATE_THREAD(gc_lock_depth)--;
|
||||
GC_EXIT();
|
||||
}
|
||||
|
||||
void gc_sweep_all(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
gc_collect_end();
|
||||
}
|
||||
@ -488,18 +499,17 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags, bool long_lived) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check if GC is locked
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (MP_STATE_MEM(gc_pool_start) == 0) {
|
||||
reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
|
||||
}
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
// check if GC is locked
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
GC_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t found_block = 0xffffffff;
|
||||
size_t end_block;
|
||||
size_t start_block;
|
||||
@ -676,13 +686,13 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
||||
// force the freeing of a piece of memory
|
||||
// TODO: freeing here does not call finaliser
|
||||
void gc_free(void *ptr) {
|
||||
GC_ENTER();
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
// TODO how to deal with this error?
|
||||
GC_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
DEBUG_printf("gc_free(%p)\n", ptr);
|
||||
|
||||
if (ptr == NULL) {
|
||||
@ -837,15 +847,14 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ptr = ptr_in;
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
GC_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the GC block number corresponding to this pointer
|
||||
assert(VERIFY_PTR(ptr));
|
||||
size_t block = BLOCK_FROM_PTR(ptr);
|
||||
|
@ -20,6 +20,7 @@ ifeq ("$(origin V)", "command line")
|
||||
BUILD_VERBOSE=$(V)
|
||||
endif
|
||||
ifndef BUILD_VERBOSE
|
||||
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
|
||||
BUILD_VERBOSE = 0
|
||||
endif
|
||||
ifeq ($(BUILD_VERBOSE),0)
|
||||
@ -32,10 +33,6 @@ else
|
||||
Q =
|
||||
STEPECHO = @echo
|
||||
endif
|
||||
# Since this is a new feature, advertise it
|
||||
ifeq ($(BUILD_VERBOSE),0)
|
||||
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
|
||||
endif
|
||||
|
||||
# default settings; can be overridden in main Makefile
|
||||
|
||||
|
@ -125,9 +125,13 @@ if(MICROPY_FROZEN_MANIFEST)
|
||||
MICROPY_MODULE_FROZEN_MPY=\(1\)
|
||||
)
|
||||
|
||||
if(NOT MICROPY_LIB_DIR)
|
||||
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${MICROPY_FROZEN_CONTENT}
|
||||
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
|
||||
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
|
||||
DEPENDS MICROPY_FORCE_BUILD
|
||||
${MICROPY_QSTRDEFS_GENERATED}
|
||||
VERBATIM
|
||||
|
@ -374,7 +374,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("ord expects a character"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -132,13 +132,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_he
|
||||
|
||||
STATIC mp_obj_t mp_micropython_heap_unlock(void) {
|
||||
gc_unlock();
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock);
|
||||
|
||||
#if MICROPY_PY_MICROPYTHON_HEAP_LOCKED
|
||||
STATIC mp_obj_t mp_micropython_heap_locked(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked);
|
||||
#endif
|
||||
|
@ -173,6 +173,9 @@ STATIC void *thread_entry(void *args_in) {
|
||||
mp_pystack_init(mini_pystack, &mini_pystack[128]);
|
||||
#endif
|
||||
|
||||
// The GC starts off unlocked on this thread.
|
||||
ts.gc_lock_depth = 0;
|
||||
|
||||
// set locals and globals from the calling context
|
||||
mp_locals_set(args->dict_locals);
|
||||
mp_globals_set(args->dict_globals);
|
||||
|
@ -570,6 +570,12 @@
|
||||
#define MICROPY_VM_HOOK_RETURN
|
||||
#endif
|
||||
|
||||
// Hook for mp_sched_schedule when a function gets scheduled on sched_queue
|
||||
// (this macro executes within an atomic section)
|
||||
#ifndef MICROPY_SCHED_HOOK_SCHEDULED
|
||||
#define MICROPY_SCHED_HOOK_SCHEDULED
|
||||
#endif
|
||||
|
||||
// Whether to include the garbage collector
|
||||
#ifndef MICROPY_ENABLE_GC
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
@ -692,6 +698,8 @@ typedef long long mp_longint_impl_t;
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#endif
|
||||
|
||||
// Exception messages are removed (requires disabling MICROPY_ROM_TEXT_COMPRESSION)
|
||||
#define MICROPY_ERROR_REPORTING_NONE (0)
|
||||
// Exception messages are short static strings
|
||||
#define MICROPY_ERROR_REPORTING_TERSE (1)
|
||||
// Exception messages provide basic error details
|
||||
@ -1518,8 +1526,12 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to wrap functions with attributes */
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_KEYBOARD_INTERRUPT
|
||||
#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
|
||||
#define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT
|
||||
#define MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE
|
||||
|
@ -82,7 +82,6 @@ typedef struct _mp_state_mem_t {
|
||||
|
||||
int gc_stack_overflow;
|
||||
MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
|
||||
uint16_t gc_lock_depth;
|
||||
|
||||
// This variable controls auto garbage collection. If set to false then the
|
||||
// GC won't automatically run when gc_alloc can't find enough blocks. But
|
||||
@ -253,6 +252,9 @@ typedef struct _mp_state_thread_t {
|
||||
uint8_t *pystack_cur;
|
||||
#endif
|
||||
|
||||
// Locking of the GC is done per thread.
|
||||
uint16_t gc_lock_depth;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// START ROOT POINTER SECTION
|
||||
// Everything that needs GC scanning must start here, and
|
||||
|
@ -50,7 +50,7 @@ __asm(
|
||||
"stp x27, x28, [x0, #96]\n"
|
||||
"str x29, [x0, #112]\n"
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"b _nlr_push_tail \n" // do the rest in C
|
||||
"b _nlr_push_tail \n" // do the rest in C
|
||||
#else
|
||||
"b nlr_push_tail \n" // do the rest in C
|
||||
#endif
|
||||
|
@ -58,7 +58,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
|
||||
#else
|
||||
|
||||
__asm volatile (
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"pop %rbp \n" // undo function's prelude
|
||||
#endif
|
||||
"movq (%rsp), %rax \n" // load return %rip
|
||||
@ -70,7 +70,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
|
||||
"movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf
|
||||
"movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf
|
||||
"movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"jmp _nlr_push_tail \n" // do the rest in C
|
||||
#else
|
||||
"jmp nlr_push_tail \n" // do the rest in C
|
||||
|
20
py/obj.c
20
py/obj.c
@ -391,7 +391,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
|
||||
mp_float_t val;
|
||||
|
||||
if (!mp_obj_get_float_maybe(arg, &val)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert to %q"), MP_QSTR_float);
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -431,7 +431,7 @@ bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag)
|
||||
|
||||
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
if (!mp_obj_get_complex_maybe(arg, real, imag)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -449,7 +449,7 @@ void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
|
||||
} else if (mp_obj_is_type(o, &mp_type_list)) {
|
||||
mp_obj_list_get(o, len, items);
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -463,7 +463,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
|
||||
size_t seq_len;
|
||||
mp_obj_get_array(o, &seq_len, items);
|
||||
if (seq_len != len) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
@ -478,7 +478,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
|
||||
if (mp_obj_is_small_int(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -498,7 +498,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
|
||||
}
|
||||
} else {
|
||||
if (i < 0 || (mp_uint_t)i >= len) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_IndexError(MP_ERROR_TEXT("index out of range"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_IndexError,
|
||||
@ -533,7 +533,7 @@ mp_obj_t mp_obj_id(mp_obj_t o_in) {
|
||||
mp_obj_t mp_obj_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -575,21 +575,21 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
|
||||
}
|
||||
}
|
||||
if (value == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
|
||||
#endif
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
|
||||
#endif
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
5
py/obj.h
5
py/obj.h
@ -792,8 +792,13 @@ extern uint64_t float_to_uint64(float f);
|
||||
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
|
||||
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
|
||||
#define mp_obj_new_exception_msg(exc_type, msg) mp_obj_new_exception(exc_type)
|
||||
#define mp_obj_new_exception_msg_varg(exc_type, ...) mp_obj_new_exception(exc_type)
|
||||
#else
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg);
|
||||
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
#endif
|
||||
#ifdef va_start
|
||||
mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list ap); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
#endif
|
||||
|
@ -211,11 +211,7 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args,
|
||||
|
||||
mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
|
||||
mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
|
||||
self->base.type = &mp_type_memoryview;
|
||||
self->typecode = typecode;
|
||||
self->memview_offset = 0;
|
||||
self->len = nitems;
|
||||
self->items = items;
|
||||
mp_obj_memoryview_init(self, typecode, 0, nitems, items);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
@ -234,6 +230,14 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args,
|
||||
bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),
|
||||
bufinfo.buf));
|
||||
|
||||
// If the input object is a memoryview then need to point the items of the
|
||||
// new memoryview to the start of the buffer so the GC can trace it.
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_memoryview) {
|
||||
mp_obj_array_t *other = MP_OBJ_TO_PTR(args[0]);
|
||||
self->memview_offset = other->memview_offset;
|
||||
self->items = other->items;
|
||||
}
|
||||
|
||||
// test if the object can be written to
|
||||
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
|
||||
self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
|
||||
@ -288,6 +292,17 @@ STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int typecode_for_comparison(int typecode, bool *is_unsigned) {
|
||||
if (typecode == BYTEARRAY_TYPECODE) {
|
||||
typecode = 'B';
|
||||
}
|
||||
if (typecode <= 'Z') {
|
||||
typecode += 32; // to lowercase
|
||||
*is_unsigned = true;
|
||||
}
|
||||
return typecode;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
|
||||
switch (op) {
|
||||
@ -376,14 +391,33 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
case MP_BINARY_OP_EQUAL: {
|
||||
case MP_BINARY_OP_EQUAL:
|
||||
case MP_BINARY_OP_LESS:
|
||||
case MP_BINARY_OP_LESS_EQUAL:
|
||||
case MP_BINARY_OP_MORE:
|
||||
case MP_BINARY_OP_MORE_EQUAL: {
|
||||
mp_buffer_info_t lhs_bufinfo;
|
||||
mp_buffer_info_t rhs_bufinfo;
|
||||
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
|
||||
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
// mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
|
||||
// The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
|
||||
// just check if the typecodes are compatible; for testing equality the types should have the
|
||||
// same code except for signedness, and not be floating point because nan never equals nan.
|
||||
// For > and < the types should be the same and unsigned.
|
||||
// Note that typecode_for_comparison always returns lowercase letters to save code size.
|
||||
// No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
|
||||
bool is_unsigned = false;
|
||||
const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_unsigned);
|
||||
const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_unsigned);
|
||||
if (lhs_code == rhs_code && lhs_code != 'f' && lhs_code != 'd' && (op == MP_BINARY_OP_EQUAL || is_unsigned)) {
|
||||
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
}
|
||||
// mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
|
||||
// for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -367,9 +367,11 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args,
|
||||
return exc_type->make_new(exc_type, n_args, args, NULL);
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_NONE
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
|
||||
return mp_obj_new_exception_msg_varg(exc_type, msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The following struct and function implement a simple printer that conservatively
|
||||
// allocates memory and truncates the output data if no more memory can be obtained.
|
||||
|
@ -108,7 +108,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
||||
n_kw = kw_args->used;
|
||||
}
|
||||
if (n_args + n_kw != num_fields) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
|
||||
mp_raise_TypeError_varg(
|
||||
@ -134,7 +134,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
||||
qstr kw = mp_obj_str_get_qstr(kw_args->table[i].key);
|
||||
size_t id = mp_obj_namedtuple_find_field(type, kw);
|
||||
if (id == (size_t)-1) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -142,7 +142,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
||||
#endif
|
||||
}
|
||||
if (tuple->items[id] != MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
38
py/objstr.c
38
py/objstr.c
@ -968,7 +968,7 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
STATIC NORETURN void terse_str_format_value_error(void) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad format string"));
|
||||
}
|
||||
@ -989,7 +989,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
vstr_add_byte(&vstr, '}');
|
||||
continue;
|
||||
}
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("single '}' encountered in format string"));
|
||||
@ -1028,7 +1028,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
if (str < top && (*str == 'r' || *str == 's')) {
|
||||
conversion = *str++;
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad conversion specifier"));
|
||||
@ -1066,14 +1066,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
}
|
||||
}
|
||||
if (str >= top) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unmatched '{' in format"));
|
||||
#endif
|
||||
}
|
||||
if (*str != '}') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("expected ':' after format specifier"));
|
||||
@ -1086,7 +1086,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
int index = 0;
|
||||
if (MP_LIKELY(unichar_isdigit(*field_name))) {
|
||||
if (*arg_i > 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
@ -1116,7 +1116,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
}
|
||||
} else {
|
||||
if (*arg_i < 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
@ -1209,7 +1209,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
type = *s++;
|
||||
}
|
||||
if (*s) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid format specifier"));
|
||||
@ -1230,14 +1230,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
|
||||
if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) {
|
||||
if (type == 's') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("sign not allowed in string format specifier"));
|
||||
#endif
|
||||
}
|
||||
if (type == 'c') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
@ -1301,7 +1301,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
break;
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
@ -1373,7 +1373,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
#endif
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
@ -1385,7 +1385,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
// arg doesn't look like a number
|
||||
|
||||
if (align == '=') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
@ -1409,7 +1409,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
||||
}
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
@ -1438,7 +1438,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
||||
mp_check_self(mp_obj_is_str_or_bytes(pattern));
|
||||
|
||||
GET_STR_DATA_LEN(pattern, str, len);
|
||||
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_TERSE
|
||||
const byte *start_str = str;
|
||||
#endif
|
||||
bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes);
|
||||
@ -1470,7 +1470,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
||||
const byte *key = ++str;
|
||||
while (*str != ')') {
|
||||
if (str >= top) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format key"));
|
||||
@ -1534,7 +1534,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
||||
|
||||
if (str >= top) {
|
||||
incomplete_format:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format"));
|
||||
@ -1620,7 +1620,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
||||
break;
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
@ -2165,7 +2165,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
|
||||
}
|
||||
|
||||
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly"));
|
||||
#else
|
||||
const qstr src_name = mp_obj_get_type_qstr(self_in);
|
||||
|
@ -373,7 +373,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, cons
|
||||
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
|
||||
}
|
||||
if (init_ret != mp_const_none) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("__init__() should return None"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("__init__() should return None, not '%q'"),
|
||||
@ -889,7 +889,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
|
||||
mp_obj_t call = mp_obj_instance_get_call(self_in, member);
|
||||
if (call == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"),
|
||||
@ -1029,7 +1029,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
|
||||
mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->make_new == NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("cannot create '%q' instances"), self->name);
|
||||
@ -1171,7 +1171,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
|
||||
// TODO: Verify with CPy, tested on function type
|
||||
if (t->make_new == NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("type is not an acceptable base type"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -147,7 +147,7 @@ overflow:
|
||||
|
||||
value_error:
|
||||
{
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
MP_ERROR_TEXT("invalid syntax for integer"));
|
||||
raise_exc(exc, lex);
|
||||
|
@ -298,9 +298,7 @@ STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t
|
||||
mp_prof_is_executing = false;
|
||||
|
||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
|
||||
nlr_raise(obj);
|
||||
mp_handle_pending(true);
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
12
py/repl.c
12
py/repl.c
@ -167,13 +167,13 @@ STATIC const char *find_completions(const char *s_start, size_t s_len,
|
||||
for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
|
||||
size_t d_len;
|
||||
const char *d_str = (const char *)qstr_data(q, &d_len);
|
||||
// special case; filter out words that begin with underscore
|
||||
// unless there's already a partial match
|
||||
if (s_len == 0 && d_str[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
|
||||
if (test_qstr(obj, q)) {
|
||||
// special case; filter out words that begin with underscore
|
||||
// unless there's already a partial match
|
||||
if (s_len == 0 && d_str[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
if (match_str == NULL) {
|
||||
match_str = d_str;
|
||||
*match_len = d_len;
|
||||
@ -297,7 +297,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
|
||||
if (q_first == 0) {
|
||||
// If there're no better alternatives, and if it's first word
|
||||
// in the line, try to complete "import".
|
||||
if (s_start == org_str && s_len > 0) {
|
||||
if (s_start == org_str && s_len > 0 && s_len < sizeof(import_str) - 1) {
|
||||
if (memcmp(s_start, import_str, s_len) == 0) {
|
||||
*compl_str = import_str + s_len;
|
||||
return sizeof(import_str) - 1 - s_len;
|
||||
|
71
py/runtime.c
71
py/runtime.c
@ -159,9 +159,6 @@ void mp_deinit(void) {
|
||||
#ifdef MICROPY_PORT_DEINIT_FUNC
|
||||
MICROPY_PORT_DEINIT_FUNC;
|
||||
#endif
|
||||
|
||||
// mp_obj_dict_free(&dict_main);
|
||||
// mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map));
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_name(qstr qst) {
|
||||
@ -193,7 +190,7 @@ mp_obj_t mp_load_global(qstr qst) {
|
||||
#endif
|
||||
elem = mp_map_lookup((mp_map_t *)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
|
||||
if (elem == NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_msg(&mp_type_NameError, MP_ERROR_TEXT("name not defined"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT("name '%q' is not defined"), qst);
|
||||
@ -293,20 +290,20 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
|
||||
}
|
||||
// With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int().
|
||||
// In this case provide a more focused error message to not confuse, e.g. chr(1.0)
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
if (op == MP_UNARY_OP_INT) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int"));
|
||||
} else {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
|
||||
}
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
if (op == MP_UNARY_OP_INT) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int"));
|
||||
} else {
|
||||
if (op == MP_UNARY_OP_INT) {
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to int"), mp_obj_get_type_qstr(arg));
|
||||
} else {
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported type for %q: '%q'"),
|
||||
mp_unary_op_method_name[op], mp_obj_get_type_qstr(arg));
|
||||
}
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
|
||||
}
|
||||
#else
|
||||
if (op == MP_UNARY_OP_INT) {
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to int"), mp_obj_get_type_qstr(arg));
|
||||
} else {
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported type for %q: '%q'"),
|
||||
mp_unary_op_method_name[op], mp_obj_get_type_qstr(arg));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,7 +609,7 @@ generic_binary_op:
|
||||
}
|
||||
|
||||
unsupported_op:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -654,7 +651,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons
|
||||
return type->call(fun_in, n_args, n_kw, args);
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_obj_get_type_qstr(fun_in));
|
||||
@ -882,14 +879,14 @@ void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) {
|
||||
return;
|
||||
|
||||
too_short:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
|
||||
#else
|
||||
mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"),
|
||||
(int)seq_len);
|
||||
#endif
|
||||
too_long:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
|
||||
#else
|
||||
mp_raise_ValueError_varg(MP_ERROR_TEXT("too many values to unpack (expected %d)"),
|
||||
@ -951,7 +948,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) {
|
||||
return;
|
||||
|
||||
too_short:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
|
||||
#else
|
||||
mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"),
|
||||
@ -1138,7 +1135,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
|
||||
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
// no attribute/method called attr
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute"));
|
||||
#else
|
||||
// following CPython, we give a more detailed error message for type objects
|
||||
@ -1212,7 +1209,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_AttributeError,
|
||||
@ -1257,7 +1254,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
}
|
||||
|
||||
// object not iterable
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not iterable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
@ -1279,7 +1276,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) {
|
||||
// __next__ exists, call it and return its result
|
||||
return mp_call_method_n_kw(0, 0, dest);
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"),
|
||||
@ -1315,7 +1312,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"),
|
||||
@ -1565,6 +1562,26 @@ NORETURN void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(exc_type, arg));
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
|
||||
|
||||
NORETURN void mp_raise_type(const mp_obj_type_t *exc_type) {
|
||||
nlr_raise(mp_obj_new_exception(exc_type));
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ValueError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_ValueError);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_TypeError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_TypeError);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_NotImplementedError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_NotImplementedError);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
|
||||
if (msg == NULL) {
|
||||
nlr_raise(mp_obj_new_exception(exc_type));
|
||||
@ -1691,6 +1708,8 @@ NORETURN void mp_raise_MpyError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_MpyError, msg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
|
||||
NORETURN void mp_raise_recursion_depth(void) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded"));
|
||||
|
15
py/runtime.h
15
py/runtime.h
@ -68,7 +68,8 @@ extern const byte mp_binary_op_method_name[];
|
||||
void mp_init(void);
|
||||
void mp_deinit(void);
|
||||
|
||||
void mp_keyboard_interrupt(void);
|
||||
void mp_sched_exception(mp_obj_t exc);
|
||||
void mp_sched_keyboard_interrupt(void);
|
||||
void mp_handle_pending(bool raise_exc);
|
||||
void mp_handle_pending_tail(mp_uint_t atomic_state);
|
||||
|
||||
@ -162,6 +163,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
|
||||
mp_obj_t mp_import_from(mp_obj_t module, qstr name);
|
||||
void mp_import_all(mp_obj_t module);
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
|
||||
NORETURN void mp_raise_type(const mp_obj_type_t *exc_type);
|
||||
NORETURN void mp_raise_ValueError_no_msg(void);
|
||||
NORETURN void mp_raise_TypeError_no_msg(void);
|
||||
NORETURN void mp_raise_NotImplementedError_no_msg(void);
|
||||
#define mp_raise_msg(exc_type, msg) mp_raise_type(exc_type)
|
||||
#define mp_raise_msg_varg(exc_type, ...) mp_raise_type(exc_type)
|
||||
#define mp_raise_ValueError(msg) mp_raise_ValueError_no_msg()
|
||||
#define mp_raise_TypeError(msg) mp_raise_TypeError_no_msg()
|
||||
#define mp_raise_NotImplementedError(msg) mp_raise_NotImplementedError_no_msg()
|
||||
#else
|
||||
#define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL)
|
||||
#if !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME)
|
||||
NORETURN void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
@ -191,6 +203,7 @@ NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt,
|
||||
NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...);
|
||||
NORETURN void mp_raise_MpyError(const compressed_string_t *msg);
|
||||
NORETURN void mp_raise_recursion_depth(void);
|
||||
#endif
|
||||
|
||||
#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
|
||||
#undef mp_check_self
|
||||
|
@ -28,17 +28,21 @@
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
// This function may be called asynchronously at any time so only do the bare minimum.
|
||||
void MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(mp_keyboard_interrupt)(void) {
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
|
||||
void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_exception)(mp_obj_t exc) {
|
||||
MP_STATE_VM(mp_pending_exception) = exc;
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
|
||||
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
// This function may be called asynchronously at any time so only do the bare minimum.
|
||||
void MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(mp_sched_keyboard_interrupt)(void) {
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
mp_sched_exception(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
@ -130,6 +134,7 @@ bool MICROPY_WRAP_MP_SCHED_SCHEDULE(mp_sched_schedule)(mp_obj_t function, mp_obj
|
||||
uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++);
|
||||
MP_STATE_VM(sched_queue)[iput].func = function;
|
||||
MP_STATE_VM(sched_queue)[iput].arg = arg;
|
||||
MICROPY_SCHED_HOOK_SCHEDULED;
|
||||
ret = true;
|
||||
} else {
|
||||
// schedule queue is full
|
||||
|
@ -40,7 +40,7 @@ void mp_stack_check(void);
|
||||
|
||||
#else
|
||||
|
||||
#define mp_stack_set_limit(limit)
|
||||
#define mp_stack_set_limit(limit) (void)(limit)
|
||||
#define MP_STACK_CHECK()
|
||||
|
||||
#endif
|
||||
|
@ -293,7 +293,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
|
||||
// Compare mp_interrupt_char with wanted_char and ignore if not matched
|
||||
if (mp_interrupt_char == wanted_char) {
|
||||
tud_cdc_n_read_flush(itf); // flush read fifo
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,14 +41,23 @@ except ValueError:
|
||||
# equality (CPython requires both sides are array)
|
||||
print(bytes(array.array('b', [0x61, 0x62, 0x63])) == b'abc')
|
||||
print(array.array('b', [0x61, 0x62, 0x63]) == b'abc')
|
||||
print(array.array('B', [0x61, 0x62, 0x63]) == b'abc')
|
||||
print(array.array('b', [0x61, 0x62, 0x63]) != b'abc')
|
||||
print(array.array('b', [0x61, 0x62, 0x63]) == b'xyz')
|
||||
print(array.array('b', [0x61, 0x62, 0x63]) != b'xyz')
|
||||
print(b'abc' == array.array('b', [0x61, 0x62, 0x63]))
|
||||
print(b'abc' == array.array('B', [0x61, 0x62, 0x63]))
|
||||
print(b'abc' != array.array('b', [0x61, 0x62, 0x63]))
|
||||
print(b'xyz' == array.array('b', [0x61, 0x62, 0x63]))
|
||||
print(b'xyz' != array.array('b', [0x61, 0x62, 0x63]))
|
||||
|
||||
compatible_typecodes = []
|
||||
for t in ["b", "h", "i", "l", "q"]:
|
||||
compatible_typecodes.append((t, t))
|
||||
compatible_typecodes.append((t, t.upper()))
|
||||
for a, b in compatible_typecodes:
|
||||
print(array.array(a, [1, 2]) == array.array(b, [1, 2]))
|
||||
|
||||
class X(array.array):
|
||||
pass
|
||||
|
||||
@ -57,3 +66,24 @@ print(X('b', [0x61, 0x62, 0x63]) == b'abc')
|
||||
print(X('b', [0x61, 0x62, 0x63]) != b'abc')
|
||||
print(X('b', [0x61, 0x62, 0x63]) == array.array('b', [0x61, 0x62, 0x63]))
|
||||
print(X('b', [0x61, 0x62, 0x63]) != array.array('b', [0x61, 0x62, 0x63]))
|
||||
|
||||
# other comparisons
|
||||
for typecode in ["B", "H", "I", "L", "Q"]:
|
||||
a = array.array(typecode, [1, 1])
|
||||
print(a < a)
|
||||
print(a <= a)
|
||||
print(a > a)
|
||||
print(a >= a)
|
||||
|
||||
al = array.array(typecode, [1, 0])
|
||||
ab = array.array(typecode, [1, 2])
|
||||
|
||||
print(a < al)
|
||||
print(a <= al)
|
||||
print(a > al)
|
||||
print(a >= al)
|
||||
|
||||
print(a < ab)
|
||||
print(a <= ab)
|
||||
print(a > ab)
|
||||
print(a >= ab)
|
||||
|
@ -17,3 +17,15 @@ print(a[0])
|
||||
a = array.array('P')
|
||||
a.append(1)
|
||||
print(a[0])
|
||||
|
||||
# comparison between mismatching binary layouts is not implemented
|
||||
typecodes = ["b", "h", "i", "l", "q", "P", "O", "S", "f", "d"]
|
||||
for a in typecodes:
|
||||
for b in typecodes:
|
||||
if a == b and a not in ["f", "d"]:
|
||||
continue
|
||||
try:
|
||||
array.array(a) == array.array(b)
|
||||
print('FAIL')
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
19
tests/basics/async_syntaxerror.py
Normal file
19
tests/basics/async_syntaxerror.py
Normal file
@ -0,0 +1,19 @@
|
||||
# test syntax errors using async
|
||||
|
||||
try:
|
||||
exec
|
||||
except NameError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
def test_syntax(code):
|
||||
try:
|
||||
exec(code)
|
||||
print("no SyntaxError")
|
||||
except SyntaxError:
|
||||
print("SyntaxError")
|
||||
|
||||
|
||||
test_syntax("async for x in (): x")
|
||||
test_syntax("async with x: x")
|
2
tests/basics/async_syntaxerror.py.exp
Normal file
2
tests/basics/async_syntaxerror.py.exp
Normal file
@ -0,0 +1,2 @@
|
||||
SyntaxError
|
||||
SyntaxError
|
@ -27,6 +27,26 @@ print(bytearray([1]) == b"1")
|
||||
print(b"1" == bytearray([1]))
|
||||
print(bytearray() == bytearray())
|
||||
|
||||
b1 = bytearray([1, 2, 3])
|
||||
b2 = bytearray([1, 2, 3])
|
||||
b3 = bytearray([1, 3])
|
||||
print(b1 == b2)
|
||||
print(b2 != b3)
|
||||
print(b1 <= b2)
|
||||
print(b1 <= b3)
|
||||
print(b1 < b3)
|
||||
print(b1 >= b2)
|
||||
print(b3 >= b2)
|
||||
print(b3 > b2)
|
||||
print(b1 != b2)
|
||||
print(b2 == b3)
|
||||
print(b1 > b2)
|
||||
print(b1 > b3)
|
||||
print(b1 >= b3)
|
||||
print(b1 < b2)
|
||||
print(b3 < b2)
|
||||
print(b3 <= b2)
|
||||
|
||||
# comparison with other type should return False
|
||||
print(bytearray() == 1)
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
# test basic properties of exceptions
|
||||
|
||||
print(repr(IndexError()))
|
||||
print(str(IndexError()))
|
||||
|
||||
@ -12,3 +14,6 @@ s = StopIteration()
|
||||
print(s.value)
|
||||
s = StopIteration(1, 2, 3)
|
||||
print(s.value)
|
||||
|
||||
print(OSError().errno)
|
||||
print(OSError(1, "msg").errno)
|
||||
|
@ -1,14 +1,4 @@
|
||||
print(1 is 1)
|
||||
print(1 is 2)
|
||||
print(1 is not 1)
|
||||
print(1 is not 2)
|
||||
|
||||
|
||||
print([1, 2] is [1, 2])
|
||||
a = [1, 2]
|
||||
b = a
|
||||
print(b is a)
|
||||
|
||||
# TODO: strings require special "is" handling, postponed
|
||||
# until qstr refactor.
|
||||
#print("a" is "a")
|
||||
|
13
tests/basics/is_isnot_literal.py
Normal file
13
tests/basics/is_isnot_literal.py
Normal file
@ -0,0 +1,13 @@
|
||||
# test "is" and "is not" with literal arguments
|
||||
# these raise a SyntaxWarning in CPython because the results are
|
||||
# implementation dependent; see https://bugs.python.org/issue34850
|
||||
|
||||
print(1 is 1)
|
||||
print(1 is 2)
|
||||
print(1 is not 1)
|
||||
print(1 is not 2)
|
||||
|
||||
print("a" is "a")
|
||||
print("a" is "b")
|
||||
print("a" is not "a")
|
||||
print("a" is not "b")
|
8
tests/basics/is_isnot_literal.py.exp
Normal file
8
tests/basics/is_isnot_literal.py.exp
Normal file
@ -0,0 +1,8 @@
|
||||
True
|
||||
False
|
||||
False
|
||||
True
|
||||
True
|
||||
False
|
||||
False
|
||||
True
|
@ -21,3 +21,13 @@ for i in range(100000):
|
||||
|
||||
# check that the memoryview is still what we want
|
||||
print(list(m))
|
||||
|
||||
# check that creating a memoryview of a memoryview retains the underlying data
|
||||
m = None
|
||||
gc.collect() # cleanup from previous test
|
||||
m = memoryview(memoryview(bytearray(i for i in range(50)))[5:-5])
|
||||
print(sum(m), list(m[:10]))
|
||||
gc.collect()
|
||||
for i in range(10):
|
||||
list(range(10)) # allocate memory to overwrite any reclaimed heap
|
||||
print(sum(m), list(m[:10]))
|
||||
|
@ -29,18 +29,10 @@ except TypeError:
|
||||
print('TypeError')
|
||||
|
||||
# unsupported subscription
|
||||
try:
|
||||
1[0]
|
||||
except TypeError:
|
||||
print('TypeError')
|
||||
try:
|
||||
1[0] = 1
|
||||
except TypeError:
|
||||
print('TypeError')
|
||||
try:
|
||||
''['']
|
||||
except TypeError:
|
||||
print('TypeError')
|
||||
try:
|
||||
'a'[0] = 1
|
||||
except TypeError:
|
||||
@ -50,12 +42,6 @@ try:
|
||||
except TypeError:
|
||||
print('TypeError')
|
||||
|
||||
# not callable
|
||||
try:
|
||||
1()
|
||||
except TypeError:
|
||||
print('TypeError')
|
||||
|
||||
# not an iterator
|
||||
try:
|
||||
next(1)
|
||||
|
18
tests/basics/op_error_literal.py
Normal file
18
tests/basics/op_error_literal.py
Normal file
@ -0,0 +1,18 @@
|
||||
# test errors from bad operations with literals
|
||||
# these raise a SyntaxWarning in CPython; see https://bugs.python.org/issue15248
|
||||
|
||||
# unsupported subscription
|
||||
try:
|
||||
1[0]
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
try:
|
||||
""[""]
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
||||
# not callable
|
||||
try:
|
||||
1()
|
||||
except TypeError:
|
||||
print("TypeError")
|
3
tests/basics/op_error_literal.py.exp
Normal file
3
tests/basics/op_error_literal.py.exp
Normal file
@ -0,0 +1,3 @@
|
||||
TypeError
|
||||
TypeError
|
||||
TypeError
|
@ -1,6 +1,10 @@
|
||||
# test subclassing a native exception
|
||||
|
||||
|
||||
class MyExc(Exception):
|
||||
pass
|
||||
|
||||
|
||||
e = MyExc(100, "Some error")
|
||||
print(e)
|
||||
print(repr(e))
|
||||
@ -20,3 +24,19 @@ try:
|
||||
raise MyExc("Some error2")
|
||||
except:
|
||||
print("Caught user exception")
|
||||
|
||||
|
||||
class MyStopIteration(StopIteration):
|
||||
pass
|
||||
|
||||
|
||||
print(MyStopIteration().value)
|
||||
print(MyStopIteration(1).value)
|
||||
|
||||
|
||||
class MyOSError(OSError):
|
||||
pass
|
||||
|
||||
|
||||
print(MyOSError().errno)
|
||||
print(MyOSError(1, "msg").errno)
|
||||
|
13
tests/cpydiff/core_function_moduleattr.py
Normal file
13
tests/cpydiff/core_function_moduleattr.py
Normal file
@ -0,0 +1,13 @@
|
||||
"""
|
||||
categories: Core,Functions
|
||||
description: Function objects do not have the ``__module__`` attribute
|
||||
cause: MicroPython is optimized for reduced code size and RAM usage.
|
||||
workaround: Use ``sys.modules[function.__globals__['__name__']]`` for non-builtin modules.
|
||||
"""
|
||||
|
||||
|
||||
def f():
|
||||
pass
|
||||
|
||||
|
||||
print(f.__module__)
|
9
tests/cpydiff/module_array_comparison.py
Normal file
9
tests/cpydiff/module_array_comparison.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""
|
||||
categories: Modules,array
|
||||
description: Comparison between different typecodes not supported
|
||||
cause: Code size
|
||||
workaround: Compare individual elements
|
||||
"""
|
||||
import array
|
||||
|
||||
array.array("b", [1, 2]) == array.array("i", [1, 2])
|
10
tests/cpydiff/module_array_constructor.py
Normal file
10
tests/cpydiff/module_array_constructor.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""
|
||||
categories: Modules,array
|
||||
description: Overflow checking is not implemented
|
||||
cause: MicroPython implements implicit truncation in order to reduce code size and execution time
|
||||
workaround: If CPython compatibility is needed then mask the value explicitly
|
||||
"""
|
||||
import array
|
||||
|
||||
a = array.array("b", [257])
|
||||
print(a)
|
12
tests/cpydiff/modules_random_getrandbits.py
Normal file
12
tests/cpydiff/modules_random_getrandbits.py
Normal file
@ -0,0 +1,12 @@
|
||||
"""
|
||||
categories: Modules,random
|
||||
description: ``getrandbits`` method can only return a maximum of 32 bits at a time.
|
||||
cause: PRNG's internal state is only 32bits so it can only return a maximum of 32 bits of data at a time.
|
||||
workaround: If you need a number that has more than 32 bits then utilize the random module from micropython-lib.
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
x = random.getrandbits(64)
|
||||
print("{}".format(x))
|
12
tests/cpydiff/modules_random_randint.py
Normal file
12
tests/cpydiff/modules_random_randint.py
Normal file
@ -0,0 +1,12 @@
|
||||
"""
|
||||
categories: Modules,random
|
||||
description: ``randint`` method can only return an integer that is at most the native word size.
|
||||
cause: PRNG is only able to generate 32 bits of state at a time. The result is then cast into a native sized int instead of a full int object.
|
||||
workaround: If you need integers larger than native wordsize use the random module from micropython-lib.
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
x = random.randint(2 ** 128 - 1, 2 ** 128)
|
||||
print("x={}".format(x))
|
9
tests/cpydiff/types_exception_attrs.py
Normal file
9
tests/cpydiff/types_exception_attrs.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""
|
||||
categories: Types,Exception
|
||||
description: All exceptions have readable ``value`` and ``errno`` attributes, not just ``StopIteration`` and ``OSError``.
|
||||
cause: MicroPython is optimised to reduce code size.
|
||||
workaround: Only use ``value`` on ``StopIteration`` exceptions, and ``errno`` on ``OSError`` exceptions. Do not use or rely on these attributes on other exceptions.
|
||||
"""
|
||||
e = Exception(1)
|
||||
print(e.value)
|
||||
print(e.errno)
|
9
tests/cpydiff/types_int_bit_length.py
Normal file
9
tests/cpydiff/types_int_bit_length.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""
|
||||
categories: Types,int
|
||||
description: ``bit_length`` method doesn't exist.
|
||||
cause: bit_length method is not implemented.
|
||||
workaround: Avoid using this method on MicroPython.
|
||||
"""
|
||||
|
||||
x = 255
|
||||
print("{} is {} bits long.".format(x, x.bit_length()))
|
@ -65,7 +65,7 @@ print(db.seq(1, b"qux"))
|
||||
try:
|
||||
db.seq(b"foo1")
|
||||
except OSError as e:
|
||||
print(e.args[0] == uerrno.EINVAL)
|
||||
print(e.errno == uerrno.EINVAL)
|
||||
|
||||
print(list(db.keys()))
|
||||
print(list(db.values()))
|
||||
|
@ -27,7 +27,7 @@ class Device(uio.IOBase):
|
||||
try:
|
||||
db = btree.open(Device(), pagesize=511)
|
||||
except OSError as er:
|
||||
print("OSError", er.args[0] == uerrno.EINVAL)
|
||||
print("OSError", er.errno == uerrno.EINVAL)
|
||||
|
||||
# Valid pagesize, device returns error on read; errno comes from Device.readinto
|
||||
try:
|
||||
|
@ -21,3 +21,6 @@ for i in range(N):
|
||||
db[b"thekey" + str(i)] = b"thelongvalue" + str(i)
|
||||
print(db[b"thekey" + str(i)])
|
||||
gc.collect()
|
||||
|
||||
# Reclaim memory allocated by the db object.
|
||||
db.close()
|
||||
|
@ -1,9 +1,14 @@
|
||||
try:
|
||||
import framebuf
|
||||
import framebuf, usys
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
# This test and its .exp file is based on a little-endian architecture.
|
||||
if usys.byteorder != "little":
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
def printbuf():
|
||||
print("--8<--")
|
||||
|
@ -1,11 +1,16 @@
|
||||
# test subclassing framebuf.FrameBuffer
|
||||
|
||||
try:
|
||||
import framebuf
|
||||
import framebuf, usys
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
# This test and its .exp file is based on a little-endian architecture.
|
||||
if usys.byteorder != "little":
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
class FB(framebuf.FrameBuffer):
|
||||
def __init__(self, n):
|
||||
|
41
tests/extmod/uasyncio_cancel_wait_on_finished.py
Normal file
41
tests/extmod/uasyncio_cancel_wait_on_finished.py
Normal file
@ -0,0 +1,41 @@
|
||||
# Test cancelling a task that is waiting on a task that just finishes.
|
||||
|
||||
try:
|
||||
import uasyncio as asyncio
|
||||
except ImportError:
|
||||
try:
|
||||
import asyncio
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
async def sleep_task():
|
||||
print("sleep_task sleep")
|
||||
await asyncio.sleep(0)
|
||||
print("sleep_task wake")
|
||||
|
||||
|
||||
async def wait_task(t):
|
||||
print("wait_task wait")
|
||||
await t
|
||||
print("wait_task wake")
|
||||
|
||||
|
||||
async def main():
|
||||
waiting_task = asyncio.create_task(wait_task(asyncio.create_task(sleep_task())))
|
||||
|
||||
print("main sleep")
|
||||
await asyncio.sleep(0)
|
||||
print("main sleep")
|
||||
await asyncio.sleep(0)
|
||||
|
||||
waiting_task.cancel()
|
||||
print("main wait")
|
||||
try:
|
||||
await waiting_task
|
||||
except asyncio.CancelledError as er:
|
||||
print(repr(er))
|
||||
|
||||
|
||||
asyncio.run(main())
|
7
tests/extmod/uasyncio_cancel_wait_on_finished.py.exp
Normal file
7
tests/extmod/uasyncio_cancel_wait_on_finished.py.exp
Normal file
@ -0,0 +1,7 @@
|
||||
main sleep
|
||||
sleep_task sleep
|
||||
wait_task wait
|
||||
main sleep
|
||||
sleep_task wake
|
||||
main wait
|
||||
CancelledError()
|
@ -22,3 +22,19 @@ print("%.4f" % S.f64)
|
||||
|
||||
S.uf64 = 12.34
|
||||
print("%.4f" % S.uf64)
|
||||
|
||||
# array of float/double
|
||||
desc = {
|
||||
"af32": (uctypes.ARRAY | 0, uctypes.FLOAT32 | 2),
|
||||
"af64": (uctypes.ARRAY | 0, uctypes.FLOAT64 | 2),
|
||||
}
|
||||
data = bytearray(16)
|
||||
S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN)
|
||||
|
||||
S.af32[0] = 1
|
||||
S.af32[1] = 2
|
||||
print("%.4f %.4f" % (S.af32[0], S.af32[1]), data)
|
||||
|
||||
S.af64[0] = 1
|
||||
S.af64[1] = 2
|
||||
print("%.4f %.4f" % (S.af64[0], S.af64[1]), data)
|
||||
|
@ -1,3 +1,5 @@
|
||||
12.3400
|
||||
12.3400
|
||||
12.3400
|
||||
1.0000 2.0000 bytearray(b'\x00\x00\x80?\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
1.0000 2.0000 bytearray(b'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@')
|
||||
|
@ -6,3 +6,5 @@ except ImportError:
|
||||
|
||||
print(uctypes.sizeof({"f": uctypes.FLOAT32}))
|
||||
print(uctypes.sizeof({"f": uctypes.FLOAT64}))
|
||||
print(uctypes.sizeof({"f": (uctypes.ARRAY | 0, uctypes.FLOAT32 | 2)}))
|
||||
print(uctypes.sizeof({"f": (uctypes.ARRAY | 0, uctypes.FLOAT64 | 2)}))
|
||||
|
@ -1,2 +1,4 @@
|
||||
4
|
||||
8
|
||||
8
|
||||
16
|
||||
|
35
tests/extmod/uhashlib_final.py
Normal file
35
tests/extmod/uhashlib_final.py
Normal file
@ -0,0 +1,35 @@
|
||||
try:
|
||||
import uhashlib
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
for algo_name in ("md5", "sha1", "sha256"):
|
||||
algo = getattr(uhashlib, algo_name, None)
|
||||
if not algo:
|
||||
continue
|
||||
|
||||
# Running .digest() several times in row is not supported.
|
||||
h = algo(b"123")
|
||||
h.digest()
|
||||
try:
|
||||
h.digest()
|
||||
print("fail")
|
||||
except ValueError:
|
||||
# Expected path, don't print anything so test output is the
|
||||
# same even if the algorithm is not implemented on the port.
|
||||
pass
|
||||
|
||||
# Partial digests are not supported.
|
||||
h = algo(b"123")
|
||||
h.digest()
|
||||
try:
|
||||
h.update(b"456")
|
||||
print("fail")
|
||||
except ValueError:
|
||||
# Expected path, don't print anything so test output is the
|
||||
# same even if the algorithm is not implemented on the port.
|
||||
pass
|
||||
|
||||
print("done")
|
1
tests/extmod/uhashlib_final.py.exp
Normal file
1
tests/extmod/uhashlib_final.py.exp
Normal file
@ -0,0 +1 @@
|
||||
done
|
@ -22,8 +22,11 @@ r = random.getrandbits(16)
|
||||
random.seed(1)
|
||||
print(random.getrandbits(16) == r)
|
||||
|
||||
# check that it throws an error for zero bits
|
||||
# check that zero bits works
|
||||
print(random.getrandbits(0))
|
||||
|
||||
# check that it throws an error for negative bits
|
||||
try:
|
||||
random.getrandbits(0)
|
||||
random.getrandbits(-1)
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
|
4
tests/extmod/urandom_basic.py.exp
Normal file
4
tests/extmod/urandom_basic.py.exp
Normal file
@ -0,0 +1,4 @@
|
||||
True
|
||||
True
|
||||
0
|
||||
ValueError
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user