Skip to content

Commit 6c73ca1

Browse files
committed
py: add variable argument exception constructor function.
Addresses issue adafruit#104.
1 parent 199b9e0 commit 6c73ca1

8 files changed

Lines changed: 63 additions & 30 deletions

File tree

py/builtin.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
154154
revs_args[0] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
155155
return rt_build_tuple(2, revs_args);
156156
} else {
157-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
157+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
158158
}
159159
}
160160

@@ -188,7 +188,7 @@ mp_obj_t mp_builtin_len(mp_obj_t o_in) {
188188
} else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
189189
len = mp_obj_dict_len(o_in);
190190
} else {
191-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
191+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
192192
}
193193
return MP_OBJ_NEW_SMALL_INT(len);
194194
}
@@ -263,15 +263,15 @@ mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
263263
if (strlen(str) == 1) {
264264
return mp_obj_new_int(str[0]);
265265
} else {
266-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", (void*)(machine_int_t)strlen(str)));
266+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", strlen(str)));
267267
}
268268
}
269269

270270
mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args) {
271271
switch (n_args) {
272272
case 2: return rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]);
273273
case 3: return rt_binary_op(RT_BINARY_OP_MODULO, rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
274-
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "pow expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
274+
default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "pow expected at most 3 arguments, got %d", n_args));
275275
}
276276
}
277277

@@ -297,7 +297,7 @@ mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
297297
case 1: return mp_obj_new_range(0, mp_obj_get_int(args[0]), 1);
298298
case 2: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), 1);
299299
case 3: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
300-
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "range expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
300+
default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "range expected at most 3 arguments, got %d", n_args));
301301
}
302302
}
303303

@@ -306,7 +306,7 @@ mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
306306
switch (n_args) {
307307
case 1: value = mp_obj_new_int(0); break;
308308
case 2: value = args[1]; break;
309-
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "sum expected at most 2 arguments, got %d", (void*)(machine_int_t)n_args));
309+
default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "sum expected at most 2 arguments, got %d", n_args));
310310
}
311311
mp_obj_t iterable = rt_getiter(args[0]);
312312
mp_obj_t item;

py/obj.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
145145
return (machine_int_t)mp_obj_float_get(arg);
146146
#endif
147147
} else {
148-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
148+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
149149
}
150150
}
151151

@@ -160,7 +160,7 @@ machine_float_t mp_obj_get_float(mp_obj_t arg) {
160160
} else if (MP_OBJ_IS_TYPE(arg, &float_type)) {
161161
return mp_obj_float_get(arg);
162162
} else {
163-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
163+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
164164
}
165165
}
166166

@@ -180,7 +180,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
180180
} else if (MP_OBJ_IS_TYPE(arg, &complex_type)) {
181181
mp_obj_complex_get(arg, real, imag);
182182
} else {
183-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
183+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
184184
}
185185
}
186186
#endif
@@ -204,11 +204,11 @@ mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o_in, machine_int_t n) {
204204
mp_obj_list_get(o_in, &seq_len, &seq_items);
205205
}
206206
if (seq_len != n) {
207-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_IndexError, "requested length %d but object has length %d", (void*)n, (void*)(machine_uint_t)seq_len));
207+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "requested length %d but object has length %d", n, seq_len));
208208
}
209209
return seq_items;
210210
} else {
211-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in)));
211+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in)));
212212
}
213213
}
214214

@@ -220,10 +220,10 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index)
220220
i += len;
221221
}
222222
if (i < 0 || i >= len) {
223-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_IndexError, "%s index out of range", type->name));
223+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "%s index out of range", type->name));
224224
}
225225
return i;
226226
} else {
227-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "%s indices must be integers, not %s", type->name, mp_obj_get_type_str(index)));
227+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "%s indices must be integers, not %s", type->name, mp_obj_get_type_str(index)));
228228
}
229229
}

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ mp_obj_t mp_obj_new_exception(qstr id);
191191
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg);
192192
mp_obj_t mp_obj_new_exception_msg_1_arg(qstr id, const char *fmt, const char *a1);
193193
mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a1, const char *a2);
194+
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
194195
mp_obj_t mp_obj_new_range(int start, int stop, int step);
195196
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
196197
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code);

py/objbool.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static mp_obj_t bool_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args
2727
switch (n_args) {
2828
case 0: return mp_const_false;
2929
case 1: if (rt_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
30-
default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "bool takes at most 1 argument, %d given", (void*)(machine_int_t)n_args));
30+
default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "bool takes at most 1 argument, %d given", n_args));
3131
}
3232
}
3333

py/objexcept.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdlib.h>
22
#include <stdint.h>
33
#include <string.h>
4+
#include <stdarg.h>
45
#include <assert.h>
56

67
#include "nlr.h"
@@ -79,6 +80,37 @@ mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a
7980
return o;
8081
}
8182

83+
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
84+
// count number of arguments by number of % signs, excluding %%
85+
int n_args = 1; // count fmt
86+
for (const char *s = fmt; *s; s++) {
87+
if (*s == '%') {
88+
if (s[1] == '%') {
89+
s += 1;
90+
} else {
91+
n_args += 1;
92+
}
93+
}
94+
}
95+
96+
// make exception object
97+
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, n_args);
98+
o->base.type = &exception_type;
99+
o->id = id;
100+
o->n_args = n_args;
101+
o->args[0] = fmt;
102+
103+
// extract args and store them
104+
va_list ap;
105+
va_start(ap, fmt);
106+
for (int i = 1; i < n_args; i++) {
107+
o->args[i] = va_arg(ap, void*);
108+
}
109+
va_end(ap);
110+
111+
return o;
112+
}
113+
82114
qstr mp_obj_exception_get_type(mp_obj_t self_in) {
83115
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
84116
mp_obj_exception_t *self = self_in;

py/runtime.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ mp_obj_t rt_load_name(qstr qstr) {
373373
if (elem == NULL) {
374374
elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
375375
if (elem == NULL) {
376-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_NameError, "name '%s' is not defined", qstr_str(qstr)));
376+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_NameError, "name '%s' is not defined", qstr_str(qstr)));
377377
}
378378
}
379379
}
@@ -387,7 +387,7 @@ mp_obj_t rt_load_global(qstr qstr) {
387387
if (elem == NULL) {
388388
elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
389389
if (elem == NULL) {
390-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_NameError, "name '%s' is not defined", qstr_str(qstr)));
390+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_NameError, "name '%s' is not defined", qstr_str(qstr)));
391391
}
392392
}
393393
return elem->value;
@@ -447,7 +447,7 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) {
447447
}
448448
}
449449
// TODO specify in error message what the operator is
450-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "bad operand type for unary operator: '%s'", o->type->name));
450+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "bad operand type for unary operator: '%s'", o->type->name));
451451
}
452452
}
453453

@@ -532,7 +532,7 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
532532
}
533533

534534
// TODO specify in error message what the operator is
535-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "unsupported operand type for binary operator: '%s'", mp_obj_get_type_str(lhs)));
535+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unsupported operand type for binary operator: '%s'", mp_obj_get_type_str(lhs)));
536536
}
537537

538538
mp_obj_t rt_compare_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
@@ -687,7 +687,7 @@ mp_obj_t rt_call_function_n(mp_obj_t fun_in, int n_args, const mp_obj_t *args) {
687687
if (fun->type->call_n != NULL) {
688688
return fun->type->call_n(fun_in, n_args, args);
689689
} else {
690-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "'%s' object is not callable", fun->type->name));
690+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not callable", fun->type->name));
691691
}
692692
}
693693
}
@@ -705,7 +705,7 @@ mp_obj_t rt_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp
705705
if (fun->type->call_n_kw != NULL) {
706706
return fun->type->call_n_kw(fun_in, n_args, n_kw, args);
707707
} else {
708-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "'%s' object is not callable", fun->type->name));
708+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not callable", fun->type->name));
709709
}
710710
}
711711
}
@@ -754,14 +754,14 @@ void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
754754
mp_obj_list_get(seq_in, &seq_len, &seq_items);
755755
}
756756
if (seq_len < num) {
757-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_ValueError, "need more than %d values to unpack", (void*)(machine_uint_t)seq_len));
757+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", (void*)(machine_uint_t)seq_len));
758758
} else if (seq_len > num) {
759-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num));
759+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num));
760760
}
761761
memcpy(items, seq_items, num * sizeof(mp_obj_t));
762762
} else {
763763
// TODO call rt_getiter and extract via rt_iternext
764-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(seq_in)));
764+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(seq_in)));
765765
}
766766
}
767767

@@ -807,7 +807,7 @@ mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
807807
}
808808

809809
no_attr:
810-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
810+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
811811
}
812812

813813
void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
@@ -852,7 +852,7 @@ void rt_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
852852
mp_map_t *globals = mp_obj_module_get_globals(base);
853853
mp_map_lookup(globals, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
854854
} else {
855-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
855+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
856856
}
857857
}
858858

@@ -877,7 +877,7 @@ mp_obj_t rt_getiter(mp_obj_t o_in) {
877877
if (o->type->getiter != NULL) {
878878
return o->type->getiter(o_in);
879879
} else {
880-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "'%s' object is not iterable", o->type->name));
880+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not iterable", o->type->name));
881881
}
882882
}
883883
}
@@ -890,7 +890,7 @@ mp_obj_t rt_iternext(mp_obj_t o_in) {
890890
if (o->type->iternext != NULL) {
891891
return o->type->iternext(o_in);
892892
} else {
893-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "'%s' object is not an iterator", o->type->name));
893+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not an iterator", o->type->name));
894894
}
895895
}
896896
}

py/stream.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static mp_obj_t stream_read(mp_obj_t self_in, mp_obj_t arg) {
2323
int error;
2424
machine_int_t out_sz = o->type->stream_p.read(self_in, buf, sz, &error);
2525
if (out_sz == -1) {
26-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_OSError, "[Errno %d]", (const char *)error));
26+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", error));
2727
} else {
2828
buf[out_sz] = 0;
2929
return mp_obj_new_str(qstr_from_str_take(buf, /*out_sz,*/ sz + 1));
@@ -42,7 +42,7 @@ static mp_obj_t stream_write(mp_obj_t self_in, mp_obj_t arg) {
4242
int error;
4343
machine_int_t out_sz = o->type->stream_p.write(self_in, buf, sz, &error);
4444
if (out_sz == -1) {
45-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_OSError, "[Errno %d]", (const char *)error));
45+
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", error));
4646
} else {
4747
// http://docs.python.org/3/library/io.html#io.RawIOBase.write
4848
// "None is returned if the raw stream is set not to block and no single byte could be readily written to it."

unix/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static mp_obj_t fdfile_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *ar
8383

8484
o->fd = open(fname, mode, 0644);
8585
if (o->fd == -1) {
86-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_OSError, "[Errno %d]", (const char *)errno));
86+
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_OSError, "[Errno %d]", (const char *)(machine_int_t)errno));
8787
}
8888
return o;
8989
}

0 commit comments

Comments
 (0)