summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDave Hylands <dhylands@gmail.com>2014-04-02 11:42:39 -0700
committerDave Hylands <dhylands@gmail.com>2014-04-03 23:55:02 -0700
commit6756a37a77b64b804ee681a22935e0077226eb63 (patch)
treed2428d29b9ce1ccd1a1877c3663aded1e98bfce8 /py
parent5bf565e353b73bc87e0b918368dadac701644078 (diff)
downloadmicropython-6756a37a77b64b804ee681a22935e0077226eb63.tar.gz
micropython-6756a37a77b64b804ee681a22935e0077226eb63.zip
Implements most of str.modulo
The alternate form for floating point doesn't work yet. The %(name)s form doesn't work yet.
Diffstat (limited to 'py')
-rw-r--r--py/objstr.c162
1 files changed, 146 insertions, 16 deletions
diff --git a/py/objstr.c b/py/objstr.c
index a3f2d6075d..74f993a0b1 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -894,32 +894,162 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
assert(MP_OBJ_IS_STR(pattern));
GET_STR_DATA_LEN(pattern, str, len);
+ const byte *start_str = str;
int arg_i = 0;
vstr_t *vstr = vstr_new();
+ pfenv_t pfenv_vstr;
+ pfenv_vstr.data = vstr;
+ pfenv_vstr.print_strn = pfenv_vstr_add_strn;
+
for (const byte *top = str + len; str < top; str++) {
+ if (*str != '%') {
+ vstr_add_char(vstr, *str);
+ continue;
+ }
+ if (++str >= top) {
+ break;
+ }
if (*str == '%') {
- if (++str >= top) {
- break;
- }
- if (*str == '%') {
- vstr_add_char(vstr, '%');
+ vstr_add_char(vstr, '%');
+ continue;
+ }
+ if (arg_i >= n_args) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
+ }
+ int flags = 0;
+ char fill = ' ';
+ bool alt = false;
+ 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 == '0') {
+ flags |= PF_FLAG_PAD_AFTER_SIGN;
+ fill = '0';
+ } else break;
+ str++;
+ }
+ // parse width, if it exists
+ int width = 0;
+ if (str < top) {
+ if (*str == '*') {
+ width = mp_obj_get_int(args[arg_i++]);
+ str++;
} else {
- if (arg_i >= n_args) {
- nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
+ for (; str < top && '0' <= *str && *str <= '9'; str++) {
+ width = width * 10 + *str - '0';
}
- switch (*str) {
- case 's':
- mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR);
- break;
- case 'r':
- mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_REPR);
+ }
+ }
+ int prec = -1;
+ if (str < top && *str == '.') {
+ if (++str < top) {
+ if (*str == '*') {
+ prec = mp_obj_get_int(args[arg_i++]);
+ str++;
+ } else {
+ prec = 0;
+ for (; str < top && '0' <= *str && *str <= '9'; str++) {
+ prec = prec * 10 + *str - '0';
+ }
+ }
+ }
+ }
+
+ if (str >= top) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format"));
+ }
+ mp_obj_t 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_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char"));
break;
+ }
+ pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width);
+ break;
+ }
+ if (arg_looks_integer(arg)) {
+ char ch = mp_obj_get_int(arg);
+ pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width);
+ break;
+ }
+#if MICROPY_ENABLE_FLOAT
+ // This is what CPython reports, so we report the same.
+ if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
+
+ }
+#endif
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
+ break;
+
+ case 'd':
+ case 'i':
+ case 'u':
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 10, 'a', flags, fill, width);
+ break;
+
+#if MICROPY_ENABLE_FLOAT
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), *str, flags, fill, width, prec);
+ break;
+#endif
+
+ case 'o':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 8, 'a', flags, fill, width);
+ break;
+
+ case 'r':
+ case 's':
+ {
+ vstr_t *arg_vstr = vstr_new();
+ mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf,
+ arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR);
+ uint len = vstr_len(arg_vstr);
+ if (prec < 0) {
+ prec = len;
+ }
+ if (len > prec) {
+ len = prec;
}
- arg_i++;
+ pfenv_print_strn(&pfenv_vstr, vstr_str(arg_vstr), len, flags, ' ', width);
+ vstr_free(arg_vstr);
+ break;
}
- } else {
- vstr_add_char(vstr, *str);
+
+ case 'x':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'a', flags, fill, width);
+ break;
+
+ case 'X':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'A', flags, fill, width);
+ break;
+
+ default:
+ nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "unsupported format character '%c' (0x%x) at index %d",
+ *str, *str, str - start_str));
}
+ arg_i++;
}
if (arg_i != n_args) {