mirror of
https://github.com/micropython/micropython.git
synced 2025-09-06 09:50:20 +02:00
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.
130 lines
4.0 KiB
C
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;
|
|
}
|
|
}
|