Commit c5966128 authored by Damien George's avatar Damien George
Browse files

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.
parent a71c83a1
......@@ -36,7 +36,7 @@ STATIC mp_obj_t mp_builtin___build_class__(uint n_args, const mp_obj_t *args) {
mp_obj_t meta;
if (n_args == 2) {
// no explicit bases, so use 'type'
meta = (mp_obj_t)&mp_const_type;
meta = (mp_obj_t)&mp_type_type;
} else {
// use type of first base object
meta = mp_obj_get_type(args[2]);
......@@ -142,7 +142,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
byte str[1] = {ord};
return mp_obj_new_str(str, 1, true);
} else {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "chr() arg not in range(0x110000)"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
}
}
......@@ -187,7 +187,7 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
return rt_build_tuple(2, args);
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
}
}
......@@ -209,7 +209,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in);
if (len == NULL) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
} else {
return len;
}
......@@ -229,7 +229,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
}
}
if (max_obj == NULL) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "max() arg is an empty sequence"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
}
return max_obj;
} else {
......@@ -258,7 +258,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
}
}
if (min_obj == NULL) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "min() arg is an empty sequence"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
}
return min_obj;
} else {
......@@ -278,7 +278,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
mp_obj_t ret = rt_iternext(o);
if (ret == mp_const_stop_iteration) {
nlr_jump(mp_obj_new_exception(MP_QSTR_StopIteration));
nlr_jump(mp_obj_new_exception(&mp_type_StopIteration));
} else {
return ret;
}
......@@ -294,7 +294,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
// TODO unicode
return mp_obj_new_int(((const byte*)str)[0]);
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", len));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
}
}
......@@ -364,7 +364,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
assert(n_args >= 1);
if (n_args > 1) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError,
"must use keyword argument for key function"));
}
mp_obj_t self = list_type.make_new((mp_obj_t)&list_type, 1, 0, args);
......
......@@ -13,6 +13,7 @@
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
......@@ -28,14 +29,13 @@ STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse
qstr source_name = mp_lexer_source_name(lex);
// parse the string
qstr parse_exc_id;
const char *parse_exc_msg;
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_exc_id, &parse_exc_msg);
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind);
mp_lexer_free(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error; raise exception
nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
nlr_jump(mp_parse_make_exception(parse_error_kind));
}
// compile the string
......@@ -74,6 +74,7 @@ STATIC mp_obj_t mp_builtin_exec(uint n_args, const mp_obj_t *args) {
rt_locals_set(mp_obj_dict_get_map(locals));
}
mp_obj_t res = parse_compile_execute(args[0], MP_PARSE_FILE_INPUT);
// TODO if the above call throws an exception, then we never get to reset the globals/locals
rt_globals_set(old_globals);
rt_locals_set(old_locals);
return res;
......
......@@ -13,6 +13,7 @@
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
......@@ -77,7 +78,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
if (lex == NULL) {
// we verified the file exists using stat, but lexer could still fail
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ImportError, "ImportError: No module named '%s'", vstr_str(file)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", vstr_str(file)));
}
qstr source_name = mp_lexer_source_name(lex);
......@@ -91,16 +92,15 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
rt_globals_set(mp_obj_module_get_globals(module_obj));
// parse the imported script
qstr parse_exc_id;
const char *parse_exc_msg;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_exc_id, &parse_exc_msg);
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
mp_lexer_free(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error; clean up and raise exception
rt_locals_set(old_locals);
rt_globals_set(old_globals);
nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
nlr_jump(mp_parse_make_exception(parse_error_kind));
}
// compile the imported script
......@@ -172,7 +172,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
// fail if we couldn't find the file
if (stat == MP_IMPORT_STAT_NO_EXIST) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name)));
}
module_obj = mp_obj_module_get(mod_name);
......
......@@ -51,6 +51,7 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
return i == len && *str == 0;
}
#ifdef MICROPY_DEBUG_PRINTERS
void mp_token_show(const mp_token_t *tok) {
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
if (tok->str != NULL && tok->len > 0) {
......@@ -69,6 +70,7 @@ void mp_token_show(const mp_token_t *tok) {
}
printf("\n");
}
#endif
#define CUR_CHAR(lex) ((lex)->chr0)
......@@ -711,35 +713,3 @@ const mp_token_t *mp_lexer_cur(const mp_lexer_t *lex) {
bool mp_lexer_is_kind(mp_lexer_t *lex, mp_token_kind_t kind) {
return lex->tok_cur.kind == kind;
}
/*
bool mp_lexer_is_str(mp_lexer_t *lex, const char *str) {
return mp_token_is_str(&lex->tok_cur, str);
}
bool mp_lexer_opt_kind(mp_lexer_t *lex, mp_token_kind_t kind) {
if (mp_lexer_is_kind(lex, kind)) {
mp_lexer_to_next(lex);
return true;
}
return false;
}
bool mp_lexer_opt_str(mp_lexer_t *lex, const char *str) {
if (mp_lexer_is_str(lex, str)) {
mp_lexer_to_next(lex);
return true;
}
return false;
}
*/
bool mp_lexer_show_error_pythonic_prefix(mp_lexer_t *lex) {
printf(" File \"%s\", line %d column %d\n", qstr_str(lex->source_name), lex->tok_cur.src_line, lex->tok_cur.src_column);
return false;
}
bool mp_lexer_show_error_pythonic(mp_lexer_t *lex, const char *msg) {
printf(" File \"%s\", line %d column %d\n%s\n", qstr_str(lex->source_name), lex->tok_cur.src_line, lex->tok_cur.src_column, msg);
return false;
}
......@@ -40,6 +40,7 @@
#endif
// Whether to build functions that print debugging info:
// mp_token_show
// mp_byte_code_print
// mp_parse_node_print
#ifndef MICROPY_DEBUG_PRINTERS
......
......@@ -51,7 +51,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
// helper function to print an exception with traceback
void mp_obj_print_exception(mp_obj_t exc) {
if (MP_OBJ_IS_TYPE(exc, &exception_type)) {
if (mp_obj_is_exception_instance(exc)) {
machine_uint_t n, *values;
mp_obj_exception_get_traceback(exc, &n, &values);
if (n > 0) {
......@@ -133,7 +133,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
}
}
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_NotImplementedError,
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError,
"Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)));
return false;
}
......@@ -160,7 +160,7 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
} else if (MP_OBJ_IS_TYPE(arg, &int_type)) {
return mp_obj_int_get_checked(arg);
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
}
}
......@@ -175,7 +175,7 @@ machine_float_t mp_obj_get_float(mp_obj_t arg) {
} else if (MP_OBJ_IS_TYPE(arg, &float_type)) {
return mp_obj_float_get(arg);
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
}
}
......@@ -195,7 +195,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
} else if (MP_OBJ_IS_TYPE(arg, &complex_type)) {
mp_obj_complex_get(arg, real, imag);
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
}
}
#endif
......@@ -210,11 +210,11 @@ mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o_in, machine_int_t n) {
mp_obj_list_get(o_in, &seq_len, &seq_items);
}
if (seq_len != n) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "requested length %d but object has length %d", n, seq_len));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", n, seq_len));
}
return seq_items;
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in)));
}
}
......@@ -226,11 +226,11 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index)
i += len;
}
if (i < 0 || i >= len) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "%s index out of range", qstr_str(type->name)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name)));
}
return i;
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index)));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index)));
}
}
......
......@@ -188,9 +188,27 @@ struct _mp_obj_type_t {
typedef struct _mp_obj_type_t mp_obj_type_t;
// Constant types, globally accessible
extern const mp_obj_type_t mp_type_type;
extern const mp_obj_type_t mp_type_BaseException;
extern const mp_obj_type_t mp_type_AssertionError;
extern const mp_obj_type_t mp_type_AttributeError;
extern const mp_obj_type_t mp_type_ImportError;
extern const mp_obj_type_t mp_type_IndentationError;
extern const mp_obj_type_t mp_type_IndexError;
extern const mp_obj_type_t mp_type_KeyError;
extern const mp_obj_type_t mp_type_NameError;
extern const mp_obj_type_t mp_type_SyntaxError;
extern const mp_obj_type_t mp_type_TypeError;
extern const mp_obj_type_t mp_type_ValueError;
extern const mp_obj_type_t mp_type_OverflowError;
extern const mp_obj_type_t mp_type_OSError;
extern const mp_obj_type_t mp_type_NotImplementedError;
extern const mp_obj_type_t mp_type_StopIteration;
// Constant objects, globally accessible
extern const mp_obj_type_t mp_const_type;
extern const mp_obj_t mp_const_none;
extern const mp_obj_t mp_const_false;
extern const mp_obj_t mp_const_true;
......@@ -213,9 +231,9 @@ mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
mp_obj_t mp_obj_new_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
mp_obj_t mp_obj_new_exception(qstr id);
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_range(int start, int stop, int step);
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args, uint n_state, const byte *code);
......@@ -235,6 +253,7 @@ mp_obj_t mp_obj_new_module(qstr module_name);
mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in);
const char *mp_obj_get_type_str(mp_obj_t o_in);
bool mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo);
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
......@@ -274,8 +293,9 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in);
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in);
// exception
extern const mp_obj_type_t exception_type;
qstr mp_obj_exception_get_type(mp_obj_t self_in);
bool mp_obj_is_exception_type(mp_obj_t self_in);
bool mp_obj_is_exception_instance(mp_obj_t self_in);
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block);
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values);
......
......@@ -82,7 +82,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
if (n_args < 1 || n_args > 2) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected # of arguments, %d given", n_args));
}
// TODO check args
uint l;
......@@ -160,7 +160,7 @@ STATIC const mp_method_t array_type_methods[] = {
};
const mp_obj_type_t array_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_array,
.print = array_print,
.make_new = array_make_new,
......@@ -222,7 +222,7 @@ mp_obj_t array_it_iternext(mp_obj_t self_in) {
}
STATIC const mp_obj_type_t array_it_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_iterator,
.iternext = array_it_iternext,
};
......
......@@ -29,7 +29,7 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
switch (n_args) {
case 0: return mp_const_false;
case 1: if (rt_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "bool takes at most 1 argument, %d given", n_args));
default: nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bool takes at most 1 argument, %d given", n_args));
}
}
......@@ -46,7 +46,7 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
}
const mp_obj_type_t bool_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_bool,
.print = bool_print,
.make_new = bool_make_new,
......
......@@ -40,7 +40,7 @@ mp_obj_t bound_meth_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_
}
const mp_obj_type_t bound_meth_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_bound_method,
.call = bound_meth_call,
};
......
......@@ -25,7 +25,7 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) {
}
const mp_obj_type_t cell_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_, // should never need to print cell type
};
......
......@@ -41,7 +41,7 @@ mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *
}
const mp_obj_type_t closure_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_closure,
.call = closure_call,
};
......
......@@ -66,7 +66,7 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
}
default:
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "complex takes at most 2 arguments, %d given", n_args));
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "complex takes at most 2 arguments, %d given", n_args));
}
}
......@@ -86,7 +86,7 @@ STATIC mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
const mp_obj_type_t complex_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_complex,
.print = complex_print,
.make_new = complex_make_new,
......
......@@ -60,7 +60,7 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// dict load
mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
if (elem == NULL) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>"));
} else {
return elem->value;
}
......@@ -112,7 +112,7 @@ mp_obj_t dict_it_iternext(mp_obj_t self_in) {
}
STATIC const mp_obj_type_t dict_it_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_iterator,
.iternext = dict_it_iternext,
};
......@@ -187,7 +187,7 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp
if (elem == NULL || elem->value == NULL) {
if (deflt == NULL) {
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>"));
} else {
value = mp_const_none;
}
......@@ -246,7 +246,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
mp_obj_dict_t *self = self_in;
if (self->map.used == 0) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "popitem(): dictionary is empty"));
nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty"));
}
mp_obj_dict_it_t *iter = mp_obj_new_dict_iterator(self, 0);
......@@ -276,7 +276,7 @@ STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
|| value == mp_const_stop_iteration
|| stop != mp_const_stop_iteration) {
nlr_jump(mp_obj_new_exception_msg(
MP_QSTR_ValueError,
&mp_type_ValueError,
"dictionary update sequence has the wrong length"));
} else {
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
......@@ -341,7 +341,7 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
}
STATIC const mp_obj_type_t dict_view_it_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_iterator,
.iternext = dict_view_it_iternext,
.methods = NULL, /* set operations still to come */
......@@ -385,7 +385,7 @@ STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC const mp_obj_type_t dict_view_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_dict_view,
.print = dict_view_print,
.binary_op = dict_view_binary_op,
......@@ -440,7 +440,7 @@ STATIC const mp_method_t dict_type_methods[] = {
};
const mp_obj_type_t dict_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_dict,
.print = dict_print,
.make_new = dict_make_new,
......
......@@ -27,7 +27,7 @@ STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
}
const mp_obj_type_t enumerate_type = {
{ &mp_const_type },
{ &mp_type_type },
.name = MP_QSTR_enumerate,
.make_new = enumerate_make_new,
.iternext = enumerate_iternext,
......
......@@ -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