Skip to content

Commit 4db727a

Browse files
committed
objstr: Very basic implementation of % string formatting operator.
1 parent 6ce78c4 commit 4db727a

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

py/objstr.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef struct _mp_obj_str_t {
1717
const byte *data;
1818
} mp_obj_str_t;
1919

20+
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args);
2021
const mp_obj_t mp_const_empty_bytes;
2122

2223
// use this macro to extract the string hash
@@ -283,6 +284,19 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
283284
return mp_obj_str_builder_end(s);
284285
}
285286

287+
case MP_BINARY_OP_MODULO: {
288+
mp_obj_t *args;
289+
uint n_args;
290+
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) {
291+
// TODO: Support tuple subclasses?
292+
mp_obj_tuple_get(rhs_in, &n_args, &args);
293+
} else {
294+
args = &rhs_in;
295+
n_args = 1;
296+
}
297+
return str_modulo_format(lhs_in, n_args, args);
298+
}
299+
286300
// These 2 are never passed here, dealt with as a special case in mp_binary_op().
287301
//case MP_BINARY_OP_EQUAL:
288302
//case MP_BINARY_OP_NOT_EQUAL:
@@ -508,6 +522,47 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
508522
return s;
509523
}
510524

525+
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args) {
526+
assert(MP_OBJ_IS_STR(pattern));
527+
528+
GET_STR_DATA_LEN(pattern, str, len);
529+
int arg_i = 0;
530+
vstr_t *vstr = vstr_new();
531+
for (const byte *top = str + len; str < top; str++) {
532+
if (*str == '%') {
533+
if (++str >= top) {
534+
break;
535+
}
536+
if (*str == '%') {
537+
vstr_add_char(vstr, '%');
538+
} else {
539+
if (arg_i >= n_args) {
540+
nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
541+
}
542+
switch (*str) {
543+
case 's':
544+
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR);
545+
break;
546+
case 'r':
547+
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_REPR);
548+
break;
549+
}
550+
arg_i++;
551+
}
552+
} else {
553+
vstr_add_char(vstr, *str);
554+
}
555+
}
556+
557+
if (arg_i != n_args) {
558+
nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting"));
559+
}
560+
561+
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
562+
vstr_free(vstr);
563+
return s;
564+
}
565+
511566
STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
512567
assert(MP_OBJ_IS_STR(args[0]));
513568
assert(MP_OBJ_IS_STR(args[1]));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
print("=%s=" % 1)
2+
print("=%s=%s=" % (1, 2))
3+
print("=%s=" % (1,))
4+
print("=%s=" % [1, 2])
5+
6+
print("=%s=" % "str")
7+
print("=%r=" % "str")
8+
9+
try:
10+
print("=%s=%s=" % 1)
11+
except TypeError:
12+
print("TypeError")
13+
14+
try:
15+
print("=%s=%s=%s=" % (1, 2))
16+
except TypeError:
17+
print("TypeError")
18+
19+
try:
20+
print("=%s=" % (1, 2))
21+
except TypeError:
22+
print("TypeError")

0 commit comments

Comments
 (0)