py: Make compiler return a proper exception on SyntaxError.
This commit is contained in:
parent
6dba992182
commit
a91ac2011f
|
@ -36,8 +36,9 @@ void do_str(const char *src) {
|
||||||
mp_lexer_free(lex);
|
mp_lexer_free(lex);
|
||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
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
|
// compile error
|
||||||
|
mp_obj_print_exception(module_fun);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
// compile the string
|
||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||||
|
|
||||||
if (module_fun == mp_const_none) {
|
// check if there was a compile error
|
||||||
// TODO handle compile error correctly
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
return mp_const_none;
|
nlr_raise(module_fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
// complied successfully, execute it
|
// complied successfully, execute it
|
||||||
|
|
|
@ -142,11 +142,10 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||||
// compile the imported script
|
// compile the imported script
|
||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||||
|
|
||||||
if (module_fun == mp_const_none) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
// TODO handle compile error correctly
|
|
||||||
mp_locals_set(old_locals);
|
mp_locals_set(old_locals);
|
||||||
mp_globals_set(old_globals);
|
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
|
// complied successfully, execute it
|
||||||
|
|
55
py/compile.c
55
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(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__))
|
#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 {
|
typedef struct _compiler_t {
|
||||||
qstr source_file;
|
qstr source_file;
|
||||||
|
|
||||||
uint8_t is_repl;
|
uint8_t is_repl;
|
||||||
uint8_t pass; // holds enum type pass_kind_t
|
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 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;
|
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_dict_params;
|
||||||
uint16_t num_default_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_head;
|
||||||
scope_t *scope_cur;
|
scope_t *scope_cur;
|
||||||
|
|
||||||
|
@ -91,14 +96,15 @@ typedef struct _compiler_t {
|
||||||
} compiler_t;
|
} compiler_t;
|
||||||
|
|
||||||
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
|
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)) {
|
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 {
|
} 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->compile_error = exc;
|
||||||
comp->had_error = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
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;
|
comp->num_default_params = 0;
|
||||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
|
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;
|
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) {
|
if (comp->pass > MP_PASS_SCOPE) {
|
||||||
bool success = EMIT_INLINE_ASM(end_pass);
|
bool success = EMIT_INLINE_ASM(end_pass);
|
||||||
if (!success) {
|
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);
|
compiler_t *comp = m_new0(compiler_t, 1);
|
||||||
comp->source_file = source_file;
|
comp->source_file = source_file;
|
||||||
comp->is_repl = is_repl;
|
comp->is_repl = is_repl;
|
||||||
|
comp->compile_error = MP_OBJ_NULL;
|
||||||
|
|
||||||
// optimise constants
|
// optimise constants
|
||||||
mp_map_t consts;
|
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 = NULL;
|
||||||
comp->emit_inline_asm_method_table = NULL;
|
comp->emit_inline_asm_method_table = NULL;
|
||||||
uint max_num_labels = 0;
|
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 (false) {
|
||||||
#if MICROPY_EMIT_INLINE_THUMB
|
#if MICROPY_EMIT_INLINE_THUMB
|
||||||
} else if (s->emit_options == MP_EMIT_OPT_ASM_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
|
// 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);
|
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;
|
emit_inline_asm_t *emit_inline_thumb = NULL;
|
||||||
#endif
|
#endif
|
||||||
#endif // !MICROPY_EMIT_CPYTHON
|
#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) {
|
if (false) {
|
||||||
// dummy
|
// 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 = emit_inline_thumb;
|
||||||
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
|
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
|
||||||
compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);
|
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);
|
compile_scope_inline_asm(comp, s, MP_PASS_EMIT);
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#endif // !MICROPY_EMIT_CPYTHON
|
||||||
|
|
||||||
// second last pass: compute code size
|
// 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);
|
compile_scope(comp, s, MP_PASS_CODE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// final pass: emit code
|
// final pass: emit code
|
||||||
if (!comp->had_error) {
|
if (comp->compile_error == MP_OBJ_NULL) {
|
||||||
compile_scope(comp, s, MP_PASS_EMIT);
|
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
|
// free the compiler
|
||||||
bool had_error = comp->had_error;
|
mp_obj_t compile_error = comp->compile_error;
|
||||||
m_del_obj(compiler_t, comp);
|
m_del_obj(compiler_t, comp);
|
||||||
|
|
||||||
if (had_error) {
|
if (compile_error != MP_OBJ_NULL) {
|
||||||
// TODO return a proper error message
|
return compile_error;
|
||||||
return mp_const_none;
|
|
||||||
} else {
|
} else {
|
||||||
#if MICROPY_EMIT_CPYTHON
|
#if MICROPY_EMIT_CPYTHON
|
||||||
// can't create code, so just return true
|
// can't create code, so just return true
|
||||||
|
|
|
@ -36,8 +36,9 @@ void do_str(const char *src) {
|
||||||
mp_lexer_free(lex);
|
mp_lexer_free(lex);
|
||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
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
|
// compile error
|
||||||
|
mp_obj_print_exception(module_fun);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,9 @@ inline void do_str(const char *src) {
|
||||||
mp_lexer_free(lex);
|
mp_lexer_free(lex);
|
||||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
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)) {
|
||||||
tt_abort_msg("Computer error");
|
mp_obj_print_exception(module_fun);
|
||||||
|
tt_abort_msg("Compile error");
|
||||||
}
|
}
|
||||||
|
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
|
|
|
@ -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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# test if eval raises SyntaxError
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(eval("[1, *a]"))
|
||||||
|
except SyntaxError:
|
||||||
|
print("SyntaxError")
|
|
@ -79,8 +79,8 @@ void do_file(const char *file) {
|
||||||
|
|
||||||
//printf("----------------\n");
|
//printf("----------------\n");
|
||||||
|
|
||||||
if (module_fun == mp_const_none) {
|
if (mp_obj_is_exception_instance(module_fun)) {
|
||||||
printf("compile error\n");
|
mp_obj_print_exception(module_fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue