Skip to content

Commit 39eab8d

Browse files
committed
Merge pull request adafruit#161 from pfalcon/exc-more-pythonic
Move towards Python-compliant interface of exceptions
2 parents 66a5bf6 + ddf2178 commit 39eab8d

2 files changed

Lines changed: 49 additions & 65 deletions

File tree

py/objexcept.c

Lines changed: 46 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,105 +8,86 @@
88
#include "misc.h"
99
#include "mpconfig.h"
1010
#include "obj.h"
11+
#include "objtuple.h"
1112

13+
// This is unified class for C-level and Python-level exceptions
14+
// Python-level exception have empty ->msg and all arguments are in
15+
// args tuple. C-level excepttion likely have ->msg, and may as well
16+
// have args tuple (or otherwise have it as NULL).
1217
typedef struct mp_obj_exception_t {
1318
mp_obj_base_t base;
1419
qstr id;
15-
int n_args;
16-
const void *args[];
20+
qstr msg;
21+
mp_obj_tuple_t args;
1722
} mp_obj_exception_t;
1823

1924
void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
2025
mp_obj_exception_t *o = o_in;
21-
switch (o->n_args) {
22-
case 0:
23-
print(env, "%s", qstr_str(o->id));
24-
break;
25-
case 1:
26-
print(env, "%s: %s", qstr_str(o->id), (const char*)o->args[0]);
27-
break;
28-
case 2:
29-
print(env, "%s: ", qstr_str(o->id));
30-
print(env, (const char*)o->args[0], o->args[1]);
31-
break;
32-
default: // here we just assume at least 3 args, but only use first 3
33-
print(env, "%s: ", qstr_str(o->id));
34-
print(env, (const char*)o->args[0], o->args[1], o->args[2]);
35-
break;
26+
if (o->msg != 0) {
27+
print(env, "%s: %s", qstr_str(o->id), qstr_str(o->msg));
28+
} else {
29+
print(env, "%s", qstr_str(o->id));
30+
tuple_print(print, env, &o->args);
3631
}
3732
}
3833

34+
// args in reversed order
35+
static mp_obj_t exception_call(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
36+
mp_obj_exception_t *base = self_in;
37+
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, n_args);
38+
o->base.type = &exception_type;
39+
o->id = base->id;
40+
o->msg = 0;
41+
o->args.len = n_args;
42+
43+
// TODO: factor out as reusable copy_reversed()
44+
int j = 0;
45+
for (int i = n_args - 1; i >= 0; i--) {
46+
o->args.items[i] = args[j++];
47+
}
48+
return o;
49+
}
50+
3951
const mp_obj_type_t exception_type = {
4052
{ &mp_const_type },
4153
"exception",
4254
.print = exception_print,
55+
.call_n = exception_call,
4356
};
4457

4558
mp_obj_t mp_obj_new_exception(qstr id) {
46-
mp_obj_exception_t *o = m_new_obj(mp_obj_exception_t);
47-
o->base.type = &exception_type;
48-
o->id = id;
49-
o->n_args = 0;
50-
return o;
59+
return mp_obj_new_exception_msg_varg(id, NULL);
5160
}
5261

5362
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg) {
54-
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 1);
55-
o->base.type = &exception_type;
56-
o->id = id;
57-
o->n_args = 1;
58-
o->args[0] = msg;
59-
return o;
63+
return mp_obj_new_exception_msg_varg(id, msg);
6064
}
6165

6266
mp_obj_t mp_obj_new_exception_msg_1_arg(qstr id, const char *fmt, const char *a1) {
63-
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 2);
64-
o->base.type = &exception_type;
65-
o->id = id;
66-
o->n_args = 2;
67-
o->args[0] = fmt;
68-
o->args[1] = a1;
69-
return o;
67+
return mp_obj_new_exception_msg_varg(id, fmt, a1);
7068
}
7169

7270
mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a1, const char *a2) {
73-
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 3);
74-
o->base.type = &exception_type;
75-
o->id = id;
76-
o->n_args = 3;
77-
o->args[0] = fmt;
78-
o->args[1] = a1;
79-
o->args[2] = a2;
80-
return o;
71+
return mp_obj_new_exception_msg_varg(id, fmt, a1, a2);
8172
}
8273

8374
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-
9675
// make exception object
97-
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, n_args);
76+
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
9877
o->base.type = &exception_type;
9978
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*);
79+
o->args.len = 0;
80+
if (fmt == NULL) {
81+
o->msg = 0;
82+
} else {
83+
// render exception message
84+
vstr_t *vstr = vstr_new();
85+
va_list ap;
86+
va_start(ap, fmt);
87+
vstr_vprintf(vstr, fmt, ap);
88+
va_end(ap);
89+
o->msg = qstr_from_str_take(vstr->buf, vstr->alloc);
10890
}
109-
va_end(ap);
11091

11192
return o;
11293
}

tests/basics/tests/exception1.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# TODO: requires repr()
2+
#a = IndexError(1, "test", [100, 200])
3+
#print(repr(a))

0 commit comments

Comments
 (0)