From a91ac2011f0131ce550bf227d78ccccbdab4f882 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 5 Oct 2014 19:01:34 +0100 Subject: [PATCH] py: Make compiler return a proper exception on SyntaxError. --- bare-arm/main.c | 3 +- py/builtinevex.c | 6 +-- py/builtinimport.c | 5 +- py/compile.c | 55 ++++++++++++---------- qemu-arm/main.c | 3 +- qemu-arm/test_main.c | 5 +- stmhal/pyexec.c | 3 +- tests/basics/{eval1.py => builtin_eval.py} | 0 tests/basics/builtin_eval_error.py | 6 +++ unix-cpy/main.c | 4 +- 10 files changed, 53 insertions(+), 37 deletions(-) rename tests/basics/{eval1.py => builtin_eval.py} (100%) create mode 100644 tests/basics/builtin_eval_error.py diff --git a/bare-arm/main.c b/bare-arm/main.c index 983810c892..084374d3f1 100644 --- a/bare-arm/main.c +++ b/bare-arm/main.c @@ -36,8 +36,9 @@ void do_str(const char *src) { mp_lexer_free(lex); mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true); - if (module_fun == mp_const_none) { + if (mp_obj_is_exception_instance(module_fun)) { // compile error + mp_obj_print_exception(module_fun); return; } diff --git a/py/builtinevex.c b/py/builtinevex.c index 63c1547fbe..a115ec669e 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -64,9 +64,9 @@ STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse // compile the string mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); - if (module_fun == mp_const_none) { - // TODO handle compile error correctly - return mp_const_none; + // check if there was a compile error + if (mp_obj_is_exception_instance(module_fun)) { + nlr_raise(module_fun); } // complied successfully, execute it diff --git a/py/builtinimport.c b/py/builtinimport.c index 7270e1f840..04786b2104 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -142,11 +142,10 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // compile the imported script mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); - if (module_fun == mp_const_none) { - // TODO handle compile error correctly + if (mp_obj_is_exception_instance(module_fun)) { mp_locals_set(old_locals); mp_globals_set(old_globals); - nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module")); + nlr_raise(module_fun); } // complied successfully, execute it diff --git a/py/compile.c b/py/compile.c index e08469460d..644e55be08 100644 --- a/py/compile.c +++ b/py/compile.c @@ -62,24 +62,29 @@ typedef enum { #define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm)) #define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__)) +// elements in this struct are ordered to make it compact typedef struct _compiler_t { qstr source_file; + uint8_t is_repl; uint8_t pass; // holds enum type pass_kind_t - uint8_t had_error; // try to keep compiler clean from nlr uint8_t func_arg_is_super; // used to compile special case of super() function call + uint8_t have_star; + + // try to keep compiler clean from nlr + // this is set to an exception object if we have a compile error + mp_obj_t compile_error; uint next_label; - uint16_t break_label; // highest bit set indicates we are breaking out of a for loop - uint16_t continue_label; - int break_continue_except_level; - uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT - - uint8_t have_star; uint16_t num_dict_params; uint16_t num_default_params; + uint16_t break_label; // highest bit set indicates we are breaking out of a for loop + uint16_t continue_label; + uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT + int break_continue_except_level; + scope_t *scope_head; scope_t *scope_cur; @@ -91,14 +96,15 @@ typedef struct _compiler_t { } compiler_t; STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) { - // TODO store the error message to a variable in compiler_t instead of printing it + mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); + // we don't have a 'block' name, so just pass the NULL qstr to indicate this if (MP_PARSE_NODE_IS_STRUCT(pn)) { - printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line); + mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL); } else { - printf(" File \"%s\"\n", qstr_str(comp->source_file)); + // we don't have a line number, so just pass 0 + mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL); } - printf("SyntaxError: %s\n", msg); - comp->had_error = true; + comp->compile_error = exc; } STATIC const mp_map_elem_t mp_constants_table[] = { @@ -1107,7 +1113,7 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint comp->num_default_params = 0; apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param); - if (comp->had_error) { + if (comp->compile_error != MP_OBJ_NULL) { return MP_QSTR_NULL; } @@ -3415,7 +3421,8 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind if (comp->pass > MP_PASS_SCOPE) { bool success = EMIT_INLINE_ASM(end_pass); if (!success) { - comp->had_error = true; + // TODO get proper exception from inline assembler + compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler error"); } } } @@ -3550,6 +3557,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is compiler_t *comp = m_new0(compiler_t, 1); comp->source_file = source_file; comp->is_repl = is_repl; + comp->compile_error = MP_OBJ_NULL; // optimise constants mp_map_t consts; @@ -3566,7 +3574,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is comp->emit_inline_asm = NULL; comp->emit_inline_asm_method_table = NULL; uint max_num_labels = 0; - for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { if (false) { #if MICROPY_EMIT_INLINE_THUMB } else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) { @@ -3583,7 +3591,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is } // compute some things related to scope and identifiers - for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { compile_scope_compute_things(comp, s); } @@ -3600,7 +3608,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is emit_inline_asm_t *emit_inline_thumb = NULL; #endif #endif // !MICROPY_EMIT_CPYTHON - for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { if (false) { // dummy @@ -3615,7 +3623,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is comp->emit_inline_asm = emit_inline_thumb; comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table; compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); - if (!comp->had_error) { + if (comp->compile_error == MP_OBJ_NULL) { compile_scope_inline_asm(comp, s, MP_PASS_EMIT); } #endif @@ -3674,12 +3682,12 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is #endif // !MICROPY_EMIT_CPYTHON // second last pass: compute code size - if (!comp->had_error) { + if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_CODE_SIZE); } // final pass: emit code - if (!comp->had_error) { + if (comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_EMIT); } } @@ -3722,12 +3730,11 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is } // free the compiler - bool had_error = comp->had_error; + mp_obj_t compile_error = comp->compile_error; m_del_obj(compiler_t, comp); - if (had_error) { - // TODO return a proper error message - return mp_const_none; + if (compile_error != MP_OBJ_NULL) { + return compile_error; } else { #if MICROPY_EMIT_CPYTHON // can't create code, so just return true diff --git a/qemu-arm/main.c b/qemu-arm/main.c index 97591fe944..7bb8472541 100644 --- a/qemu-arm/main.c +++ b/qemu-arm/main.c @@ -36,8 +36,9 @@ void do_str(const char *src) { mp_lexer_free(lex); mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true); - if (module_fun == mp_const_none) { + if (mp_obj_is_exception_instance(module_fun)) { // compile error + mp_obj_print_exception(module_fun); return; } diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c index 563e1c91df..099cd94ba1 100644 --- a/qemu-arm/test_main.c +++ b/qemu-arm/test_main.c @@ -39,8 +39,9 @@ inline void do_str(const char *src) { mp_lexer_free(lex); mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true); - if (module_fun == mp_const_none) { - tt_abort_msg("Computer error"); + if (mp_obj_is_exception_instance(module_fun)) { + mp_obj_print_exception(module_fun); + tt_abort_msg("Compile error"); } nlr_buf_t nlr; diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 01c0173ef4..0ce4882e20 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -72,7 +72,8 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, is_repl); - if (module_fun == mp_const_none) { + if (mp_obj_is_exception_instance(module_fun)) { + mp_obj_print_exception(module_fun); return false; } diff --git a/tests/basics/eval1.py b/tests/basics/builtin_eval.py similarity index 100% rename from tests/basics/eval1.py rename to tests/basics/builtin_eval.py diff --git a/tests/basics/builtin_eval_error.py b/tests/basics/builtin_eval_error.py new file mode 100644 index 0000000000..3e8a8ff0d8 --- /dev/null +++ b/tests/basics/builtin_eval_error.py @@ -0,0 +1,6 @@ +# test if eval raises SyntaxError + +try: + print(eval("[1, *a]")) +except SyntaxError: + print("SyntaxError") diff --git a/unix-cpy/main.c b/unix-cpy/main.c index ac142f50ff..6695c7e84f 100644 --- a/unix-cpy/main.c +++ b/unix-cpy/main.c @@ -79,8 +79,8 @@ void do_file(const char *file) { //printf("----------------\n"); - if (module_fun == mp_const_none) { - printf("compile error\n"); + if (mp_obj_is_exception_instance(module_fun)) { + mp_obj_print_exception(module_fun); } } }