blob: f083e61e5288ba948913057c1a32d96b0f91cf66 [file] [log] [blame]
Damiend99b0522013-12-21 18:17:45 +00001#include <stdlib.h>
2#include <stdint.h>
3#include <string.h>
Damien George6c73ca12014-01-08 18:11:23 +00004#include <stdarg.h>
Damiend99b0522013-12-21 18:17:45 +00005#include <assert.h>
6
7#include "nlr.h"
8#include "misc.h"
9#include "mpconfig.h"
10#include "obj.h"
Paul Sokolovskyddf21782014-01-12 23:30:20 +020011#include "objtuple.h"
Damiend99b0522013-12-21 18:17:45 +000012
Paul Sokolovskyddf21782014-01-12 23:30:20 +020013// 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).
Damiend99b0522013-12-21 18:17:45 +000017typedef struct mp_obj_exception_t {
18 mp_obj_base_t base;
19 qstr id;
Paul Sokolovskyddf21782014-01-12 23:30:20 +020020 qstr msg;
21 mp_obj_tuple_t args;
Damiend99b0522013-12-21 18:17:45 +000022} mp_obj_exception_t;
23
24void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
25 mp_obj_exception_t *o = o_in;
Paul Sokolovskyddf21782014-01-12 23:30:20 +020026 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);
Damiend99b0522013-12-21 18:17:45 +000031 }
32}
33
Paul Sokolovskyddf21782014-01-12 23:30:20 +020034// args in reversed order
35static 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
Damiend99b0522013-12-21 18:17:45 +000051const mp_obj_type_t exception_type = {
52 { &mp_const_type },
53 "exception",
Damien George97209d32014-01-07 15:58:30 +000054 .print = exception_print,
Paul Sokolovskyddf21782014-01-12 23:30:20 +020055 .call_n = exception_call,
Damiend99b0522013-12-21 18:17:45 +000056};
57
58mp_obj_t mp_obj_new_exception(qstr id) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020059 return mp_obj_new_exception_msg_varg(id, NULL);
Damiend99b0522013-12-21 18:17:45 +000060}
61
62mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020063 return mp_obj_new_exception_msg_varg(id, msg);
Damiend99b0522013-12-21 18:17:45 +000064}
65
66mp_obj_t mp_obj_new_exception_msg_1_arg(qstr id, const char *fmt, const char *a1) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020067 return mp_obj_new_exception_msg_varg(id, fmt, a1);
Damiend99b0522013-12-21 18:17:45 +000068}
69
70mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a1, const char *a2) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020071 return mp_obj_new_exception_msg_varg(id, fmt, a1, a2);
Damiend99b0522013-12-21 18:17:45 +000072}
Damienb86e3f92013-12-29 17:17:43 +000073
Damien George6c73ca12014-01-08 18:11:23 +000074mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
Damien George6c73ca12014-01-08 18:11:23 +000075 // make exception object
Paul Sokolovskyddf21782014-01-12 23:30:20 +020076 mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
Damien George6c73ca12014-01-08 18:11:23 +000077 o->base.type = &exception_type;
78 o->id = id;
Paul Sokolovskyddf21782014-01-12 23:30:20 +020079 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);
Damien George6c73ca12014-01-08 18:11:23 +000090 }
Damien George6c73ca12014-01-08 18:11:23 +000091
92 return o;
93}
94
Damienb86e3f92013-12-29 17:17:43 +000095qstr mp_obj_exception_get_type(mp_obj_t self_in) {
96 assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
97 mp_obj_exception_t *self = self_in;
98 return self->id;
99}