diff --git a/src/compiler/GF/Compile/Compute/Concrete.hs b/src/compiler/GF/Compile/Compute/Concrete.hs index a4c30bacd..f24582c6f 100644 --- a/src/compiler/GF/Compile/Compute/Concrete.hs +++ b/src/compiler/GF/Compile/Compute/Concrete.hs @@ -50,6 +50,7 @@ data Value s | VMeta (Thunk s) (Env s) [Thunk s] | VGen {-# UNPACK #-} !Int [Thunk s] | VClosure (Env s) Term + | VProd BindType Ident (Value s) (Value s) | VRecType [(Label, Value s)] | VR [(Label, Thunk s)] | VP (Value s) Label [Thunk s] @@ -79,7 +80,8 @@ eval env (Abs b x t) (v:vs) = eval ((x,v):env) t vs eval env (Meta i) vs = do tnk <- newMeta i return (VMeta tnk env vs) eval env (ImplArg t) [] = eval env t [] --- eval env (Prod b x t1 t2)[] = eval env t [] +eval env (Prod b x t1 t2)[] = do v1 <- eval env t1 [] + return (VProd b x v1 (VClosure env (Abs b x t2))) eval env (Typed t ty) vs = eval env t vs eval env (RecType lbls) [] = do lbls <- mapM (\(lbl,ty) -> fmap ((,) lbl) (eval env ty [])) lbls return (VRecType lbls) @@ -188,6 +190,10 @@ value2term i (VClosure env (Abs b x t)) = do v <- eval ((x,tnk):env) t [] t <- value2term (i+1) v return (Abs b (identS ('v':show i)) t) +value2term i (VProd b x v1 v2) = do + t1 <- value2term i v1 + t2 <- value2term i v2 + return (Prod b x t1 t2) value2term i (VRecType lbls) = do lbls <- mapM (\(lbl,v) -> fmap ((,) lbl) (value2term i v)) lbls return (RecType lbls) diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index 0a6af1cd0..9d3230dff 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -638,8 +638,10 @@ PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name, PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = PgfDB::get_revision(name); - Node::add_value_ref(pgf); - db->ref_count++; + if (pgf != 0) { + Node::add_value_ref(pgf); + db->ref_count++; + } return pgf.as_object(); } PGF_API_END diff --git a/src/runtime/python/ffi.c b/src/runtime/python/ffi.c index 4fbf3e07f..4df306b62 100644 --- a/src/runtime/python/ffi.c +++ b/src/runtime/python/ffi.c @@ -159,12 +159,18 @@ PyList_AsPgfPrintContext(PyObject *pylist) PyErr_SetString(PyExc_TypeError, "variable argument in context must be a string"); return NULL; } - PgfText *input = PyUnicode_AsPgfText(item); - // TODO a better way to copy into this->name? - PgfPrintContext *this = (PgfPrintContext *)PyMem_RawMalloc(sizeof(PgfPrintContext *) + sizeof(PgfText) + input->size + 1); + if (PyUnicode_READY(item) != 0) { + return NULL; + } + + Py_ssize_t size; + const char *enc = PyUnicode_AsUTF8AndSize(item, &size); + + PgfPrintContext *this = (PgfPrintContext *)PyMem_RawMalloc(sizeof(PgfPrintContext) + size + 1); this->next = ctxt; - memcpy(&this->name, input, sizeof(PgfText)+input->size+1); + this->name.size = size; + memcpy(&this->name.text, enc, size+1); ctxt = this; } @@ -291,6 +297,7 @@ lint(PgfUnmarshaller *this, size_t size, uintmax_t *v) Py_DECREF(i); i = tmp; } + Py_DECREF(intShifter); if (PyErr_Occurred()) { return 0; } @@ -363,42 +370,61 @@ match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit) PyObject *pyobj = (PyObject *)lit; if (PyLong_Check(pyobj)) { - PyObject *intShifter = PyLong_FromUnsignedLong(pow(10, floor(log10(ULONG_MAX)))); + PyObject *intShifter = PyLong_FromUnsignedLong(LINT_BASE); // determine size size_t size = 1; - PyObject *x = PyNumber_Absolute(PyNumber_Long(pyobj)); // make a copy, ignore sign + PyObject *x = PyNumber_Absolute(pyobj); // make a copy, ignore sign while (PyObject_RichCompareBool(x, intShifter, Py_GE) == 1) { size++; - x = PyNumber_FloorDivide(x, intShifter); + PyObject *tmp = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(x); + x = tmp; } + Py_DECREF(x); // chop up into chunks, always positive - bool isPos = PyObject_RichCompareBool(pyobj, PyLong_FromLong(0), Py_GE) == 1; - x = PyNumber_Absolute(PyNumber_Long(pyobj)); // make a copy, ignore sign + PyObject *zero = PyLong_FromLong(0); + bool isPos = PyObject_RichCompareBool(pyobj, zero, Py_GE) == 1; + Py_DECREF(zero); + x = PyNumber_Absolute(pyobj); // make a copy, ignore sign uintmax_t *i = PyMem_RawMalloc(sizeof(uintmax_t)*size); // TODO when does this get freed? for (int n = size-1; n > 0; n--) { PyObject *rem = PyNumber_Remainder(x, intShifter); i[n] = PyLong_AsUnsignedLong(rem); - x = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(rem); + PyObject *tmp = PyNumber_FloorDivide(x, intShifter); + Py_DECREF(x); + x = tmp; } + Py_DECREF(intShifter); + // first chunk, re-applying polarity if (isPos) i[0] = PyLong_AsLong(x); else - i[0] = PyLong_AsLong(PyNumber_Negative(x)); + i[0] = -PyLong_AsLong(x); + + Py_DECREF(x); if (PyErr_Occurred()) { return 0; } - return u->vtbl->lint(u, size, i); + + object res = u->vtbl->lint(u, size, i); + + PyMem_RawFree(i); + + return res; } else if (PyFloat_Check(pyobj)) { double d = PyFloat_AsDouble(pyobj); return u->vtbl->lflt(u, d); } else if (PyUnicode_Check(pyobj)) { PgfText *t = PyUnicode_AsPgfText(pyobj); - return u->vtbl->lstr(u, t); + object res = u->vtbl->lstr(u, t); + FreePgfText(t); + return res; } else { PyErr_SetString(PyExc_TypeError, "unable to match on literal"); return 0; @@ -413,7 +439,10 @@ match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr) if (PyObject_TypeCheck(pyobj, &pgf_ExprAbsType)) { ExprAbsObject *eabs = (ExprAbsObject *)expr; long bt = eabs->bind_type == Py_True ? 0 : 1; - return u->vtbl->eabs(u, bt, PyUnicode_AsPgfText(eabs->name), (PgfExpr) eabs->body); + PgfText *name = PyUnicode_AsPgfText(eabs->name); + object res = u->vtbl->eabs(u, bt, name, (PgfExpr) eabs->body); + FreePgfText(name); + return res; } else if (PyObject_TypeCheck(pyobj, &pgf_ExprAppType)) { ExprAppObject *eapp = (ExprAppObject *)expr; @@ -429,7 +458,10 @@ match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr) } else if (PyObject_TypeCheck(pyobj, &pgf_ExprFunType)) { ExprFunObject *efun = (ExprFunObject *)expr; - return u->vtbl->efun(u, PyUnicode_AsPgfText(efun->name)); + PgfText *name = PyUnicode_AsPgfText(efun->name); + object res = u->vtbl->efun(u, name); + FreePgfText(name); + return res; } else if (PyObject_TypeCheck(pyobj, &pgf_ExprVarType)) { ExprVarObject *evar = (ExprVarObject *)expr; @@ -480,6 +512,7 @@ match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty) free(hypos[i].cid); Py_DECREF(hypos[i].type); } + PyMem_Free(hypos); FreePgfText(cat); return res; diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 5e27ab7f2..02d9a756a 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -150,6 +150,12 @@ PGF_categoryContext(PGFObject *self, PyObject *args) PyObject *contexts = PyList_FromHypos(hypos, n_hypos); + for (size_t i = 0; i < n_hypos; i++) { + free(hypos[i].cid); + Py_DECREF((PyObject *)hypos[i].type); + } + free(hypos); + return contexts; } diff --git a/src/runtime/python/transactions.c b/src/runtime/python/transactions.c index c2894f550..f2c5d5249 100644 --- a/src/runtime/python/transactions.c +++ b/src/runtime/python/transactions.c @@ -29,6 +29,7 @@ PGF_checkoutBranch(PGFObject *self, PyObject *args) return NULL; } + pgf_free_revision(self->db, self->revision); self->revision = rev; Py_RETURN_TRUE; @@ -202,8 +203,14 @@ Transaction_createCategory(TransactionObject *self, PyObject *args) PgfExn err; pgf_create_category(self->pgf->db, self->revision, catname, n_hypos, context, prob, &marshaller, &err); + FreePgfText(catname); - if (handleError(err) != PGF_EXN_NONE) { + for (Py_ssize_t i = 0; i < n_hypos; i++) { + FreePgfText(context[i].cid); + } + PyMem_Free(context); + + if (handleError(err) != PGF_EXN_NONE) { return NULL; }