Type initialiser accepts sequences, stores internally as tuples. Add tests which try to break things.

This commit is contained in:
John J. Camilleri
2021-09-28 11:58:22 +02:00
parent 388829d63d
commit 16eb5f1a89
7 changed files with 162 additions and 112 deletions

View File

@@ -23,16 +23,24 @@ Type_init(TypeObject *self, PyObject *args, PyObject *kwds)
PyObject* hypos;
PyObject* name;
PyObject* exprs;
if (!PyArg_ParseTuple(args, "O!UO!", &PyList_Type, &hypos, &name, &PyList_Type, &exprs)) {
if (!PyArg_ParseTuple(args, "OUO", &hypos, &name, &exprs)) {
return -1;
}
if (!PySequence_Check(hypos)) {
PyErr_SetString(PyExc_TypeError, "hypotheses must be iterable");
return -1;
}
if (!PySequence_Check(exprs)) {
PyErr_SetString(PyExc_TypeError, "expressions must be a sequence");
return -1;
}
for (Py_ssize_t i = 0; i < PyList_Size(hypos); i++) {
// if (!PyObject_TypeCheck(PyList_GetItem(hypos, i), &pgf_HypoType)) {
for (Py_ssize_t i = 0; i < PySequence_Size(hypos); i++) {
// if (!PyObject_TypeCheck(PySequence_GetItem(hypos, i), &pgf_HypoType)) {
// PyErr_SetString(PyExc_TypeError, "invalid hypo in Type initialisation");
// return -1;
// }
PyObject *tup = PyList_GetItem(hypos, i);
PyObject *tup = PySequence_GetItem(hypos, i);
if (!PyObject_TypeCheck(tup, &PyTuple_Type)) {
PyErr_SetString(PyExc_TypeError, "hypothesis must be a tuple");
return -1;
@@ -51,15 +59,15 @@ Type_init(TypeObject *self, PyObject *args, PyObject *kwds)
}
}
for (Py_ssize_t i = 0; i < PyList_Size(exprs); i++) {
if (!PyObject_TypeCheck(PyList_GetItem(exprs, i), &pgf_ExprType)) {
for (Py_ssize_t i = 0; i < PySequence_Size(exprs); i++) {
if (!PyObject_TypeCheck(PySequence_GetItem(exprs, i), &pgf_ExprType)) {
PyErr_SetString(PyExc_TypeError, "invalid expression in Type initialisation");
return -1;
}
}
self->hypos = hypos;
self->hypos = PySequence_Tuple(hypos);
self->name = name;
self->exprs = exprs;
self->exprs = PySequence_Tuple(exprs);
Py_INCREF(self->hypos);
Py_INCREF(self->name);
Py_INCREF(self->exprs);
@@ -94,18 +102,18 @@ Type_richcompare(TypeObject *t1, PyObject *p2, int op)
if (PyUnicode_Compare(t1->name, t2->name) != 0) goto done;
if (PyList_Size(t1->hypos) != PyList_Size(t2->hypos)) goto done;
for (Py_ssize_t n = 0; n < PyList_Size(t1->hypos); n++) {
PyObject *h1 = PyList_GetItem(t1->hypos, n);
PyObject *h2 = PyList_GetItem(t2->hypos, n);
if (PyTuple_Size(t1->hypos) != PyTuple_Size(t2->hypos)) goto done;
for (Py_ssize_t n = 0; n < PyTuple_Size(t1->hypos); n++) {
PyObject *h1 = PyTuple_GetItem(t1->hypos, n);
PyObject *h2 = PyTuple_GetItem(t2->hypos, n);
if (!PyObject_RichCompareBool(h1, h2, Py_EQ))
goto done;
}
if (PyList_Size(t1->exprs) != PyList_Size(t2->exprs)) goto done;
for (Py_ssize_t n = 0; n < PyList_Size(t1->exprs); n++) {
PyObject *e1 = PyList_GetItem(t1->exprs, n);
PyObject *e2 = PyList_GetItem(t2->exprs, n);
if (PyTuple_Size(t1->exprs) != PyTuple_Size(t2->exprs)) goto done;
for (Py_ssize_t n = 0; n < PyTuple_Size(t1->exprs); n++) {
PyObject *e1 = PyTuple_GetItem(t1->exprs, n);
PyObject *e2 = PyTuple_GetItem(t2->exprs, n);
if (!PyObject_RichCompareBool(e1, e2, Py_EQ))
goto done;
}
@@ -128,9 +136,9 @@ static PyMethodDef Type_methods[] = {
};
static PyMemberDef Type_members[] = {
{"hypos", T_OBJECT_EX, offsetof(TypeObject, hypos), READONLY, "list of hypotheses in the type signature"},
{"hypos", T_OBJECT_EX, offsetof(TypeObject, hypos), READONLY, "hypotheses in the type signature"},
{"cat", T_OBJECT_EX, offsetof(TypeObject, name), READONLY, "name of the category"},
{"exprs", T_OBJECT_EX, offsetof(TypeObject, exprs), READONLY, "list of indices for the category"},
{"exprs", T_OBJECT_EX, offsetof(TypeObject, exprs), READONLY, "indices for the category"},
{NULL} /* Sentinel */
};

View File

@@ -8,9 +8,9 @@
typedef struct {
PyObject_HEAD
PyObject *hypos; // PyListObject of PyTupleObject: (PyBool, PyUnicodeObject, TypeObject)
PyObject *hypos; // PyTupleObject of PyTupleObject: (PyBool, PyUnicodeObject, TypeObject)
PyObject *name; // PyUnicodeObject
PyObject *exprs; // PyListObject of ExprObject
PyObject *exprs; // PyTupleObject of ExprObject
} TypeObject;
PyTypeObject pgf_TypeType;

View File

@@ -61,18 +61,18 @@ PyUnicode_FromPgfText(PgfText *text)
}
PgfTypeHypo *
PyList_AsHypos(PyObject *pylist, Py_ssize_t *n_hypos)
PySequence_AsHypos(PyObject *pyseq, Py_ssize_t *n_hypos)
{
if (!PyList_Check(pylist)) {
PyErr_SetString(PyExc_TypeError, "hypotheses must be a list");
if (!PySequence_Check(pyseq)) {
PyErr_SetString(PyExc_TypeError, "hypotheses must be a sequence");
return NULL;
}
Py_ssize_t n = PyList_Size(pylist);
Py_ssize_t n = PySequence_Size(pyseq);
*n_hypos = n;
PgfTypeHypo *hypos = PyMem_RawMalloc(sizeof(PgfTypeHypo)*n);
for (Py_ssize_t i = 0; i < n; i++) {
// PyObject *item = PyList_GetItem(pylist, i);
// PyObject *item = PySequence_GetItem(pyseq, i);
// if (!PyObject_TypeCheck(item, &pgf_HypoType)) {
// PyErr_SetString(PyExc_TypeError, "hypothesis must be of type Hypo");
// return NULL;
@@ -82,7 +82,7 @@ PyList_AsHypos(PyObject *pylist, Py_ssize_t *n_hypos)
// hypos[i].cid = PyUnicode_AsPgfText(hypo->cid);
// hypos[i].type = (PgfType) hypo->type;
PyObject *tup = PyList_GetItem(pylist, i);
PyObject *tup = PySequence_GetItem(pyseq, i);
if (!PyTuple_Check(tup)) {
PyErr_SetString(PyExc_TypeError, "hypothesis must be a tuple");
return NULL;
@@ -317,12 +317,12 @@ dtyp(PgfUnmarshaller *this, int n_hypos, PgfTypeHypo *hypos, PgfText *cat, int n
{
TypeObject *pytype = (TypeObject *)pgf_TypeType.tp_alloc(&pgf_TypeType, 0);
pytype->hypos = PyList_FromHypos(hypos, n_hypos);
pytype->hypos = PySequence_Tuple(PyList_FromHypos(hypos, n_hypos));
pytype->name = PyUnicode_FromStringAndSize(cat->text, cat->size);
pytype->exprs = PyList_New(n_exprs);
pytype->exprs = PyTuple_New(n_exprs);
for (int i = 0; i < n_exprs; i++) {
PyObject *expr = (PyObject *)exprs[i];
PyList_SetItem(pytype->exprs, i, expr);
PyTuple_SetItem(pytype->exprs, i, expr);
Py_INCREF(expr);
}
@@ -454,19 +454,20 @@ match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty)
TypeObject *type = (TypeObject *)ty;
Py_ssize_t n_hypos;
PgfTypeHypo *hypos = PyList_AsHypos(type->hypos, &n_hypos);
if (PyErr_Occurred())
PgfTypeHypo *hypos = PySequence_AsHypos(type->hypos, &n_hypos);
if (hypos == NULL) {
return 0;
}
PgfText *cat = PyUnicode_AsPgfText(type->name);
if (cat == NULL) {
return 0;
}
Py_ssize_t n_exprs = PyList_Size(type->exprs);
Py_ssize_t n_exprs = PySequence_Size(type->exprs);
PgfExpr exprs[n_exprs];
for (Py_ssize_t i = 0; i < n_exprs; i++) {
exprs[i] = (PgfExpr)PyList_GetItem(type->exprs, i);
exprs[i] = (PgfExpr)PySequence_GetItem(type->exprs, i);
Py_INCREF(exprs[i]);
}

View File

@@ -20,7 +20,7 @@ PgfText *CString_AsPgfText(const char *s, size_t size);
PgfText *PyUnicode_AsPgfText(PyObject *pystr);
PyObject *PyUnicode_FromPgfText(PgfText *text);
PgfTypeHypo *PyList_AsHypos(PyObject *pylist, Py_ssize_t *n_hypos);
PgfTypeHypo *PySequence_AsHypos(PyObject *pyseq, Py_ssize_t *n_hypos);
PyObject *PyList_FromHypos(PgfTypeHypo *hypos, const size_t n_hypos);
PgfPrintContext *PyList_AsPgfPrintContext(PyObject *pylist);

View File

@@ -219,9 +219,11 @@ def test_Type_getters():
h0 = mkDepHypo("x", Type([], "N", []))
e0 = ExprVar(0)
type = Type([h0], "N", [e0])
assert type.hypos == [h0]
assert len(type.hypos) == 1
assert type.hypos[0] == h0
assert type.cat == "N"
assert type.exprs == [e0]
assert len(type.exprs) == 1
assert type.exprs[0] == e0
with pytest.raises(AttributeError):
type.fake

View File

@@ -0,0 +1,35 @@
import os
import pytest
from pgf import *
@pytest.fixture(scope="module")
def PGF():
return readPGF("../haskell/tests/basic.pgf")
def test_init_Type_tuples():
hypos = [mkDepHypo("x", Type([], "N", []))]
exprs = [ExprVar(0)]
ty = Type(tuple(hypos), "P", tuple(exprs))
assert str(ty) == "(x : N) -> P x"
def test_init_Type_lists():
hypos = [mkDepHypo("x", Type([], "N", []))]
exprs = [ExprVar(0)]
ty = Type(hypos, "P", exprs)
assert str(ty) == "(x : N) -> P x"
def test_Type_modify_shallow():
hypos = [(BIND_TYPE_EXPLICIT, "x", Type([], "N", []))]
exprs = [ExprVar(0)]
ty = Type(hypos, "P", exprs)
hypos.append(None)
assert str(ty) == "(x : N) -> P x"
def test_Type_modify_deep():
hypos = [(BIND_TYPE_EXPLICIT, "x", Type([], "N", []))]
exprs = [ExprVar(0)]
ty = Type(hypos, "P", exprs)
with pytest.raises(AttributeError):
hypos[0][2].exprs.append(None)
assert str(ty) == "(x : N) -> P x"

View File

@@ -184,13 +184,17 @@ Transaction_createCategory(TransactionObject *self, PyObject *args)
Py_ssize_t size;
PyObject *hypos;
prob_t prob = 0.0;
if (!PyArg_ParseTuple(args, "s#O!f", &s, &size, &PyList_Type, &hypos, &prob))
if (!PyArg_ParseTuple(args, "s#Of", &s, &size, &hypos, &prob))
return NULL;
if (!PySequence_Check(hypos)) {
PyErr_SetString(PyExc_TypeError, "context must be a sequence");
return NULL;
}
PgfText *catname = CString_AsPgfText(s, size);
Py_ssize_t n_hypos;
PgfTypeHypo *context = PyList_AsHypos(hypos, &n_hypos);
PgfTypeHypo *context = PySequence_AsHypos(hypos, &n_hypos);
if (PyErr_Occurred()) {
FreePgfText(catname);
return NULL;