From df223d566e464c0dc234e816811d19c32be943b7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 25 Feb 2014 18:32:17 -0800 Subject: [PATCH] Fix bug in parser error handling --- include/tree_sitter/parser.h | 26 ++++++++++++-------------- spec/runtime/json_spec.cpp | 10 ++++++++++ src/runtime/tree.cpp | 2 ++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/include/tree_sitter/parser.h b/include/tree_sitter/parser.h index b871e993..8b3dba7b 100644 --- a/include/tree_sitter/parser.h +++ b/include/tree_sitter/parser.h @@ -45,7 +45,6 @@ typedef struct { ts_state lex_state; ts_stack_entry *stack; size_t stack_size; - ts_tree *result; } ts_parser; static void ts_lex(ts_parser *parser); @@ -58,7 +57,6 @@ static ts_parser ts_parser_make(const char *input) { .lex_state = 0, .stack = calloc(INITIAL_STACK_SIZE, sizeof(ts_stack_entry)), .stack_size = 0, - .result = NULL, }; return result; } @@ -123,7 +121,7 @@ static void ts_parser_reduce(ts_parser *parser, ts_symbol symbol, int immediate_ static void ts_parser_advance(ts_parser *parser, ts_state lex_state) { DEBUG_LEX("character: '%c' \n", ts_parser_lookahead_char(parser)); - if (ts_parser_lookahead_char(parser) != '\0') + if (ts_parser_lookahead_char(parser)) parser->position++; parser->lex_state = lex_state; } @@ -143,14 +141,11 @@ static void ts_parser_skip_whitespace(ts_parser *parser) { parser->position++; } -static void ts_parser_handle_error(ts_parser *parser, size_t count, const ts_symbol *expected_symbols) { - if (parser->error_mode) { - parser->lex_state = ts_lex_state_error; - ts_lex(parser); - } else { - parser->error_mode = 1; - parser->lookahead_node = ts_tree_make_error(ts_parser_lookahead_char(parser), count, expected_symbols); - } +static int ts_parser_handle_error(ts_parser *parser, size_t count, const ts_symbol *expected_symbols) { + parser->error_mode = 1; + ts_tree *error = ts_tree_make_error(ts_parser_lookahead_char(parser), count, expected_symbols); + parser->stack[0].node = error; + return 0; } #pragma mark - DSL @@ -220,9 +215,12 @@ goto next_state; \ #define PARSE_ERROR(count, inputs) \ { \ -static const ts_symbol expected_inputs[] = inputs; \ -ts_parser_handle_error(parser, count, expected_inputs); \ -goto next_state; \ + static const ts_symbol expected_inputs[] = inputs; \ + if (ts_parser_handle_error(parser, count, expected_inputs)) { \ + goto next_state; \ + } else { \ + goto done; \ + } \ } #define LEX_PANIC() \ diff --git a/spec/runtime/json_spec.cpp b/spec/runtime/json_spec.cpp index f19d590e..8296eab3 100644 --- a/spec/runtime/json_spec.cpp +++ b/spec/runtime/json_spec.cpp @@ -48,6 +48,16 @@ describe("json", []() { ts_document_set_text(doc, "[1, 2, 3]"); AssertThat(string(ts_document_string(doc)), Equals("(value (array (value (number)) (value (number)) (value (number))))")); }); + + describe("errors", [&]() { + it("reports errors in the top-level node", [&]() { + ts_document_set_text(doc, "["); + AssertThat(string(ts_document_string(doc)), Equals("(ERROR)")); + + ts_document_set_text(doc, "{ \"key1\": 1, "); + AssertThat(string(ts_document_string(doc)), Equals("(ERROR)")); + }); + }); }); END_TEST \ No newline at end of file diff --git a/src/runtime/tree.cpp b/src/runtime/tree.cpp index 05771569..f7e5e010 100644 --- a/src/runtime/tree.cpp +++ b/src/runtime/tree.cpp @@ -33,6 +33,7 @@ ts_tree * ts_tree_make_node(ts_symbol symbol, size_t child_count, ts_tree **chil ts_tree * ts_tree_make_error(char lookahead_char, size_t expected_input_count, const ts_symbol *expected_inputs) { ts_tree *result = new ts_tree(); + result->symbol = ts_symbol_error; result->data.error = { .lookahead_char = lookahead_char, .expected_input_count = expected_input_count, @@ -84,6 +85,7 @@ size_t ts_tree_child_count(const ts_tree *tree) { static string __tree_to_string(const ts_tree *tree, const char **symbol_names) { if (!tree) return "#"; + if (tree->symbol == ts_symbol_error) return "(ERROR)"; string result = string("(") + symbol_names[tree->symbol]; for (int i = 0; i < tree->data.children.count; i++) result += " " + __tree_to_string(tree->data.children.contents[i], symbol_names);