From a8efc6157999c0500f71074e4951449ec7769cba Mon Sep 17 00:00:00 2001 From: "John J. Camilleri" Date: Mon, 6 Sep 2021 14:06:57 +0200 Subject: [PATCH] Working readType, functionType, unmarshaller for types (except exprs) in Python bindings --- src/runtime/python/compat.h | 28 +++++++++ src/runtime/python/expr.c | 102 ++++++++++++++++--------------- src/runtime/python/expr.h | 9 +-- src/runtime/python/marshaller.c | 26 +++++--- src/runtime/python/pypgf.c | 74 ++++++---------------- src/runtime/python/test_suite.py | 10 +++ 6 files changed, 133 insertions(+), 116 deletions(-) create mode 100644 src/runtime/python/compat.h diff --git a/src/runtime/python/compat.h b/src/runtime/python/compat.h new file mode 100644 index 000000000..a6080e55e --- /dev/null +++ b/src/runtime/python/compat.h @@ -0,0 +1,28 @@ +#ifndef PYPGF_COMPAT_H_ +#define PYPGF_COMPAT_H_ + +#if PY_MAJOR_VERSION >= 3 + // #define PyIntObject PyLongObject + // #define PyInt_Type PyLong_Type + // #define PyInt_Check(op) PyLong_Check(op) + // #define PyInt_CheckExact(op) PyLong_CheckExact(op) + // #define PyInt_FromString PyLong_FromString + // #define PyInt_FromUnicode PyLong_FromUnicode + // #define PyInt_FromLong PyLong_FromLong + // #define PyInt_FromSize_t PyLong_FromSize_t + // #define PyInt_FromSsize_t PyLong_FromSsize_t + // #define PyInt_AsLong PyLong_AsLong + // #define PyInt_AS_LONG PyLong_AS_LONG + // #define PyInt_AsSsize_t PyLong_AsSsize_t + // #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + // #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + + #define PyStringObject PyUnicodeObject + // #define PyString_Check PyUnicode_Check + #define PyString_FromStringAndSize PyUnicode_FromStringAndSize + // #define PyString_FromFormat PyUnicode_FromFormat + // #define PyString_Concat(ps,s) {PyObject* tmp = *(ps); *(ps) = PyUnicode_Concat(tmp,s); Py_DECREF(tmp);} + #define PyString_Compare PyUnicode_Compare +#endif + +#endif // PYPGF_COMPAT_H_ diff --git a/src/runtime/python/expr.c b/src/runtime/python/expr.c index 03fb6d1e2..09726de98 100644 --- a/src/runtime/python/expr.c +++ b/src/runtime/python/expr.c @@ -2,7 +2,7 @@ #include #include -#include "expr.h" +#include "./expr.h" // static ExprObject* // Expr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -665,36 +665,28 @@ // ---------------------------------------------------------------------------- -static TypeObject* -Type_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - TypeObject* self = (TypeObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->master = NULL; - // self->pool = NULL; - // self->type = NULL; - self->cat = NULL; - } +// static TypeObject* +// Type_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +// { +// TypeObject* self = (TypeObject *)type->tp_alloc(type, 0); +// if (self != NULL) { +// self->hypos = NULL; +// self->cat = NULL; +// self->exprs = NULL; +// } +// +// return self; +// } - return self; -} +// static void +// Type_dealloc(TypeObject *self) +// { +// Py_TYPE(self)->tp_free((PyObject*)self); +// } -static void -Type_dealloc(TypeObject* self) -{ - if (self->master != NULL) { - Py_DECREF(self->master); - } - // if (self->pool != NULL) { - // gu_pool_free(self->pool); - // } - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -Type_init(TypeObject *self, PyObject *args, PyObject *kwds) -{ +// static int +// Type_init(TypeObject *self, PyObject *args, PyObject *kwds) +// { // PyObject* py_hypos; // const char* catname_s; // PyObject* py_exprs; @@ -813,9 +805,9 @@ Type_init(TypeObject *self, PyObject *args, PyObject *kwds) // // self->type->exprs[i] = ((ExprObject*) obj)->expr; // } - - return 0; -} +// +// return 0; +// } static PyObject * Type_repr(TypeObject *self) @@ -835,29 +827,43 @@ Type_repr(TypeObject *self) // return pystr; PyErr_SetString(PyExc_TypeError, "Type_repr: not implemented"); - return NULL; -} - -bool pgfTextEqual(PgfText *t1, PgfText *t2) { - if (t1->size != t2->size) return false; - for (size_t i = 0; i < t1->size; i++) { - if (t1->text[i] != t2->text[i]) return false; - } - return true; + Py_RETURN_NOTIMPLEMENTED; } static PyObject * Type_richcompare(TypeObject *t1, TypeObject *t2, int op) { - bool cmp = pgfTextEqual(t1->cat, t2->cat); + bool same = false; + if (PyString_Compare(t1->cat, t2->cat) != 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_GetItem(h1, 0) != PyTuple_GetItem(h2, 0)) goto done; + if (PyString_Compare(PyTuple_GetItem(h1, 1), PyTuple_GetItem(h2, 1)) != 0) goto done; + TypeObject *ht1 = (TypeObject *)PyTuple_GetItem(h1, 2); + TypeObject *ht2 = (TypeObject *)PyTuple_GetItem(h2, 2); + if (Type_richcompare(ht1, ht2, Py_EQ) != Py_True) 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++) { + // ExprObject *e1 = PyList_GetItem(t1->exprs, n); + // ExprObject *e2 = PyList_GetItem(t2->exprs, n); + // if (Expr_richcompare(e1, e2, Py_EQ) != Py_True) goto done; // TODO + // } + + same = true; +done: if (op == Py_EQ) { - if (cmp) Py_RETURN_TRUE; else Py_RETURN_FALSE; + if (same) Py_RETURN_TRUE; else Py_RETURN_FALSE; } else if (op == Py_NE) { - if (cmp) Py_RETURN_FALSE; else Py_RETURN_TRUE; + if (same) Py_RETURN_FALSE; else Py_RETURN_TRUE; } else { PyErr_SetString(PyExc_TypeError, "comparison operation not supported"); - return NULL; + Py_RETURN_NOTIMPLEMENTED; } } @@ -1044,7 +1050,7 @@ PyTypeObject pgf_TypeType = { "pgf.Type", /*tp_name*/ sizeof(TypeObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor) Type_dealloc, /*tp_dealloc*/ + 0, //(destructor) Type_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -1075,7 +1081,7 @@ PyTypeObject pgf_TypeType = { 0, /*tp_descr_get */ 0, /*tp_descr_set */ 0, /*tp_dictoffset */ - (initproc) Type_init, /*tp_init */ + 0, //(initproc) Type_init, /*tp_init */ 0, /*tp_alloc */ - (newfunc) Type_new, /*tp_new */ + 0, //(newfunc) Type_new, /*tp_new */ }; diff --git a/src/runtime/python/expr.h b/src/runtime/python/expr.h index 54a989d3a..e305eccdd 100644 --- a/src/runtime/python/expr.h +++ b/src/runtime/python/expr.h @@ -6,12 +6,13 @@ #include +#include "./compat.h" + typedef struct { PyObject_HEAD - PyObject* master; - // GuPool* pool; - // PgfType* type; - PgfText *cat; + PyObject *hypos; // PyListObject of PyTupleObject: (bind_type: int, cid: string, type: TypeObject) + PyObject *cat; // PyStringObject + PyObject *exprs; // PyListObject of ExprObject } TypeObject; extern PyTypeObject pgf_TypeType; diff --git a/src/runtime/python/marshaller.c b/src/runtime/python/marshaller.c index 5ab3ebe08..22f87045d 100644 --- a/src/runtime/python/marshaller.c +++ b/src/runtime/python/marshaller.c @@ -1,7 +1,9 @@ -// #define PY_SSIZE_T_CLEAN -// #include +#define PY_SSIZE_T_CLEAN +#include #include + +#include "./compat.h" #include "./expr.h" /* The PgfUnmarshaller structure tells the runtime how to create @@ -71,12 +73,22 @@ PgfLiteral lstr(PgfUnmarshaller *this, PgfText *v) PgfType dtyp(PgfUnmarshaller *this, int n_hypos, PgfTypeHypo *hypos, PgfText *cat, int n_exprs, PgfExpr *exprs) { - PgfText *catname = (PgfText*) malloc(sizeof(PgfText)+cat->size+1); - memcpy(catname->text, cat->text, cat->size+1); - catname->size = cat->size; + TypeObject *pytype = (TypeObject *)pgf_TypeType.tp_alloc(&pgf_TypeType, 0); - TypeObject *pytype = (TypeObject*) pgf_TypeType.tp_alloc(&pgf_TypeType, 0); - pytype->cat = catname; + pytype->hypos = PyList_New(0); + for (int i = 0; i < n_hypos; i++) { + PgfTypeHypo *hypo = hypos + i; + PyObject *tup = PyTuple_New(3); + PyTuple_SetItem(tup, 0, PyLong_FromLong(hypo->bind_type == PGF_BIND_TYPE_EXPLICIT ? 0 : 1)); // TODO + PyTuple_SetItem(tup, 1, PyString_FromStringAndSize(hypo->cid->text, hypo->cid->size)); + PyTuple_SetItem(tup, 2, (PyObject *)hypo->type); + Py_INCREF(hypo->type); + PyList_Append(pytype->hypos, tup); + } + + pytype->cat = PyString_FromStringAndSize(cat->text, cat->size); + + pytype->exprs = PyList_New(0); return (PgfType) pytype; } diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 387920b6f..8c3afa189 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -3,34 +3,11 @@ #include "structmember.h" #include +#include "./compat.h" #include "./expr.h" #include "./marshaller.h" -#if PY_MAJOR_VERSION >= 3 - #define PyIntObject PyLongObject - #define PyInt_Type PyLong_Type - #define PyInt_Check(op) PyLong_Check(op) - #define PyInt_CheckExact(op) PyLong_CheckExact(op) - #define PyInt_FromString PyLong_FromString - #define PyInt_FromUnicode PyLong_FromUnicode - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyInt_FromSsize_t PyLong_FromSsize_t - #define PyInt_AsLong PyLong_AsLong - #define PyInt_AS_LONG PyLong_AS_LONG - #define PyInt_AsSsize_t PyLong_AsSsize_t - #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask - #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask -#endif - -#if PY_MAJOR_VERSION >= 3 - #define PyString_Check PyUnicode_Check - #define PyString_FromStringAndSize PyUnicode_FromStringAndSize - #define PyString_FromFormat PyUnicode_FromFormat - #define PyString_Concat(ps,s) {PyObject* tmp = *(ps); *(ps) = PyUnicode_Concat(tmp,s); Py_DECREF(tmp);} -#endif - -static PyObject* PGFError; +static PyObject *PGFError; // static PyObject* ParseError; @@ -38,7 +15,7 @@ static PyObject* PGFError; typedef struct { PyObject_HEAD - PgfPGF* pgf; + PgfPGF *pgf; } PGFObject; // typedef struct IterObject { @@ -1983,33 +1960,25 @@ PGF_functionsByCat(PGFObject* self, PyObject *args) return functions; } -static TypeObject* -PGF_functionType(PGFObject* self, PyObject *args) +static TypeObject * +PGF_functionType(PGFObject *self, PyObject *args) { - const char* s; + const char *s; Py_ssize_t size; if (!PyArg_ParseTuple(args, "s#", &s, &size)) return NULL; - PgfText* funname = (PgfText*) alloca(sizeof(PgfText)+size+1); + PgfText *funname = (PgfText *)alloca(sizeof(PgfText)+size+1); memcpy(funname->text, s, size+1); funname->size = size; PgfType type = pgf_function_type(self->pgf, funname, &unmarshaller); - // if (type == NULL) { - // PyErr_Format(PyExc_KeyError, "Function '%s' is not defined", funname->text); - // return NULL; - // } - // - // TypeObject* pytype = (TypeObject*) pgf_TypeType.tp_alloc(&pgf_TypeType, 0); - // if (pytype == NULL) - // return NULL; - // // pytype->pool = NULL; - // pytype->type = &type; - // pytype->master = (PyObject*) self; - // Py_XINCREF(self); - // return pytype; - return (TypeObject*) type; + if (type == 0) { + PyErr_Format(PyExc_KeyError, "Function '%s' is not defined", funname->text); + return NULL; + } + + return (TypeObject *)type; } // static IterObject* @@ -2525,15 +2494,15 @@ pgf_readNGF(PyObject *self, PyObject *args) // return pyexpr; // } -static TypeObject* +static TypeObject * pgf_readType(PyObject *self, PyObject *args) { - const char* s; + const char *s; Py_ssize_t size; if (!PyArg_ParseTuple(args, "s#", &s, &size)) return NULL; - PgfText* input = (PgfText*) alloca(sizeof(PgfText)+size+1); + PgfText *input = (PgfText *)alloca(sizeof(PgfText)+size+1); memcpy(input->text, s, size+1); input->size = size; @@ -2543,16 +2512,7 @@ pgf_readType(PyObject *self, PyObject *args) return NULL; } - // TypeObject* pytype = (TypeObject*) pgf_TypeType.tp_alloc(&pgf_TypeType, 0); - // if (pytype == NULL) - // return NULL; - // // pytype->pool = NULL; - // pytype->type = &type; - // pytype->master = (PyObject*) self; - // Py_XINCREF(self); - // return pytype; - - return (TypeObject*) type; + return (TypeObject *)type; } static PyMethodDef module_methods[] = { diff --git a/src/runtime/python/test_suite.py b/src/runtime/python/test_suite.py index ec8793f80..00c9b4d36 100644 --- a/src/runtime/python/test_suite.py +++ b/src/runtime/python/test_suite.py @@ -94,6 +94,9 @@ def test_readType_equality_1(): def test_readType_equality_2(): assert pgf.readType("A -> B") == pgf.readType("A->B") +def test_readType_equality_3(): + assert pgf.readType("A -> B -> C") == pgf.readType("A->B -> C") + def test_readType_inequality_1(): assert pgf.readType("A") != pgf.readType("B") @@ -109,6 +112,13 @@ def test_functionType_2(PGF): def test_functionType_3(PGF): assert PGF.functionType("c") == pgf.readType("N -> S") +def test_functionType_non_existant(PGF): + with pytest.raises(KeyError): + assert PGF.functionType("cbx") + +def test_functionType_wrong(PGF): + assert PGF.functionType("c") != pgf.readType("N -> S -> X") + def test_startCat(PGF): with pytest.raises(pgf.PGFError): PGF.startCat()