diff --git a/include/tree_sitter/parser.h b/include/tree_sitter/parser.h index e3df0c34..f90259ad 100644 --- a/include/tree_sitter/parser.h +++ b/include/tree_sitter/parser.h @@ -268,34 +268,45 @@ static ts_lr_parser * ts_lr_parser_make() { result->stack = ts_stack_make(); return result; } - -static size_t ts_lr_parser_breakdown_stack(ts_lr_parser *parser, ts_input_edit *edit) { - if (parser->stack.size == 0) return 0; - - ts_tree *node = ts_stack_top_node(&parser->stack); - size_t left_position = 0; - size_t right_position = node->offset + node->size; - size_t child_count; - ts_tree ** children = ts_tree_children(node, &child_count); - while (right_position > edit->position || children) { - parser->stack.size--; - ts_tree *child; - for (size_t i = 0; i < child_count; i++) { - child = children[i]; - right_position = left_position + child->offset + child->size; - ts_tree_retain(child); - state_id parse_state = ts_parse_actions[ts_stack_top_state(&parser->stack)][child->symbol].data.to_state; - ts_stack_push(&parser->stack, parse_state, child); - if (right_position >= edit->position) break; - left_position = right_position; - } - ts_tree_release(node); - node = child; - children = ts_tree_children(node, &child_count); - } +static size_t ts_lr_parser_breakdown_stack(ts_lr_parser *parser, ts_input_edit *edit) { + if (!edit) return 0; + + ts_tree *node; + size_t position; - return right_position; + for (;;) { + node = ts_stack_top_node(&parser->stack); + if (!node) break; + + position = 0; + for (size_t i = 0; i < parser->stack.size; i++) { + ts_tree *node = parser->stack.entries[i].node; + position += node->offset + node->size; + } + + size_t child_count = 0; + ts_tree **children = ts_tree_children(node, &child_count); + + if (position <= edit->position && !children) break; + + parser->stack.size--; + position -= (node->offset + node->size); + + for (size_t i = 0; i < child_count && position < edit->position; i++) { + ts_tree *child = children[i]; + + state_id state = ts_stack_top_state(&parser->stack); + state_id next_state = ts_parse_actions[state][child->symbol].data.to_state; + ts_stack_push(&parser->stack, next_state, child); + ts_tree_retain(child); + position += child->offset + child->size; + } + + ts_tree_release(node); + } + + return position; } static void ts_lr_parser_initialize(ts_lr_parser *parser, ts_input input, ts_input_edit *edit) { diff --git a/spec/runtime/parser_spec.cc b/spec/runtime/parser_spec.cc index 7eae8984..7643a302 100644 --- a/spec/runtime/parser_spec.cc +++ b/spec/runtime/parser_spec.cc @@ -38,7 +38,7 @@ describe("incremental parsing", [&]() { }))); }); - describe("modifying the input", [&]() { + describe("modifying the end of the input", [&]() { before_each([&]() { size_t position(string("{ \"key\": [1, 2]").length()); string inserted_text(", \"key2\": 4"); @@ -69,6 +69,39 @@ describe("incremental parsing", [&]() { AssertThat(reader->strings_read[1], Equals(", \"key2\": 4 }")); }); }); + + describe("modifying the beginning of the input", [&]() { + before_each([&]() { + size_t position(string("{ ").length()); + string inserted_text("\"key2\": 4, "); + + reader->content.insert(position, inserted_text); + ts_document_edit(doc, { + .position = position, + .bytes_removed = 0, + .bytes_inserted = inserted_text.length() + }); + }); + + it("2 updates the parse tree", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(value " + "(object " + "(string) " + "(value (number)) " + "(string) " + "(value (array " + "(value (number)) " + "(value (number))))))" + )); + }); + + it_skip("re-reads only the changed portion of the input", [&]() { + AssertThat(reader->strings_read.size(), Equals(2)); + AssertThat(reader->strings_read[1], Equals("\"key2\": 4, ")); + }); + }); + }); END_TEST diff --git a/src/compiler/generate_code/c_code.cc b/src/compiler/generate_code/c_code.cc index ffa33e8d..7b76dbff 100644 --- a/src/compiler/generate_code/c_code.cc +++ b/src/compiler/generate_code/c_code.cc @@ -189,7 +189,7 @@ namespace tree_sitter { body += _default("LEX_PANIC();"); return _switch("LEX_STATE()", body); } - + string symbol_count() { return "#define TS_SYMBOL_COUNT " + to_string(parse_table.symbols.size()); } diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 37f223f3..87629b1c 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -71,7 +71,7 @@ int ts_tree_equals(const ts_tree *node1, const ts_tree *node2) { } ts_tree ** ts_tree_children(const ts_tree *tree, size_t *count) { - if (tree->symbol == ts_builtin_sym_error) { + if (!tree || tree->symbol == ts_builtin_sym_error) { if (count) *count = 0; return NULL; } @@ -82,13 +82,13 @@ ts_tree ** ts_tree_children(const ts_tree *tree, size_t *count) { static size_t tree_write_to_string(const ts_tree *tree, const char **symbol_names, char *string, size_t limit, int is_beginning) { char *cursor = string; char **destination = (limit > 0) ? &cursor : &string; - + if (!tree) return snprintf(*destination, limit, "(NULL)"); if (!tree->is_hidden && !is_beginning) cursor += snprintf(*destination, limit, " "); - + if (tree->symbol == ts_builtin_sym_error) { cursor += snprintf(*destination, limit, "(ERROR)"); return cursor - string; @@ -104,7 +104,7 @@ static size_t tree_write_to_string(const ts_tree *tree, const char **symbol_name if (!tree->is_hidden) cursor += snprintf(*destination, limit, ")"); - + return cursor - string; }