diff --git a/src/runtime/haskell/tests/basic.hs b/src/runtime/haskell/tests/basic.hs index a2a28aaba..e7e977520 100644 --- a/src/runtime/haskell/tests/basic.hs +++ b/src/runtime/haskell/tests/basic.hs @@ -21,10 +21,10 @@ main = do ,TestCase (assertBool "type of z" (eqJust (readType "N") (functionType gr "z"))) ,TestCase (assertBool "type of s" (eqJust (readType "N->N") (functionType gr "s"))) ,TestCase (assertBool "type of c" (eqJust (readType "N->S") (functionType gr "c"))) - ,TestCase (assertEqual "category context 1" [] (categoryContext gr "N")) - ,TestCase (assertEqual "category context 2" [] (categoryContext gr "S")) - ,TestCase (assertEqual "category context 3" [(Explicit,"_",DTyp [] "N" [])] (categoryContext gr "P")) - ,TestCase (assertEqual "category context 4" [] (categoryContext gr "X")) -- no such category + ,TestCase (assertEqual "category context 1" (Just []) (categoryContext gr "N")) + ,TestCase (assertEqual "category context 2" (Just []) (categoryContext gr "S")) + ,TestCase (assertEqual "category context 3" (Just [(Explicit,"_",DTyp [] "N" [])]) (categoryContext gr "P")) + ,TestCase (assertEqual "category context 4" Nothing (categoryContext gr "X")) -- no such category ,TestCase (assertEqual "function is constructor 1" True (functionIsConstructor gr "s")) ,TestCase (assertEqual "function is constructor 2" True (functionIsConstructor gr "z")) ,TestCase (assertEqual "function is constructor 3" True (functionIsConstructor gr "c")) diff --git a/src/runtime/haskell/tests/transactions.hs b/src/runtime/haskell/tests/transactions.hs index 37e75776e..fbd62f0d1 100644 --- a/src/runtime/haskell/tests/transactions.hs +++ b/src/runtime/haskell/tests/transactions.hs @@ -28,16 +28,16 @@ main = do ,TestCase (assertEqual "original categories" ["Float","Int","N","P","S","String"] (categories gr1)) ,TestCase (assertEqual "extended categories" ["Float","Int","N","P","Q","S","String"] (categories gr2)) ,TestCase (assertEqual "branched categories" ["Float","Int","N","P","R","S","String"] (categories gr3)) - ,TestCase (assertEqual "Q context" [(Explicit,"x",ty)] (categoryContext gr2 "Q")) - ,TestCase (assertEqual "R context" [(Explicit,"x",ty)] (categoryContext gr3 "R")) + ,TestCase (assertEqual "Q context" (Just [(Explicit,"x",ty)]) (categoryContext gr2 "Q")) + ,TestCase (assertEqual "R context" (Just [(Explicit,"x",ty)]) (categoryContext gr3 "R")) ,TestCase (assertEqual "reduced functions" ["c","s","z"] (functions gr6)) ,TestCase (assertEqual "reduced categories" ["Float","Int","N","P","String"] (categories gr6)) ,TestCase (assertEqual "old function type" Nothing (functionType gr1 "foo")) ,TestCase (assertEqual "new function type" (Just ty) (functionType gr2 "foo")) - ,TestCase (assertEqual "old function prob" (-log 0) (functionProb gr1 "foo")) - ,TestCase (assertEqual "new function prob" pi (functionProb gr2 "foo")) + ,TestCase (assertEqual "old function prob" (-log 0) (functionProbability gr1 "foo")) + ,TestCase (assertEqual "new function prob" pi (functionProbability gr2 "foo")) ] - + performMajorGC if (errors c == 0) && (failures c == 0) diff --git a/src/runtime/python/expr.c b/src/runtime/python/expr.c index dcd5b16e7..82ac1f028 100644 --- a/src/runtime/python/expr.c +++ b/src/runtime/python/expr.c @@ -242,10 +242,10 @@ ExprMeta_init(ExprMetaObject *self, PyObject *args, PyObject *kwds) return -1; } if (lit == NULL) { - self->index = PyLong_FromLong(0); + self->id = PyLong_FromLong(0); return 0; } else if (PyLong_Check(lit)) { - self->index = lit; + self->id = lit; return 0; } else { PyErr_SetString(PyExc_TypeError, "invalid argument in ExprMeta_init"); @@ -257,7 +257,7 @@ static PyObject * ExprMeta_richcompare(ExprMetaObject *t1, ExprMetaObject *t2, int op) { bool same = false; - if (PyObject_RichCompareBool(t1->index, t2->index, Py_EQ) != 1) goto done; + if (PyObject_RichCompareBool(t1->id, t2->id, Py_EQ) != 1) goto done; same = true; done: @@ -317,6 +317,96 @@ PyTypeObject pgf_ExprMetaType = { // ---------------------------------------------------------------------------- +static ExprVarObject * +ExprVar_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) +{ + ExprVarObject* self = (ExprVarObject *)subtype->tp_alloc(subtype, 0); + return self; +} + +static int +ExprVar_init(ExprVarObject *self, PyObject *args, PyObject *kwds) +{ + PyObject* lit = NULL; + if (!PyArg_ParseTuple(args, "|O", &lit)) { + return -1; + } + if (lit == NULL) { + self->index = PyLong_FromLong(0); + return 0; + } else if (PyLong_Check(lit)) { + self->index = lit; + return 0; + } else { + PyErr_SetString(PyExc_TypeError, "invalid argument in ExprVar_init"); + return -1; + } +} + +static PyObject * +ExprVar_richcompare(ExprVarObject *t1, ExprVarObject *t2, int op) +{ + bool same = false; + if (PyObject_RichCompareBool(t1->index, t2->index, Py_EQ) != 1) goto done; + + same = true; +done: + + if (op == Py_EQ) { + if (same) Py_RETURN_TRUE; else Py_RETURN_FALSE; + } else if (op == Py_NE) { + if (same) Py_RETURN_FALSE; else Py_RETURN_TRUE; + } else { + PyErr_SetString(PyExc_TypeError, "comparison operation not supported"); + Py_RETURN_NOTIMPLEMENTED; + } +} + +/* static */ +PyTypeObject pgf_ExprVarType = { + PyVarObject_HEAD_INIT(NULL, 0) + //0, /*ob_size*/ + "pgf.ExprVar", /*tp_name*/ + sizeof(ExprVarObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, //(destructor)Expr_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, //(hashfunc) Expr_hash, /*tp_hash */ + 0, //(ternaryfunc) Expr_call, /*tp_call*/ + 0, //(reprfunc) Expr_str, /*tp_str*/ + 0, //(getattrofunc) Expr_getattro,/*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "variable", /*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + (richcmpfunc) ExprVar_richcompare, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + 0, //Expr_methods, /*tp_methods */ + 0, /*tp_members */ + 0, //Expr_getseters, /*tp_getset */ + &pgf_ExprType, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc) ExprVar_init, /*tp_init */ + 0, /*tp_alloc */ + (newfunc) ExprVar_new, /*tp_new */ +}; + +// ---------------------------------------------------------------------------- + static PyObject * Type_str(TypeObject *self) { diff --git a/src/runtime/python/expr.h b/src/runtime/python/expr.h index e1e2562de..19b3fa45d 100644 --- a/src/runtime/python/expr.h +++ b/src/runtime/python/expr.h @@ -28,13 +28,20 @@ typedef struct { typedef struct { PyObject_HEAD - PyObject *index; + PyObject *id; } ExprMetaObject; +typedef struct { + PyObject_HEAD + PyObject *index; +} ExprVarObject; + extern PyTypeObject pgf_ExprType; extern PyTypeObject pgf_ExprLitType; extern PyTypeObject pgf_ExprMetaType; +extern PyTypeObject pgf_ExprVarType; + #endif // PYPGF_EXPR_H_ diff --git a/src/runtime/python/marshaller.c b/src/runtime/python/marshaller.c index ee1702712..e2dab89fd 100644 --- a/src/runtime/python/marshaller.c +++ b/src/runtime/python/marshaller.c @@ -38,7 +38,7 @@ PgfExpr elit(PgfUnmarshaller *this, PgfLiteral lit) PgfExpr emeta(PgfUnmarshaller *this, PgfMetaId meta) { ExprMetaObject *pyexpr = (ExprMetaObject *)pgf_ExprMetaType.tp_alloc(&pgf_ExprMetaType, 0); - pyexpr->index = PyLong_FromLong(meta); + pyexpr->id = PyLong_FromLong(meta); return (PgfExpr) pyexpr; } @@ -50,8 +50,9 @@ PgfExpr efun(PgfUnmarshaller *this, PgfText *name) PgfExpr evar(PgfUnmarshaller *this, int index) { - PyErr_SetString(PyExc_NotImplementedError, "evar not implemented"); - return 0; + ExprVarObject *pyexpr = (ExprVarObject *)pgf_ExprVarType.tp_alloc(&pgf_ExprVarType, 0); + pyexpr->index = PyLong_FromLong(index); + return (PgfExpr) pyexpr; } PgfExpr etyped(PgfUnmarshaller *this, PgfExpr expr, PgfType typ) @@ -153,7 +154,7 @@ PgfUnmarshaller unmarshaller = { &unmarshallerVtbl }; // ---------------------------------------------------------------------------- -static PgfText * +PgfText * PyUnicode_AsPgfText(PyObject *pystr) { if (!PyUnicode_Check(pystr)) { @@ -165,7 +166,7 @@ PyUnicode_AsPgfText(PyObject *pystr) } Py_ssize_t size; - const char * enc = PyUnicode_AsUTF8AndSize(pystr, &size); + const char *enc = PyUnicode_AsUTF8AndSize(pystr, &size); PgfText *ptext = malloc(sizeof(PgfText)+size+1); memcpy(ptext->text, enc, size+1); ptext->size = size; @@ -221,14 +222,21 @@ object match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit) } } -object match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr ex) +object match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr) { - ExprObject *expr = (ExprObject *)ex; + PyObject *pyobj = (PyObject *)expr; - if (expr->ob_base.ob_type == &pgf_ExprLitType) { // use PyObject_IsInstance ? - ExprLitObject *elit= (ExprLitObject *)expr; + if (PyObject_TypeCheck(pyobj, &pgf_ExprLitType)) { + ExprLitObject *elit = (ExprLitObject *)expr; return this->vtbl->match_lit(this, u, (PgfLiteral) elit->value); + } else if (PyObject_TypeCheck(pyobj, &pgf_ExprMetaType)) { + ExprMetaObject *emeta = (ExprMetaObject *)expr; + return u->vtbl->emeta(u, (PgfMetaId) PyLong_AsLong(emeta->id)); + } else if (PyObject_TypeCheck(pyobj, &pgf_ExprVarType)) { + ExprVarObject *evar = (ExprVarObject *)expr; + return u->vtbl->evar(u, PyLong_AsLong(evar->index)); } else { + PyErr_SetString(PyExc_TypeError, "unable to match on expression"); return 0; } } diff --git a/src/runtime/python/marshaller.h b/src/runtime/python/marshaller.h index 71793ec2c..bec013fe8 100644 --- a/src/runtime/python/marshaller.h +++ b/src/runtime/python/marshaller.h @@ -6,6 +6,8 @@ #include +PgfText *PyUnicode_AsPgfText(PyObject *pystr); + extern PgfUnmarshaller unmarshaller; extern PgfMarshaller marshaller; diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 438e51bfe..6b4bff183 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -1917,6 +1917,10 @@ PGF_categoryContext(PGFObject *self, PyObject *args) return NULL; } + if (hypos == NULL) { + Py_RETURN_NONE; + } + PyObject *contexts = PyList_New(n_hypos); if (contexts == NULL) { return NULL; @@ -2537,7 +2541,7 @@ const char *fpath; return py_pgf; } -static ExprObject* +static ExprObject * pgf_readExpr(PyObject *self, PyObject *args) { const char *s; @@ -2559,6 +2563,36 @@ pgf_readExpr(PyObject *self, PyObject *args) return (ExprObject *)expr; } +static PyObject * +pgf_showExpr(PyObject *self, PyObject *args) +{ + PyObject *pylist; + PyObject *pyexpr; + if (!PyArg_ParseTuple(args, "O!O!", &PyList_Type, &pylist, &pgf_ExprType, &pyexpr)) + return NULL; + + PgfPrintContext *ctxt = NULL; + for (Py_ssize_t i = PyList_Size(pylist); i > 0 ; i--) { + PyObject *item = PyList_GetItem(pylist, i-1); + if (!PyUnicode_Check(item)) { + PyErr_SetString(PyExc_TypeError, "invalid variable argument in showExpr"); + return NULL; + } + PgfText *input = PyUnicode_AsPgfText(item); + + // TODO a better way to copy into this->name? + PgfPrintContext *this = (PgfPrintContext *)PyMem_Malloc(sizeof(PgfPrintContext *) + sizeof(PgfText) + input->size + 1); + this->next = ctxt; + memcpy(&this->name, input, sizeof(PgfText) + input->size + 1); + ctxt = this; + } + + PgfText *s = pgf_print_expr((PgfExpr) pyexpr, ctxt, 0, &marshaller); + PyObject *str = PyUnicode_FromStringAndSize(s->text, s->size); + free(s); + return str; +} + static TypeObject * pgf_readType(PyObject *self, PyObject *args) { @@ -2590,6 +2624,8 @@ static PyMethodDef module_methods[] = { "Reads an NGF file into memory"}, {"readExpr", (void*)pgf_readExpr, METH_VARARGS, "Parses a string as an abstract tree"}, + {"showExpr", (void*)pgf_showExpr, METH_VARARGS, + "Renders an expression as a string"}, {"readType", (void*)pgf_readType, METH_VARARGS, "Parses a string as an abstract type"}, {NULL, NULL, 0, NULL} /* Sentinel */ @@ -2636,6 +2672,9 @@ MOD_INIT(pgf) if (PyType_Ready(&pgf_ExprMetaType) < 0) return MOD_ERROR_VAL; + if (PyType_Ready(&pgf_ExprVarType) < 0) + return MOD_ERROR_VAL; + if (PyType_Ready(&pgf_TypeType) < 0) return MOD_ERROR_VAL; @@ -2670,6 +2709,9 @@ MOD_INIT(pgf) PyModule_AddObject(m, "ExprMeta", (PyObject *) &pgf_ExprMetaType); Py_INCREF(&pgf_ExprMetaType); + PyModule_AddObject(m, "ExprVar", (PyObject *) &pgf_ExprVarType); + Py_INCREF(&pgf_ExprVarType); + PyModule_AddObject(m, "Type", (PyObject *) &pgf_TypeType); Py_INCREF(&pgf_TypeType); diff --git a/src/runtime/python/test_suite.py b/src/runtime/python/test_suite.py index bbb170879..b3fb45a59 100644 --- a/src/runtime/python/test_suite.py +++ b/src/runtime/python/test_suite.py @@ -98,7 +98,7 @@ def test_categoryContext_3(PGF): assert tup[2] == pgf.readType("N") def test_categoryContext_4(PGF): - assert PGF.categoryContext("X") == [] + assert PGF.categoryContext("X") == None def test_functionIsConstructor_1(PGF): assert PGF.functionIsConstructor("s") == True @@ -222,10 +222,30 @@ def test_readExpr_lstr_str(): # expressions: variables - # ,TestCase (assertEqual "show expression 4" "x" (showExpr ["x"] (EVar 0))) - # ,TestCase (assertEqual "show expression 5" "#1" (showExpr ["x"] (EVar 1))) - # ,TestCase (assertEqual "show expression 6" "z" (showExpr ["z","y","x"] (EVar 0))) - # ,TestCase (assertEqual "show expression 7" "y" (showExpr ["z","y","x"] (EVar 1))) +# def test_readExpr_evar_equality_1(): +# assert pgf.readExpr("#0") == pgf.ExprVar() +# assert pgf.readExpr("#0") == pgf.ExprVar(0) + +# def test_readExpr_evar_equality_2(): +# assert pgf.readExpr("#42") == pgf.ExprVar(42) + +def test_readExpr_evar_str_1(): + assert str(pgf.ExprVar(0)) == "#0" + +def test_readExpr_evar_str_2(): + assert str(pgf.ExprVar(42)) == "#42" + +def test_showExpr_evar_1(): + assert pgf.showExpr(["x"], pgf.ExprVar(0)) == "x" + +def test_showExpr_evar_2(): + assert pgf.showExpr(["x"], pgf.ExprVar(1)) == "#1" + +def test_showExpr_evar_3(): + assert pgf.showExpr(["z", "y", "x"], pgf.ExprVar(0)) == "z" + +def test_showExpr_evar_4(): + assert pgf.showExpr(["z", "y", "x"], pgf.ExprVar(1)) == "y" # expressions: lambda abstractions @@ -247,6 +267,12 @@ def test_readExpr_emeta_1(): def test_readExpr_emeta_2(): assert pgf.readExpr("?42") == pgf.ExprMeta(42) +def test_readExpr_emeta_str_1(): + assert str(pgf.readExpr("?")) == "?" + +def test_readExpr_emeta_str_2(): + assert str(pgf.readExpr("?42")) == "?42" + # expressions: typed expressions # ,TestCase (assertEqual "show expression 18" "" (showExpr [] (ETyped (EFun "z") (DTyp [] "N" []))))