diff --git a/src/runtime/python/ffi.c b/src/runtime/python/ffi.c index 2315b5537..944a615b9 100644 --- a/src/runtime/python/ffi.c +++ b/src/runtime/python/ffi.c @@ -323,7 +323,8 @@ match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty) TypeObject *type = (TypeObject *)ty; Py_ssize_t n_hypos = PyList_Size(type->hypos); - PgfTypeHypo *hypos = alloca(sizeof(PgfTypeHypo)*n_hypos); + PgfTypeHypo hypos[n_hypos]; + // PgfTypeHypo *hypos = alloca(sizeof(PgfTypeHypo)*n_hypos); for (Py_ssize_t i = 0; i < n_hypos; i++) { PyObject *hytup = (PyObject *)PyList_GetItem(type->hypos, i); hypos[i].bind_type = PyLong_AsLong(PyTuple_GetItem(hytup, 0)); @@ -338,7 +339,8 @@ match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty) } Py_ssize_t n_exprs = PyList_Size(type->exprs); - PgfExpr *exprs = alloca(sizeof(PgfExpr)*n_exprs); + PgfExpr exprs[n_exprs]; + // PgfExpr *exprs = alloca(sizeof(PgfExpr)*n_exprs); for (Py_ssize_t i = 0; i < n_exprs; i++) { exprs[i] = (PgfExpr)PyList_GetItem(type->exprs, i); Py_INCREF(exprs[i]); diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index cc5337886..10fb5653d 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -287,6 +287,28 @@ PGF_functionIsConstructor(PGFObject *self, PyObject *args) return PyBool_FromLong(isCon); } +static PyObject * +PGF_functionProbability(PGFObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "s#", &s, &size)) + return NULL; + + PgfText *funname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1); + memcpy(funname->text, s, size+1); + funname->size = size; + + PgfExn err; + prob_t prob = pgf_function_prob(self->db, self->revision, funname, &err); + PyMem_Free(funname); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } + + return PyFloat_FromDouble((double)prob); +} + static PyGetSetDef PGF_getseters[] = { {"abstractName", (getter)PGF_getAbstractName, NULL, @@ -324,6 +346,9 @@ static PyMethodDef PGF_methods[] = { {"functionIsConstructor", (PyCFunction)PGF_functionIsConstructor, METH_VARARGS, "Checks whether a function is a constructor" }, + {"functionProbability", (PyCFunction)PGF_functionProbability, METH_VARARGS, + "Returns the probability of a function" + }, {"newTransaction", (PyCFunction)PGF_newTransaction, METH_VARARGS, "Create new transaction" diff --git a/src/runtime/python/tests/test_transactions.py b/src/runtime/python/tests/test_transactions.py index 6e7d52a37..c2932fc90 100644 --- a/src/runtime/python/tests/test_transactions.py +++ b/src/runtime/python/tests/test_transactions.py @@ -1,8 +1,9 @@ import pytest from pgf import * +import math ty = readType("(N -> N) -> P (s z)") -prob = 3.142 +prob = math.pi @pytest.fixture(scope="module") def gr1(): @@ -12,7 +13,7 @@ def gr1(): def gr2(gr1): t = gr1.newTransaction() t.createFunction("foo", ty, 0, prob), - # t.createCategory("Q", [(BIND_TYPE_EXPLICIT, "x", ty)], prob) + t.createCategory("Q", [(BIND_TYPE_EXPLICIT, "x", ty)], prob) assert t.commit() return gr1 @@ -20,7 +21,7 @@ def gr2(gr1): def gr3(gr1): with gr1.newTransaction("bar_branch") as t: t.createFunction("bar", ty, 0, prob), - # t.createCategory("R", [(BIND_TYPE_EXPLICIT, "x", ty)], prob) + t.createCategory("R", [(BIND_TYPE_EXPLICIT, "x", ty)], prob) return gr1 # gr1 @@ -35,26 +36,29 @@ def test_original_function_type(gr1): with pytest.raises(KeyError): gr1.functionType("foo") -# def test_original_function_prob(gr1): -# with pytest.raises(KeyError): -# gr1.functionProbability("foo") +def test_original_function_prob(gr1): + # with pytest.raises(KeyError): + # gr1.functionProbability("foo") + assert gr1.functionProbability("foo") == float('inf') # gr2 def test_extended_functions(gr2): assert gr2.functions == ["c", "foo", "ind", "s", "z"] -# def test_extended_categories(gr2): -# assert gr2.categories == ["Float","Int","N","P","Q","S","String"] -# -# def test_extended_category_context(gr2): -# assert gr2.categoryContext("Q") == [(BIND_TYPE_EXPLICIT, "x", ty)] +def test_extended_categories(gr2): + assert gr2.categories == ["Float","Int","N","P","Q","S","String"] + +def test_extended_category_context(gr2): + assert gr2.categoryContext("Q") == [(BIND_TYPE_EXPLICIT, "x", ty)] def test_extended_function_type(gr2): assert gr2.functionType("foo") == ty -# def test_extended_function_prob(gr2): -# assert gr2.functionProbability("foo") == prob +def test_extended_function_prob(gr2): + # TODO: can't we get higher precision? + # assert gr2.functionProbability("foo") == prob + assert math.isclose(gr2.functionProbability("foo"), prob, rel_tol=1e-06) # gr3 diff --git a/src/runtime/python/transactions.c b/src/runtime/python/transactions.c index 3f3734d5f..b6c5db408 100644 --- a/src/runtime/python/transactions.c +++ b/src/runtime/python/transactions.c @@ -104,16 +104,25 @@ Transaction_createCategory(TransactionObject *self, PyObject *args) { const char *s; Py_ssize_t size; + PyObject *hypos; float prob = 0.0; - if (!PyArg_ParseTuple(args, "s#f", &s, &size, prob)) + if (!PyArg_ParseTuple(args, "s#O!f", &s, &size, &PyList_Type, &hypos, prob)) return NULL; PgfText *catname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1); memcpy(catname->text, s, size+1); catname->size = size; - Py_ssize_t n_hypos = 0; - PgfTypeHypo *context = NULL; + Py_ssize_t n_hypos = PyList_Size(hypos); + PgfTypeHypo context[n_hypos]; + // PgfTypeHypo *context = alloca(sizeof(PgfTypeHypo)*n_hypos); + for (Py_ssize_t i = 0; i < n_hypos; i++) { + PyObject *hytup = (PyObject *)PyList_GetItem(hypos, i); + context[i].bind_type = PyLong_AsLong(PyTuple_GetItem(hytup, 0)); + context[i].cid = PyUnicode_AsPgfText(PyTuple_GetItem(hytup, 1)); + context[i].type = (PgfType) PyTuple_GetItem(hytup, 2); + Py_INCREF(context[i].type); + } PgfExn err; pgf_create_category(self->pgf->db, self->revision, catname, n_hypos, context, prob, &marshaller, &err);