From 7483da41842275fb476396bd635086ea286b62b6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 31 Aug 2016 17:29:14 -0700 Subject: [PATCH] Add push_count to stack, use it in error comparisons --- spec/runtime/stack_spec.cc | 18 ++++++++++ src/runtime/error_costs.h | 25 ++++++++------ src/runtime/stack.c | 68 ++++++++++++++++++++++++-------------- src/runtime/stack.h | 2 ++ 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/spec/runtime/stack_spec.cc b/spec/runtime/stack_spec.cc index 7c3d48a2..1beb5b22 100644 --- a/spec/runtime/stack_spec.cc +++ b/spec/runtime/stack_spec.cc @@ -119,6 +119,12 @@ describe("Stack", [&]() { {1, 3}, }))); }); + + it("increments the version's push count", [&]() { + AssertThat(ts_stack_push_count(stack, 0), Equals(0)); + ts_stack_push(stack, 0, trees[0], false, stateA); + AssertThat(ts_stack_push_count(stack, 0), Equals(1)); + }); }); describe("merge()", [&]() { @@ -261,6 +267,18 @@ describe("Stack", [&]() { free_slice_array(&pop.slices); }); + it("preserves the push count of the popped version", [&]() { + // . <──0── A <──1── B <──2── C* + // ↑ + // └─* + StackPopResult pop = ts_stack_pop_count(stack, 0, 2); + + AssertThat(ts_stack_push_count(stack, 0), Equals(3)); + AssertThat(ts_stack_push_count(stack, 1), Equals(3)); + + free_slice_array(&pop.slices); + }); + describe("when the version has been merged", [&]() { before_each([&]() { // . <──0── A <──1── B <──2── C <──3── D <──10── I* diff --git a/src/runtime/error_costs.h b/src/runtime/error_costs.h index b1640a30..c628672e 100644 --- a/src/runtime/error_costs.h +++ b/src/runtime/error_costs.h @@ -8,33 +8,36 @@ typedef struct { unsigned cost; unsigned count; - unsigned depth; + unsigned push_count; } ErrorStatus; -static inline int error_status_compare(ErrorStatus a, ErrorStatus b) { - static unsigned ERROR_COST_THRESHOLD = 3 * ERROR_COST_PER_SKIPPED_TREE; - static unsigned ERROR_COUNT_THRESHOLD = 1; +static double error_threshold(unsigned push_count) { + return 6 * ERROR_COST_PER_SKIPPED_TREE / (1 + push_count / 2); +} +static inline int error_status_compare(ErrorStatus a, ErrorStatus b) { // TODO remove a.cost += ERROR_COST_PER_SKIPPED_TREE * a.count; b.cost += ERROR_COST_PER_SKIPPED_TREE * b.count; - if ((a.count + ERROR_COUNT_THRESHOLD < b.count) || + if ((a.count + 1 < b.count) || (a.count < b.count && a.cost <= b.cost)) { return -1; } - if ((b.count + ERROR_COUNT_THRESHOLD < a.count) || + if ((b.count + 1 < a.count) || (b.count < a.count && b.cost <= a.cost)) { return 1; } - if (a.cost + ERROR_COST_THRESHOLD < b.cost) { - return -1; - } + if (a.cost == b.cost) { + if (a.cost + error_threshold(a.push_count) < b.cost) { + return -1; + } - if (b.cost + ERROR_COST_THRESHOLD < a.cost) { - return 1; + if (b.cost + error_threshold(b.push_count) < a.cost) { + return 1; + } } return 0; diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 7e9dc0e9..c1eb1873 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -49,6 +49,7 @@ typedef Array(StackNode *) StackNodeArray; typedef struct { StackNode *node; bool is_halted; + unsigned push_count; } StackHead; struct Stack { @@ -163,14 +164,16 @@ static void stack_node_add_link(StackNode *self, StackLink link) { } } -static StackVersion ts_stack__add_version(Stack *self, StackNode *node) { - if (!array_push(&self->heads, ((StackHead){ node, false }))) +static StackVersion ts_stack__add_version(Stack *self, StackNode *node, + unsigned push_count) { + if (!array_push(&self->heads, ((StackHead){ node, false, push_count }))) return STACK_VERSION_NONE; stack_node_retain(node); return (StackVersion)(self->heads.size - 1); } -static bool ts_stack__add_slice(Stack *self, StackNode *node, TreeArray *trees) { +static bool ts_stack__add_slice(Stack *self, StackNode *node, TreeArray *trees, + unsigned push_count) { for (size_t i = self->slices.size - 1; i + 1 > 0; i--) { StackVersion version = self->slices.contents[i].version; if (self->heads.contents[version].node == node) { @@ -179,7 +182,7 @@ static bool ts_stack__add_slice(Stack *self, StackNode *node, TreeArray *trees) } } - StackVersion version = ts_stack__add_version(self, node); + StackVersion version = ts_stack__add_version(self, node, push_count); if (version == STACK_VERSION_NONE) return false; StackSlice slice = { *trees, version }; @@ -189,14 +192,15 @@ static bool ts_stack__add_slice(Stack *self, StackNode *node, TreeArray *trees) INLINE StackPopResult stack__iter(Stack *self, StackVersion version, StackIterateCallback callback, void *payload) { array_clear(&self->slices); + array_clear(&self->pop_paths); + StackHead *head = array_get(&self->heads, version); PopPath pop_path = { - .node = array_get(&self->heads, version)->node, + .node = head->node, .trees = array_new(), .tree_count = 0, .is_pending = true, }; - array_clear(&self->pop_paths); if (!array_push(&self->pop_paths, pop_path)) goto error; @@ -219,7 +223,7 @@ INLINE StackPopResult stack__iter(Stack *self, StackVersion version, if (!ts_tree_array_copy(trees, &trees)) goto error; array_reverse(&trees); - if (!ts_stack__add_slice(self, node, &trees)) + if (!ts_stack__add_slice(self, node, &trees, head->push_count)) goto error; } @@ -300,7 +304,7 @@ Stack *ts_stack_new() { if (!self->base_node) goto error; - array_push(&self->heads, ((StackHead){ self->base_node, false })); + array_push(&self->heads, ((StackHead){ self->base_node, false, 0 })); return self; @@ -349,12 +353,16 @@ TSLength ts_stack_top_position(const Stack *self, StackVersion version) { return array_get(&self->heads, version)->node->position; } +unsigned ts_stack_push_count(const Stack *self, StackVersion version) { + return array_get(&self->heads, version)->push_count; +} + ErrorStatus ts_stack_error_status(const Stack *self, StackVersion version) { - StackNode *node = array_get(&self->heads, version)->node; + StackHead *head = array_get(&self->heads, version); return (ErrorStatus){ - .cost = node->error_cost, - .count = node->error_count, - .depth = node->error_depth, + .cost = head->node->error_cost, + .count = head->node->error_count, + .push_count = head->push_count, }; } @@ -365,16 +373,21 @@ unsigned ts_stack_error_count(const Stack *self, StackVersion version) { bool ts_stack_push(Stack *self, StackVersion version, TSTree *tree, bool is_pending, TSStateId state) { - StackNode *node = array_get(&self->heads, version)->node; - TSLength position = - tree ? ts_length_add(node->position, ts_tree_total_size(tree)) - : node->position; + StackHead *head = array_get(&self->heads, version); + StackNode *node = head->node; + TSLength position = node->position; + if (tree) + position = ts_length_add(position, ts_tree_total_size(tree)); StackNode *new_node = stack_node_new(node, tree, is_pending, state, position, &self->node_pool); if (!new_node) return false; stack_node_release(node, &self->node_pool); - self->heads.contents[version].node = new_node; + head->node = new_node; + if (state == TS_STATE_ERROR) + head->push_count = 0; + else + head->push_count++; return true; } @@ -484,8 +497,10 @@ StackVersion ts_stack_duplicate_version(Stack *self, StackVersion version) { } bool ts_stack_merge(Stack *self, StackVersion version, StackVersion new_version) { - StackNode *node = self->heads.contents[version].node; - StackNode *new_node = self->heads.contents[new_version].node; + StackHead *head = &self->heads.contents[version]; + StackHead *new_head = &self->heads.contents[new_version]; + StackNode *node = head->node; + StackNode *new_node = new_head->node; if (new_node->state == node->state && new_node->position.chars == node->position.chars && @@ -493,6 +508,8 @@ bool ts_stack_merge(Stack *self, StackVersion version, StackVersion new_version) new_node->error_cost == node->error_cost) { for (size_t j = 0; j < new_node->link_count; j++) stack_node_add_link(node, new_node->links[j]); + if (new_head->push_count > head->push_count) + head->push_count = new_head->push_count; ts_stack_remove_version(self, new_version); return true; } else { @@ -513,7 +530,7 @@ void ts_stack_clear(Stack *self) { for (size_t i = 0; i < self->heads.size; i++) stack_node_release(self->heads.contents[i].node, &self->node_pool); array_clear(&self->heads); - array_push(&self->heads, ((StackHead){ self->base_node, false })); + array_push(&self->heads, ((StackHead){ self->base_node, false, 0 })); } bool ts_stack_print_dot_graph(Stack *self, const char **symbol_names, FILE *f) { @@ -529,14 +546,15 @@ bool ts_stack_print_dot_graph(Stack *self, const char **symbol_names, FILE *f) { array_clear(&self->pop_paths); for (size_t i = 0; i < self->heads.size; i++) { - if (self->heads.contents[i].is_halted) + StackHead *head = &self->heads.contents[i]; + if (head->is_halted) continue; - StackNode *node = self->heads.contents[i].node; fprintf(f, "node_head_%lu [shape=none, label=\"\"]\n", i); fprintf( - f, "node_head_%lu -> node_%p [label=%lu, fontcolor=blue, weight=10000]\n", - i, node, i); - if (!array_push(&self->pop_paths, ((PopPath){.node = node }))) + f, "node_head_%lu -> node_%p [label=%lu, fontcolor=blue, weight=10000, " + "labeltooltip=\"push_count: %u\"]\n", + i, head->node, i, head->push_count); + if (!array_push(&self->pop_paths, ((PopPath){.node = head->node }))) goto error; } diff --git a/src/runtime/stack.h b/src/runtime/stack.h index 4eba9f3d..b898cf51 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -68,6 +68,8 @@ size_t ts_stack_version_count(const Stack *); */ TSStateId ts_stack_top_state(const Stack *, StackVersion); +unsigned ts_stack_push_count(const Stack *, StackVersion); + /* * Get the position at the top of the given version of the stack. If the stack * is empty, this returns zero.