From baec9f2c9aa7415432e2474bfcc78c8d50afd4f7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 2 Jun 2014 13:32:36 -0700 Subject: [PATCH] Move computation of tree size/offset into tree constructor --- include/tree_sitter/runtime.h | 2 +- spec/runtime/tree_spec.cc | 75 ++++++++++++++++++++++++++--------- src/runtime/stack.c | 10 +---- src/runtime/tree.c | 15 +++++-- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index d460f868..7c768d37 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -14,7 +14,7 @@ typedef unsigned short ts_symbol; typedef struct ts_tree ts_tree; ts_tree * ts_tree_make_leaf(ts_symbol symbol, size_t size, size_t offset); -ts_tree * ts_tree_make_node(ts_symbol symbol, size_t child_count, size_t immediate_child_count, ts_tree **children, size_t size, size_t offset); +ts_tree * ts_tree_make_node(ts_symbol symbol, size_t child_count, size_t immediate_child_count, ts_tree **children); ts_tree * ts_tree_make_error(char lookahead_char, size_t expected_input_count, const ts_symbol *expected_inputs, size_t size, size_t offset); void ts_tree_retain(ts_tree *tree); void ts_tree_release(ts_tree *tree); diff --git a/spec/runtime/tree_spec.cc b/spec/runtime/tree_spec.cc index 551069e2..11337be8 100644 --- a/spec/runtime/tree_spec.cc +++ b/spec/runtime/tree_spec.cc @@ -9,54 +9,91 @@ static ts_tree ** tree_array(vector trees) { START_TEST -enum { cat = 2, dog = 3, pig = 4 }; -static const char *names[] = { "error", "end", "cat", "dog", "pig" }; +enum { + cat = 2, + dog = 3, + pig = 4, +}; + +static const char *names[] = { + [ts_builtin_sym_error] = "error", + [ts_builtin_sym_end] = "end", + [cat] = "cat", + [dog] = "dog", + [pig] = "pig", +}; describe("trees", []() { - ts_tree *tree1, *parent1; + ts_tree *tree1, *tree2, *parent1; before_each([&]() { - tree1 = ts_tree_make_leaf(cat, 0, 0); - parent1 = ts_tree_make_node(dog, 1, 1, tree_array({ tree1, tree1 }), 0, 0); + tree1 = ts_tree_make_leaf(cat, 5, 2); + tree2 = ts_tree_make_leaf(cat, 3, 1); + parent1 = ts_tree_make_node(dog, 2, 2, tree_array({ + tree1, tree2, // children + tree1, tree2, // immediate_children + })); }); after_each([&]() { ts_tree_release(tree1); + ts_tree_release(tree2); ts_tree_release(parent1); }); + + describe("making a parent node", [&]() { + it("computes its offset and size based on its child nodes", [&]() { + AssertThat(ts_tree_size(parent1), Equals(9)); + }); + + it("computes its offset based on its first child", [&]() { + AssertThat(ts_tree_offset(parent1), Equals(2)); + }); + }); describe("equality", [&]() { it("returns true for identical trees", [&]() { - ts_tree *tree2 = ts_tree_make_leaf(cat, 0, 0); - AssertThat(ts_tree_equals(tree1, tree2), Equals(1)); + ts_tree *tree1_copy = ts_tree_make_leaf(cat, 5, 2); + AssertThat(ts_tree_equals(tree1, tree1_copy), Equals(1)); + ts_tree *tree2_copy = ts_tree_make_leaf(cat, 3, 1); + AssertThat(ts_tree_equals(tree2, tree2_copy), Equals(1)); - ts_tree *parent2 = ts_tree_make_node(dog, 1, 1, tree_array({ tree2, tree2 }), 0, 0); + ts_tree *parent2 = ts_tree_make_node(dog, 2, 2, tree_array({ + tree1_copy, tree2_copy, + tree1_copy, tree2_copy, + })); AssertThat(ts_tree_equals(parent1, parent2), Equals(1)); - ts_tree_release(tree2); + ts_tree_release(tree1_copy); + ts_tree_release(tree2_copy); ts_tree_release(parent2); }); it("returns false for trees with different symbols", [&]() { - ts_tree *tree2 = ts_tree_make_leaf(pig, 0, 0); - AssertThat(ts_tree_equals(tree1, tree2), Equals(0)); - ts_tree_release(tree2); + ts_tree *different_tree = ts_tree_make_leaf(pig, 0, 0); + AssertThat(ts_tree_equals(tree1, different_tree), Equals(0)); + ts_tree_release(different_tree); }); it("returns false for trees with different children", [&]() { - ts_tree *tree2 = ts_tree_make_leaf(pig, 0, 0); - ts_tree *parent2 = ts_tree_make_node(dog, 1, 1, tree_array({ tree2, tree2 }), 0, 0); - AssertThat(ts_tree_equals(parent2, parent1), Equals(0)); - AssertThat(ts_tree_equals(parent1, parent2), Equals(0)); - ts_tree_release(tree2); - ts_tree_release(parent2); + ts_tree *different_tree = ts_tree_make_leaf(pig, 0, 0); + ts_tree *different_parent = ts_tree_make_node(dog, 2, 2, tree_array({ + different_tree, different_tree, + tree2, tree2, + })); + + AssertThat(ts_tree_equals(different_parent, parent1), Equals(0)); + AssertThat(ts_tree_equals(parent1, different_parent), Equals(0)); + + ts_tree_release(different_tree); + ts_tree_release(different_parent); }); }); describe("serialization", [&]() { it("returns a readable string", [&]() { AssertThat(string(ts_tree_string(tree1, names)), Equals("(cat)")); - AssertThat(string(ts_tree_string(parent1, names)), Equals("(dog (cat))")); + AssertThat(string(ts_tree_string(parent1, names)), Equals("(dog (cat) (cat))")); }); }); }); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index d070b5b6..6065d185 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -81,7 +81,6 @@ ts_tree * ts_stack_reduce(ts_stack *stack, // later collapse the stack again when the document is edited. // We store the children and immediate children in the same array, // to reduce allocations. - size_t size = 0, offset = 0; size_t child_index = child_count; ts_tree **children = malloc((child_count + immediate_child_count) * sizeof(ts_tree *)); ts_tree **immediate_children = children + child_count; @@ -99,16 +98,9 @@ ts_tree * ts_stack_reduce(ts_stack *stack, child_index--; children[child_index] = child; } - - if (child_index == 0) { - offset += ts_tree_offset(child); - size += ts_tree_size(child); - } else { - size += ts_tree_offset(child) + ts_tree_size(child); - } } - ts_tree *lookahead = ts_tree_make_node(symbol, child_count, immediate_child_count, children, size, offset); + ts_tree *lookahead = ts_tree_make_node(symbol, child_count, immediate_child_count, children); ts_stack_shrink(stack, stack->size - immediate_child_count); return lookahead; } diff --git a/src/runtime/tree.c b/src/runtime/tree.c index 146577df..e8427f4c 100644 --- a/src/runtime/tree.c +++ b/src/runtime/tree.c @@ -40,10 +40,19 @@ ts_tree * ts_tree_make_leaf(ts_symbol symbol, size_t size, size_t offset) { return result; } -ts_tree * ts_tree_make_node(ts_symbol symbol, size_t child_count, size_t immediate_child_count, ts_tree **children, size_t size, size_t offset) { +ts_tree * ts_tree_make_node(ts_symbol symbol, size_t child_count, size_t immediate_child_count, ts_tree **children) { ts_tree **immediate_children = children + child_count; - for (size_t i = 0; i < immediate_child_count; i++) - ts_tree_retain(immediate_children[i]); + size_t size, offset; + for (size_t i = 0; i < immediate_child_count; i++) { + ts_tree *child = immediate_children[i]; + ts_tree_retain(child); + if (i == 0) { + offset = ts_tree_offset(child); + size = ts_tree_size(child); + } else { + size += ts_tree_offset(child) + ts_tree_size(child); + } + } ts_tree *result = ts_tree_make(symbol, size, offset); result->data.children.count = child_count; result->data.children.immediate_count = immediate_child_count;