blob: 67e6d63155d2e8f2d9c6b88a4c08ddb17f9a49be [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
Paul Sokolovsky76d982e2014-01-13 19:19:16 +020024void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
Damiend99b0522013-12-21 18:17:45 +000025 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 {
Paul Sokolovsky76d982e2014-01-13 19:19:16 +020029 // Yes, that's how CPython has it
30 if (kind == PRINT_REPR) {
31 print(env, "%s", qstr_str(o->id));
32 }
33 if (kind == PRINT_STR) {
34 if (o->args.len == 0) {
35 print(env, "");
36 return;
37 } else if (o->args.len == 1) {
38 mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
39 return;
40 }
41 }
42 tuple_print(print, env, &o->args, kind);
Damiend99b0522013-12-21 18:17:45 +000043 }
44}
45
Paul Sokolovskyddf21782014-01-12 23:30:20 +020046// args in reversed order
47static mp_obj_t exception_call(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
48 mp_obj_exception_t *base = self_in;
49 mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, n_args);
50 o->base.type = &exception_type;
51 o->id = base->id;
52 o->msg = 0;
53 o->args.len = n_args;
54
55 // TODO: factor out as reusable copy_reversed()
56 int j = 0;
57 for (int i = n_args - 1; i >= 0; i--) {
58 o->args.items[i] = args[j++];
59 }
60 return o;
61}
62
Damiend99b0522013-12-21 18:17:45 +000063const mp_obj_type_t exception_type = {
64 { &mp_const_type },
65 "exception",
Damien George97209d32014-01-07 15:58:30 +000066 .print = exception_print,
Paul Sokolovskyddf21782014-01-12 23:30:20 +020067 .call_n = exception_call,
Damiend99b0522013-12-21 18:17:45 +000068};
69
70mp_obj_t mp_obj_new_exception(qstr id) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020071 return mp_obj_new_exception_msg_varg(id, NULL);
Damiend99b0522013-12-21 18:17:45 +000072}
73
74mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020075 return mp_obj_new_exception_msg_varg(id, msg);
Damiend99b0522013-12-21 18:17:45 +000076}
77
78mp_obj_t mp_obj_new_exception_msg_1_arg(qstr id, const char *fmt, const char *a1) {
Paul Sokolovskyddf21782014-01-12 23:30:20 +020079 return mp_obj_new_exception_msg_varg(id, fmt, a1);
Damiend99b0522013-12-21 18:17:45 +000080}
81
82mp_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 +020083 return mp_obj_new_exception_msg_varg(id, fmt, a1, a2);
Damiend99b0522013-12-21 18:17:45 +000084}
Damienb86e3f92013-12-29 17:17:43 +000085
Damien George6c73ca12014-01-08 18:11:23 +000086mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
Damien George6c73ca12014-01-08 18:11:23 +000087 // make exception object
Paul Sokolovskyddf21782014-01-12 23:30:20 +020088 mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
Damien George6c73ca12014-01-08 18:11:23 +000089 o->base.type = &exception_type;
90 o->id = id;
Paul Sokolovskyddf21782014-01-12 23:30:20 +020091 o->args.len = 0;
92 if (fmt == NULL) {
93 o->msg = 0;
94 } else {
95 // render exception message
96 vstr_t *vstr = vstr_new();
97 va_list ap;
98 va_start(ap, fmt);
99 vstr_vprintf(vstr, fmt, ap);
100 va_end(ap);
101 o->msg = qstr_from_str_take(vstr->buf, vstr->alloc);
Damien George6c73ca12014-01-08 18:11:23 +0000102 }
Damien George6c73ca12014-01-08 18:11:23 +0000103
104 return o;
105}
106
Damienb86e3f92013-12-29 17:17:43 +0000107qstr mp_obj_exception_get_type(mp_obj_t self_in) {
108 assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
109 mp_obj_exception_t *self = self_in;
110 return self->id;
111}