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

Add source file name and line number to error messages.

Byte code has a map from byte-code offset to source-code line number,
used to give better error messages.
parent aefe7988
mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state);
bool mp_execute_byte_code_2(const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out);
bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out);
......@@ -28,6 +28,7 @@ static mp_obj_t mp_builtin_eval(mp_obj_t o_in) {
qstr parse_exc_id;
const char *parse_exc_msg;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_EVAL_INPUT, &parse_exc_id, &parse_exc_msg);
qstr source_name = mp_lexer_source_name(lex);
mp_lexer_free(lex);
if (pn == MP_PARSE_NODE_NULL) {
......@@ -36,7 +37,7 @@ static mp_obj_t mp_builtin_eval(mp_obj_t o_in) {
}
// compile the string
mp_obj_t module_fun = mp_compile(pn, false);
mp_obj_t module_fun = mp_compile(pn, source_name, false);
if (module_fun == mp_const_none) {
// TODO handle compile error correctly
......
......@@ -51,6 +51,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
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);
qstr source_name = mp_lexer_source_name(lex);
mp_lexer_free(lex);
if (pn == MP_PARSE_NODE_NULL) {
......@@ -61,7 +62,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
}
// compile the imported script
mp_obj_t module_fun = mp_compile(pn, false);
mp_obj_t module_fun = mp_compile(pn, source_name, false);
if (module_fun == mp_const_none) {
// TODO handle compile error correctly
......
......@@ -2505,6 +2505,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
}
} else {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
EMIT(set_line_number, pns->source_line);
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
......@@ -3024,7 +3025,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
}
}
mp_obj_t mp_compile(mp_parse_node_t pn, bool is_repl) {
mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
compiler_t *comp = m_new(compiler_t, 1);
comp->is_repl = is_repl;
......@@ -3131,7 +3132,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, bool is_repl) {
default:
if (emit_bc == NULL) {
emit_bc = emit_bc_new(max_num_labels);
emit_bc = emit_bc_new(source_file, max_num_labels);
}
comp->emit = emit_bc;
comp->emit_method_table = &emit_bc_method_table;
......
mp_obj_t mp_compile(mp_parse_node_t pn, bool is_repl);
mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl);
......@@ -23,6 +23,7 @@ typedef struct _emit_method_table_t {
bool (*last_emit_was_return_value)(emit_t *emit);
int (*get_stack_size)(emit_t *emit);
void (*set_stack_size)(emit_t *emit, int size);
void (*set_line_number)(emit_t *emit, int line);
void (*load_id)(emit_t *emit, qstr qstr);
void (*store_id)(emit_t *emit, qstr qstr);
......@@ -119,7 +120,7 @@ extern const emit_method_table_t emit_native_thumb_method_table;
emit_t *emit_pass1_new(qstr qstr___class__);
void emit_pass1_free(emit_t *emit);
emit_t *emit_cpython_new(uint max_num_labels);
emit_t *emit_bc_new(uint max_num_labels);
emit_t *emit_bc_new(qstr source_file, uint max_num_labels);
emit_t *emit_native_x64_new(uint max_num_labels);
emit_t *emit_native_thumb_new(uint max_num_labels);
......
This diff is collapsed.
......@@ -68,6 +68,9 @@ static void emit_cpy_set_stack_size(emit_t *emit, int size) {
emit->stack_size = size;
}
static void emit_cpy_set_source_line(emit_t *emit, int source_line) {
}
static void emit_cpy_load_id(emit_t *emit, qstr qstr) {
emit_common_load_id(emit, &emit_cpython_method_table, emit->scope, qstr);
}
......@@ -798,6 +801,7 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_last_emit_was_return_value,
emit_cpy_get_stack_size,
emit_cpy_set_stack_size,
emit_cpy_set_source_line,
emit_cpy_load_id,
emit_cpy_store_id,
......
......@@ -281,6 +281,9 @@ static void emit_native_set_stack_size(emit_t *emit, int size) {
emit->stack_size = size;
}
static void emit_native_set_source_line(emit_t *emit, int source_line) {
}
static void adjust_stack(emit_t *emit, int stack_size_delta) {
emit->stack_size += stack_size_delta;
assert(emit->stack_size >= 0);
......@@ -1228,6 +1231,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_last_emit_was_return_value,
emit_native_get_stack_size,
emit_native_set_stack_size,
emit_native_set_source_line,
emit_native_load_id,
emit_native_store_id,
......
......@@ -103,6 +103,7 @@ const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
emit_pass1_load_id,
emit_pass1_store_id,
......
......@@ -3,6 +3,7 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "misc.h"
......@@ -14,7 +15,7 @@
// don't know if that's intentional or not, but we don't allow it
struct _mp_lexer_t {
const char *name; // name of source
qstr source_name; // name of source
void *stream_data; // data for stream
mp_lexer_stream_next_char_t stream_next_char; // stream callback to get next char
mp_lexer_stream_close_t stream_close; // stream callback to free
......@@ -49,7 +50,7 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
}
void mp_token_show(const mp_token_t *tok) {
printf("(%s:%d:%d) kind:%d str:%p len:%d", tok->src_name, tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
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) {
const char *i = tok->str;
const char *j = i + tok->len;
......@@ -292,7 +293,6 @@ static void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
next_char(lex);
if (!is_physical_newline(lex)) {
// SyntaxError: unexpected character after line continuation character
tok->src_name = lex->name;
tok->src_line = lex->line;
tok->src_column = lex->column;
tok->kind = MP_TOKEN_BAD_LINE_CONTINUATION;
......@@ -309,7 +309,6 @@ static void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
}
// set token source information
tok->src_name = lex->name;
tok->src_line = lex->line;
tok->src_column = lex->column;
......@@ -594,7 +593,7 @@ static void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
mp_lexer_t *mp_lexer_new(const char *src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close) {
mp_lexer_t *lex = m_new(mp_lexer_t, 1);
lex->name = src_name; // TODO do we need to strdup this?
lex->source_name = qstr_from_strn_copy(src_name, strlen(src_name));
lex->stream_data = stream_data;
lex->stream_next_char = stream_next_char;
lex->stream_close = stream_close;
......@@ -642,6 +641,10 @@ void mp_lexer_free(mp_lexer_t *lex) {
}
}
qstr mp_lexer_source_name(mp_lexer_t *lex) {
return lex->source_name;
}
void mp_lexer_to_next(mp_lexer_t *lex) {
mp_lexer_next_token_into(lex, &lex->tok_cur, false);
}
......@@ -677,11 +680,11 @@ bool mp_lexer_opt_str(mp_lexer_t *lex, const char *str) {
*/
bool mp_lexer_show_error_pythonic_prefix(mp_lexer_t *lex) {
printf(" File \"%s\", line %d column %d\n", lex->tok_cur.src_name, lex->tok_cur.src_line, lex->tok_cur.src_column);
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", lex->tok_cur.src_name, lex->tok_cur.src_line, lex->tok_cur.src_column, 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;
}
......@@ -105,7 +105,6 @@ typedef enum _mp_token_kind_t {
} mp_token_kind_t;
typedef struct _mp_token_t {
const char *src_name; // name of source
uint src_line; // source line
uint src_column; // source column
......@@ -129,6 +128,7 @@ mp_lexer_t *mp_lexer_new(const char *src_name, void *stream_data, mp_lexer_strea
mp_lexer_t *mp_lexer_new_from_str_len(const char *src_name, const char *str, uint len, uint free_len);
void mp_lexer_free(mp_lexer_t *lex);
qstr mp_lexer_source_name(mp_lexer_t *lex);
void mp_lexer_to_next(mp_lexer_t *lex);
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);
......
......@@ -273,6 +273,8 @@ 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);
void mp_obj_exception_set_source_info(mp_obj_t self_in, qstr file, machine_uint_t line);
void mp_obj_exception_get_source_info(mp_obj_t self_in, qstr *file, machine_uint_t *line);
// str
extern const mp_obj_type_t str_type;
......
......@@ -17,6 +17,8 @@
// have args tuple (or otherwise have it as NULL).
typedef struct mp_obj_exception_t {
mp_obj_base_t base;
qstr source_file;
machine_uint_t source_line;
qstr id;
qstr msg;
mp_obj_tuple_t args;
......@@ -87,6 +89,8 @@ mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
// make exception object
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
o->base.type = &exception_type;
o->source_file = 0;
o->source_line = 0;
o->id = id;
o->args.len = 0;
if (fmt == NULL) {
......@@ -109,3 +113,23 @@ qstr mp_obj_exception_get_type(mp_obj_t self_in) {
mp_obj_exception_t *self = self_in;
return self->id;
}
void mp_obj_exception_set_source_info(mp_obj_t self_in, qstr file, machine_uint_t line) {
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
mp_obj_exception_t *self = self_in;
// TODO make a list of file/line pairs for the traceback
// for now, just keep the first one
if (file != 0 && self->source_file == 0) {
self->source_file = file;
}
if (line != 0 && self->source_line == 0) {
self->source_line = line;
}
}
void mp_obj_exception_get_source_info(mp_obj_t self_in, qstr *file, machine_uint_t *line) {
assert(MP_OBJ_IS_TYPE(self_in, &exception_type));
mp_obj_exception_t *self = self_in;
*file = self->source_file;
*line = self->source_line;
}
......@@ -58,6 +58,7 @@ mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) {
typedef struct _mp_obj_gen_instance_t {
mp_obj_base_t base;
const byte *code_info;
const byte *ip;
mp_obj_t *sp;
uint n_state;
......@@ -74,7 +75,7 @@ mp_obj_t gen_instance_getiter(mp_obj_t self_in) {
mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
mp_obj_gen_instance_t *self = self_in;
bool yield = mp_execute_byte_code_2(&self->ip, &self->state[self->n_state - 1], &self->sp);
bool yield = mp_execute_byte_code_2(self->code_info, &self->ip, &self->state[self->n_state - 1], &self->sp);
if (yield) {
return *self->sp;
} else {
......@@ -98,6 +99,7 @@ const mp_obj_type_t gen_instance_type = {
mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args) {
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, mp_obj_t, n_state);
o->base.type = &gen_instance_type;
o->code_info = bytecode;
o->ip = bytecode;
o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state
o->n_state = n_state;
......@@ -111,6 +113,10 @@ mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args,
// prelude for making cells (closed over variables)
// for now we just make sure there are no cells variables
// need to work out how to implement closed over variables in generators
// get code info size
machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
o->ip += code_info_size;
assert(o->ip[0] == 0);
o->ip += 1;
......
......@@ -80,7 +80,8 @@ static const rule_t *rules[] = {
};
typedef struct _rule_stack_t {
byte rule_id;
unsigned int src_line : 24;
unsigned int rule_id : 8;
int32_t arg_i; // what should be the size and signedness?
} rule_stack_t;
......@@ -92,45 +93,54 @@ typedef struct _parser_t {
uint result_stack_alloc;
uint result_stack_top;
mp_parse_node_t *result_stack;
mp_lexer_t *lexer;
} parser_t;
static void push_rule(parser_t *parser, const rule_t *rule, int arg_i) {
static void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) {
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
parser->rule_stack = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2);
parser->rule_stack_alloc *= 2;
}
parser->rule_stack[parser->rule_stack_top].rule_id = rule->rule_id;
parser->rule_stack[parser->rule_stack_top].arg_i = arg_i;
parser->rule_stack_top += 1;
rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
rs->src_line = src_line;
rs->rule_id = rule->rule_id;
rs->arg_i = arg_i;
}
static void push_rule_from_arg(parser_t *parser, uint arg) {
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
uint rule_id = arg & RULE_ARG_ARG_MASK;
assert(rule_id < RULE_maximum_number_of);
push_rule(parser, rules[rule_id], 0);
push_rule(parser, mp_lexer_cur(parser->lexer)->src_line, rules[rule_id], 0);
}
static void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i) {
static void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) {
parser->rule_stack_top -= 1;
*rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
*arg_i = parser->rule_stack[parser->rule_stack_top].arg_i;
*src_line = parser->rule_stack[parser->rule_stack_top].src_line;
}
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
return (mp_parse_node_t)(kind | (arg << 4));
}
int num_parse_nodes_allocated = 0;
mp_parse_node_struct_t *parse_node_new_struct(int rule_id, int num_args) {
//int num_parse_nodes_allocated = 0;
mp_parse_node_struct_t *parse_node_new_struct(int src_line, int rule_id, int num_args) {
mp_parse_node_struct_t *pn = m_new_obj_var(mp_parse_node_struct_t, mp_parse_node_t, num_args);
pn->source = 0; // TODO
pn->source_line = src_line;
pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);
num_parse_nodes_allocated += 1;
//num_parse_nodes_allocated += 1;
return pn;
}
void mp_parse_node_show(mp_parse_node_t pn, int indent) {
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line);
} else {
printf(" ");
}
for (int i = 0; i < indent; i++) {
printf(" ");
}
......@@ -258,8 +268,8 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
push_result_node(parser, pn);
}
static void push_result_rule(parser_t *parser, const rule_t *rule, int num_args) {
mp_parse_node_struct_t *pn = parse_node_new_struct(rule->rule_id, num_args);
static void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) {
mp_parse_node_struct_t *pn = parse_node_new_struct(src_line, rule->rule_id, num_args);
for (int i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
......@@ -280,6 +290,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
parser->result_stack_top = 0;
parser->result_stack = m_new(mp_parse_node_t, parser->result_stack_alloc);
parser->lexer = lex;
// work out the top-level rule to use, and push it on the stack
int top_level_rule;
switch (input_kind) {
......@@ -287,13 +299,14 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
default: top_level_rule = RULE_file_input;
}
push_rule(parser, rules[top_level_rule], 0);
push_rule(parser, mp_lexer_cur(lex)->src_line, rules[top_level_rule], 0);
// parse!
uint n, i;
uint n, i; // state for the current rule
uint rule_src_line; // source line for the first token matched by the current rule
bool backtrack = false;
const rule_t *rule;
const rule_t *rule = NULL;
mp_token_kind_t tok_kind;
bool emit_rule;
bool had_trailing_sep;
......@@ -304,7 +317,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
break;
}
pop_rule(parser, &rule, &i);
pop_rule(parser, &rule, &i, &rule_src_line);
n = rule->act & RULE_ACT_ARG_MASK;
/*
......@@ -333,8 +346,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
}
break;
case RULE_ARG_RULE:
push_rule(parser, rule, i + 1);
push_rule_from_arg(parser, rule->arg[i]);
push_rule(parser, rule_src_line, rule, i + 1); // save this or-rule
push_rule_from_arg(parser, rule->arg[i]); // push child of or-rule
goto next_rule;
default:
assert(0);
......@@ -398,14 +411,9 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
}
break;
case RULE_ARG_RULE:
//if (i + 1 < n) {
push_rule(parser, rule, i + 1);
//}
push_rule_from_arg(parser, rule->arg[i]);
goto next_rule;
case RULE_ARG_OPT_RULE:
push_rule(parser, rule, i + 1);
push_rule_from_arg(parser, rule->arg[i]);
push_rule(parser, rule_src_line, rule, i + 1); // save this and-rule
push_rule_from_arg(parser, rule->arg[i]); // push child of and-rule
goto next_rule;
default:
assert(0);
......@@ -462,9 +470,9 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
}
//printf("done and %s n=%d i=%d notnil=%d\n", rule->rule_name, n, i, num_not_nil);
if (emit_rule) {
push_result_rule(parser, rule, i);
push_result_rule(parser, rule_src_line, rule, i);
} else if (num_not_nil == 0) {
push_result_rule(parser, rule, i); // needed for, eg, atom_paren, testlist_comp_3b
push_result_rule(parser, rule_src_line, rule, i); // needed for, eg, atom_paren, testlist_comp_3b
//result_stack_show(parser);
//assert(0);
} else if (num_not_nil == 1) {
......@@ -478,7 +486,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
}
push_result_node(parser, pn);
} else {
push_result_rule(parser, rule, i);
push_result_rule(parser, rule_src_line, rule, i);
}
break;
......@@ -538,8 +546,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
}
break;
case RULE_ARG_RULE:
push_rule(parser, rule, i + 1);
push_rule_from_arg(parser, arg);
push_rule(parser, rule_src_line, rule, i + 1); // save this list-rule
push_rule_from_arg(parser, arg); // push child of list-rule
goto next_rule;
default:
assert(0);
......@@ -559,13 +567,13 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr
// list matched single item
if (had_trailing_sep) {
// if there was a trailing separator, make a list of a single item
push_result_rule(parser, rule, i);
push_result_rule(parser, rule_src_line, rule, i);
} else {
// just leave single item on stack (ie don't wrap in a list)
}
} else {
//printf("done list %s %d %d\n", rule->rule_name, n, i);
push_result_rule(parser, rule, i);
push_result_rule(parser, rule_src_line, rule, i);
}
break;
......
......@@ -28,7 +28,7 @@ struct _mp_lexer_t;
typedef machine_uint_t mp_parse_node_t; // must be pointer size
typedef struct _mp_parse_node_struct_t {
uint32_t source; // file identifier, and line number
uint32_t source_line; // line number in source file
uint32_t kind_num_nodes; // parse node kind, and number of nodes
mp_parse_node_t nodes[]; // nodes
} mp_parse_node_struct_t;
......
......@@ -18,6 +18,10 @@
void mp_show_byte_code(const byte *ip, int len) {
const byte *ip_start = ip;
// get code info size
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
ip += code_info_size;
// decode prelude
{
uint n_local = *ip++;
......
......@@ -38,8 +38,13 @@ mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_arg
assert(i < 8);
state[n_state - 1 - i] = args[i];
}
const byte *ip = code;
// get code info size
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
ip += code_info_size;
// execute prelude to make any cells (closed over variables)
{
for (uint n_local = *ip++; n_local > 0; n_local--) {
......@@ -53,7 +58,7 @@ mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_arg
}
// execute the byte code
if (mp_execute_byte_code_2(&ip, &state[n_state - 1], &sp)) {
if (mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp)) {
// it shouldn't yield
assert(0);
}
......@@ -65,7 +70,7 @@ mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_arg
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
// sp points to bottom of stack which grows up
bool mp_execute_byte_code_2(const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out) {
bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out) {
// careful: be sure to declare volatile any variables read in the exception handler (written is ok, I think)
const byte *ip = *ip_in_out;
......@@ -79,12 +84,14 @@ bool mp_execute_byte_code_2(const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **
volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions
machine_uint_t exc_stack[8]; // on the exception stack we store (ip, sp | X) for each block, X = previous value of currently_in_except_block
machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack
const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
// outer exception handling loop
for (;;) {
if (nlr_push(&nlr) == 0) {
// loop to execute byte code
for (;;) {
save_ip = ip;
int op = *ip++;
switch (op) {
case MP_BC_LOAD_CONST_FALSE:
......@@ -518,6 +525,23 @@ bool mp_execute_byte_code_2(const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **
} else {
// exception occurred
// set file and line number that the exception occurred at
if (MP_OBJ_IS_TYPE(nlr.ret_val, &exception_type)) {
machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
qstr = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
machine_uint_t source_line = 1;
machine_uint_t bc = save_ip - code_info - code_info_size;
//printf("find %lu %d %d\n", bc, code_info[8], code_info[9]);
for (const byte* ci = code_info + 8; bc > ci[0]; ci += 2) {
bc -= ci[0];
source_line += ci[1];
if (ci[0] == 0 && ci[1] == 0) {
break;
}
}
mp_obj_exception_set_source_info(nlr.ret_val, qstr, source_line);
}
while (currently_in_except_block) {
// nested exception
......
......@@ -421,6 +421,7 @@ void do_repl(void) {
qstr parse_exc_id;
const char *parse_exc_msg;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_exc_id, &parse_exc_msg);
qstr source_name = mp_lexer_source_name(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error
......@@ -430,7 +431,7 @@ void do_repl(void) {
} else {
// parse okay
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, true);
mp_obj_t module_fun = mp_compile(pn, source_name, true);
if (module_fun != mp_const_none) {
nlr_buf_t nlr;
uint32_t start = sys_tick_counter;
......@@ -465,6 +466,7 @@ bool do_file(const char *filename) {
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);
qstr source_name = mp_lexer_source_name(lex);