Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ msgid ""
"https://github.com/adafruit/circuitpython/issues\n"
msgstr ""

#: py/obj.c shared-bindings/traceback/__init__.c
#: py/obj.c shared-module/traceback/__init__.c
msgid " File \"%q\""
msgstr ""

#: py/obj.c shared-bindings/traceback/__init__.c
#: py/obj.c shared-module/traceback/__init__.c
msgid " File \"%q\", line %d"
msgstr ""

Expand Down Expand Up @@ -103,6 +103,10 @@ msgstr ""
msgid "%q must be %d-%d"
msgstr ""

#: py/argcheck.c
msgid "%q must be %d-%d%s"
msgstr ""

#: shared-bindings/usb_hid/Device.c
msgid "%q must be 0-255"
msgstr ""
Expand Down Expand Up @@ -131,6 +135,10 @@ msgstr ""
msgid "%q must be None or between 1 and len(report_descriptor)-1"
msgstr ""

#: py/argcheck.c
msgid "%q must be a power of 2"
msgstr ""

#: py/argcheck.c
msgid "%q must be a string"
msgstr ""
Expand All @@ -151,6 +159,10 @@ msgstr ""
msgid "%q must of type %q"
msgstr ""

#: py/argcheck.c
msgid "%q must of type %q or a subclass"
msgstr ""

#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#: shared-bindings/canio/Match.c
msgid "%q out of range"
Expand Down Expand Up @@ -322,7 +334,7 @@ msgstr ""
msgid "*x must be assignment target"
msgstr ""

#: py/obj.c shared-bindings/traceback/__init__.c
#: py/obj.c shared-module/traceback/__init__.c
msgid ", in %q\n"
msgstr ""

Expand Down Expand Up @@ -2211,7 +2223,7 @@ msgstr ""
msgid "Touch alarms not available"
msgstr ""

#: py/obj.c shared-bindings/traceback/__init__.c
#: py/obj.c shared-module/traceback/__init__.c
msgid "Traceback (most recent call last):\n"
msgstr ""

Expand Down Expand Up @@ -3903,6 +3915,10 @@ msgstr ""
#: ports/esp32s2/boards/espressif_saola_1_wrover/mpconfigboard.h
#: ports/esp32s2/boards/franzininho_wifi_wroom/mpconfigboard.h
#: ports/esp32s2/boards/franzininho_wifi_wrover/mpconfigboard.h
#: ports/esp32s2/boards/gravitech_cucumber_m/mpconfigboard.h
#: ports/esp32s2/boards/gravitech_cucumber_ms/mpconfigboard.h
#: ports/esp32s2/boards/gravitech_cucumber_r/mpconfigboard.h
#: ports/esp32s2/boards/gravitech_cucumber_rs/mpconfigboard.h
#: ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
#: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
Expand Down
163 changes: 156 additions & 7 deletions py/argcheck.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <stdlib.h>
#include <assert.h>
#include <math.h>

#include "py/runtime.h"

Expand Down Expand Up @@ -89,6 +90,152 @@ inline void mp_arg_check_num_kw_array(size_t n_args, size_t n_kw, size_t n_args_
mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw));
}

static mp_arg_val_t get_defval(const mp_arg_t *arginfo) {
mp_arg_val_t result = arginfo->defval;

int kind = arginfo->flags & MP_ARG_KIND_MASK;
if (kind >= MP_ARG_FUNC) {
if (arginfo->flags & MP_ARG_FLOAT) {
if (arginfo->flags & MP_ARG_OR_NONE) {
result.u_float = MICROPY_FLOAT_C_FUN(nan)("");
} else {
result.u_float = -1;
}
} else if (kind >= MP_ARG_RANGE16) {
result.u_int = -1;
} else {
result.u_obj = mp_const_none;
}
}

return result;
}

static mp_arg_val_t validate_convert_argument(const mp_arg_t *arginfo, mp_obj_t given_arg) {
mp_arg_val_t result = {.u_obj = given_arg };
uint16_t arg_name = arginfo->qst;

int kind = arginfo->flags & MP_ARG_KIND_MASK;

if (arginfo->flags & MP_ARG_OR_MINUS1) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
if ((mp_obj_is_int(given_arg) && mp_obj_get_int(given_arg) == -1)
|| ((kind & MP_ARG_FLOAT) && mp_obj_is_float(given_arg) && mp_obj_get_float(given_arg) == MICROPY_FLOAT_CONST(-1.))) {
#pragma GCC diagnostic pop
if (kind & MP_ARG_FLOAT) {
result.u_float = MICROPY_FLOAT_CONST(-1.);
}
if (kind >= MP_ARG_NUMBER) {
result.u_int = -1;
}
return result;
}
}

if (arginfo->flags & MP_ARG_OR_NONE) {
if (given_arg == mp_const_none) {
if (kind & MP_ARG_FLOAT) {
result.u_float = MICROPY_FLOAT_C_FUN(nan)("");
}
if (kind >= MP_ARG_NUMBER) {
result.u_int = -1;
}
return result;
}
}

int lo = 0, hi = 0;

switch (kind) {

case MP_ARG_BOOL:
result.u_bool = mp_obj_is_true(given_arg);
return result;

case MP_ARG_OBJ:
return result;

case MP_ARG_TYPE:
mp_arg_validate_type(given_arg, arginfo->defval.u_obj, arg_name);
return result;

case MP_ARG_XTYPE:
if (!mp_obj_is_subclass_fast(mp_obj_get_type(given_arg), arginfo->defval.u_obj)) {
mp_obj_type_t *type = MP_OBJ_TO_PTR(arginfo->defval.u_obj);
mp_raise_TypeError_varg(translate("%q must of type %q or a subclass"), arg_name, type->name);
}
return result;

case MP_ARG_FUNC:
return arginfo->defval.u_func(arginfo, given_arg);

case MP_ARG_NUMBER:
if (arginfo->flags & MP_ARG_FLOAT) {
result.u_float = mp_obj_get_float(given_arg);
} else {
result.u_int = mp_obj_get_int(given_arg);
}
return result;

case MP_ARG_RANGE16:
lo = arginfo->defval.u_slo;
hi = arginfo->defval.u_shi;
break;

case MP_ARG_URANGE16:
lo = arginfo->defval.u_ulo;
hi = arginfo->defval.u_uhi;
break;

case MP_ARG_1_TO_N:
lo++;
MP_FALLTHROUGH;

case MP_ARG_0_TO_N:
hi = arginfo->defval.u_int;
break;

case MP_ARG_POW2: {
int val = mp_obj_get_int(given_arg);
if (val & (val - 1)) {
mp_raise_TypeError_varg(translate("%q must be a power of 2"), arginfo->qst);
}
lo = 1 << arginfo->defval.u_ulo;
hi = 1 << arginfo->defval.u_uhi;
break;
}

default:
assert(false);
}

const char *extra = "";
if (arginfo->flags & MP_ARG_OR_NONE) {
if (arginfo->flags & MP_ARG_OR_MINUS1) {
extra = ", None, or -1";
} else {
extra = " or None";
}
} else if (arginfo->flags & MP_ARG_OR_MINUS1) {
extra = " or -1";
}

if (arginfo->flags & MP_ARG_FLOAT) {
result.u_float = mp_obj_get_float(given_arg);
if (result.u_float < lo || result.u_float > hi) {
mp_raise_ValueError_varg(translate("%q must be %d-%d%s"), arg_name, lo, hi, extra);
}
return result;
}

result.u_int = mp_obj_get_int(given_arg);
if (result.u_int < lo || result.u_int > hi) {
mp_raise_ValueError_varg(translate("%q must be %d-%d%s"), arg_name, lo, hi, extra);
}
return result;
}

void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
size_t pos_found = 0, kws_found = 0;
for (size_t i = 0; i < n_allowed; i++) {
Expand All @@ -112,22 +259,24 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst);
#endif
}
out_vals[i] = allowed[i].defval;
out_vals[i] = get_defval(&allowed[i]);
continue;
} else {
kws_found++;
given_arg = kw->value;
}
}
if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_BOOL) {
out_vals[i].u_bool = mp_obj_is_true(given_arg);
} else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) {
out_vals[i].u_int = mp_obj_get_int(given_arg);
} else {
assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ);
if (allowed[i].flags & MP_ARG_SEQUENCE_OF) {
mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(given_arg));
for (mp_int_t j = 0; j < len; j++) {
(void)validate_convert_argument(&allowed[i], mp_obj_subscr(given_arg, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
}
out_vals[i].u_obj = given_arg;
} else {
out_vals[i] = validate_convert_argument(&allowed[i], given_arg);
}
}

if (pos_found < n_pos) {
extra_positional:
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
Expand Down
89 changes: 86 additions & 3 deletions py/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,105 @@ typedef enum {
MP_VM_RETURN_EXCEPTION,
} mp_vm_return_kind_t;

// Note: there's space for 16 bits in the structure
typedef enum {
// The corresponding argument is converted as if by bool() and stored in .u_bool
MP_ARG_BOOL = 0x001,
MP_ARG_INT = 0x002,
MP_ARG_OBJ = 0x003,
MP_ARG_KIND_MASK = 0x0ff,

// The corresponding object is stored in u_obj
MP_ARG_OBJ = 0x002,

// The corresponding argument is converted to an integer (or a float, if
// MP_ARG_FLOAT is or'd in) and stored in u_int or u_float. The default
// is the mp_arg_val_t's u_int or u_float.
MP_ARG_NUMBER = 0x003,
MP_ARG_INT = MP_ARG_NUMBER,

// The corresponding object is passed to a function, which may return
// a populated mp_arg_val_t or raise an exception
MP_ARG_FUNC = 0x004,

// The corresponding value must be an instance of the type stored in u_obj, or
// one of its subtypes
MP_ARG_TYPE = 0x005,

// The corresponding value must be an instance of exactly the type stored in u_obj
MP_ARG_XTYPE = 0x006,

// The corresponding value must be an integer or float in the signed
// inclusive range given by u_slo..u_shi. The default is None if
// MP_ARG_OR_NONE is specified, else -1 if MP_ARG_OR_MINUS1 is specified,
// else u_slo.
MP_ARG_RANGE16 = 0x007,

// The corresponding value must be an integer or float in the unsigned
// inclusive range given by u_ulo..u_uhi. The default is None if
// MP_ARG_OR_NONE is specified, else -1 if MP_ARG_OR_MINUS1 is specified,
// else u_lo.

MP_ARG_URANGE16 = 0x008,
// The corresponding value must be an integer or float in the signed
// inclusive 0..u_int or u..u_float. The default is none if MP_ARG_OR_NONE
// is specified, else -1 if MP_ARG_OR_MINUS1 is specified, else 0.
MP_ARG_0_TO_N = 0x009,

// The corresponding value must be an integer or float in the signed
// inclusive 1..u_int or u..u_float. The default is none if MP_ARG_OR_NONE
// is specified, else -1 if MP_ARG_OR_MINUS1 is specified, else 1.
MP_ARG_1_TO_N = 0x00a,

// The corresponding value must be an a power of two in the range
// 2^u_ulo .. 2^u_uhi inclusive. The default is None if MP_ARG_OR_NONE is
// specified, else -1 if MP_ARG_OR_MINUS1 is specified, else 2^u_ulo.
// Incompatible with MP_ARG_FLOAT.
MP_ARG_POW2 = 0x00b,

// A bitmask that includes all enumerated values above
MP_ARG_KIND_MASK = 0x01f,

// A numeric argument (MP_ARG_NUMBER, MP_ARG_RANGExx, etc) is a float,
// not an int
MP_ARG_FLOAT = 0x020,

// None is also accepted. If a u_int is to be stored, it is stored as -1.
// If a u_float is to be stored, it is stored as a NaN. None will be used
// as the default value if the defval field's meaning is overloaded.
MP_ARG_OR_NONE = 0x040,

// -1 is also accepted. -1 will be used as the default value if the defval
// field's meaning is overloaded, unless MP_ARG_OR_NONE is also specified.
MP_ARG_OR_MINUS1 = 0x080,

MP_ARG_REQUIRED = 0x100,
MP_ARG_KW_ONLY = 0x200,

// Instead of a single argument, a sequence where all items conform to the
// value specification is required. MP_ARG_FUNC becomes a predicate only,
// the transformed value is discarded.
MP_ARG_SEQUENCE_OF = 0x400,
} mp_arg_flag_t;

struct _mp_arg_t;
typedef union _mp_arg_val_t (*mp_arg_function_t)(const struct _mp_arg_t *arginfo, const mp_obj_t obj);

typedef union _mp_arg_val_t {
bool u_bool;
mp_int_t u_int;
mp_float_t u_float;
mp_obj_t u_obj;
mp_rom_obj_t u_rom_obj;
mp_arg_function_t u_func;
void *u_ptr;
const void *u_cptr;
struct {
uint16_t u_ulo, u_uhi;
};
struct {
uint16_t u_slo, u_shi;
};
} mp_arg_val_t;

#define MP_ARG_VAL(arg) ((mp_arg_val_t) {arg})
typedef struct _mp_arg_t {
uint16_t qst;
uint16_t flags;
Expand Down
4 changes: 2 additions & 2 deletions shared-bindings/alarm/pin/PinAlarm.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ STATIC mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t
self->base.type = &alarm_pin_pinalarm_type;
enum { ARG_pin, ARG_value, ARG_edge, ARG_pull };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_FUNC, {.u_func = arg_is_free_pin} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_BOOL },
{ MP_QSTR_edge, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
const mcu_pin_obj_t *pin = args[ARG_pin].u_cptr;

common_hal_alarm_pin_pinalarm_construct(self,
pin,
Expand Down
Loading