From 5337b4bef73e375d1f8cf4bb5eae543e7cab4922 Mon Sep 17 00:00:00 2001 From: "kr.angelov" Date: Thu, 15 Aug 2013 08:06:37 +0000 Subject: [PATCH] graphvizAbstractTree in the C and Python runtimes --- src/runtime/c/Makefile.am | 2 + src/runtime/c/pgf/graphviz.c | 93 +++++++++++++++++++++++++++++++ src/runtime/c/pgf/graphviz.h | 7 +++ src/runtime/c/utils/pgf-service.c | 83 +-------------------------- src/runtime/python/pypgf.c | 26 +++++++++ 5 files changed, 129 insertions(+), 82 deletions(-) create mode 100644 src/runtime/c/pgf/graphviz.c create mode 100644 src/runtime/c/pgf/graphviz.h diff --git a/src/runtime/c/Makefile.am b/src/runtime/c/Makefile.am index 47dd082fc..207545bd6 100644 --- a/src/runtime/c/Makefile.am +++ b/src/runtime/c/Makefile.am @@ -47,6 +47,7 @@ pgfinclude_HEADERS = \ pgf/parser.h \ pgf/lexer.h \ pgf/literals.h \ + pgf/graphviz.h \ pgf/pgf.h libgu_la_SOURCES = \ @@ -115,6 +116,7 @@ libpgf_la_SOURCES = \ pgf/linearizer.c \ pgf/reasoner.c \ pgf/printer.c \ + pgf/graphviz.c \ pgf/pgf.c \ pgf/pgf.h diff --git a/src/runtime/c/pgf/graphviz.c b/src/runtime/c/pgf/graphviz.c new file mode 100644 index 000000000..cf2346fee --- /dev/null +++ b/src/runtime/c/pgf/graphviz.c @@ -0,0 +1,93 @@ +#include "data.h" +#include "graphviz.h" + +static int +pgf_graphviz_abstract_tree_(PgfExpr expr, int *pid, + GuWriter* wtr, GuExn* err) +{ + int id = -1; + + GuVariantInfo ei = gu_variant_open(expr); + switch (ei.tag) { + case PGF_EXPR_ABS: + gu_impossible(); + break; + case PGF_EXPR_APP: { + PgfExprApp* app = ei.data; + id = pgf_graphviz_abstract_tree_(app->fun, pid, wtr, err); + int arg_id = pgf_graphviz_abstract_tree_(app->arg, pid, wtr, err); + gu_printf(wtr, err, "n%d -- n%d [style = \"solid\"]\n", id, arg_id); + break; + } + case PGF_EXPR_LIT: { + PgfExprLit* lit = ei.data; + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"", id); + + GuVariantInfo ei = gu_variant_open(lit->lit); + switch (ei.tag) { + case PGF_LITERAL_STR: { + PgfLiteralStr* lit = ei.data; + gu_puts("\\\"", wtr, err); + gu_string_write(lit->val, wtr, err); + gu_puts("\\\"", wtr, err); + break; + } + case PGF_LITERAL_INT: { + PgfLiteralInt* lit = ei.data; + gu_printf(wtr, err, "%d", lit->val); + break; + } + case PGF_LITERAL_FLT: { + PgfLiteralFlt* lit = ei.data; + gu_printf(wtr, err, "%lf", lit->val); + break; + } + default: + gu_impossible(); + } + + gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); + break; + } + case PGF_EXPR_META: + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"?\", style = \"solid\", shape = \"plaintext\"]\n", id); + break; + case PGF_EXPR_FUN: { + PgfExprFun* fun = ei.data; + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"", id); + gu_string_write(fun->fun, wtr, err); + gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); + break; + } + case PGF_EXPR_VAR: + gu_impossible(); + break; + case PGF_EXPR_TYPED: { + PgfExprTyped* typed = ei.data; + id = pgf_graphviz_abstract_tree_(typed->expr, pid, wtr, err); + break; + } + case PGF_EXPR_IMPL_ARG: { + PgfExprImplArg* implarg = ei.data; + id = pgf_graphviz_abstract_tree_(implarg->expr, pid, wtr, err); + break; + } + default: + gu_impossible(); + } + + return id; +} + +void +pgf_graphviz_abstract_tree(PgfExpr expr, GuWriter* wtr, GuExn* err) +{ + int id = 0; + + gu_puts("graph {\n", wtr, err); + pgf_graphviz_abstract_tree_(expr, &id, wtr, err); + gu_puts("}", wtr, err); +} diff --git a/src/runtime/c/pgf/graphviz.h b/src/runtime/c/pgf/graphviz.h new file mode 100644 index 000000000..749c6ef5f --- /dev/null +++ b/src/runtime/c/pgf/graphviz.h @@ -0,0 +1,7 @@ +#ifndef PGF_GRAPHVIZ_H_ +#define PGF_GRAPHVIZ_H_ + +void +pgf_graphviz_abstract_tree(PgfExpr expr, GuWriter* wtr, GuExn* err); + +#endif diff --git a/src/runtime/c/utils/pgf-service.c b/src/runtime/c/utils/pgf-service.c index 33369b9f5..b0cb190b8 100644 --- a/src/runtime/c/utils/pgf-service.c +++ b/src/runtime/c/utils/pgf-service.c @@ -55,87 +55,6 @@ url_escape(char *str) *pw++ = 0; } -static int -generate_graphviz_expr(PgfExpr expr, int *pid, - GuWriter* wtr, GuExn* err, GuPool* pool) -{ - int id = -1; - - GuVariantInfo ei = gu_variant_open(expr); - switch (ei.tag) { - case PGF_EXPR_FUN: { - PgfExprFun* fun = ei.data; - id = (*pid)++; - gu_printf(wtr, err, "n%d[label = \"", id); - gu_string_write(fun->fun, wtr, err); - gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); - break; - } - case PGF_EXPR_APP: { - PgfExprApp* app = ei.data; - id = generate_graphviz_expr(app->fun, pid, wtr, err, pool); - int arg_id = generate_graphviz_expr(app->arg, pid, wtr, err, pool); - gu_printf(wtr, err, "n%d -- n%d [style = \"solid\"]\n", id, arg_id); - break; - } - case PGF_EXPR_ABS: - case PGF_EXPR_LIT: { - PgfExprLit* lit = ei.data; - id = (*pid)++; - gu_printf(wtr, err, "n%d[label = \"", id); - - GuVariantInfo ei = gu_variant_open(lit->lit); - switch (ei.tag) { - case PGF_LITERAL_STR: { - PgfLiteralStr* lit = ei.data; - gu_puts("\\\"", wtr, err); - gu_string_write(lit->val, wtr, err); - gu_puts("\\\"", wtr, err); - break; - } - case PGF_LITERAL_INT: { - PgfLiteralInt* lit = ei.data; - gu_printf(wtr, err, "%d", lit->val); - break; - } - case PGF_LITERAL_FLT: { - PgfLiteralFlt* lit = ei.data; - gu_printf(wtr, err, "%lf", lit->val); - break; - } - default: - gu_impossible(); - } - - gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); - break; - } - case PGF_EXPR_META: - id = (*pid)++; - gu_printf(wtr, err, "n%d[label = \"?\", style = \"solid\", shape = \"plaintext\"]\n", id); - break; - case PGF_EXPR_VAR: - case PGF_EXPR_TYPED: - case PGF_EXPR_IMPL_ARG: - gu_impossible(); - break; - default: - gu_impossible(); - } - - return id; -} - -static void -generate_graphviz(PgfExpr expr, GuWriter* wtr, GuExn* err, GuPool* pool) -{ - int id = 0; - - gu_puts("graph {\n", wtr, err); - generate_graphviz_expr(expr, &id, wtr, err, pool); - gu_puts("}", wtr, err); -} - static int render(PgfExpr expr, GuPool* pool) { @@ -175,7 +94,7 @@ render(PgfExpr expr, GuPool* pool) GuWriter* wtr = gu_new_utf8_writer(out, pool); GuExn* err = gu_new_exn(NULL, gu_kind(type), pool); - generate_graphviz(expr, wtr, err, pool); + pgf_graphviz_abstract_tree(expr, wtr, err); fclose(fstream); close(cp[1]); diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 094744885..b623f6a81 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -2215,6 +2215,30 @@ pgf_readType(PyObject *self, PyObject *args) { return pytype; } +static PyObject* +pgf_graphvizAbstractTree(PyObject *self, PyObject *args) { + ExprObject* pyexpr; + if (!PyArg_ParseTuple(args, "O!", &pgf_ExprType, &pyexpr)) + return NULL; + + GuPool* tmp_pool = gu_local_pool(); + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + GuStringBuf* sbuf = gu_string_buf(tmp_pool); + GuWriter* wtr = gu_string_buf_writer(sbuf); + + pgf_graphviz_abstract_tree(pyexpr->expr, wtr, err); + if (!gu_ok(err)) { + PyErr_SetString(PGFError, "The abstract tree cannot be visualized"); + return NULL; + } + + GuString str = gu_string_buf_freeze(sbuf, tmp_pool); + PyObject* pystr = gu2py_string(str); + + gu_pool_free(tmp_pool); + return pystr; +} + static PyMethodDef module_methods[] = { {"readPGF", (void*)pgf_readPGF, METH_VARARGS, "Reads a PGF file in memory"}, @@ -2222,6 +2246,8 @@ static PyMethodDef module_methods[] = { "Parses a string as an abstract tree"}, {"readType", (void*)pgf_readType, METH_VARARGS, "Parses a string as an abstract type"}, + {"graphvizAbstractTree", (void*)pgf_graphvizAbstractTree, METH_VARARGS, + "Renders an abstract syntax tree in a Graphviz format"}, {NULL, NULL, 0, NULL} /* Sentinel */ };