diff --git a/spec/runtime/document_spec.cc b/spec/runtime/document_spec.cc index 13041eb4..d9337dc0 100644 --- a/spec/runtime/document_spec.cc +++ b/spec/runtime/document_spec.cc @@ -6,82 +6,113 @@ extern "C" const TSLanguage * ts_language_json(); START_TEST -describe("incremental parsing", [&]() { - TSDocument *doc; +describe("Document", [&]() { + TSDocument *doc; + + before_each([&]() { + doc = ts_document_make(); + }); + + after_each([&]() { + ts_document_free(doc); + }); + + describe("when the language is not set", [&]() { + describe("setting the input", [&]() { + SpyReader *reader; + + before_each([&]() { + reader = new SpyReader("{ \"key\": [1, 2] }", 5); + ts_document_set_input(doc, reader->input); + }); + + after_each([&]() { + delete reader; + }); + + it("does not try to parse the document", [&]() { + AssertThat(ts_document_root_node(doc), Equals(nullptr)); + }); + + describe("setting the language", [&]() { + before_each([&]() { + ts_document_set_language(doc, ts_language_json()); + }); + + it("parses the document", [&]() { + TSNode *node = ts_document_root_node(doc); + AssertThat(string(ts_node_string(node)), Equals( + "(object (string) (array (number) (number)))")); + ts_node_release(node); + }); + }); + }); + }); + + describe("setting the language and input", [&]() { + SpyReader *reader; before_each([&]() { - doc = ts_document_make(); - ts_document_set_language(doc, ts_language_json()); + reader = new SpyReader("{ \"key\": [1, 2] }", 5); + ts_document_set_language(doc, ts_language_json()); + ts_document_set_input(doc, reader->input); }); after_each([&]() { - ts_document_free(doc); + delete reader; }); - describe("incremental parsing", [&]() { - SpyReader *reader; - - before_each([&]() { - reader = new SpyReader("{ \"key\": [1, 2] }", 5); - ts_document_set_input(doc, reader->input); - }); - - after_each([&]() { - delete reader; - }); - - it("parses the input", [&]() { - AssertThat(string(ts_document_string(doc)), Equals( - "(object (string) (array (number) (number)))")); - }); - - it("reads the entire input", [&]() { - AssertThat(reader->strings_read, Equals(vector({ - "{ \"key\": [1, 2] }" - }))); - }); - - describe("modifying the end of the input", [&]() { - before_each([&]() { - size_t position(string("{ \"key\": [1, 2]").length()); - string inserted_text(", \"key2\": 4"); - - reader->content.insert(position, inserted_text); - ts_document_edit(doc, { position, 0, inserted_text.length() }); - }); - - it("updates the parse tree", [&]() { - AssertThat(string(ts_document_string(doc)), Equals( - "(object (string) (array (number) (number)) (string) (number))")); - }); - - it("re-reads only the changed portion of the input", [&]() { - AssertThat(reader->strings_read.size(), Equals(2)); - 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, 0, inserted_text.length() }); - }); - - it("updates the parse tree", [&]() { - AssertThat(string(ts_document_string(doc)), Equals( - "(object (string) (number) (string) (array (number) (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, ")); - }); - }); + it("parses the input", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(object (string) (array (number) (number)))")); }); + it("reads the entire input", [&]() { + AssertThat(reader->strings_read, Equals(vector({ + "{ \"key\": [1, 2] }" + }))); + }); + + describe("modifying the end of the input", [&]() { + before_each([&]() { + size_t position(string("{ \"key\": [1, 2]").length()); + string inserted_text(", \"key2\": 4"); + + reader->content.insert(position, inserted_text); + ts_document_edit(doc, { position, 0, inserted_text.length() }); + }); + + it("updates the parse tree", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(object (string) (array (number) (number)) (string) (number))")); + }); + + it("re-reads only the changed portion of the input", [&]() { + AssertThat(reader->strings_read.size(), Equals(2)); + 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, 0, inserted_text.length() }); + }); + + it("updates the parse tree", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(object (string) (number) (string) (array (number) (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/runtime/document.c b/src/runtime/document.c index 3bf7b5b0..a734998f 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -31,6 +31,8 @@ void ts_document_set_language(TSDocument *document, const TSLanguage *language) { ts_parser_destroy(&document->parser); document->parser = ts_parser_make(language); + if (document->input.read_fn) + document->tree = ts_parser_parse(&document->parser, document->input, NULL); } const TSTree *ts_document_tree(const TSDocument *document) { @@ -44,7 +46,8 @@ const char *ts_document_string(const TSDocument *document) { void ts_document_set_input(TSDocument *document, TSInput input) { document->input = input; - document->tree = ts_parser_parse(&document->parser, document->input, NULL); + if (document->parser.language) + document->tree = ts_parser_parse(&document->parser, document->input, NULL); } void ts_document_edit(TSDocument *document, TSInputEdit edit) { @@ -96,8 +99,11 @@ void ts_document_set_input_string(TSDocument *document, const char *text) { } TSNode *ts_document_root_node(const TSDocument *document) { - return ts_node_make_root(document->tree, - document->parser.language->symbol_names); + if (document->tree) + return ts_node_make_root(document->tree, + document->parser.language->symbol_names); + else + return NULL; } TSNode *ts_document_get_node(const TSDocument *document, size_t pos) {