diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtin.c | 2 | ||||
-rw-r--r-- | py/builtinimport.c | 12 | ||||
-rw-r--r-- | py/gc.c | 10 | ||||
-rw-r--r-- | py/makeqstrdata.py | 3 | ||||
-rw-r--r-- | py/modgc.c | 6 | ||||
-rw-r--r-- | py/mpconfig.h | 5 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objarray.c | 2 | ||||
-rw-r--r-- | py/objdict.c | 11 | ||||
-rw-r--r-- | py/objexcept.c | 2 | ||||
-rw-r--r-- | py/objint.c | 4 | ||||
-rw-r--r-- | py/objstr.c | 111 | ||||
-rw-r--r-- | py/objtuple.c | 2 | ||||
-rw-r--r-- | py/objtype.c | 2 | ||||
-rw-r--r-- | py/pfenv.c | 56 | ||||
-rw-r--r-- | py/pfenv.h | 2 | ||||
-rw-r--r-- | py/runtime.c | 2 |
17 files changed, 163 insertions, 70 deletions
diff --git a/py/builtin.c b/py/builtin.c index c336378109..8621b0b003 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -466,7 +466,7 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { assert(MP_OBJ_IS_QSTR(attr_in)); mp_obj_t dest[2]; - // TODO: https://docs.python.org/3.3/library/functions.html?highlight=hasattr#hasattr + // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr // explicitly says "This is implemented by calling getattr(object, name) and seeing // whether it raises an AttributeError or not.", so we should explicitly wrap this // in nlr_push and handle exception. diff --git a/py/builtinimport.c b/py/builtinimport.c index 50780c01d6..795d9fd5e1 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -163,16 +163,6 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { mp_globals_set(old_globals); } -// TODO: Move to objdict? -STATIC inline mp_obj_t mp_obj_dict_get(mp_obj_t dict_in, mp_obj_t key) { - mp_obj_dict_t *dict = dict_in; - mp_map_elem_t *elem = mp_map_lookup(&dict->map, key, MP_MAP_LOOKUP); - if (elem == NULL) { - return elem; - } - return elem->value; -} - mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { #if DEBUG_PRINT printf("__import__:\n"); @@ -316,7 +306,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { if (stat == MP_IMPORT_STAT_DIR) { DEBUG_printf("%s is dir\n", vstr_str(&path)); - // https://docs.python.org/3.3/reference/import.html + // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); vstr_add_char(&path, PATH_SEP_CHAR); @@ -231,7 +231,14 @@ STATIC void gc_deal_with_stack_overflow(void) { } } +#if MICROPY_PY_GC_COLLECT_RETVAL +uint gc_collected; +#endif + STATIC void gc_sweep(void) { + #if MICROPY_PY_GC_COLLECT_RETVAL + gc_collected = 0; + #endif // free unmarked heads and their tails int free_tail = 0; for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) { @@ -254,6 +261,9 @@ STATIC void gc_sweep(void) { } #endif free_tail = 1; + #if MICROPY_PY_GC_COLLECT_RETVAL + gc_collected++; + #endif // fall through to free the head case AT_TAIL: diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 2ec5a1fb69..599b936f9e 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -27,7 +27,8 @@ def compute_hash(qstr): hash = 5381 for char in qstr: hash = (hash * 33) ^ ord(char) - return hash & 0xffff + # Make sure that valid hash is never zero, zero means "hash not computed" + return (hash & 0xffff) or 1 def do_work(infiles): # read the qstrs in from the input files diff --git a/py/modgc.c b/py/modgc.c index 03b520b949..c53eed235f 100644 --- a/py/modgc.c +++ b/py/modgc.c @@ -37,9 +37,15 @@ #if MICROPY_PY_GC && MICROPY_ENABLE_GC +extern uint gc_collected; + STATIC mp_obj_t py_gc_collect(void) { gc_collect(); +#if MICROPY_PY_GC_COLLECT_RETVAL + return MP_OBJ_NEW_SMALL_INT((machine_uint_t)gc_collected); +#else return mp_const_none; +#endif } MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect); diff --git a/py/mpconfig.h b/py/mpconfig.h index 77b76bf13d..93e98c25b6 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -279,6 +279,11 @@ typedef double mp_float_t; #define MICROPY_PY_GC (1) #endif +// Whether to return number of collected objects from gc.collect() +#ifndef MICROPY_PY_GC_COLLECT_RETVAL +#define MICROPY_PY_GC_COLLECT_RETVAL (0) +#endif + // Whether to provide "io" module #ifndef MICROPY_PY_IO #define MICROPY_PY_IO (1) @@ -505,6 +505,7 @@ typedef struct _mp_obj_dict_t { } mp_obj_dict_t; void mp_obj_dict_init(mp_obj_dict_t *dict, int n_args); uint mp_obj_dict_len(mp_obj_t self_in); +mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index); mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key); mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in); diff --git a/py/objarray.c b/py/objarray.c index 44fbf2f998..edf3ee8121 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -181,7 +181,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, - "Only slices with step=1 (aka None) are supported")); + "only slices with step=1 (aka None) are supported")); } mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start); int sz = mp_binary_get_size('@', o->typecode, NULL); diff --git a/py/objdict.c b/py/objdict.c index 8a0a08772a..696aad80f5 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -117,6 +117,17 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } } +// TODO: Make sure this is inlined in dict_subscr() below. +mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { + mp_obj_dict_t *self = self_in; + mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); + if (elem == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + } else { + return elem->value; + } +} + STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete diff --git a/py/objexcept.c b/py/objexcept.c index b0ccb90fd6..9f421373bb 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -157,7 +157,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \ }; // List of all exceptions, arranged as in the table at: -// http://docs.python.org/3.3/library/exceptions.html +// http://docs.python.org/3/library/exceptions.html MP_DEFINE_EXCEPTION_BASE(BaseException) MP_DEFINE_EXCEPTION(SystemExit, BaseException) //MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) diff --git a/py/objint.c b/py/objint.c index 74b7564550..331fdfa1b9 100644 --- a/py/objint.c +++ b/py/objint.c @@ -127,7 +127,7 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } -// This routine expects you to pass in a buffer and size (in *buf and buf_size). +// This routine expects you to pass in a buffer and size (in *buf and *buf_size). // If, for some reason, this buffer is too small, then it will allocate a // buffer and return the allocated buffer and size in *buf and *buf_size. It // is the callers responsibility to free this allocated buffer. @@ -154,7 +154,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob #endif } else { // Not an int. - buf[0] = '\0'; + **buf = '\0'; *fmt_size = 0; return *buf; } diff --git a/py/objstr.c b/py/objstr.c index 012d6404f7..4e70b00812 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -40,7 +40,7 @@ #include "objstr.h" #include "objlist.h" -STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args); +STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict); const mp_obj_t mp_const_empty_bytes; // use this macro to extract the string hash @@ -307,14 +307,19 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_MODULO: { mp_obj_t *args; uint n_args; + mp_obj_t dict = MP_OBJ_NULL; if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { // TODO: Support tuple subclasses? mp_obj_tuple_get(rhs_in, &n_args, &args); + } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + args = NULL; + n_args = 0; + dict = rhs_in; } else { args = &rhs_in; n_args = 1; } - return str_modulo_format(lhs_in, n_args, args); + return str_modulo_format(lhs_in, n_args, args, dict); } //case MP_BINARY_OP_NOT_EQUAL: // This is never passed here @@ -353,7 +358,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, - "Only slices with step=1 (aka None) are supported")); + "only slices with step=1 (aka None) are supported")); } return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start); } @@ -776,7 +781,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { vstr_add_char(vstr, '}'); continue; } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Single '}' encountered in format string")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "single '}' encountered in format string")); } if (*str != '{') { vstr_add_char(vstr, *str); @@ -822,7 +827,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { // '{:d}'.format(True) returns '1' // So we treat {:} as {} and this later gets treated to be {!s} if (*str != '}') { - format_spec = vstr_new(); + format_spec = vstr_new(); while (str < top && *str != '}') { vstr_add_char(format_spec, *str++); } @@ -840,7 +845,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { if (field_name) { if (arg_i > 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from automatic field numbering to manual field specification")); } int index = 0; if (str_to_int(vstr_str(field_name), &index) != vstr_len(field_name) - 1) { @@ -855,7 +860,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { field_name = NULL; } else { if (arg_i < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from manual field specification to automatic field numbering")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from manual field specification to automatic field numbering")); } if (arg_i >= n_args - 1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); @@ -873,7 +878,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { } else if (conversion == 'r') { print_kind = PRINT_REPR; } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown conversion specifier %c", conversion)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", conversion)); } vstr_t *arg_vstr = vstr_new(); mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, arg_vstr, arg, print_kind); @@ -976,7 +981,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { if (arg_looks_integer(arg)) { switch (type) { case 'b': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width, 0); continue; case 'c': @@ -989,7 +994,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { case '\0': // No explicit format type implies 'd' case 'n': // I don't think we support locales in uPy so use 'd' case 'd': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width, 0); continue; case 'o': @@ -997,15 +1002,12 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { flags |= PF_FLAG_SHOW_OCTAL_LETTER; } - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width); - continue; - - case 'x': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, 0); continue; case 'X': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'A', flags, fill, width); + case 'x': + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width, 0); continue; case 'e': @@ -1021,7 +1023,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); + "unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } } @@ -1033,7 +1035,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { // Even though the docs say that an unspecified type is the same // as 'g', there is one subtle difference, when the exponent // is one less than the precision. - // + // // '{:10.1}'.format(0.0) ==> '0e+00' // '{:10.1g}'.format(0.0) ==> '0' // @@ -1072,7 +1074,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { case 'F': case 'g': case 'G': - pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision); + pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision); break; case '%': @@ -1083,7 +1085,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Unknown format code '%c' for object of type 'float'", + "unknown format code '%c' for object of type 'float'", type, mp_obj_get_type_str(arg))); } } else { @@ -1114,7 +1116,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Unknown format code '%c' for object of type 'str'", + "unknown format code '%c' for object of type 'str'", type, mp_obj_get_type_str(arg))); } } @@ -1125,7 +1127,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { return s; } -STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict) { assert(MP_OBJ_IS_STR(pattern)); GET_STR_DATA_LEN(pattern, str, len); @@ -1137,6 +1139,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t pfenv_vstr.print_strn = pfenv_vstr_add_strn; for (const byte *top = str + len; str < top; str++) { + mp_obj_t arg = MP_OBJ_NULL; if (*str != '%') { vstr_add_char(vstr, *str); continue; @@ -1148,17 +1151,29 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t vstr_add_char(vstr, '%'); continue; } - if (arg_i >= n_args) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string")); + + // Dictionary value lookup + if (*str == '(') { + const byte *key = ++str; + while (*str != ')') { + if (str >= top) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format key")); + } + ++str; + } + mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true); + arg = mp_obj_dict_get(dict, k_obj); + str++; } + int flags = 0; char fill = ' '; - bool alt = false; + int alt = 0; while (str < top) { if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST; else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN; else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN; - else if (*str == '#') alt = true; + else if (*str == '#') alt = PF_FLAG_SHOW_PREFIX; else if (*str == '0') { flags |= PF_FLAG_PAD_AFTER_SIGN; fill = '0'; @@ -1166,9 +1181,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t str++; } // parse width, if it exists - int width = 0; + int width = 0; if (str < top) { if (*str == '*') { + if (arg_i >= n_args) { + goto not_enough_args; + } width = mp_obj_get_int(args[arg_i++]); str++; } else { @@ -1181,6 +1199,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t if (str < top && *str == '.') { if (++str < top) { if (*str == '*') { + if (arg_i >= n_args) { + goto not_enough_args; + } prec = mp_obj_get_int(args[arg_i++]); str++; } else { @@ -1195,14 +1216,22 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t if (str >= top) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format")); } - mp_obj_t arg = args[arg_i]; + + // Tuple value lookup + if (arg == MP_OBJ_NULL) { + if (arg_i >= n_args) { +not_enough_args: + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string")); + } + arg = args[arg_i++]; + } switch (*str) { case 'c': if (MP_OBJ_IS_STR(arg)) { uint len; const char *s = mp_obj_str_get_data(arg, &len); if (len != 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%%c requires int or char")); break; } pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width); @@ -1216,17 +1245,17 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t #if MICROPY_PY_BUILTINS_FLOAT // This is what CPython reports, so we report the same. if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float")); } #endif - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required")); - break; + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required")); + break; case 'd': case 'i': case 'u': - pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width, prec); break; #if MICROPY_PY_BUILTINS_FLOAT @@ -1244,7 +1273,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t if (alt) { flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER); } - pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 8, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, prec); break; case 'r': @@ -1265,18 +1294,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t break; } - case 'x': - if (alt) { - flags |= PF_FLAG_SHOW_PREFIX; - } - pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'a', flags, fill, width); - break; - case 'X': - if (alt) { - flags |= PF_FLAG_SHOW_PREFIX; - } - pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'A', flags, fill, width); + case 'x': + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec); break; default: @@ -1284,7 +1304,6 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t "unsupported format character '%c' (0x%x) at index %d", *str, *str, str - start_str)); } - arg_i++; } if (arg_i != n_args) { diff --git a/py/objtuple.c b/py/objtuple.c index fc97f53cf2..2be04400fe 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -166,7 +166,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, - "Only slices with step=1 (aka None) are supported")); + "only slices with step=1 (aka None) are supported")); } mp_obj_tuple_t *res = mp_obj_new_tuple(slice.stop - slice.start, NULL); mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); diff --git a/py/objtype.c b/py/objtype.c index a51e12f1fd..dfe5eaa8f0 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -352,7 +352,7 @@ STATIC const qstr binary_op_method_name[] = { // Given a member that was extracted from an instance, convert it correctly // and put the result in the dest[] array for a possible method call. // Conversion means dealing with static/class methods, callables, and values. -// see http://docs.python.org/3.3/howto/descriptor.html +// see http://docs.python.org/3/howto/descriptor.html STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { assert(dest[1] == NULL); if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { diff --git a/py/pfenv.c b/py/pfenv.c index e4db4da046..e631f8654a 100644 --- a/py/pfenv.c +++ b/py/pfenv.c @@ -91,8 +91,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in left_pad -= p; } } - pfenv->print_strn(pfenv->data, str, len); - total_chars_printed += len; + if (len) { + pfenv->print_strn(pfenv->data, str, len); + total_chars_printed += len; + } if (right_pad > 0) { total_chars_printed += right_pad; while (right_pad > 0) { @@ -181,13 +183,19 @@ int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, i return len; } -int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) { +int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec) { if (!MP_OBJ_IS_INT(x)) { // This will convert booleans to int, or raise an error for // non-integer types. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); } + if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') { + if (prec > width) { + width = prec; + } + prec = 0; + } char prefix_buf[4]; char *prefix = prefix_buf; @@ -230,6 +238,9 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int int fmt_size = 0; char *str; + if (prec > 1) { + flags |= PF_FLAG_PAD_AFTER_SIGN; + } char sign = '\0'; if (flags & PF_FLAG_PAD_AFTER_SIGN) { // We add the pad in this function, so since the pad goes after @@ -245,7 +256,39 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int x, base, prefix, base_char, comma); } + int spaces_before = 0; + int spaces_after = 0; + + if (prec > 1) { + // If prec was specified, then prec specifies the width to zero-pad the + // the number to. This zero-padded number then gets left or right + // aligned in width characters. + + int prec_width = fmt_size; // The digits + if (prec_width < prec) { + prec_width = prec; + } + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + if (sign) { + prec_width++; + } + prec_width += prefix_len; + } + if (prec_width < width) { + if (flags & PF_FLAG_LEFT_ADJUST) { + spaces_after = width - prec_width; + } else { + spaces_before = width - prec_width; + } + } + fill = '0'; + flags &= ~PF_FLAG_LEFT_ADJUST; + } + int len = 0; + if (spaces_before) { + len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before); + } if (flags & PF_FLAG_PAD_AFTER_SIGN) { // pad after sign implies pad after prefix as well. if (sign) { @@ -257,9 +300,16 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int width -= prefix_len; } } + if (prec > 1) { + width = prec; + } len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width); + if (spaces_after) { + len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after); + } + if (buf != stack_buf) { m_free(buf, buf_size); } diff --git a/py/pfenv.h b/py/pfenv.h index 2a3de6c32d..55eca6fed1 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -45,7 +45,7 @@ void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len); int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width); int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width); -int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width); +int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec); #if MICROPY_PY_BUILTINS_FLOAT int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec); #endif diff --git a/py/runtime.c b/py/runtime.c index f13cc1d892..cdbf99d4a5 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -837,7 +837,7 @@ void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) { mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { // check if the methods are functions, static or class methods - // see http://docs.python.org/3.3/howto/descriptor.html + // see http://docs.python.org/3/howto/descriptor.html if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) { // return just the function dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun; |