summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/builtin.c2
-rw-r--r--py/builtinimport.c12
-rw-r--r--py/gc.c10
-rw-r--r--py/makeqstrdata.py3
-rw-r--r--py/modgc.c6
-rw-r--r--py/mpconfig.h5
-rw-r--r--py/obj.h1
-rw-r--r--py/objarray.c2
-rw-r--r--py/objdict.c11
-rw-r--r--py/objexcept.c2
-rw-r--r--py/objint.c4
-rw-r--r--py/objstr.c111
-rw-r--r--py/objtuple.c2
-rw-r--r--py/objtype.c2
-rw-r--r--py/pfenv.c56
-rw-r--r--py/pfenv.h2
-rw-r--r--py/runtime.c2
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);
diff --git a/py/gc.c b/py/gc.c
index 87c458f82c..7fab0409a9 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -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)
diff --git a/py/obj.h b/py/obj.h
index 7c83715111..aa78b2a22d 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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;