diff --git a/include/tree_sitter/parser/lr_parser.h b/include/tree_sitter/parser/lr_parser.h index 12c2bc75..2c3cc852 100644 --- a/include/tree_sitter/parser/lr_parser.h +++ b/include/tree_sitter/parser/lr_parser.h @@ -191,6 +191,8 @@ ts_lr_parser_tree_root(ts_lr_parser *parser) { ts_tree *top_node = ts_stack_top_node(stack); if (stack->size <= 1) return top_node; + if (ts_tree_symbol(top_node) == ts_builtin_sym_error) + return top_node; size_t immediate_child_count; ts_tree **immedate_children = ts_tree_immediate_children(top_node, &immediate_child_count); diff --git a/spec/runtime/languages/arithmetic/errors.txt b/spec/runtime/languages/arithmetic/errors.txt index 37ec51fc..160141b4 100644 --- a/spec/runtime/languages/arithmetic/errors.txt +++ b/spec/runtime/languages/arithmetic/errors.txt @@ -3,7 +3,7 @@ recovers from errors at the top level ===================================================== x * * y --- -(ERROR) +(ERROR '*') ===================================================== recovers from errors inside parenthesized expressions @@ -12,4 +12,4 @@ x + (y * + z) * 5 --- (expression (sum (variable) - (product (group (ERROR)) (number)))) \ No newline at end of file + (product (group (ERROR '+')) (number)))) \ No newline at end of file diff --git a/spec/runtime/languages/javascript/errors.txt b/spec/runtime/languages/javascript/errors.txt index 6cb11efc..2535f78d 100644 --- a/spec/runtime/languages/javascript/errors.txt +++ b/spec/runtime/languages/javascript/errors.txt @@ -3,7 +3,7 @@ recovers from errors in function calls ========================================== stuff(|||); --- -(program (expression_statement (function_call (identifier) (ERROR)))) +(program (expression_statement (function_call (identifier) (ERROR '|')))) ========================================== recovers from errors in if statements @@ -16,8 +16,8 @@ moreStuff(); --- (program (expression_statement (function_call (identifier))) - (if_statement (ERROR) - (statement_block (expression_statement (ERROR)))) + (if_statement (ERROR '*') + (statement_block (expression_statement (ERROR '*')))) (expression_statement (function_call (identifier)))) ========================================== @@ -33,8 +33,8 @@ moreStuff(); (expression_statement (function_call (identifier))) (for_statement (var_declaration (assignment (identifier) (number))) - (expression_statement (ERROR)) - (ERROR) - (statement_block (expression_statement (ERROR)))) + (expression_statement (ERROR '*')) + (ERROR '*') + (statement_block (expression_statement (ERROR '*')))) (expression_statement (function_call (identifier)))) diff --git a/spec/runtime/languages/json/errors.txt b/spec/runtime/languages/json/errors.txt index 621b41fb..3e1beb27 100644 --- a/spec/runtime/languages/json/errors.txt +++ b/spec/runtime/languages/json/errors.txt @@ -3,14 +3,14 @@ recovers from top-level errors ========================================== [} --- -(ERROR) +(ERROR '}') ========================================== recovers from unexpected tokens ========================================== barf --- -(ERROR) +(ERROR 'b') ========================================== recovers from errors inside arrays @@ -19,7 +19,7 @@ recovers from errors inside arrays --- (value (array (number) - (ERROR) + (ERROR ) (number))) ========================================== @@ -27,7 +27,7 @@ recovers from errors inside objects ========================================== { "key1": 1, oops } --- -(value (object (string) (number) (ERROR))) +(value (object (string) (number) (ERROR 'o'))) ========================================== recovers from errors inside nested objects @@ -35,6 +35,6 @@ recovers from errors inside nested objects { "key1": { "key2": 1, 2 }, [, "key3": 3 } --- (value (object - (string) (object (string) (number) (ERROR)) - (ERROR) + (string) (object (string) (number) (ERROR '2')) + (ERROR '[') (string) (number))) diff --git a/src/runtime/tree.c b/src/runtime/tree.c index b784d792..146577df 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -124,14 +124,27 @@ ts_tree ** ts_tree_children(const ts_tree *tree, size_t *count) { return tree->data.children.contents; } +static size_t write_lookahead_to_string(char *string, size_t limit, char lookahead) { + switch (lookahead) { + case '\0': + return snprintf(string, limit, ""); + default: + return snprintf(string, limit, "'%c'", lookahead); + } +} + static size_t tree_write_to_string(const ts_tree *tree, const char **symbol_names, char *string, size_t limit) { char *cursor = string; char **destination = (limit > 0) ? &cursor : &string; if (!tree) return snprintf(*destination, limit, "(NULL)"); - if (tree->symbol == ts_builtin_sym_error) - return snprintf(*destination, limit, "(ERROR)"); + if (tree->symbol == ts_builtin_sym_error) { + cursor += snprintf(*destination, limit, "(ERROR "); + cursor += write_lookahead_to_string(*destination, limit, tree->data.error.lookahead_char); + cursor += snprintf(*destination, limit, ")"); + return cursor - string; + } cursor += snprintf(*destination, limit, "(%s", symbol_names[tree->symbol]); size_t count;