Skip to content

Commit c596612

Browse files
committed
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.
1 parent a71c83a commit c596612

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+473
-347
lines changed

py/builtin.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ STATIC mp_obj_t mp_builtin___build_class__(uint n_args, const mp_obj_t *args) {
3636
mp_obj_t meta;
3737
if (n_args == 2) {
3838
// no explicit bases, so use 'type'
39-
meta = (mp_obj_t)&mp_const_type;
39+
meta = (mp_obj_t)&mp_type_type;
4040
} else {
4141
// use type of first base object
4242
meta = mp_obj_get_type(args[2]);
@@ -142,7 +142,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
142142
byte str[1] = {ord};
143143
return mp_obj_new_str(str, 1, true);
144144
} else {
145-
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "chr() arg not in range(0x110000)"));
145+
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
146146
}
147147
}
148148

@@ -187,7 +187,7 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
187187
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
188188
return rt_build_tuple(2, args);
189189
} else {
190-
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)));
190+
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)));
191191
}
192192
}
193193

@@ -209,7 +209,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
209209
STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) {
210210
mp_obj_t len = mp_obj_len_maybe(o_in);
211211
if (len == NULL) {
212-
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)));
212+
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)));
213213
} else {
214214
return len;
215215
}
@@ -229,7 +229,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
229229
}
230230
}
231231
if (max_obj == NULL) {
232-
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "max() arg is an empty sequence"));
232+
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
233233
}
234234
return max_obj;
235235
} else {
@@ -258,7 +258,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
258258
}
259259
}
260260
if (min_obj == NULL) {
261-
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "min() arg is an empty sequence"));
261+
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
262262
}
263263
return min_obj;
264264
} else {
@@ -278,7 +278,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
278278
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
279279
mp_obj_t ret = rt_iternext(o);
280280
if (ret == mp_const_stop_iteration) {
281-
nlr_jump(mp_obj_new_exception(MP_QSTR_StopIteration));
281+
nlr_jump(mp_obj_new_exception(&mp_type_StopIteration));
282282
} else {
283283
return ret;
284284
}
@@ -294,7 +294,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
294294
// TODO unicode
295295
return mp_obj_new_int(((const byte*)str)[0]);
296296
} else {
297-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", len));
297+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
298298
}
299299
}
300300

@@ -364,7 +364,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
364364
STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
365365
assert(n_args >= 1);
366366
if (n_args > 1) {
367-
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
367+
nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError,
368368
"must use keyword argument for key function"));
369369
}
370370
mp_obj_t self = list_type.make_new((mp_obj_t)&list_type, 1, 0, args);

py/builtinevex.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "lexerunix.h"
1414
#include "parse.h"
1515
#include "obj.h"
16+
#include "parsehelper.h"
1617
#include "compile.h"
1718
#include "runtime0.h"
1819
#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
2829
qstr source_name = mp_lexer_source_name(lex);
2930

3031
// parse the string
31-
qstr parse_exc_id;
32-
const char *parse_exc_msg;
33-
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_exc_id, &parse_exc_msg);
32+
mp_parse_error_kind_t parse_error_kind;
33+
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind);
3434
mp_lexer_free(lex);
3535

3636
if (pn == MP_PARSE_NODE_NULL) {
3737
// parse error; raise exception
38-
nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
38+
nlr_jump(mp_parse_make_exception(parse_error_kind));
3939
}
4040

4141
// compile the string
@@ -74,6 +74,7 @@ STATIC mp_obj_t mp_builtin_exec(uint n_args, const mp_obj_t *args) {
7474
rt_locals_set(mp_obj_dict_get_map(locals));
7575
}
7676
mp_obj_t res = parse_compile_execute(args[0], MP_PARSE_FILE_INPUT);
77+
// TODO if the above call throws an exception, then we never get to reset the globals/locals
7778
rt_globals_set(old_globals);
7879
rt_locals_set(old_locals);
7980
return res;

py/builtinimport.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "lexerunix.h"
1414
#include "parse.h"
1515
#include "obj.h"
16+
#include "parsehelper.h"
1617
#include "compile.h"
1718
#include "runtime0.h"
1819
#include "runtime.h"
@@ -77,7 +78,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
7778

7879
if (lex == NULL) {
7980
// we verified the file exists using stat, but lexer could still fail
80-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ImportError, "ImportError: No module named '%s'", vstr_str(file)));
81+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", vstr_str(file)));
8182
}
8283

8384
qstr source_name = mp_lexer_source_name(lex);
@@ -91,16 +92,15 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
9192
rt_globals_set(mp_obj_module_get_globals(module_obj));
9293

9394
// parse the imported script
94-
qstr parse_exc_id;
95-
const char *parse_exc_msg;
96-
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_exc_id, &parse_exc_msg);
95+
mp_parse_error_kind_t parse_error_kind;
96+
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
9797
mp_lexer_free(lex);
9898

9999
if (pn == MP_PARSE_NODE_NULL) {
100100
// parse error; clean up and raise exception
101101
rt_locals_set(old_locals);
102102
rt_globals_set(old_globals);
103-
nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
103+
nlr_jump(mp_parse_make_exception(parse_error_kind));
104104
}
105105

106106
// compile the imported script
@@ -172,7 +172,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
172172

173173
// fail if we couldn't find the file
174174
if (stat == MP_IMPORT_STAT_NO_EXIST) {
175-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name)));
175+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name)));
176176
}
177177

178178
module_obj = mp_obj_module_get(mod_name);

py/lexer.c

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
5151
return i == len && *str == 0;
5252
}
5353

54+
#ifdef MICROPY_DEBUG_PRINTERS
5455
void mp_token_show(const mp_token_t *tok) {
5556
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
5657
if (tok->str != NULL && tok->len > 0) {
@@ -69,6 +70,7 @@ void mp_token_show(const mp_token_t *tok) {
6970
}
7071
printf("\n");
7172
}
73+
#endif
7274

7375
#define CUR_CHAR(lex) ((lex)->chr0)
7476

@@ -711,35 +713,3 @@ const mp_token_t *mp_lexer_cur(const mp_lexer_t *lex) {
711713
bool mp_lexer_is_kind(mp_lexer_t *lex, mp_token_kind_t kind) {
712714
return lex->tok_cur.kind == kind;
713715
}
714-
715-
/*
716-
bool mp_lexer_is_str(mp_lexer_t *lex, const char *str) {
717-
return mp_token_is_str(&lex->tok_cur, str);
718-
}
719-
720-
bool mp_lexer_opt_kind(mp_lexer_t *lex, mp_token_kind_t kind) {
721-
if (mp_lexer_is_kind(lex, kind)) {
722-
mp_lexer_to_next(lex);
723-
return true;
724-
}
725-
return false;
726-
}
727-
728-
bool mp_lexer_opt_str(mp_lexer_t *lex, const char *str) {
729-
if (mp_lexer_is_str(lex, str)) {
730-
mp_lexer_to_next(lex);
731-
return true;
732-
}
733-
return false;
734-
}
735-
*/
736-
737-
bool mp_lexer_show_error_pythonic_prefix(mp_lexer_t *lex) {
738-
printf(" File \"%s\", line %d column %d\n", qstr_str(lex->source_name), lex->tok_cur.src_line, lex->tok_cur.src_column);
739-
return false;
740-
}
741-
742-
bool mp_lexer_show_error_pythonic(mp_lexer_t *lex, const char *msg) {
743-
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);
744-
return false;
745-
}

py/mpconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#endif
4141

4242
// Whether to build functions that print debugging info:
43+
// mp_token_show
4344
// mp_byte_code_print
4445
// mp_parse_node_print
4546
#ifndef MICROPY_DEBUG_PRINTERS

py/obj.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
5151

5252
// helper function to print an exception with traceback
5353
void mp_obj_print_exception(mp_obj_t exc) {
54-
if (MP_OBJ_IS_TYPE(exc, &exception_type)) {
54+
if (mp_obj_is_exception_instance(exc)) {
5555
machine_uint_t n, *values;
5656
mp_obj_exception_get_traceback(exc, &n, &values);
5757
if (n > 0) {
@@ -133,7 +133,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
133133
}
134134
}
135135

136-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_NotImplementedError,
136+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError,
137137
"Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)));
138138
return false;
139139
}
@@ -160,7 +160,7 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
160160
} else if (MP_OBJ_IS_TYPE(arg, &int_type)) {
161161
return mp_obj_int_get_checked(arg);
162162
} else {
163-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
163+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
164164
}
165165
}
166166

@@ -175,7 +175,7 @@ machine_float_t mp_obj_get_float(mp_obj_t arg) {
175175
} else if (MP_OBJ_IS_TYPE(arg, &float_type)) {
176176
return mp_obj_float_get(arg);
177177
} else {
178-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
178+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
179179
}
180180
}
181181

@@ -195,7 +195,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
195195
} else if (MP_OBJ_IS_TYPE(arg, &complex_type)) {
196196
mp_obj_complex_get(arg, real, imag);
197197
} else {
198-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
198+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
199199
}
200200
}
201201
#endif
@@ -210,11 +210,11 @@ mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o_in, machine_int_t n) {
210210
mp_obj_list_get(o_in, &seq_len, &seq_items);
211211
}
212212
if (seq_len != n) {
213-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "requested length %d but object has length %d", n, seq_len));
213+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", n, seq_len));
214214
}
215215
return seq_items;
216216
} else {
217-
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)));
217+
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)));
218218
}
219219
}
220220

@@ -226,11 +226,11 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index)
226226
i += len;
227227
}
228228
if (i < 0 || i >= len) {
229-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_IndexError, "%s index out of range", qstr_str(type->name)));
229+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name)));
230230
}
231231
return i;
232232
} else {
233-
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)));
233+
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)));
234234
}
235235
}
236236

py/obj.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,27 @@ struct _mp_obj_type_t {
188188

189189
typedef struct _mp_obj_type_t mp_obj_type_t;
190190

191+
// Constant types, globally accessible
192+
193+
extern const mp_obj_type_t mp_type_type;
194+
extern const mp_obj_type_t mp_type_BaseException;
195+
extern const mp_obj_type_t mp_type_AssertionError;
196+
extern const mp_obj_type_t mp_type_AttributeError;
197+
extern const mp_obj_type_t mp_type_ImportError;
198+
extern const mp_obj_type_t mp_type_IndentationError;
199+
extern const mp_obj_type_t mp_type_IndexError;
200+
extern const mp_obj_type_t mp_type_KeyError;
201+
extern const mp_obj_type_t mp_type_NameError;
202+
extern const mp_obj_type_t mp_type_SyntaxError;
203+
extern const mp_obj_type_t mp_type_TypeError;
204+
extern const mp_obj_type_t mp_type_ValueError;
205+
extern const mp_obj_type_t mp_type_OverflowError;
206+
extern const mp_obj_type_t mp_type_OSError;
207+
extern const mp_obj_type_t mp_type_NotImplementedError;
208+
extern const mp_obj_type_t mp_type_StopIteration;
209+
191210
// Constant objects, globally accessible
192211

193-
extern const mp_obj_type_t mp_const_type;
194212
extern const mp_obj_t mp_const_none;
195213
extern const mp_obj_t mp_const_false;
196214
extern const mp_obj_t mp_const_true;
@@ -213,9 +231,9 @@ mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
213231
mp_obj_t mp_obj_new_float(mp_float_t val);
214232
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
215233
#endif
216-
mp_obj_t mp_obj_new_exception(qstr id);
217-
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg);
218-
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!)
234+
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
235+
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
236+
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!)
219237
mp_obj_t mp_obj_new_range(int start, int stop, int step);
220238
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
221239
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);
235253

236254
mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in);
237255
const char *mp_obj_get_type_str(mp_obj_t o_in);
256+
bool mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo);
238257

239258
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
240259
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);
274293
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in);
275294

276295
// exception
277-
extern const mp_obj_type_t exception_type;
278-
qstr mp_obj_exception_get_type(mp_obj_t self_in);
296+
bool mp_obj_is_exception_type(mp_obj_t self_in);
297+
bool mp_obj_is_exception_instance(mp_obj_t self_in);
298+
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
279299
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block);
280300
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values);
281301

py/objarray.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
8282

8383
STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
8484
if (n_args < 1 || n_args > 2) {
85-
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args));
85+
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected # of arguments, %d given", n_args));
8686
}
8787
// TODO check args
8888
uint l;
@@ -160,7 +160,7 @@ STATIC const mp_method_t array_type_methods[] = {
160160
};
161161

162162
const mp_obj_type_t array_type = {
163-
{ &mp_const_type },
163+
{ &mp_type_type },
164164
.name = MP_QSTR_array,
165165
.print = array_print,
166166
.make_new = array_make_new,
@@ -222,7 +222,7 @@ mp_obj_t array_it_iternext(mp_obj_t self_in) {
222222
}
223223

224224
STATIC const mp_obj_type_t array_it_type = {
225-
{ &mp_const_type },
225+
{ &mp_type_type },
226226
.name = MP_QSTR_iterator,
227227
.iternext = array_it_iternext,
228228
};

0 commit comments

Comments
 (0)