summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/c/Makefile.am2
-rw-r--r--src/runtime/c/pgf/graphviz.c93
-rw-r--r--src/runtime/c/pgf/graphviz.h7
-rw-r--r--src/runtime/c/utils/pgf-service.c83
-rw-r--r--src/runtime/python/pypgf.c26
5 files changed, 129 insertions, 82 deletions
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
@@ -56,87 +56,6 @@ url_escape(char *str)
}
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)
{
int pid;
@@ -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 */
};