From 6dd92c3abe96f70e60a370bb3c0b21a6cc6d5f4d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 23 Feb 2016 00:08:55 -0800 Subject: [PATCH] Add function for rendering the stack as a DOT graph --- src/runtime/stack.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ src/runtime/stack.h | 2 ++ 2 files changed, 79 insertions(+) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 56e5eb07..19cb9639 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -475,3 +475,80 @@ void ts_stack_delete(Stack *self) { array_delete(&self->heads); ts_free(self); } + +size_t ts_stack__write_dot_graph(Stack *self, char *string, size_t n, + const char **symbol_names) { + char *cursor = string; + char **s = n > 0 ? &cursor : &string; + cursor += snprintf(*s, n, "digraph stack {\n"); + cursor += snprintf(*s, n, "rankdir=\"RL\";\n"); + cursor += snprintf(*s, n, "node_%p [label=\"0:NULL\"];\n", NULL); + + array_clear(&self->pop_paths); + for (int i = 0; i < self->heads.size; i++) + array_push(&self->pop_paths, ((PopPath){ + .node = self->heads.contents[i], + })); + + bool all_paths_done = false; + while (!all_paths_done) { + all_paths_done = true; + + for (size_t i = 0; i < self->pop_paths.size; i++) { + PopPath *path = &self->pop_paths.contents[i]; + StackNode *node = path->node; + + if (!node) + continue; + + all_paths_done = false; + + cursor += snprintf(*s, n, "node_%p [label=\"%d:%s\"];\n", node, + node->entry.state, + symbol_names[node->entry.tree->symbol]); + + path->node = node->successors[0]; + cursor += snprintf(*s, n, "node_%p -> node_%p;\n", node, node->successors[0]); + + for (int j = 1; j < node->successor_count; j++) { + if (!array_push(&self->pop_paths, *path)) + goto error; + cursor += snprintf(*s, n, "node_%p -> node_%p;\n", node, node->successors[j]); + + PopPath *next_path = array_back(&self->pop_paths); + next_path->node = node->successors[j]; + next_path->is_shared = true; + } + } + } + + cursor += snprintf(*s, n, "}\n"); + + return cursor - string; + +error: + return (size_t)-1; +} + +char *ts_stack_dot_graph(Stack *self, const char **symbol_names) { + static char SCRATCH[1]; + char *result = NULL; + size_t size = ts_stack__write_dot_graph(self, SCRATCH, 0, symbol_names) + 1; + if (size == -1) + goto error; + + result = ts_malloc(size * sizeof(char)); + if (!result) + goto error; + + size = ts_stack__write_dot_graph(self, result, size, symbol_names); + if (size == -1) + goto error; + + return result; + +error: + if (result) + ts_free(result); + return NULL; +} diff --git a/src/runtime/stack.h b/src/runtime/stack.h index 450f334a..ae76c2e6 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -119,6 +119,8 @@ void ts_stack_clear(Stack *); void ts_stack_set_tree_selection_callback(Stack *, void *, TreeSelectionFunction); +char *ts_stack_dot_graph(Stack *, const char **); + #ifdef __cplusplus } #endif