diff --git a/src/runtime/c/Makefile.am b/src/runtime/c/Makefile.am index a9fd75ecb..75bd0a253 100644 --- a/src/runtime/c/Makefile.am +++ b/src/runtime/c/Makefile.am @@ -80,6 +80,7 @@ libpgf_la_SOURCES = \ pgf/linearizer.c \ pgf/typechecker.c \ pgf/reasoner.c \ + pgf/evaluator.c \ pgf/printer.c \ pgf/graphviz.c \ pgf/pgf.c \ diff --git a/src/runtime/c/pgf/evaluator.c b/src/runtime/c/pgf/evaluator.c new file mode 100644 index 000000000..7c4598a86 --- /dev/null +++ b/src/runtime/c/pgf/evaluator.c @@ -0,0 +1,443 @@ +#include "pgf/pgf.h" +#include "pgf/data.h" + +typedef struct PgfEnv PgfEnv; +typedef struct PgfClosure PgfClosure; +typedef struct PgfEvalState PgfEvalState; + +struct PgfEnv { + PgfEnv* next; + PgfClosure* closure; +}; + +struct PgfClosure { + PgfClosure* (*code)(PgfEvalState* state, PgfClosure* val); +}; + +typedef struct { + PgfClosure header; + PgfEnv* env; + PgfExpr expr; +} PgfExprThunk; + +typedef struct { + PgfClosure header; + PgfClosure* val; +} PgfIndirection; + +typedef struct { + PgfClosure header; + PgfAbsFun* absfun; + size_t n_args; + PgfClosure* args[]; +} PgfValue; + +typedef struct { + PgfClosure header; + int level; + size_t n_args; + PgfClosure* args[]; +} PgfValueGen; + +typedef struct { + PgfClosure header; + PgfEnv* env; + PgfMetaId id; + size_t n_args; + PgfClosure* args[]; +} PgfValueMeta; + +typedef struct { + PgfClosure header; + PgfLiteral lit; +} PgfValueLit; + +struct PgfEvalState { + PgfPGF* pgf; + GuPool* pool; + GuExn* err; + GuBuf* stack; +}; + +static PgfClosure* +pgf_evaluate_indirection(PgfEvalState* state, PgfClosure* closure) +{ + PgfIndirection* indir = (PgfIndirection*) closure; + return indir->val; +} + +static PgfClosure* +pgf_evaluate_value(PgfEvalState* state, PgfClosure* closure) +{ + PgfValue* val = (PgfValue*) closure; + + size_t n_args = val->n_args + gu_buf_length(state->stack); + PgfValue* new_val = + gu_new_flex(state->pool, PgfValue, args, n_args); + new_val->header.code = pgf_evaluate_value; + new_val->absfun = val->absfun; + new_val->n_args = n_args; + + size_t i = 0; + while (i < val->n_args) { + new_val->args[i] = val->args[i]; + i++; + } + while (i < n_args) { + val->args[i] = gu_buf_pop(state->stack, PgfClosure*); + i++; + } + + return &new_val->header; +} + +static PgfClosure* +pgf_evaluate_value_gen(PgfEvalState* state, PgfClosure* closure) +{ + PgfValueGen* val = (PgfValueGen*) closure; + + size_t n_args = val->n_args + gu_buf_length(state->stack); + PgfValueGen* new_val = + gu_new_flex(state->pool, PgfValueGen, args, n_args); + new_val->header.code = pgf_evaluate_value_gen; + new_val->level = val->level; + new_val->n_args = n_args; + + size_t i = 0; + while (i < val->n_args) { + new_val->args[i] = val->args[i]; + i++; + } + while (i < n_args) { + new_val->args[i] = gu_buf_pop(state->stack, PgfClosure*); + i++; + } + + return &new_val->header; +} + +static PgfClosure* +pgf_evaluate_value_meta(PgfEvalState* state, PgfClosure* closure) +{ + PgfValueMeta* val = (PgfValueMeta*) closure; + + size_t n_args = val->n_args + gu_buf_length(state->stack); + PgfValueMeta* new_val = + gu_new_flex(state->pool, PgfValueMeta, args, n_args); + new_val->header.code = pgf_evaluate_value_meta; + new_val->id = val->id; + new_val->n_args = n_args; + + size_t i = 0; + while (i < val->n_args) { + new_val->args[i] = val->args[i]; + i++; + } + while (i < n_args) { + val->args[i] = gu_buf_pop(state->stack, PgfClosure*); + i++; + } + + return &new_val->header; +} + +static PgfClosure* +pgf_evaluate_value_lit(PgfEvalState* state, PgfClosure* closure) +{ + return closure; +} + +static PgfClosure* +pgf_evaluate_expr_thunk(PgfEvalState* state, PgfClosure* closure) +{ + PgfExprThunk* thunk = (PgfExprThunk*) closure; + PgfEnv* env = thunk->env; + PgfExpr expr = thunk->expr; + + for (;;) { + GuVariantInfo ei = gu_variant_open(expr); + switch (ei.tag) { + case PGF_EXPR_ABS: { + PgfExprAbs* eabs = ei.data; + + if (gu_buf_length(state->stack) > 0) { + PgfEnv* new_env = gu_new(PgfEnv, state->pool); + new_env->next = env; + new_env->closure = gu_buf_pop(state->stack, PgfClosure*); + + env = new_env; + expr = eabs->body; + } else { + thunk->expr = expr; + return closure; + } + break; + } + case PGF_EXPR_APP: { + PgfExprApp* eapp = ei.data; + PgfExprThunk* thunk = + gu_new(PgfExprThunk, state->pool); + thunk->header.code = pgf_evaluate_expr_thunk; + thunk->env = env; + thunk->expr = eapp->arg; + gu_buf_push(state->stack, PgfClosure*, &thunk->header); + expr = eapp->fun; + break; + } + case PGF_EXPR_LIT: { + PgfExprLit* elit = ei.data; + + if (gu_buf_length(state->stack) > 0) { + GuExnData* err_data = gu_raise(state->err, PgfExn); + if (err_data) { + err_data->data = "found literal of function type"; + } + return NULL; + } + + PgfValueLit* val = (PgfValueLit*) closure; + val->header.code = pgf_evaluate_value_lit; + val->lit = elit->lit; + return &val->header; + } + case PGF_EXPR_META: { + PgfExprMeta* emeta = ei.data; + + size_t n_args = gu_buf_length(state->stack); + + PgfValueMeta* val = + gu_new_flex(state->pool, PgfValueMeta, args, n_args); + val->header.code = pgf_evaluate_value_meta; + val->id = emeta->id; + val->n_args = n_args; + for (size_t i = 0; i < n_args; i++) { + val->args[i] = gu_buf_pop(state->stack, PgfClosure*); + } + + PgfIndirection* indir = (PgfIndirection*) closure; + indir->header.code = pgf_evaluate_indirection; + indir->val = &val->header; + + return &val->header; + } + case PGF_EXPR_FUN: { + PgfExprFun* efun = ei.data; + + PgfAbsFun* absfun = + gu_map_get(state->pgf->abstract.funs, efun->fun, PgfAbsFun*); + if (absfun == NULL) { + GuExnData* err_data = gu_raise(state->err, PgfExn); + if (err_data) { + err_data->data = (char* const) + gu_format_string(err_data->pool, + "Unknown function: %s", + efun->fun); + } + return NULL; + } + + size_t n_args = gu_buf_length(state->stack); + + PgfValue* val = + gu_new_flex(state->pool, PgfValue, args, n_args); + val->header.code = pgf_evaluate_value; + val->absfun = absfun; + val->n_args = n_args; + for (size_t i = 0; i < n_args; i++) { + val->args[i] = gu_buf_pop(state->stack, PgfClosure*); + } + + PgfIndirection* indir = (PgfIndirection*) closure; + indir->header.code = pgf_evaluate_indirection; + indir->val = &val->header; + + return &val->header; + } + case PGF_EXPR_VAR: { + PgfExprVar* evar = ei.data; + PgfEnv* tmp_env = env; + size_t i = evar->var; + while (i > 0) { + tmp_env = tmp_env->next; + if (tmp_env == NULL) { + GuExnData* err_data = gu_raise(state->err, PgfExn); + if (err_data) { + err_data->data = "invalid de Bruijn index"; + } + return NULL; + } + i--; + } + + PgfClosure* val = + tmp_env->closure->code(state, tmp_env->closure); + + PgfIndirection* indir = (PgfIndirection*) closure; + indir->header.code = pgf_evaluate_indirection; + indir->val = val; + + return val; + } + case PGF_EXPR_TYPED: { + PgfExprTyped* etyped = ei.data; + expr = etyped->expr; + break; + } + case PGF_EXPR_IMPL_ARG: { + PgfExprImplArg* eimpl = ei.data; + expr = eimpl->expr; + break; + } + default: + gu_impossible(); + } + } +} + +static PgfExpr +pgf_value2expr(PgfEvalState* state, int level, PgfClosure* clos, GuPool* pool) +{ + clos = clos->code(state, clos); + if (clos == NULL) + return gu_null_variant; + + PgfExpr expr = gu_null_variant; + size_t n_args = 0; + PgfClosure** args; + + if (clos->code == pgf_evaluate_value) { + PgfValue* val = (PgfValue*) clos; + + expr = val->absfun->ep.expr; + n_args = val->n_args; + args = val->args; + } else if (clos->code == pgf_evaluate_value_gen) { + PgfValueGen* val = (PgfValueGen*) clos; + + PgfExprVar *evar = + gu_new_variant(PGF_EXPR_VAR, + PgfExprVar, + &expr, pool); + evar->var = level - val->level - 1; + + n_args = val->n_args; + args = val->args; + } else if (clos->code == pgf_evaluate_value_meta) { + PgfValueMeta* val = (PgfValueMeta*) clos; + + PgfExprMeta *emeta = + gu_new_variant(PGF_EXPR_META, + PgfExprMeta, + &expr, pool); + emeta->id = val->id; + + n_args = val->n_args; + args = val->args; + } else if (clos->code == pgf_evaluate_value_lit) { + PgfValueLit* val = (PgfValueLit*) clos; + + PgfExprLit *elit = + gu_new_variant(PGF_EXPR_LIT, + PgfExprLit, + &expr, pool); + + GuVariantInfo i = gu_variant_open(val->lit); + switch (i.tag) { + case PGF_LITERAL_STR: { + PgfLiteralStr* lstr = i.data; + + PgfLiteralStr* new_lstr = + gu_new_flex_variant(PGF_LITERAL_STR, + PgfLiteralStr, + val, strlen(lstr->val)+1, + &elit->lit, pool); + strcpy(new_lstr->val, lstr->val); + break; + } + case PGF_LITERAL_INT: { + PgfLiteralInt* lint = i.data; + + PgfLiteralInt* new_lint = + gu_new_variant(PGF_LITERAL_INT, + PgfLiteralInt, + &elit->lit, pool); + new_lint->val = lint->val; + break; + } + case PGF_LITERAL_FLT: { + PgfLiteralFlt* lflt = i.data; + + PgfLiteralFlt* new_lflt = + gu_new_variant(PGF_LITERAL_FLT, + PgfLiteralFlt, + &elit->lit, pool); + new_lflt->val = lflt->val; + break; + } + default: + gu_impossible(); + } + } else { + PgfExprThunk *old_thunk = (PgfExprThunk*) clos; + PgfExprAbs *old_eabs = gu_variant_open(old_thunk->expr).data; + + PgfValueGen* gen = + gu_new(PgfValueGen, state->pool); + gen->header.code = pgf_evaluate_value_gen; + gen->level = level; + gen->n_args = 0; + + PgfEnv* new_env = gu_new(PgfEnv, state->pool); + new_env->next = old_thunk->env; + new_env->closure = &gen->header; + + PgfExprThunk* new_thunk = + gu_new(PgfExprThunk, state->pool); + new_thunk->header.code = pgf_evaluate_expr_thunk; + new_thunk->env = new_env; + new_thunk->expr = old_eabs->body; + + PgfExprAbs *eabs = + gu_new_variant(PGF_EXPR_ABS, + PgfExprAbs, + &expr, pool); + eabs->bind_type = old_eabs->bind_type; + eabs->id = gu_format_string(pool, "v%d", level); + eabs->body = pgf_value2expr(state, level+1, &new_thunk->header, pool); + } + + for (size_t i = 0; i < n_args; i++) { + PgfExpr fun = expr; + PgfExpr arg = + pgf_value2expr(state, level, args[i], pool); + if (gu_variant_is_null(arg)) + return gu_null_variant; + + PgfExprApp* e = + gu_new_variant(PGF_EXPR_APP, + PgfExprApp, + &expr, pool); + e->fun = fun; + e->arg = arg; + } + + return expr; +} + +PgfExpr +pgf_compute(PgfPGF* pgf, PgfExpr expr, GuExn* err, GuPool* pool, GuPool* out_pool) +{ + PgfEvalState* state = gu_new(PgfEvalState, pool); + state->pgf = pgf; + state->pool = pool; + state->err = err; + state->stack = gu_new_buf(PgfClosure*, pool); + + PgfExprThunk* thunk = + gu_new(PgfExprThunk, pool); + thunk->header.code = pgf_evaluate_expr_thunk; + thunk->env = NULL; + thunk->expr = expr; + + return pgf_value2expr(state, 0, &thunk->header, out_pool); +} diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index 7cddbbcae..bc9fb7d99 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -99,7 +99,11 @@ pgf_linearize(PgfConcr* concr, PgfExpr expr, GuOut* out, GuExn* err); bool pgf_parseval(PgfConcr* concr, PgfExpr expr, PgfCId cat, double *precision, double *recall, double *exact); - + +PgfExpr +pgf_compute(PgfPGF* pgf, PgfExpr expr, GuExn* err, + GuPool* pool, GuPool* out_pool); + PgfExprEnum* pgf_generate_all(PgfPGF* pgf, PgfCId cat, GuPool* pool); diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index ddc1abe12..d31c3e77e 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -2301,8 +2301,30 @@ PGF_compute(PGFObject* self, PyObject *args) if (!PyArg_ParseTuple(args, "O!", &pgf_ExprType, &py_expr)) return NULL; - Py_INCREF(py_expr); - return py_expr; + ExprObject* py_expr_res = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); + if (py_expr_res == NULL) + return NULL; + + GuPool* tmp_pool = gu_new_pool(); + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + py_expr_res->pool = gu_new_pool(); + py_expr_res->expr = pgf_compute(self->pgf, py_expr->expr, err, + tmp_pool, py_expr_res->pool); + py_expr_res->master = (PyObject*) self; + Py_INCREF(py_expr_res->master); + + if (!gu_ok(err)) { + GuString msg = (GuString) gu_exn_caught_data(err); + PyErr_SetString(PGFError, msg); + + Py_DECREF(py_expr_res); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return py_expr_res; } static ExprObject*