py: Make inline assembler raise proper SyntaxError exception on error.

Also gives line number of location of error.  Very useful!
This commit is contained in:
Damien George 2015-02-13 01:00:51 +00:00
parent 1bf5a022fe
commit 8dfbd2d589
3 changed files with 41 additions and 34 deletions

View File

@ -92,10 +92,10 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); 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 // 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)) {
mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL); mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, comp->scope_cur->simple_name);
} else { } else {
// we don't have a line number, so just pass 0 // we don't have a line number, so just pass 0
mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL); mp_obj_exception_add_traceback(exc, comp->source_file, 0, comp->scope_cur->simple_name);
} }
comp->compile_error = exc; comp->compile_error = exc;
} }
@ -3426,7 +3426,7 @@ 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) {
EMIT_INLINE_ASM_ARG(start_pass, comp->pass, comp->scope_cur); EMIT_INLINE_ASM_ARG(start_pass, comp->pass, comp->scope_cur, &comp->compile_error);
} }
// get the function definition parse node // get the function definition parse node
@ -3441,6 +3441,9 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
mp_parse_node_t *pn_params; mp_parse_node_t *pn_params;
int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params); int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params);
scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params); scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
if (comp->compile_error != MP_OBJ_NULL) {
goto inline_asm_error;
}
} }
assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type
@ -3519,14 +3522,21 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg); EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg);
} }
} }
if (comp->compile_error != MP_OBJ_NULL) {
pns = pns2; // this is the parse node that had the error
goto inline_asm_error;
}
} }
if (comp->pass > MP_PASS_SCOPE) { if (comp->pass > MP_PASS_SCOPE) {
bool success = EMIT_INLINE_ASM(end_pass); EMIT_INLINE_ASM(end_pass);
if (!success) { }
// TODO get proper exception from inline assembler
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler error"); if (comp->compile_error != MP_OBJ_NULL) {
} // inline assembler had an error; add traceback to its exception
inline_asm_error:
mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, (mp_uint_t)pns->source_line, comp->scope_cur->simple_name);
} }
} }
#endif #endif

View File

@ -192,8 +192,8 @@ void emit_native_arm_free(emit_t *emit);
typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_t emit_inline_asm_t;
typedef struct _emit_inline_asm_method_table_t { typedef struct _emit_inline_asm_method_table_t {
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope); void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope, mp_obj_t *error_slot);
bool (*end_pass)(emit_inline_asm_t *emit); void (*end_pass)(emit_inline_asm_t *emit);
mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params);
void (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); void (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id);
void (*align)(emit_inline_asm_t *emit, mp_uint_t align); void (*align)(emit_inline_asm_t *emit, mp_uint_t align);

View File

@ -44,20 +44,19 @@ typedef enum {
struct _emit_inline_asm_t { struct _emit_inline_asm_t {
uint16_t pass; uint16_t pass;
uint16_t success;
scope_t *scope; scope_t *scope;
mp_obj_t *error_slot;
mp_uint_t max_num_labels; mp_uint_t max_num_labels;
qstr *label_lookup; qstr *label_lookup;
asm_thumb_t *as; asm_thumb_t *as;
}; };
STATIC void emit_inline_thumb_error(emit_inline_asm_t *emit, const char *fmt, ...) { STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const char *msg) {
printf("SyntaxError: "); *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
emit->success = false; }
va_list ap;
va_start(ap, fmt); STATIC void emit_inline_thumb_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) {
vprintf(fmt, ap); *emit->error_slot = exc;
va_end(ap);
} }
emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) { emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) {
@ -75,15 +74,15 @@ void emit_inline_thumb_free(emit_inline_asm_t *emit) {
m_del_obj(emit_inline_asm_t, emit); m_del_obj(emit_inline_asm_t, emit);
} }
STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope) { STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope, mp_obj_t *error_slot) {
emit->pass = pass; emit->pass = pass;
emit->success = true;
emit->scope = scope; emit->scope = scope;
emit->error_slot = error_slot;
asm_thumb_start_pass(emit->as, pass == MP_PASS_EMIT ? ASM_THUMB_PASS_EMIT : ASM_THUMB_PASS_COMPUTE); asm_thumb_start_pass(emit->as, pass == MP_PASS_EMIT ? ASM_THUMB_PASS_EMIT : ASM_THUMB_PASS_COMPUTE);
asm_thumb_entry(emit->as, 0); asm_thumb_entry(emit->as, 0);
} }
STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
asm_thumb_exit(emit->as); asm_thumb_exit(emit->as);
asm_thumb_end_pass(emit->as); asm_thumb_end_pass(emit->as);
@ -91,23 +90,21 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
void *f = asm_thumb_get_code(emit->as); void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0); mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
} }
return emit->success;
} }
STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) { STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {
if (n_params > 4) { if (n_params > 4) {
emit_inline_thumb_error(emit, "can only have up to 4 parameters to inline thumb assembly\n"); emit_inline_thumb_error_msg(emit, "can only have up to 4 parameters to Thumb assembly");
return 0; return 0;
} }
for (mp_uint_t i = 0; i < n_params; i++) { for (mp_uint_t i = 0; i < n_params; i++) {
if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
emit_inline_thumb_error(emit, "parameter to inline assembler must be an identifier\n"); emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
return 0; return 0;
} }
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
emit_inline_thumb_error(emit, "parameter %d to inline assembler must be r%d\n", i + 1, i); emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
return 0; return 0;
} }
} }
@ -161,7 +158,7 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
const reg_name_t *r = &reg_name_table[i]; const reg_name_t *r = &reg_name_table[i];
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) { if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
if (r->reg > max_reg) { if (r->reg > max_reg) {
emit_inline_thumb_error(emit, "'%s' expects at most r%d\n", op, max_reg); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects at most r%d", op, max_reg));
return 0; return 0;
} else { } else {
return r->reg; return r->reg;
@ -169,18 +166,18 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
} }
} }
} }
emit_inline_thumb_error(emit, "'%s' expects a register\n", op); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a register", op));
return 0; return 0;
} }
STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int fit_mask) { STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int fit_mask) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn)) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn)) {
emit_inline_thumb_error(emit, "'%s' expects an integer\n", op); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op));
return 0; return 0;
} }
int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn); int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
if ((i & (~fit_mask)) != 0) { if ((i & (~fit_mask)) != 0) {
emit_inline_thumb_error(emit, "'%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer 0x%x does not fit in mask 0x%x", op, i, fit_mask));
return 0; return 0;
} }
return i; return i;
@ -204,13 +201,13 @@ STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_
return true; return true;
bad_arg: bad_arg:
emit_inline_thumb_error(emit, "'%s' expects an address of the form [a, b]\n", op); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an address of the form [a, b]", op));
return false; return false;
} }
STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
if (!MP_PARSE_NODE_IS_ID(pn)) { if (!MP_PARSE_NODE_IS_ID(pn)) {
emit_inline_thumb_error(emit, "'%s' expects a label\n", op); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op));
return 0; return 0;
} }
qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn); qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
@ -221,7 +218,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
} }
// only need to have the labels on the last pass // only need to have the labels on the last pass
if (emit->pass == MP_PASS_EMIT) { if (emit->pass == MP_PASS_EMIT) {
emit_inline_thumb_error(emit, "label '%s' not defined\n", qstr_str(label_qstr)); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%s' not defined", qstr_str(label_qstr)));
} }
return 0; return 0;
} }
@ -450,7 +447,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
return; return;
unknown_op: unknown_op:
emit_inline_thumb_error(emit, "unsupported Thumb instruction '%s' with %d arguments\n", op_str, n_args); emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Thumb instruction '%s' with %d arguments", op_str, n_args));
} }
const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {