pretty printing for expressions and types

This commit is contained in:
krangelov
2021-08-26 15:46:16 +02:00
parent 07bda06fb2
commit 275addfcbe
11 changed files with 572 additions and 11 deletions

View File

@@ -473,7 +473,7 @@ uintptr_t PgfExprParser::parse_arg()
return arg;
}
PgfText wildcard = {size: 1, text: {'_','0'}};
PGF_INTERNAL PgfText wildcard = {size: 1, text: {'_','0'}};
PgfBind *PgfExprParser::parse_bind(PgfBind *next)
{

View File

@@ -169,4 +169,6 @@ public:
bool eof();
};
PGF_INTERNAL_DECL extern PgfText wildcard;
#endif /* EXPR_H_ */

View File

@@ -2,6 +2,7 @@
#include <math.h>
#include "data.h"
#include "reader.h"
#include "printer.h"
static void
pgf_exn_clear(PgfExn* err)
@@ -314,6 +315,16 @@ prob_t pgf_function_prob(PgfPGF *pgf, PgfText *funname)
return absfun->ep.prob;
}
PGF_API
PgfText *pgf_print_expr(uintptr_t e,
PgfPrintContext *ctxt, int prio,
PgfMarshaller *m)
{
PgfPrinter printer(ctxt,prio,m);
m->match_expr(&printer, e);
return printer.get_text();
}
PGF_API uintptr_t
pgf_read_expr(PgfText *input, PgfUnmarshaller *u)
{
@@ -326,6 +337,16 @@ pgf_read_expr(PgfText *input, PgfUnmarshaller *u)
return res;
}
PGF_API
PgfText *pgf_print_type(uintptr_t ty,
PgfPrintContext *ctxt, int prio,
PgfMarshaller *m)
{
PgfPrinter printer(ctxt,prio,m);
m->match_type(&printer, ty);
return printer.get_text();
}
PGF_API uintptr_t
pgf_read_type(PgfText *input, PgfUnmarshaller *u)
{

View File

@@ -232,9 +232,26 @@ int pgf_function_is_constructor(PgfPGF *pgf, PgfText *funname);
PGF_API_DECL
prob_t pgf_function_prob(PgfPGF *pgf, PgfText *funname);
typedef struct PgfPrintContext PgfPrintContext;
struct PgfPrintContext {
PgfPrintContext* next;
PgfText name;
};
PGF_API_DECL
PgfText *pgf_print_expr(uintptr_t e,
PgfPrintContext *ctxt, int prio,
PgfMarshaller *m);
PGF_API_DECL
uintptr_t pgf_read_expr(PgfText *input, PgfUnmarshaller *u);
PGF_API_DECL
PgfText *pgf_print_type(uintptr_t ty,
PgfPrintContext *ctxt, int prio,
PgfMarshaller *m);
PGF_API_DECL
uintptr_t pgf_read_type(PgfText *input, PgfUnmarshaller *u);

View File

@@ -0,0 +1,362 @@
#include <stdarg.h>
#include "data.h"
#include "printer.h"
PgfPrinter::PgfPrinter(PgfPrintContext *context, int priority,
PgfMarshaller *marshaller)
{
ctxt = context;
printing_lambdas = false;
prio = priority;
res = NULL;
m = marshaller;
}
void PgfPrinter::puts(PgfText *s)
{
if (res) {
size_t size = res->size+s->size;
res = (PgfText *) realloc(res, sizeof(PgfText)+size+1);
memcpy(res->text+res->size, s->text, s->size+1);
res->size = size;
} else {
res = textdup(s);
}
}
void PgfPrinter::puts(const char *s)
{
size_t len = strlen(s);
if (res) {
size_t size = res->size+len;
res = (PgfText *) realloc(res, sizeof(PgfText)+size+1);
memcpy(res->text+res->size, s, len+1);
res->size = size;
} else {
res = (PgfText *) malloc(sizeof(PgfText)+len+1);
memcpy(res->text, s, len+1);
res->size = len;
}
}
void PgfPrinter::nprintf(size_t buf_size, const char *format, ...)
{
if (res) {
size_t size = res->size+buf_size;
res = (PgfText *) realloc(res, sizeof(PgfText)+size+1);
} else {
res = (PgfText *) malloc(sizeof(PgfText)+buf_size+1);
res->size = 0;
}
va_list ap;
va_start(ap, format);
res->size +=
vsnprintf(res->text+res->size, buf_size, format, ap);
va_end(ap);
}
PgfText *PgfPrinter::get_text()
{
return res;
}
void PgfPrinter::flush_lambdas()
{
if (!printing_lambdas)
return;
if (this->btype == PGF_BIND_TYPE_IMPLICIT) {
puts("}");
}
puts("->");
printing_lambdas = false;
}
void PgfPrinter::push_variable(PgfText *name)
{
PgfPrintContext *c = (PgfPrintContext *)
malloc(sizeof(PgfPrintContext)+name->size+1);
c->next = ctxt;
c->name.size = name->size;
memcpy(c->name.text, name->text, name->size+1);
int i = 0;
bool clash;
do {
clash = false;
PgfPrintContext *c2 = ctxt;
while (c2 != NULL) {
if (textcmp(&c->name, &c2->name) == 0) {
clash = true;
if (i == 0) {
// the first time when we encounter a clash,
// we ensure enough space to add a number to the name.
c = (PgfPrintContext *)
realloc(c,sizeof(PgfPrintContext)+name->size+1+15);
}
i++;
char *buffer = c->name.text+name->size;
snprintf(buffer,15,"%d",i);
c->name.size = name->size+strlen(buffer);
break;
}
c2 = c2->next;
}
} while (clash);
ctxt = c;
}
void PgfPrinter::pop_variable()
{
PgfPrintContext *tmp = ctxt;
ctxt = ctxt->next;
free(tmp);
}
uintptr_t PgfPrinter::eabs(PgfBindType btype, PgfText *name, uintptr_t body)
{
bool p = (prio > 1);
if (p) puts("(");
push_variable(name);
if (!printing_lambdas) {
// This is the outermost lambda possibly in a chain of nested lambdas
printing_lambdas = true;
puts("\\");
if (btype == PGF_BIND_TYPE_IMPLICIT) {
puts("{");
}
} else {
if (btype == PGF_BIND_TYPE_EXPLICIT &&
this->btype == PGF_BIND_TYPE_IMPLICIT) {
puts("}");
}
puts(",");
if (btype == PGF_BIND_TYPE_IMPLICIT &&
this->btype == PGF_BIND_TYPE_EXPLICIT) {
puts("{");
}
}
this->btype = btype;
puts(&ctxt->name);
prio = 1;
m->match_expr(this, body);
pop_variable();
if (p) puts(")");
return 0;
}
uintptr_t PgfPrinter::eapp(uintptr_t fun, uintptr_t arg)
{
flush_lambdas();
bool p = (prio > 3);
if (p) puts("(");
prio = 3;
m->match_expr(this, fun);
puts(" ");
prio = 4;
m->match_expr(this, arg);
if (p) puts(")");
return 0;
}
uintptr_t PgfPrinter::elit(uintptr_t lit)
{
flush_lambdas();
return m->match_lit(this, lit);
}
uintptr_t PgfPrinter::emeta(PgfMetaId meta)
{
flush_lambdas();
if (meta == 0) {
puts("?");
} else {
nprintf(16, "?%d", meta);
}
return 0;
}
uintptr_t PgfPrinter::efun(PgfText *name)
{
flush_lambdas();
puts(name);
return 0;
}
uintptr_t PgfPrinter::evar(int index)
{
flush_lambdas();
PgfPrintContext *var = ctxt;
for (int i = 0; i < index; i++) {
if (var == NULL)
break;
var = var->next;
}
if (var == NULL) {
nprintf(16, "#%d", index);
} else {
puts(&var->name);
}
return 0;
}
uintptr_t PgfPrinter::etyped(uintptr_t expr, uintptr_t ty)
{
flush_lambdas();
puts("<");
prio = 0;
m->match_expr(this, expr);
puts(" : ");
prio = 0;
m->match_type(this, ty);
puts(">");
return 0;
}
uintptr_t PgfPrinter::eimplarg(uintptr_t expr)
{
flush_lambdas();
puts("{");
prio = 0;
m->match_expr(this, expr);
puts("}");
return 0;
}
uintptr_t PgfPrinter::lint(int v)
{
nprintf(16, "%d", v);
return 0;
}
uintptr_t PgfPrinter::lflt(double v)
{
nprintf(16,"%lg",v);
return 0;
}
uintptr_t PgfPrinter::lstr(PgfText *v)
{
PgfText *charbuf = (PgfText *) alloca(sizeof(PgfText)+7);
puts("\"");
const uint8_t* start = (uint8_t*) v->text;
const uint8_t* end = start + v->size;
while (start < end) {
const uint8_t* s = start;
uint32_t c = pgf_utf8_decode(&s);
switch (c) {
case '\\':
puts("\\\\");
break;
case '"':
puts("\\\"");
break;
case '\n':
puts("\\n");
break;
case '\r':
puts("\\r");
break;
case '\b':
puts("\\b");
break;
case '\t':
puts("\\t");
break;
case '\0':
puts("\\0");
break;
default:
charbuf->size = s-start;
memcpy(charbuf->text, start, charbuf->size);
charbuf->text[charbuf->size] = 0;
puts(charbuf);
}
start = s;
}
puts("\"");
return 0;
}
uintptr_t PgfPrinter::dtyp(int n_hypos, PgfTypeHypo *hypos,
PgfText *cat,
int n_exprs, uintptr_t *exprs)
{
bool p = (prio > 0 && n_hypos > 0) ||
(prio > 3 && n_exprs > 0);
if (p) puts("(");
PgfPrintContext *save_ctxt = ctxt;
for (int i = 0; i < n_hypos; i++) {
if (textcmp(hypos[i].cid, &wildcard) == 0) {
prio = 1;
m->match_type(this, hypos[i].type);
} else {
push_variable(hypos[i].cid);
puts("(");
if (hypos[i].bind_type == PGF_BIND_TYPE_IMPLICIT)
puts("{");
puts(&ctxt->name);
if (hypos[i].bind_type == PGF_BIND_TYPE_IMPLICIT)
puts("}");
puts(" : ");
m->match_type(this, hypos[i].type);
puts(")");
}
puts(" -> ");
}
puts(cat);
for (int i = 0; i < n_exprs; i++) {
puts(" ");
prio = 4;
m->match_expr(this, exprs[i]);
}
while (ctxt != save_ctxt) {
pop_variable();
}
if (p) puts(")");
return 0;
}
void PgfPrinter::free_ref(uintptr_t x)
{
}
void PgfPrinter::free_me()
{
}

View File

@@ -0,0 +1,66 @@
#ifndef PRINTER_H
#define PRINTER_H
class PGF_INTERNAL_DECL PgfPrinter : public PgfUnmarshaller {
// List of free variables in order reverse to the order of binding
PgfPrintContext *ctxt;
// Each lambda abstraction is a separate object, but when we print
// them we want to colapse them into one abstraction with
// several variables. For that reason, if we are in the process
// of printing nested lambda abstractions, printing_lambdas is true
// and btype is the binding type for the last variable.
bool printing_lambdas;
PgfBindType btype;
// This method should be called before printing any other form of
// expression but a lambda. In this way the printing of a chain
// of lambda expressions is finished.
void flush_lambdas();
// Push a new variable in the printing context. If the name
// collides with an existing variable, the variable is renamed
// by adding a number.
void push_variable(PgfText *name);
// Pop the last variable name from the context.
void pop_variable();
// The current operator priority
int prio;
// The generated text
PgfText *res;
// The marshaller for pattern matching
PgfMarshaller *m;
public:
PgfPrinter(PgfPrintContext *context, int priority,
PgfMarshaller *marshaller);
void puts(PgfText *s);
void puts(const char *s);
void nprintf(size_t buf_size, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
PgfText *get_text();
virtual uintptr_t eabs(PgfBindType btype, PgfText *name, uintptr_t body);
virtual uintptr_t eapp(uintptr_t fun, uintptr_t arg);
virtual uintptr_t elit(uintptr_t lit);
virtual uintptr_t emeta(PgfMetaId meta);
virtual uintptr_t efun(PgfText *name);
virtual uintptr_t evar(int index);
virtual uintptr_t etyped(uintptr_t expr, uintptr_t typ);
virtual uintptr_t eimplarg(uintptr_t expr);
virtual uintptr_t lint(int v);
virtual uintptr_t lflt(double v);
virtual uintptr_t lstr(PgfText *v);
virtual uintptr_t dtyp(int n_hypos, PgfTypeHypo *hypos,
PgfText *cat,
int n_exprs, uintptr_t *exprs);
virtual void free_ref(uintptr_t x);
virtual void free_me();
};
#endif

View File

@@ -19,9 +19,9 @@ int textcmp(PgfText *t1, PgfText *t2)
PGF_INTERNAL
PgfText* textdup(PgfText *t1)
{
PgfText *t2 = (PgfText *) malloc(sizeof(PgfText) + t1->size + 1);
t2->size = t1->size;
memcpy(t2->text, t1->text, t1->size+1);
size_t size = sizeof(PgfText)+t1->size+1;
PgfText *t2 = (PgfText *) malloc(size);
memcpy(t2, t1, size);
return t2;
}