Fix bug in parser error handling

This commit is contained in:
Max Brunsfeld 2014-02-25 18:32:17 -08:00
parent 4541332c2b
commit df223d566e
3 changed files with 24 additions and 14 deletions

View file

@ -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() \

View file

@ -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

View file

@ -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 "#<null-tree>";
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);