|
8 | 8 | #include "misc.h" |
9 | 9 | #include "mpconfig.h" |
10 | 10 | #include "obj.h" |
| 11 | +#include "objtuple.h" |
11 | 12 |
|
| 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). |
12 | 17 | typedef struct mp_obj_exception_t { |
13 | 18 | mp_obj_base_t base; |
14 | 19 | qstr id; |
15 | | - int n_args; |
16 | | - const void *args[]; |
| 20 | + qstr msg; |
| 21 | + mp_obj_tuple_t args; |
17 | 22 | } mp_obj_exception_t; |
18 | 23 |
|
19 | 24 | void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) { |
20 | 25 | 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); |
36 | 31 | } |
37 | 32 | } |
38 | 33 |
|
| 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 | + |
39 | 51 | const mp_obj_type_t exception_type = { |
40 | 52 | { &mp_const_type }, |
41 | 53 | "exception", |
42 | 54 | .print = exception_print, |
| 55 | + .call_n = exception_call, |
43 | 56 | }; |
44 | 57 |
|
45 | 58 | 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); |
51 | 60 | } |
52 | 61 |
|
53 | 62 | 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); |
60 | 64 | } |
61 | 65 |
|
62 | 66 | 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); |
70 | 68 | } |
71 | 69 |
|
72 | 70 | 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); |
81 | 72 | } |
82 | 73 |
|
83 | 74 | 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 | 75 | // 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); |
98 | 77 | o->base.type = &exception_type; |
99 | 78 | 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); |
108 | 90 | } |
109 | | - va_end(ap); |
110 | 91 |
|
111 | 92 | return o; |
112 | 93 | } |
|
0 commit comments