diff --git a/src/runtime/python/expr.c b/src/runtime/python/expr.c index f066c0ec8..e617cbc48 100644 --- a/src/runtime/python/expr.c +++ b/src/runtime/python/expr.c @@ -111,30 +111,39 @@ done: } static PyMethodDef Type_methods[] = { -// {"unpack", (PyCFunction)Type_unpack, METH_VARARGS, -// "Decomposes a type into its components" -// }, -// {"__reduce_ex__", (PyCFunction)Type_reduce_ex, METH_VARARGS, -// "This method allows for transparent pickling/unpickling of types." -// }, {NULL} /* Sentinel */ }; -static PyGetSetDef Type_getseters[] = { +static PyObject * +Type_getattro(TypeObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "hypos") == 0) { + return self->hypos; + } else if (PyUnicode_CompareWithASCIIString(attr, "cat") == 0) { + return self->cat; + } else if (PyUnicode_CompareWithASCIIString(attr, "exprs") == 0) { + return self->exprs; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.Type' object has no attribute '%U'", attr); + return NULL; + } +} + +// static PyGetSetDef Type_getseters[] = { // {"hypos", // (getter)Type_getHypos, NULL, -// "this is the list of hypotheses in the type signature", +// "list of hypotheses in the type signature", // NULL}, // {"cat", // (getter)Type_getCat, NULL, -// "this is the name of the category", +// "name of the category", // NULL}, // {"exprs", // (getter)Type_getExprs, NULL, -// "this is the list of indices for the category", +// "list of indices for the category", // NULL}, - {NULL} /* Sentinel */ -}; +// {NULL} /* Sentinel */ +// }; PyTypeObject pgf_TypeType = { PyVarObject_HEAD_INIT(NULL, 0) @@ -154,7 +163,7 @@ PyTypeObject pgf_TypeType = { 0, /*tp_hash */ 0, /*tp_call*/ (reprfunc) Type_str, /*tp_str*/ - 0, /*tp_getattro*/ + (getattrofunc) Type_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -167,7 +176,7 @@ PyTypeObject pgf_TypeType = { 0, /*tp_iternext */ Type_methods, /*tp_methods */ 0, /*tp_members */ - Type_getseters, /*tp_getset */ + 0, //Type_getseters, /*tp_getset */ 0, /*tp_base */ 0, /*tp_dict */ 0, /*tp_descr_get */ @@ -191,19 +200,6 @@ Expr_str(ExprObject *self) } static PyMethodDef Expr_methods[] = { -// {"unpack", (PyCFunction)Expr_unpack, METH_VARARGS, -// "Decomposes an expression into its components" -// }, -// {"visit", (PyCFunction)Expr_visit, METH_VARARGS, -// "Implementation of the visitor pattern for abstract syntax trees. " -// "If e is an expression equal to f a1 .. an then " -// "e.visit(self) calls method self.on_f(a1,..an). " -// "If the method doesn't exist then the method self.default(e) " -// "is called." -// }, -// {"__reduce_ex__", (PyCFunction)Expr_reduce_ex, METH_VARARGS, -// "This method allows for transparent pickling/unpickling of expressions." -// }, {NULL} /* Sentinel */ }; @@ -253,7 +249,7 @@ PyTypeObject pgf_ExprType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ (reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + 0, //(getattrofunc) Expr_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -327,6 +323,21 @@ done: } } +static PyObject * +ExprAbs_getattro(ExprAbsObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "bindType") == 0) { + return self->bindType; + } else if (PyUnicode_CompareWithASCIIString(attr, "var") == 0) { + return self->var; + } else if (PyUnicode_CompareWithASCIIString(attr, "expr") == 0) { + return (PyObject *)self->expr; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprAbs' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprAbsType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -345,7 +356,7 @@ PyTypeObject pgf_ExprAbsType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprAbs_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -415,6 +426,19 @@ done: } } +static PyObject * +ExprApp_getattro(ExprAppObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "e1") == 0) { + return (PyObject *)self->e1; + } else if (PyUnicode_CompareWithASCIIString(attr, "e2") == 0) { + return (PyObject *)self->e2; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprApp' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprAppType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -433,7 +457,7 @@ PyTypeObject pgf_ExprAppType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprApp_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -520,12 +544,23 @@ done: } } +static PyObject * +ExprLit_getattro(ExprLitObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "value") == 0) { + return self->value; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprLit' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprLitType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ - "pgf.ExprLit", /*tp_name*/ - sizeof(ExprLitObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ + "pgf.ExprLit", /*tp_name*/ + sizeof(ExprLitObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ 0, //(destructor)Expr_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ @@ -538,7 +573,7 @@ PyTypeObject pgf_ExprLitType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprLit_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -549,9 +584,9 @@ PyTypeObject pgf_ExprLitType = { 0, /*tp_weaklistoffset */ 0, /*tp_iter */ 0, /*tp_iternext */ - 0, //Expr_methods, /*tp_methods */ + 0, /*tp_methods */ 0, /*tp_members */ - 0, //Expr_getseters, /*tp_getset */ + 0, /*tp_getset */ &pgf_ExprType, /*tp_base */ 0, /*tp_dict */ 0, /*tp_descr_get */ @@ -612,6 +647,17 @@ done: } } +static PyObject * +ExprMeta_getattro(ExprMetaObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "id") == 0) { + return (PyObject *)self->id; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprMeta' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprMetaType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -630,7 +676,7 @@ PyTypeObject pgf_ExprMetaType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprMeta_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -696,6 +742,17 @@ done: } } +static PyObject * +ExprFun_getattro(ExprFunObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "name") == 0) { + return (PyObject *)self->name; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprFun' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprFunType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -714,7 +771,7 @@ PyTypeObject pgf_ExprFunType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprFun_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -788,6 +845,17 @@ done: } } +static PyObject * +ExprVar_getattro(ExprVarObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "index") == 0) { + return (PyObject *)self->index; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprVar' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprVarType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -806,7 +874,7 @@ PyTypeObject pgf_ExprVarType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprVar_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -876,6 +944,19 @@ done: } } +static PyObject * +ExprTyped_getattro(ExprTypedObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "expr") == 0) { + return (PyObject *)self->expr; + } else if (PyUnicode_CompareWithASCIIString(attr, "type") == 0) { + return (PyObject *)self->type; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprTyped' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprTypedType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -894,7 +975,7 @@ PyTypeObject pgf_ExprTypedType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprTyped_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ @@ -960,6 +1041,17 @@ done: } } +static PyObject * +ExprImplArg_getattro(ExprImplArgObject *self, PyObject *attr) +{ + if (PyUnicode_CompareWithASCIIString(attr, "expr") == 0) { + return (PyObject *)self->expr; + } else { + PyErr_Format(PyExc_AttributeError, "'pgf.ExprImplArg' object has no attribute '%U'", attr); + return NULL; + } +} + PyTypeObject pgf_ExprImplArgType = { PyVarObject_HEAD_INIT(NULL, 0) //0, /*ob_size*/ @@ -978,7 +1070,7 @@ PyTypeObject pgf_ExprImplArgType = { 0, //(hashfunc) Expr_hash, /*tp_hash */ 0, //(ternaryfunc) Expr_call, /*tp_call*/ 0, //(reprfunc) Expr_str, /*tp_str*/ - 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + (getattrofunc) ExprImplArg_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 7f1765462..099382f72 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -306,8 +306,6 @@ static PyGetSetDef PGF_getseters[] = { }; static PyMemberDef PGF_members[] = { - // {"revision", T_PYSSIZET, offsetof(PGFObject, revision), READONLY, - // "the revision number of this PGF"}, {NULL} /* Sentinel */ }; @@ -392,7 +390,6 @@ pgf_readPGF(PyObject *self, PyObject *args) PGFObject *py_pgf = (PGFObject *)pgf_PGFType.tp_alloc(&pgf_PGFType, 0); - // Read the PGF grammar. PgfExn err; py_pgf->db = pgf_read_pgf(fpath, &py_pgf->revision, &err); if (handleError(err) != PGF_EXN_NONE) { @@ -413,7 +410,6 @@ pgf_bootNGF(PyObject *self, PyObject *args) PGFObject *py_pgf = (PGFObject *)pgf_PGFType.tp_alloc(&pgf_PGFType, 0); - // Read the PGF grammar. PgfExn err; py_pgf->db = pgf_boot_ngf(fpath, npath, &py_pgf->revision, &err); if (handleError(err) != PGF_EXN_NONE) { @@ -433,7 +429,6 @@ pgf_readNGF(PyObject *self, PyObject *args) PGFObject *py_pgf = (PGFObject *)pgf_PGFType.tp_alloc(&pgf_PGFType, 0); - // Read the NGF grammar. PgfExn err; py_pgf->db = pgf_read_ngf(fpath, &py_pgf->revision, &err); if (handleError(err) != PGF_EXN_NONE) { @@ -457,7 +452,6 @@ pgf_newNGF(PyObject *self, PyObject *args) PGFObject *py_pgf = (PGFObject *)pgf_PGFType.tp_alloc(&pgf_PGFType, 0); - // Read the NGF grammar. PgfExn err; py_pgf->db = pgf_new_ngf(absname, fpath, &py_pgf->revision, &err); FreePgfText(absname); diff --git a/src/runtime/python/tests/test_basic.py b/src/runtime/python/tests/test_basic.py index 161571e32..3310cebfb 100644 --- a/src/runtime/python/tests/test_basic.py +++ b/src/runtime/python/tests/test_basic.py @@ -205,6 +205,16 @@ def test_showType_9(PGF): type = Type([mkDepHypo("x", Type([], "N", [])), mkDepHypo("y", Type([], "P", [ExprVar(0)]))], "S", []) assert showType(["n"], type) == "(x : N) -> (y : P x) -> S" +def test_Type_getters(): + h0 = mkDepHypo("x", Type([], "N", [])) + e0 = ExprVar(0) + type = Type([h0], "N", [e0]) + assert type.hypos == [h0] + assert type.cat == "N" + assert type.exprs == [e0] + with pytest.raises(AttributeError): + type.fake + # expressions def test_readExpr_invalid(): @@ -270,6 +280,13 @@ def test_readExpr_lstr_null(): def test_readExpr_lstr_newline(): assert str(ExprLit("ab\nc")) == "\"ab\\nc\"" +def test_ExprLit_getters(): + assert ExprLit(123).value == 123 + assert ExprLit("123").value == "123" + assert ExprLit(1.23).value == 1.23 + with pytest.raises(AttributeError): + ExprLit(1.23).fake + # expressions: functions def test_readExpr_efun_equality_1(): @@ -324,6 +341,21 @@ def test_readExpr_efun_str_unicode_3(): def test_readExpr_efun_str_unicode_4(): assert str(readExpr("'а\\'б'")) == "'а\\'б'" +def test_ExprApp_getters(): + e1 = ExprFun("f") + e2 = ExprFun("x") + expr = ExprApp(e1, e2) + assert expr.e1 == e1 + assert expr.e2 == e2 + with pytest.raises(AttributeError): + expr.fake + +def test_ExprFun_getters(): + expr = ExprFun("f") + assert expr.name == "f" + with pytest.raises(AttributeError): + expr.fake + # expressions: variables # def test_readExpr_evar_equality_1(): @@ -351,6 +383,12 @@ def test_showExpr_evar_3(): def test_showExpr_evar_4(): assert showExpr(["z", "y", "x"], ExprVar(1)) == "y" +def test_ExprVar_getters(): + expr = ExprVar(456) + assert expr.index == 456 + with pytest.raises(AttributeError): + expr.fake + # expressions: lambda abstractions def test_showExpr_eabs_1(): @@ -397,6 +435,15 @@ def test_showExpr_eabs_freshvars_3(): expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprVar(1)))) assert showExpr([], expr) == "\\v,v1,v2->v1" +def test_ExprAbs_getters(): + e0 = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprVar(1)) + expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", e0) + assert expr.bindType == BIND_TYPE_EXPLICIT + assert expr.var == "v" + assert expr.expr == e0 + with pytest.raises(AttributeError): + expr.fake + # expressions: meta variables def test_readExpr_emeta_1(): @@ -412,6 +459,12 @@ def test_readExpr_emeta_str_1(): def test_readExpr_emeta_str_2(): assert str(readExpr("?42")) == "?42" +def test_ExprMeta_getters(): + expr = ExprMeta(123) + assert expr.id == 123 + with pytest.raises(AttributeError): + expr.fake + # expressions: typed expressions def test_readExpr_emeta_equality(): @@ -419,3 +472,19 @@ def test_readExpr_emeta_equality(): def test_readExpr_emeta_str(): assert str(readExpr("")) == "" + +def test_ExprTyped_getters(): + e = ExprFun("z") + ty = readType("N") + expr = ExprTyped(e, ty) + assert expr.expr == e + assert expr.type == ty + with pytest.raises(AttributeError): + expr.fake + +def test_ExprImplArg_getters(): + e = ExprFun("z") + expr = ExprImplArg(e) + assert expr.expr == e + with pytest.raises(AttributeError): + expr.fake