summaryrefslogtreecommitdiffstatshomepage
path: root/py/objexcept.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-02-15 16:10:44 +0000
committerDamien George <damien.p.george@gmail.com>2014-02-15 16:10:44 +0000
commitc5966128c7c8a768f6726f299d85d5daef6bed48 (patch)
treefea6913ae43d722078a837d8c7fd9a1e459f3891 /py/objexcept.c
parenta71c83a1d1aeca1d81d7c673929f8e836dec131e (diff)
downloadmicropython-c5966128c7c8a768f6726f299d85d5daef6bed48.tar.gz
micropython-c5966128c7c8a768f6726f299d85d5daef6bed48.zip
Implement proper exception type hierarchy.
Each built-in exception is now a type, with base type BaseException. C exceptions are created by passing a pointer to the exception type to make an instance of. When raising an exception from the VM, an instance is created automatically if an exception type is raised (as opposed to an exception instance). Exception matching (RT_BINARY_OP_EXCEPTION_MATCH) is now proper. Handling of parse error changed to match new exceptions. mp_const_type renamed to mp_type_type for consistency.
Diffstat (limited to 'py/objexcept.c')
-rw-r--r--py/objexcept.c108
1 files changed, 80 insertions, 28 deletions
diff --git a/py/objexcept.c b/py/objexcept.c
index e2c154de97..d5c056a8d9 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -17,19 +17,18 @@
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) {
+STATIC void mp_obj_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));
+ print(env, "%s: %s", qstr_str(o->base.type->name), vstr_str(o->msg));
} else {
// Yes, that's how CPython has it
if (kind == PRINT_REPR) {
- print(env, "%s", qstr_str(o->id));
+ print(env, "%s", qstr_str(o->base.type->name));
}
if (kind == PRINT_STR) {
if (o->args.len == 0) {
@@ -44,46 +43,74 @@ STATIC void exception_print(void (*print)(void *env, const char *fmt, ...), void
}
}
-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;
+STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+ mp_obj_type_t *type = type_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)));
+ nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", type->name));
}
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args);
- o->base.type = &exception_type;
+ o->base.type = 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,
+const mp_obj_type_t mp_type_BaseException = {
+ { &mp_type_type },
+ .name = MP_QSTR_BaseException,
+ .print = mp_obj_exception_print,
+ .make_new = mp_obj_exception_make_new,
};
-mp_obj_t mp_obj_new_exception(qstr id) {
- return mp_obj_new_exception_msg_varg(id, NULL);
+#define MP_DEFINE_EXCEPTION(exc_name) \
+STATIC const mp_obj_tuple_t mp_type_ ## exc_name ## _bases_tuple = {{&tuple_type}, 1, {(mp_obj_t)&mp_type_BaseException}};\
+const mp_obj_type_t mp_type_ ## exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_ ## exc_name, \
+ .print = mp_obj_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .bases_tuple = (mp_obj_t)&mp_type_ ## exc_name ## _bases_tuple, \
+};
+
+MP_DEFINE_EXCEPTION(AssertionError)
+MP_DEFINE_EXCEPTION(AttributeError)
+MP_DEFINE_EXCEPTION(ImportError)
+MP_DEFINE_EXCEPTION(IndentationError)
+MP_DEFINE_EXCEPTION(IndexError)
+MP_DEFINE_EXCEPTION(KeyError)
+MP_DEFINE_EXCEPTION(NameError)
+MP_DEFINE_EXCEPTION(SyntaxError)
+MP_DEFINE_EXCEPTION(TypeError)
+MP_DEFINE_EXCEPTION(ValueError)
+MP_DEFINE_EXCEPTION(OverflowError)
+MP_DEFINE_EXCEPTION(OSError)
+MP_DEFINE_EXCEPTION(NotImplementedError)
+MP_DEFINE_EXCEPTION(StopIteration)
+
+mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
+ return mp_obj_new_exception_msg_varg(exc_type, 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(const mp_obj_type_t *exc_type, const char *msg) {
+ return mp_obj_new_exception_msg_varg(exc_type, msg);
}
-mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
+mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) {
+ // check that the given type is an exception type
+ assert(exc_type->make_new == mp_obj_exception_make_new);
+
// 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;
+ mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, 0);
+ o->base.type = exc_type;
o->traceback = MP_OBJ_NULL;
- o->id = id;
o->args.len = 0;
+
if (fmt == NULL) {
+ // no message
o->msg = NULL;
} else {
// render exception message
@@ -97,18 +124,41 @@ mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
return o;
}
-qstr mp_obj_exception_get_type(mp_obj_t self_in) {
- assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
+// return true if the given object is an exception type
+// TODO make this work for user defined exceptions
+bool mp_obj_is_exception_type(mp_obj_t self_in) {
+ if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) {
+ mp_obj_type_t *self = self_in;
+ return self->make_new == mp_obj_exception_make_new;
+ } else {
+ return false;
+ }
+}
+
+// return true if the given object is an instance of an exception type
+// TODO make this work for user defined exceptions
+bool mp_obj_is_exception_instance(mp_obj_t self_in) {
+ return mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new;
+}
+
+void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
+ // make sure self_in is an exception instance
+ assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new);
mp_obj_exception_t *self = self_in;
- return self->id;
+
+ // just set the traceback to the null object
+ // we don't want to call any memory management functions here
+ self->traceback = MP_OBJ_NULL;
}
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));
+ // make sure self_in is an exception instance
+ assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new);
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);
+ self->traceback = mp_obj_new_list(3, 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);
@@ -116,8 +166,10 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t
}
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));
+ // make sure self_in is an exception instance
+ assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new);
mp_obj_exception_t *self = self_in;
+
if (self->traceback == MP_OBJ_NULL) {
*n = 0;
*values = NULL;