diff options
author | Damien George <damien.p.george@gmail.com> | 2015-02-07 18:33:58 +0000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2015-02-07 18:33:58 +0000 |
commit | 0bfc7638baa4c5a4a2351364ab770a188dcab302 (patch) | |
tree | 0127fcea13a875d37dd9cfa07dc6921bf387c578 /py/parse.c | |
parent | e1e359ff59d6bbf09441cc1f3965be63f1046182 (diff) |
py: Protect mp_parse and mp_compile with nlr push/pop block.
To enable parsing constants more efficiently, mp_parse should be allowed
to raise an exception, and mp_compile can already raise a MemoryError.
So these functions need to be protected by an nlr push/pop block.
This patch adds that feature in all places. This allows to simplify how
mp_parse and mp_compile are called: they now raise an exception if they
have an error and so explicit checking is not needed anymore.
Diffstat (limited to 'py/parse.c')
-rw-r--r-- | py/parse.c | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/py/parse.c b/py/parse.c index 881a11e73..569cf257a 100644 --- a/py/parse.c +++ b/py/parse.c @@ -30,6 +30,7 @@ #include <assert.h> #include <string.h> +#include "py/nlr.h" #include "py/lexer.h" #include "py/parse.h" #include "py/parsenum.h" @@ -382,7 +383,7 @@ STATIC void push_result_rule(parser_t *parser, mp_uint_t src_line, const rule_t push_result_node(parser, (mp_parse_node_t)pn); } -mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_parse_error_kind_t *parse_error_kind_out) { +mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // initialise parser and allocate memory for its stacks @@ -717,15 +718,15 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p } } - mp_parse_node_t result; + mp_obj_t exc = MP_OBJ_NULL; + mp_parse_node_t result = MP_PARSE_NODE_NULL; // check if we had a memory error if (parser.had_memory_error) { memory_error: - *parse_error_kind_out = MP_PARSE_ERROR_MEMORY; - result = MP_PARSE_NODE_NULL; + exc = mp_obj_new_exception_msg(&mp_type_MemoryError, + "parser could not allocate enough memory"); goto finished; - } // check we are at the end of the token stream @@ -747,17 +748,30 @@ finished: // free the memory that we don't need anymore m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc); m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc); - - // return the result - return result; + // we also free the lexer on behalf of the caller (see below) + + if (exc != MP_OBJ_NULL) { + // had an error so raise the exception + // add traceback to give info about file name and location + // we don't have a 'block' name, so just pass the NULL qstr to indicate this + mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); + mp_lexer_free(lex); + nlr_raise(exc); + } else { + mp_lexer_free(lex); + return result; + } syntax_error: if (lex->tok_kind == MP_TOKEN_INDENT) { - *parse_error_kind_out = MP_PARSE_ERROR_UNEXPECTED_INDENT; + exc = mp_obj_new_exception_msg(&mp_type_IndentationError, + "unexpected indent"); } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) { - *parse_error_kind_out = MP_PARSE_ERROR_UNMATCHED_UNINDENT; + exc = mp_obj_new_exception_msg(&mp_type_IndentationError, + "unindent does not match any outer indentation level"); } else { - *parse_error_kind_out = MP_PARSE_ERROR_INVALID_SYNTAX; + exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, + "invalid syntax"); #ifdef USE_RULE_NAME // debugging: print the rule name that failed and the token printf("rule: %s\n", rule->rule_name); @@ -766,6 +780,5 @@ syntax_error: #endif #endif } - result = MP_PARSE_NODE_NULL; goto finished; } |