diff --git a/src/runtime/c/pgf/graphviz.cxx b/src/runtime/c/pgf/graphviz.cxx new file mode 100644 index 000000000..a86b41481 --- /dev/null +++ b/src/runtime/c/pgf/graphviz.cxx @@ -0,0 +1,354 @@ +#include "data.h" +#include "printer.h" +#include "linearizer.h" +#include "graphviz.h" + + +PgfLinearizationGraphvizOutput::PgfLinearizationGraphvizOutput() +{ + parent = NULL; + level = 0; + n_internals = 0; + internals = NULL; + leaves.n_nodes = 0; + leaves.nodes = NULL; + + meta = (PgfText*) malloc(sizeof(PgfText)+2); + meta->text[0] = '?'; + meta->text[1] = 0; +} + +PgfLinearizationGraphvizOutput::~PgfLinearizationGraphvizOutput() +{ + free(meta); +} + +PgfLinearizationGraphvizOutput::ParseNode::ParseNode(ParseLevel *level, + int id, + ParseNode *parent, + PgfText *fun, + PgfText *label) +{ + this->id = id; + this->parent = parent; + this->fun = fun; + this->label = label; + + level->nodes = (ParseNode**) + realloc(level->nodes, (level->n_nodes+1)*sizeof(ParseNode*)); + level->nodes[level->n_nodes++] = this; +} + +void PgfLinearizationGraphvizOutput::symbol_token(PgfText *tok) +{ + new ParseNode(&leaves, 100000 + leaves.n_nodes, parent, NULL, tok); +} + +void PgfLinearizationGraphvizOutput::begin_phrase(PgfText *cat, int fid, PgfText *ann, PgfText *fun) +{ + if (cat->size == 1 && cat->text[0] == '_') + return; + + level++; + + ParseLevel *internal; + if (level < n_internals) { + internal = internals[level]; + + for (size_t i = 0; i < internal->n_nodes; i++) { + ParseNode *node = internal->nodes[i]; + if (node->id == fid) { + parent = node; + return; + } + } + } else { + internal = new ParseLevel(); + internal->n_nodes = 0; + internal->nodes = NULL; + internals = (ParseLevel**) + realloc(internals, (n_internals+1)*sizeof(ParseLevel*)); + internals[n_internals++] = internal; + } + + parent = new ParseNode(internal, fid, parent, fun, cat); +} + +void PgfLinearizationGraphvizOutput::end_phrase(PgfText *cat, int fid, PgfText *ann, PgfText *fun) +{ + if (cat->size == 1 && cat->text[0] == '_') + return; + + level--; + parent = parent->parent; +} + +void PgfLinearizationGraphvizOutput::symbol_ne() +{ +} + +void PgfLinearizationGraphvizOutput::symbol_bind() +{ +} + +void PgfLinearizationGraphvizOutput::symbol_meta(PgfMetaId id) +{ + new ParseNode(&leaves, 100000 + leaves.n_nodes, parent, NULL, meta); +} + +void PgfLinearizationGraphvizOutput::generate_graphviz_level(PgfPrinter *printer, PgfGraphvizOptions* opts, ParseLevel *level) +{ + printer->puts("\n subgraph {\n rank=same;\n"); + + if (level->n_nodes > 1) + printer->puts(" edge[style=invis]\n"); + + for (size_t i = 0; i < level->n_nodes; i++) { + ParseNode* node = level->nodes[i]; + if (node->fun != NULL) { + printer->nprintf(32, " n%d[label=\"", node->id); + if (!opts->noFun) + printer->efun(node->fun); + if (!opts->noFun && !opts->noCat) + printer->puts(" : "); + if (!opts->noCat) + printer->efun(node->label); + printer->puts("\""); + if (opts->nodeColor != NULL && *opts->nodeColor) + printer->nprintf(40, ", fontcolor = \"%s\"", opts->nodeColor); + if (opts->nodeFont != NULL && *opts->nodeFont) + printer->nprintf(40, ", fontname = \"%s\"", opts->nodeFont); + printer->puts("]\n"); + } else { + if (opts->noLeaves) + printer->nprintf(25, " n%d[label=\"\"]\n", node->id); + else { + printer->nprintf(25, " n%d[label=\"", node->id); + printer->puts(node->label); + printer->puts("\""); + if (opts->leafColor != NULL && *opts->leafColor) + printer->nprintf(40, ", fontcolor = \"%s\"", opts->leafColor); + if (opts->leafFont != NULL && *opts->leafFont) + printer->nprintf(40, ", fontname = \"%s\"", opts->leafFont); + printer->puts("]\n"); + } + } + } + + if (level->n_nodes > 1) { + for (size_t i = 0; i < level->n_nodes; i++) { + ParseNode* node = level->nodes[i]; + + printer->puts((i == 0) ? " " : " -- "); + printer->nprintf(32, "n%d", node->id); + } + printer->puts("\n"); + } + + printer->puts(" }\n"); + + for (size_t i = 0; i < level->n_nodes; i++) { + ParseNode* node = level->nodes[i]; + if (node->parent != NULL) { + printer->nprintf(40, " n%d -- n%d", node->parent->id, node->id); + + const char *edgeStyle, *color; + if (node->fun == NULL) { + edgeStyle = opts->leafEdgeStyle; + color = opts->leafColor; + } else { + edgeStyle = opts->nodeEdgeStyle; + color = opts->nodeColor; + } + + if (edgeStyle != NULL && *edgeStyle && color != NULL && *color) + printer->nprintf(50, " [style = \"%s\", color = \"%s\"]", edgeStyle, color); + else if (edgeStyle != NULL && *edgeStyle) + printer->nprintf(40, " [style = \"%s\"]", edgeStyle); + else if (color != NULL && *color) + printer->nprintf(40, " [color = \"%s\"]", color); + + printer->puts("\n"); + } + } +} + +PgfText *PgfLinearizationGraphvizOutput::generate_graphviz(PgfGraphvizOptions* opts) +{ + PgfPrinter printer(NULL, 0, NULL); + + printer.puts("graph {\n"); + printer.puts(" node[shape=plaintext]\n"); + + for (size_t i = 0; i < n_internals; i++) { + ParseLevel* level = internals[i]; + generate_graphviz_level(&printer, opts, level); + } + generate_graphviz_level(&printer, opts, &leaves); + + printer.puts("}"); + + return printer.get_text(); +} + +PgfAbstractGraphvizOutput::PgfAbstractGraphvizOutput(PgfAbstr *abstr, PgfGraphvizOptions* opts, PgfMarshaller *m) + : printer(NULL, 0, NULL) +{ + this->abstr = abstr; + this->opts = opts; + this->m = m; + + this->id = 0; + this->n_vars = 0; +} + +PgfText *PgfAbstractGraphvizOutput::generate_graphviz(PgfExpr expr) +{ + printer.puts("graph {\n"); + m->match_expr(this, expr); + printer.puts("}"); + return printer.get_text(); +} + +PgfExpr PgfAbstractGraphvizOutput::eabs(PgfBindType bind_type, PgfText *name, PgfExpr body) +{ + n_vars++; + printer.push_variable(name); + PgfExpr res = m->match_expr(this, body); + printer.pop_variable(); + return res; +} + +PgfExpr PgfAbstractGraphvizOutput::eapp(PgfExpr fun, PgfExpr arg) +{ + int fun_id = (int) m->match_expr(this, fun); + int arg_id = (int) m->match_expr(this, arg); + + printer.nprintf(32, "n%d -- n%d", fun_id, arg_id); + if (opts->nodeEdgeStyle != NULL && *opts->nodeEdgeStyle && opts->nodeColor != NULL && *opts->nodeColor) + printer.nprintf(50, " [style = \"%s\", color = \"%s\"]", opts->nodeEdgeStyle, opts->nodeColor); + else if (opts->nodeEdgeStyle != NULL && *opts->nodeEdgeStyle) + printer.nprintf(30, " [style = \"%s\"]", opts->nodeEdgeStyle); + else if (opts->nodeColor != NULL && *opts->nodeColor) + printer.nprintf(30, " [color = \"%s\"]", opts->nodeColor); + printer.puts("\n"); + + return fun_id; +} + +PgfExpr PgfAbstractGraphvizOutput::elit(PgfLiteral lit) +{ + int id = this->id++; + printer.nprintf(20, "n%d[label = \"", id); + m->match_lit(this, lit); + printer.puts("\", style = \"solid\", shape = \"plaintext\"]\n"); + return id; +} + +PgfExpr PgfAbstractGraphvizOutput::emeta(PgfMetaId meta_id) +{ + int id = this->id++; + printer.nprintf(20, "n%d[label = \"", id); + PgfExpr res = printer.emeta(meta_id); + printer.puts(", style = \"solid\", shape = \"plaintext\"]\n"); + return res; +} + +PgfExpr PgfAbstractGraphvizOutput::efun(PgfText *name) +{ + int id = this->id++; + if (opts->noFun && opts->noCat) { + printer.nprintf(32, "n%d[shape = \"point\"]\n", id); + } else { + printer.nprintf(20, "n%d[label = \"", id); + ref absfun = + (opts->noCat) ? 0 : namespace_lookup(abstr->funs, name); + if (!opts->noFun) { + if (n_vars > 0) { + printer.puts("\\\\"); + printer.bindings(n_vars); + printer.puts(" . "); + n_vars = 0; + } + printer.efun(name); + } + if (!opts->noFun && absfun != 0) + printer.puts(" : "); + if (absfun != 0) + printer.efun(&absfun->type->name); + printer.puts("\", shape = \"plaintext\", style = \"solid\""); + if (opts->nodeColor != NULL && *opts->nodeColor) + printer.nprintf(40, ", fontcolor = \"%s\"", opts->nodeColor); + if (opts->nodeFont != NULL && *opts->nodeFont) + printer.nprintf(40, ", fontname = \"%s\"", opts->nodeFont); + printer.puts("]\n"); + } + + return id; +} + +PgfExpr PgfAbstractGraphvizOutput::evar(int index) +{ + int id = this->id++; + if (opts->noFun && opts->noCat) { + printer.nprintf(32, "n%d[shape = \"point\"]\n", id); + } else { + printer.nprintf(20, "n%d[label = \"", id); + if (!opts->noFun) { + if (n_vars > 0) { + printer.puts("\\\\"); + printer.bindings(n_vars); + printer.puts(" . "); + n_vars = 0; + } + printer.evar(index); + } + printer.puts("\", shape = \"plaintext\", style = \"solid\""); + if (opts->nodeColor != NULL && *opts->nodeColor) + printer.nprintf(40, ", fontcolor = \"%s\"", opts->nodeColor); + if (opts->nodeFont != NULL && *opts->nodeFont) + printer.nprintf(40, ", fontname = \"%s\"", opts->nodeFont); + printer.puts("]\n"); + } + + return id; +} + +PgfExpr PgfAbstractGraphvizOutput::etyped(PgfExpr expr, PgfType ty) +{ + return m->match_expr(this, expr); +} + +PgfExpr PgfAbstractGraphvizOutput::eimplarg(PgfExpr expr) +{ + return m->match_expr(this, expr); +} + +PgfLiteral PgfAbstractGraphvizOutput::lint(size_t size, uintmax_t *val) +{ + return printer.lint(size, val); +} + +PgfLiteral PgfAbstractGraphvizOutput::lflt(double val) +{ + return printer.lflt(val); +} + +PgfLiteral PgfAbstractGraphvizOutput::lstr(PgfText *val) +{ + printer.puts("\\\""); + printer.puts(val); + printer.puts("\\\""); + return 0; +} + +PgfType PgfAbstractGraphvizOutput::dtyp(size_t n_hypos, PgfTypeHypo *hypos, + PgfText *cat, + size_t n_exprs, PgfExpr *exprs) +{ + return 0; +} + +void PgfAbstractGraphvizOutput::free_ref(object x) +{ +}