Files
micropython/py/objexcept.c
Damien George a71c83a1d1 Change mp_obj_type_t.name from const char * to qstr.
Ultimately all static strings should be qstr.  This entry in the type
structure is only used for printing error messages (to tell the type of
the bad argument), and printing objects that don't supply a .print method.
2014-02-15 11:34:50 +00:00

130 lines
4.0 KiB
C

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "objtuple.h"
// This is unified class for C-level and Python-level exceptions
// Python-level exceptions have empty ->msg and all arguments are in
// args tuple. C-level exceptions likely have ->msg set, and args is empty.
typedef struct mp_obj_exception_t {
mp_obj_base_t base;
mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now
qstr id;
vstr_t *msg;
mp_obj_tuple_t args;
} mp_obj_exception_t;
STATIC void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = o_in;
if (o->msg != NULL) {
print(env, "%s: %s", qstr_str(o->id), vstr_str(o->msg));
} else {
// Yes, that's how CPython has it
if (kind == PRINT_REPR) {
print(env, "%s", qstr_str(o->id));
}
if (kind == PRINT_STR) {
if (o->args.len == 0) {
print(env, "");
return;
} else if (o->args.len == 1) {
mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
return;
}
}
tuple_print(print, env, &o->args, kind);
}
}
STATIC mp_obj_t exception_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_exception_t *base = self_in;
if (n_kw != 0) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "%s does not take keyword arguments", qstr_str(base->id)));
}
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args);
o->base.type = &exception_type;
o->traceback = MP_OBJ_NULL;
o->id = base->id;
o->msg = NULL;
o->args.len = n_args;
memcpy(o->args.items, args, n_args * sizeof(mp_obj_t));
return o;
}
const mp_obj_type_t exception_type = {
{ &mp_const_type },
.name = MP_QSTR_, // TODO proper exception names
.print = exception_print,
.call = exception_call,
};
mp_obj_t mp_obj_new_exception(qstr id) {
return mp_obj_new_exception_msg_varg(id, NULL);
}
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg) {
return mp_obj_new_exception_msg_varg(id, msg);
}
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
// make exception object
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
o->base.type = &exception_type;
o->traceback = MP_OBJ_NULL;
o->id = id;
o->args.len = 0;
if (fmt == NULL) {
o->msg = NULL;
} else {
// render exception message
o->msg = vstr_new();
va_list ap;
va_start(ap, fmt);
vstr_vprintf(o->msg, fmt, ap);
va_end(ap);
}
return o;
}
qstr mp_obj_exception_get_type(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
mp_obj_exception_t *self = self_in;
return self->id;
}
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) {
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
mp_obj_exception_t *self = self_in;
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
if (self->traceback == MP_OBJ_NULL) {
self->traceback = mp_obj_new_list(0, NULL);
}
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file);
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line);
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block);
}
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) {
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
mp_obj_exception_t *self = self_in;
if (self->traceback == MP_OBJ_NULL) {
*n = 0;
*values = NULL;
} else {
uint n2;
mp_obj_list_get(self->traceback, &n2, (mp_obj_t**)values);
*n = n2;
}
}