From 3b1907cd8c384f28523781d855cae88c6438bb0b Mon Sep 17 00:00:00 2001 From: "John J. Camilleri" Date: Wed, 8 Sep 2021 16:03:54 +0200 Subject: [PATCH] Add Expr and ExprLit types to Python bindings. Seem to work for readExpr. --- .gitignore | 3 + src/runtime/python/expr.c | 1061 +++++------------------------- src/runtime/python/expr.h | 19 +- src/runtime/python/marshaller.c | 57 +- src/runtime/python/pypgf.c | 75 ++- src/runtime/python/setup.py | 2 +- src/runtime/python/test_suite.py | 35 +- 7 files changed, 269 insertions(+), 983 deletions(-) diff --git a/.gitignore b/.gitignore index b698d53ab..8e9cac9a3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.jar *.gfo *.pgf +*.ngf debian/.debhelper debian/debhelper-build-stamp debian/gf @@ -46,6 +47,8 @@ src/runtime/c/sg/.dirstamp src/runtime/c/stamp-h1 src/runtime/java/.libs/ src/runtime/python/build/ +src/runtime/python/__pycache__/ +src/runtime/python/.pytest_cache/ .cabal-sandbox cabal.sandbox.config .stack-work diff --git a/src/runtime/python/expr.c b/src/runtime/python/expr.c index 134f2bff4..6eb719f54 100644 --- a/src/runtime/python/expr.c +++ b/src/runtime/python/expr.c @@ -6,122 +6,34 @@ #include "./expr.h" #include "./marshaller.h" -// static ExprObject* -// Expr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -// { -// ExprObject* self = (ExprObject *)type->tp_alloc(type, 0); -// if (self != NULL) { -// self->master = NULL; -// self->pool = NULL; -// self->expr = gu_null_variant; -// } -// -// return self; -// } -// -// static void -// Expr_dealloc(ExprObject* 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 PyObject* -// Expr_getattro(ExprObject *self, PyObject *attr_name); -// -// static int -// Expr_initMeta(ExprObject *self); -// -// static int -// Expr_initLiteral(ExprObject *self, PyObject *lit); -// -// static int -// Expr_initApp(ExprObject *self, const char* fname, PyObject *args); -// -// static ExprObject* -// Expr_call(ExprObject* e, PyObject* args, PyObject* kw); -// -// static PyObject* -// Expr_unpack(ExprObject* self, PyObject *args); -// -// static PyObject* -// Expr_visit(ExprObject* self, PyObject *args); -// -// static PyObject* -// Expr_reduce_ex(ExprObject* self, PyObject *args); -// -// static int -// Expr_init(ExprObject *self, PyObject *args, PyObject *kwds) -// { -// Py_ssize_t tuple_size = PyTuple_Size(args); -// -// if (tuple_size == 0) { -// return Expr_initMeta(self); -// } else if (tuple_size == 1) { -// PyObject* lit = NULL; -// if (!PyArg_ParseTuple(args, "O", &lit)) -// return -1; -// return Expr_initLiteral(self, lit); -// } else if (tuple_size == 2) { -// const char* fname; -// PyObject* list = NULL; -// if (!PyArg_ParseTuple(args, "sO!", &fname, &PyList_Type, &list)) -// return -1; -// return Expr_initApp(self, fname, list); -// } else { -// PyErr_Format(PyExc_TypeError, "function takes 0, 1 or 2 arguments (%d given)", (int) tuple_size); -// return -1; -// } -// -// return 0; -// } -// -// static PyObject * -// Expr_repr(ExprObject *self) -// { -// GuPool* tmp_pool = gu_local_pool(); -// -// GuExn* err = gu_exn(tmp_pool); -// GuStringBuf* sbuf = gu_new_string_buf(tmp_pool); -// GuOut* out = gu_string_buf_out(sbuf); -// -// pgf_print_expr(self->expr, NULL, 0, out, err); -// -// PyObject* pystr = PyString_FromStringAndSize(gu_string_buf_data(sbuf), -// gu_string_buf_length(sbuf)); -// -// gu_pool_free(tmp_pool); -// return pystr; -// } -// -// static PyObject * -// Expr_richcompare(ExprObject *e1, ExprObject *e2, int op) -// { -// bool cmp = pgf_expr_eq(e1->expr,e2->expr); -// -// if (op == Py_EQ) { -// if (cmp) Py_RETURN_TRUE; else Py_RETURN_FALSE; -// } else if (op == Py_NE) { -// if (cmp) Py_RETURN_FALSE; else Py_RETURN_TRUE; -// } else { -// PyErr_SetString(PyExc_TypeError, "the operation is not supported"); -// return NULL; -// } -// } -// -// static long -// Expr_hash(ExprObject *e) -// { -// return (long) pgf_expr_hash(0, e->expr); -// } -// -// static PyMethodDef Expr_methods[] = { +static PyObject * +Expr_str(ExprObject *self) +{ + PgfText *s = pgf_print_expr((PgfExpr) &self, NULL, 1, &marshaller); + return PyString_FromStringAndSize(s->text, s->size); +} + +static PyObject * +Expr_richcompare(ExprObject *e1, ExprObject *e2, int op) +{ + bool same = false; + + // TODO + + // 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 PyMethodDef Expr_methods[] = { // {"unpack", (PyCFunction)Expr_unpack, METH_VARARGS, // "Decomposes an expression into its components" // }, @@ -135,10 +47,10 @@ // {"__reduce_ex__", (PyCFunction)Expr_reduce_ex, METH_VARARGS, // "This method allows for transparent pickling/unpickling of expressions." // }, -// {NULL} /* Sentinel */ -// }; -// -// static PyGetSetDef Expr_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyGetSetDef Expr_getseters[] = { // {"fun", // NULL, NULL, // "this is the function in a function application", @@ -163,653 +75,128 @@ // NULL, NULL, // "this is the de Bruijn index of a variable", // NULL}, -// {NULL} /* Sentinel */ -// }; -// -// static PyTypeObject pgf_ExprType = { -// PyVarObject_HEAD_INIT(NULL, 0) -// //0, /*ob_size*/ -// "pgf.Expr", /*tp_name*/ -// sizeof(ExprObject), /*tp_basicsize*/ -// 0, /*tp_itemsize*/ -// (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*/ -// (hashfunc) Expr_hash, /*tp_hash */ -// (ternaryfunc) Expr_call, /*tp_call*/ -// (reprfunc) Expr_repr, /*tp_str*/ -// (getattrofunc) Expr_getattro,/*tp_getattro*/ -// 0, /*tp_setattro*/ -// 0, /*tp_as_buffer*/ -// Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ -// "abstract syntax tree", /*tp_doc*/ -// 0, /*tp_traverse */ -// 0, /*tp_clear */ -// (richcmpfunc) Expr_richcompare, /*tp_richcompare */ -// 0, /*tp_weaklistoffset */ -// 0, /*tp_iter */ -// 0, /*tp_iternext */ -// Expr_methods, /*tp_methods */ -// 0, /*tp_members */ -// Expr_getseters, /*tp_getset */ -// 0, /*tp_base */ -// 0, /*tp_dict */ -// 0, /*tp_descr_get */ -// 0, /*tp_descr_set */ -// 0, /*tp_dictoffset */ -// (initproc)Expr_init, /*tp_init */ -// 0, /*tp_alloc */ -// (newfunc) Expr_new, /*tp_new */ -// }; -// -// static int -// Expr_initMeta(ExprObject *self) -// { -// self->master = NULL; -// self->pool = gu_new_pool(); -// PgfExprMeta* e = -// gu_new_variant(PGF_EXPR_META, -// PgfExprMeta, -// &self->expr, self->pool); -// e->id = 0; -// return 0; -// } -// -// static int -// Expr_initLiteral(ExprObject *self, PyObject *lit) -// { -// self->master = NULL; -// self->pool = gu_new_pool(); -// PgfExprLit* e = -// gu_new_variant(PGF_EXPR_LIT, -// PgfExprLit, -// &self->expr, self->pool); -// e->lit = gu_null_variant; -// -// if (PyString_Check(lit)) { -// char* s; -// Py_ssize_t len; -// -// #if PY_MAJOR_VERSION >= 3 -// PyObject* bytes = PyUnicode_AsUTF8String(lit); -// if (bytes == NULL) -// return -1; -// if (PyBytes_AsStringAndSize(bytes,&s,&len) < 0) -// return -1; -// #else -// if (PyString_AsStringAndSize(lit,&s,&len) < 0) -// return -1; -// #endif -// -// PgfLiteralStr* slit = -// gu_new_flex_variant(PGF_LITERAL_STR, -// PgfLiteralStr, -// val, len+1, -// &e->lit, self->pool); -// memcpy(slit->val, s, len+1); -// -// #if PY_MAJOR_VERSION >= 3 -// Py_DECREF(bytes); -// #endif -// } else if (PyInt_Check(lit)) { -// PgfLiteralInt* ilit = -// gu_new_variant(PGF_LITERAL_INT, -// PgfLiteralInt, -// &e->lit, self->pool); -// ilit->val = PyInt_AsLong(lit); -// } else if (PyFloat_Check(lit)) { -// PgfLiteralFlt* flit = -// gu_new_variant(PGF_LITERAL_FLT, -// PgfLiteralFlt, -// &e->lit, self->pool); -// flit->val = PyFloat_AsDouble(lit); -// } else { -// PyErr_SetString(PyExc_TypeError, "the literal must be a string, an integer, or a float"); -// return -1; -// } -// return 0; -// } -// -// static int -// Expr_initApp(ExprObject *self, const char* fname, PyObject *args) -// { -// Py_ssize_t n_args = PyList_Size(args); -// -// self->master = PyTuple_New(n_args); -// if (self->master == NULL) -// return -1; -// -// self->pool = gu_new_pool(); -// PgfExprFun* e = -// gu_new_flex_variant(PGF_EXPR_FUN, -// PgfExprFun, -// fun, strlen(fname)+1, -// &self->expr, self->pool); -// strcpy(e->fun, fname); -// -// for (Py_ssize_t i = 0; i < n_args; i++) { -// PyObject* obj = PyList_GetItem(args, i); -// if (obj->ob_type != &pgf_ExprType) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the list must be expressions"); -// return -1; -// } -// -// PyTuple_SetItem(self->master, i, obj); -// Py_INCREF(obj); -// -// PgfExpr fun = self->expr; -// PgfExpr arg = ((ExprObject*) obj)->expr; -// -// PgfExprApp* e = -// gu_new_variant(PGF_EXPR_APP, -// PgfExprApp, -// &self->expr, self->pool); -// e->fun = fun; -// e->arg = arg; -// } -// -// return 0; -// } -// -// static ExprObject* -// Expr_call(ExprObject* self, PyObject* args, PyObject* kw) -// { -// ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (pyexpr == NULL) -// return NULL; -// -// size_t n_args = PyTuple_Size(args); -// -// pyexpr->master = PyTuple_New(n_args+1); -// if (pyexpr->master == NULL) { -// Py_DECREF(pyexpr); -// return NULL; -// } -// -// PyTuple_SetItem(pyexpr->master, 0, (PyObject*) self); -// Py_INCREF(self); -// -// pyexpr->pool = gu_new_pool(); -// pyexpr->expr = self->expr; -// -// for (Py_ssize_t i = 0; i < n_args; i++) { -// PyObject* obj = PyTuple_GetItem(args, i); -// if (obj->ob_type != &pgf_ExprType) { -// PyErr_SetString(PyExc_TypeError, "the arguments must be expressions"); -// return NULL; -// } -// -// PyTuple_SetItem(pyexpr->master, i+1, obj); -// Py_INCREF(obj); -// -// PgfExpr fun = pyexpr->expr; -// PgfExpr arg = ((ExprObject*) obj)->expr; -// -// PgfExprApp* e = -// gu_new_variant(PGF_EXPR_APP, -// PgfExprApp, -// &pyexpr->expr, pyexpr->pool); -// e->fun = fun; -// e->arg = arg; -// } -// -// return pyexpr; -// } -// -// static PyObject* -// Expr_unpack(ExprObject* self, PyObject *fargs) -// { -// PgfExpr expr = self->expr; -// PyObject* args = PyList_New(0); -// -// for (;;) { -// GuVariantInfo i = gu_variant_open(expr); -// switch (i.tag) { -// case PGF_EXPR_ABS: { -// PgfExprAbs* eabs = i.data; -// -// ExprObject* py_body = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (py_body == NULL) { -// Py_DECREF(args); -// return NULL; -// } -// py_body->pool = NULL; -// py_body->master = (self->master) ? self->master : (PyObject*) self; -// py_body->expr = eabs->body; -// Py_INCREF(py_body->master); -// -// PyObject* py_bindtype = -// (eabs->bind_type == PGF_BIND_TYPE_EXPLICIT) ? Py_True -// : Py_False; -// PyObject* py_var = PyString_FromString(eabs->id); -// PyObject* res = -// Py_BuildValue("OOOO", py_bindtype, py_var, py_body, args); -// Py_DECREF(py_var); -// Py_DECREF(py_body); -// Py_DECREF(args); -// return res; -// } -// case PGF_EXPR_APP: { -// PgfExprApp* eapp = i.data; -// -// ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (pyexpr == NULL) { -// Py_DECREF(args); -// return NULL; -// } -// pyexpr->pool = NULL; -// pyexpr->master = (self->master) ? self->master : (PyObject*) self; -// pyexpr->expr = eapp->arg; -// Py_INCREF(pyexpr->master); -// -// if (PyList_Insert(args, 0, (PyObject*) pyexpr) == -1) { -// Py_DECREF(args); -// return NULL; -// } -// -// Py_DECREF((PyObject*) pyexpr); -// -// expr = eapp->fun; -// break; -// } -// case PGF_EXPR_LIT: { -// PgfExprLit* elit = i.data; -// -// Py_DECREF(args); -// -// GuVariantInfo i = gu_variant_open(elit->lit); -// switch (i.tag) { -// case PGF_LITERAL_STR: { -// PgfLiteralStr* lstr = i.data; -// return PyString_FromString(lstr->val); -// } -// case PGF_LITERAL_INT: { -// PgfLiteralInt* lint = i.data; -// return PyInt_FromLong(lint->val); -// } -// case PGF_LITERAL_FLT: { -// PgfLiteralFlt* lflt = i.data; -// return PyFloat_FromDouble(lflt->val); -// } -// default: -// gu_impossible(); -// return NULL; -// } -// } -// case PGF_EXPR_META: { -// PyObject* res = Py_BuildValue("OO", Py_None, args); -// Py_DECREF(args); -// return res; -// } -// case PGF_EXPR_FUN: { -// PgfExprFun* efun = i.data; -// PyObject* fun = PyString_FromString(efun->fun); -// PyObject* res = Py_BuildValue("OO", fun, args); -// Py_DECREF(fun); -// Py_DECREF(args); -// return res; -// } -// case PGF_EXPR_VAR: { -// PgfExprVar* evar = i.data; -// PyObject* res = Py_BuildValue("iO", evar->var, args); -// Py_DECREF(args); -// return res; -// } -// case PGF_EXPR_TYPED: { -// PgfExprTyped* etyped = i.data; -// expr = etyped->expr; -// break; -// } -// case PGF_EXPR_IMPL_ARG: { -// PgfExprImplArg* eimpl = i.data; -// expr = eimpl->expr; -// break; -// } -// default: -// gu_impossible(); -// return NULL; -// } -// } -// return NULL; -// } -// -// static PyObject* -// Expr_visit(ExprObject* self, PyObject *args) -// { -// PyObject* py_visitor = NULL; -// PgfExpr expr = self->expr; -// if (!PyArg_ParseTuple(args, "O", &py_visitor)) -// return NULL; -// -// GuPool* tmp_pool = gu_local_pool(); -// -// PgfApplication* app = pgf_expr_unapply(expr, tmp_pool); -// if (app != NULL) { -// char* method_name = gu_malloc(tmp_pool, strlen(app->fun)+4); -// strcpy(method_name, "on_"); -// strcat(method_name, app->fun); -// -// if (PyObject_HasAttrString(py_visitor, method_name)) { -// PyObject* method_args = PyTuple_New(app->n_args); -// if (method_args == NULL) { -// gu_pool_free(tmp_pool); -// return NULL; -// } -// -// for (size_t i = 0; i < app->n_args; i++) { -// ExprObject* pyarg = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (pyarg == NULL) { -// Py_DECREF(args); -// gu_pool_free(tmp_pool); -// return NULL; -// } -// pyarg->pool = NULL; -// pyarg->master = (self->master) ? self->master : (PyObject*) self; -// pyarg->expr = app->args[i]; -// Py_INCREF(pyarg->master); -// -// if (PyTuple_SetItem(method_args, i, (PyObject*) pyarg) == -1) { -// Py_DECREF(args); -// gu_pool_free(tmp_pool); -// return NULL; -// } -// } -// -// PyObject* method = -// PyObject_GetAttrString(py_visitor, method_name); -// if (method == NULL) { -// Py_DECREF(args); -// gu_pool_free(tmp_pool); -// return NULL; -// } -// -// gu_pool_free(tmp_pool); -// -// return PyObject_CallObject(method, method_args); -// } -// } -// -// gu_pool_free(tmp_pool); -// -// return PyObject_CallMethod(py_visitor, "default", "O", self); -// } -// -// static PyObject* -// Expr_reduce_ex(ExprObject* self, PyObject *args) -// { -// int protocol; -// if (!PyArg_ParseTuple(args, "i", &protocol)) -// return NULL; -// -// PyObject* myModule = PyImport_ImportModule("pgf"); -// if (myModule == NULL) -// return NULL; -// PyObject* py_readExpr = PyObject_GetAttrString(myModule, "readExpr"); -// Py_DECREF(myModule); -// if (py_readExpr == NULL) -// return NULL; -// -// PyObject* py_str = Expr_repr(self); -// if (py_str == NULL) { -// Py_DECREF(py_readExpr); -// return NULL; -// } -// -// PyObject* py_tuple = -// Py_BuildValue("O(O)", py_readExpr, py_str); -// -// Py_DECREF(py_str); -// Py_DECREF(py_readExpr); -// -// return py_tuple; -// } -// -// static PyObject* -// Expr_getattro(ExprObject *self, PyObject *attr_name) { -// #if PY_MAJOR_VERSION >= 3 -// #define IS_ATTR(attr) (PyUnicode_CompareWithASCIIString(attr_name,attr) == 0) -// #else -// const char* name = PyString_AsString(attr_name); -// #define IS_ATTR(attr) (strcmp(name, attr) == 0) -// #endif -// -// PgfExpr expr = self->expr; -// -// redo:; -// GuVariantInfo i = gu_variant_open(expr); -// switch (i.tag) { -// case PGF_EXPR_APP: { -// PgfExprApp* eapp = i.data; -// -// ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (pyexpr == NULL) -// return NULL; -// pyexpr->pool = NULL; -// pyexpr->master = (self->master) ? self->master : (PyObject*) self; -// pyexpr->expr = gu_null_variant; -// Py_INCREF(pyexpr->master); -// -// if (IS_ATTR("fun")) { -// pyexpr->expr = eapp->fun; -// return ((PyObject*) pyexpr); -// } else if (IS_ATTR("arg")) { -// pyexpr->expr = eapp->arg; -// return ((PyObject*) pyexpr); -// } else { -// Py_DECREF(pyexpr); -// } -// break; -// } -// case PGF_EXPR_LIT: { -// PgfExprLit* elit = i.data; -// -// if (IS_ATTR("val")) { -// GuVariantInfo i = gu_variant_open(elit->lit); -// switch (i.tag) { -// case PGF_LITERAL_INT: { -// PgfLiteralInt* lint = i.data; -// return PyInt_FromLong(lint->val); -// } -// case PGF_LITERAL_FLT: { -// PgfLiteralFlt* lflt = i.data; -// return PyFloat_FromDouble(lflt->val); -// } -// case PGF_LITERAL_STR: { -// PgfLiteralStr* lstr = i.data; -// return PyString_FromString(lstr->val); -// } -// } -// } -// break; -// } -// case PGF_EXPR_META: { -// PgfExprMeta* emeta = i.data; -// if (IS_ATTR("id")) -// return PyInt_FromLong(emeta->id); -// break; -// } -// case PGF_EXPR_FUN: { -// PgfExprFun* efun = i.data; -// if (IS_ATTR("name")) { -// return PyString_FromString(efun->fun); -// } -// break; -// } -// case PGF_EXPR_VAR: { -// PgfExprVar* evar = i.data; -// if (IS_ATTR("index")) { -// return PyInt_FromLong(evar->var); -// } -// break; -// } -// case PGF_EXPR_TYPED: { -// PgfExprTyped* etyped = i.data; -// expr = etyped->expr; -// goto redo; -// } -// case PGF_EXPR_IMPL_ARG: { -// PgfExprImplArg* eimpl = i.data; -// expr = eimpl->expr; -// goto redo; -// } -// default: -// gu_impossible(); -// } -// -// return PyObject_GenericGetAttr((PyObject*)self, attr_name); -// } + {NULL} /* Sentinel */ +}; + +/* static */ +PyTypeObject pgf_ExprType = { + PyVarObject_HEAD_INIT(NULL, 0) + //0, /*ob_size*/ + "pgf.Expr", /*tp_name*/ + sizeof(ExprObject), /*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*/ + (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*/ + "abstract syntax tree", /*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + (richcmpfunc) Expr_richcompare, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + Expr_methods, /*tp_methods */ + 0, /*tp_members */ + Expr_getseters, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + 0, //(initproc)Expr_init, /*tp_init */ + 0, /*tp_alloc */ + 0, //(newfunc) Expr_new, /*tp_new */ +}; // ---------------------------------------------------------------------------- -// 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; -// } +static PyObject * +ExprLit_richcompare(ExprLitObject *t1, ExprLitObject *t2, int op) +{ + bool same = false; + if (t1->type != t2->type) goto done; -// static void -// Type_dealloc(TypeObject *self) -// { -// Py_TYPE(self)->tp_free((PyObject*)self); -// } + if (t1->type == 0) { + if (PyLong_AsLong(t1->value) != PyLong_AsLong(t2->value)) goto done; + } else if (t1->type == 1) { + if (PyFloat_AsDouble(t1->value) != PyFloat_AsDouble(t2->value)) goto done; + } else if (t1->type == 2) { + if (PyString_Compare(t1->value, t2->value) != 0) goto done; + } else { + PyErr_SetString(PyExc_TypeError, "unknown literal type"); + return NULL; + } -// static int -// Type_init(TypeObject *self, PyObject *args, PyObject *kwds) -// { -// PyObject* py_hypos; -// const char* catname_s; -// PyObject* py_exprs; -// size_t n_exprs; -// size_t n_hypos; -// -// if (PyTuple_Size(args) == 1) { -// py_hypos = NULL; -// py_exprs = NULL; -// n_exprs = 0; -// n_hypos = 0; -// if (!PyArg_ParseTuple(args, "s", &catname_s)) -// return -1; -// } else { -// if (!PyArg_ParseTuple(args, "O!sO!", -// &PyList_Type, &py_hypos, -// &catname_s, -// &PyList_Type, &py_exprs)) -// return -1; -// -// n_exprs = PyList_Size(py_exprs); -// n_hypos = PyList_Size(py_hypos); -// } -// -// self->pool = gu_new_pool(); -// self->master = -// (n_exprs+n_hypos > 0) ? PyTuple_New(n_exprs+n_hypos) : NULL; -// -// self->type = gu_new_flex(self->pool, PgfType, exprs, n_exprs); -// -// self->type->hypos = -// gu_new_seq(PgfHypo, n_hypos, self->pool); -// -// for (size_t i = 0; i < n_hypos; i++) { -// PyObject* obj = PyList_GetItem(py_hypos, i); -// PyObject* py_bindtype; -// PgfCId cid; -// PyObject* py_type; -// -// if (Py_TYPE(obj) == &pgf_TypeType) { -// py_bindtype = Py_True; -// cid = "_"; -// py_type = obj; -// } else { -// if (!PyTuple_Check(obj) || -// PyTuple_GET_SIZE(obj) != 3) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the first list must be triples of (boolean,string,pgf.Type)"); -// return -1; -// } -// -// py_bindtype = PyTuple_GetItem(obj, 0); -// if (!PyBool_Check(py_bindtype)) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the first list must be triples of (boolean,string,pgf.Type)"); -// return -1; -// } -// -// PyObject* py_var = PyTuple_GetItem(obj, 1); -// if (!PyString_Check(py_var)) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the first list must be triples of (boolean,string,pgf.Type)"); -// return -1; -// } -// -// { -// char* s; -// Py_ssize_t len; -// -// #if PY_MAJOR_VERSION >= 3 -// PyObject* bytes = PyUnicode_AsUTF8String(py_var); -// if (bytes == NULL) -// return -1; -// if (PyBytes_AsStringAndSize(bytes,&s,&len) < 0) -// return -1; -// #else -// if (PyString_AsStringAndSize(py_var,&s,&len) < 0) -// return -1; -// #endif -// -// cid = gu_malloc(self->pool, len+1); -// memcpy((char*)cid, s, len+1); -// -// #if PY_MAJOR_VERSION >= 3 -// Py_DECREF(bytes); -// #endif -// } -// -// py_type = PyTuple_GetItem(obj, 2); -// if (Py_TYPE(py_type) != &pgf_TypeType) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the first list must be triples of (boolean,string,pgf.Type)"); -// return -1; -// } -// } -// -// PgfHypo* hypo = gu_seq_index(self->type->hypos, PgfHypo, i); -// hypo->bind_type = -// (py_bindtype == Py_True) ? PGF_BIND_TYPE_EXPLICIT -// : PGF_BIND_TYPE_IMPLICIT; -// hypo->cid = cid; -// hypo->type = ((TypeObject*) py_type)->type; -// -// PyTuple_SetItem(self->master, i, py_type); -// Py_INCREF(py_type); -// } -// -// self->type->cid = gu_string_copy(catname_s, self->pool); -// -// self->type->n_exprs = n_exprs; -// for (Py_ssize_t i = 0; i < n_exprs; i++) { -// PyObject* obj = PyList_GetItem(py_exprs, i); -// if (Py_TYPE(obj) != &pgf_ExprType) { -// PyErr_SetString(PyExc_TypeError, "the arguments in the second list must be expressions"); -// return -1; -// } -// -// PyTuple_SetItem(self->master, n_hypos+i, obj); -// Py_INCREF(obj); -// -// self->type->exprs[i] = ((ExprObject*) obj)->expr; -// } -// -// return 0; -// } + 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_ExprLitType = { + PyVarObject_HEAD_INIT(NULL, 0) + //0, /*ob_size*/ + "pgf.ExprLit", /*tp_name*/ + sizeof(ExprLitObject), /*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*/ + "literal", /*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + (richcmpfunc) ExprLit_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 */ + 0, //(initproc)Expr_init, /*tp_init */ + 0, /*tp_alloc */ + 0, //(newfunc) Expr_new, /*tp_new */ +}; + +// ---------------------------------------------------------------------------- static PyObject * Type_str(TypeObject *self) @@ -855,156 +242,6 @@ done: } } -// static PyObject* -// Type_getHypos(TypeObject *self, void *closure) -// { -// PgfType* type = self->type; -// -// PyObject* py_hypos = PyList_New(0); -// if (py_hypos == NULL) -// return NULL; -// -// size_t n_hypos = gu_seq_length(type->hypos); -// for (size_t i = 0; i < n_hypos; i++) { -// PgfHypo* hypo = gu_seq_index(type->hypos, PgfHypo, i); -// -// PyObject* py_bindtype = -// (hypo->bind_type == PGF_BIND_TYPE_EXPLICIT) ? Py_True -// : Py_False; -// -// PyObject* py_var = PyString_FromString(hypo->cid); -// if (py_var == NULL) -// goto fail; -// -// TypeObject* py_type = (TypeObject*) pgf_TypeType.tp_alloc(&pgf_TypeType, 0); -// if (py_type == NULL) { -// Py_DECREF(py_var); -// goto fail; -// } -// -// py_type->pool = NULL; -// py_type->master = (PyObject*) self; -// py_type->type = hypo->type; -// Py_INCREF(self); -// -// PyObject* py_hypo = -// Py_BuildValue("OOO", py_bindtype, py_var, py_type); -// Py_DECREF(py_var); -// Py_DECREF(py_type); -// -// if (py_hypo == NULL) -// goto fail; -// -// if (PyList_Append(py_hypos, (PyObject*) py_hypo) == -1) -// goto fail; -// -// Py_DECREF(py_hypo); -// } -// -// return py_hypos; -// -// fail: -// Py_DECREF(py_hypos); -// return NULL; -// } -// -// static PyObject* -// Type_getCat(TypeObject *self, void *closure) -// { -// return PyString_FromString(self->type->cid); -// } -// -// static PyObject* -// Type_getExprs(TypeObject *self, void *closure) -// { -// PgfType* type = self->type; -// -// PyObject* py_exprs = PyList_New(0); -// if (py_exprs == NULL) -// return NULL; -// -// for (size_t i = 0; i < type->n_exprs; i++) { -// ExprObject* py_expr = -// (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (py_expr == NULL) -// goto fail; -// py_expr->pool = NULL; -// py_expr->master = (PyObject*) self; -// py_expr->expr = type->exprs[i]; -// Py_INCREF(py_expr->master); -// -// if (PyList_Append(py_exprs, (PyObject*) py_expr) == -1) -// goto fail; -// -// Py_DECREF((PyObject*) py_expr); -// } -// -// return py_exprs; -// -// fail: -// Py_DECREF(py_exprs); -// return NULL; -// } -// -// static PyObject* -// Type_unpack(TypeObject* self, PyObject *fargs) -// { -// PyObject* res = NULL; -// PyObject* py_hypos = NULL; -// PyObject* py_cat = NULL; -// PyObject* py_exprs = NULL; -// -// py_hypos = Type_getHypos(self, NULL); -// if (py_hypos == NULL) -// goto fail; -// -// py_cat = Type_getCat(self, NULL); -// if (py_cat == NULL) -// goto fail; -// -// py_exprs = Type_getExprs(self, NULL); -// if (py_exprs == NULL) -// goto fail; -// -// res = Py_BuildValue("OOO", py_hypos, py_cat, py_exprs); -// -// fail: -// Py_XDECREF(py_hypos); -// Py_XDECREF(py_cat); -// Py_XDECREF(py_exprs); -// return res; -// } -// -// static PyObject* -// Type_reduce_ex(TypeObject* self, PyObject *args) -// { -// int protocol; -// if (!PyArg_ParseTuple(args, "i", &protocol)) -// return NULL; -// -// PyObject* myModule = PyImport_ImportModule("pgf"); -// if (myModule == NULL) -// return NULL; -// PyObject* py_readType = PyObject_GetAttrString(myModule, "readType"); -// Py_DECREF(myModule); -// if (py_readType == NULL) -// return NULL; -// -// PyObject* py_str = Type_repr(self); -// if (py_str == NULL) { -// Py_DECREF(py_readType); -// return NULL; -// } -// -// PyObject* py_tuple = -// Py_BuildValue("O(O)", py_readType, py_str); -// -// Py_DECREF(py_str); -// Py_DECREF(py_readType); -// -// return py_tuple; -// } -// static PyMethodDef Type_methods[] = { // {"unpack", (PyCFunction)Type_unpack, METH_VARARGS, // "Decomposes a type into its components" diff --git a/src/runtime/python/expr.h b/src/runtime/python/expr.h index e305eccdd..3c7ada762 100644 --- a/src/runtime/python/expr.h +++ b/src/runtime/python/expr.h @@ -17,11 +17,18 @@ typedef struct { extern PyTypeObject pgf_TypeType; -// typedef struct { -// PyObject_HEAD -// PyObject* master; -// GuPool* pool; -// PgfExpr expr; -// } ExprObject; +typedef struct { + PyObject_HEAD +} ExprObject; + +typedef struct { + PyObject_HEAD + int type; // 0 = int, 1 = float, 2 = str + PyObject *value; // depends on type +} ExprLitObject; + +extern PyTypeObject pgf_ExprType; + +extern PyTypeObject pgf_ExprLitType; #endif // PYPGF_EXPR_H_ diff --git a/src/runtime/python/marshaller.c b/src/runtime/python/marshaller.c index a4bdc4889..2d9f6b382 100644 --- a/src/runtime/python/marshaller.c +++ b/src/runtime/python/marshaller.c @@ -16,56 +16,72 @@ PgfExpr eabs(PgfUnmarshaller *this, PgfBindType btype, PgfText *name, PgfExpr body) { PyErr_SetString(PyExc_NotImplementedError, "eabs not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr eapp(PgfUnmarshaller *this, PgfExpr fun, PgfExpr arg) { PyErr_SetString(PyExc_NotImplementedError, "eapp not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr elit(PgfUnmarshaller *this, PgfLiteral lit) { - PyErr_SetString(PyExc_NotImplementedError, "elit not implemented"); - return 0; + ExprLitObject *pyexpr = (ExprLitObject *)pgf_ExprLitType.tp_alloc(&pgf_ExprLitType, 0); + + PyObject *pyobj = (PyObject *)lit; + pyexpr->value = pyobj; + + if (PyLong_Check(pyobj)) { + pyexpr->type = 0; + } else if (PyFloat_Check(pyobj)) { + pyexpr->type = 1; + } else if (PyString_Check(pyobj)) { + pyexpr->type = 2; + } else { + PyErr_SetString(PyExc_TypeError, "unable to unmarshall literal"); + return 0; + } + + Py_INCREF(pyobj); + return (PgfExpr) pyexpr; } PgfExpr emeta(PgfUnmarshaller *this, PgfMetaId meta) { PyErr_SetString(PyExc_NotImplementedError, "emeta not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr efun(PgfUnmarshaller *this, PgfText *name) { PyErr_SetString(PyExc_NotImplementedError, "efun not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr evar(PgfUnmarshaller *this, int index) { PyErr_SetString(PyExc_NotImplementedError, "evar not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr etyped(PgfUnmarshaller *this, PgfExpr expr, PgfType typ) { PyErr_SetString(PyExc_NotImplementedError, "etyped not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfExpr eimplarg(PgfUnmarshaller *this, PgfExpr expr) { PyErr_SetString(PyExc_NotImplementedError, "eimplarg not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } PgfLiteral lint(PgfUnmarshaller *this, size_t size, uintmax_t *v) { if (size > 1) { PyErr_SetString(PyExc_NotImplementedError, "multi-part integers not implemented"); // TODO - return 0; + Py_RETURN_NOTIMPLEMENTED; } PyObject *i = PyLong_FromUnsignedLong(*v); return (PgfLiteral) i; @@ -160,17 +176,14 @@ object match_lit(PgfUnmarshaller *u, PgfLiteral lit) if (PyLong_Check(pyobj)) { uintmax_t i = PyLong_AsUnsignedLong(pyobj); size_t size = 1; // TODO - return u->vtbl->lint(NULL, size, &i); - } - else if (PyFloat_Check(pyobj)) { + return u->vtbl->lint(u, size, &i); + } else if (PyFloat_Check(pyobj)) { double d = PyFloat_AsDouble(pyobj); - return u->vtbl->lflt(NULL, d); - } - else if (PyString_Check(pyobj)) { + return u->vtbl->lflt(u, d); + } else if (PyString_Check(pyobj)) { PgfText *t = PyString_AsPgfText(pyobj); - return u->vtbl->lstr(NULL, t); - } - else { + return u->vtbl->lstr(u, t); + } else { PyErr_SetString(PyExc_TypeError, "unable to match on literal"); return 0; } @@ -179,14 +192,14 @@ object match_lit(PgfUnmarshaller *u, PgfLiteral lit) object match_expr(PgfUnmarshaller *u, PgfExpr expr) { PyErr_SetString(PyExc_NotImplementedError, "match_expr not implemented"); - return 0; + Py_RETURN_NOTIMPLEMENTED; } object match_type(PgfUnmarshaller *u, PgfType ty) { TypeObject *type = (TypeObject *)ty; - PySys_WriteStdout(">%s<\n", PyUnicode_AS_DATA(type->cat)); + // PySys_WriteStdout(">%s<\n", PyUnicode_AS_DATA(type->cat)); int n_hypos = 0; //PyList_Size(type->hypos); PgfTypeHypo *hypos = NULL; // TODO @@ -196,7 +209,7 @@ object match_type(PgfUnmarshaller *u, PgfType ty) int n_exprs = 0; //PyList_Size(type->exprs); PgfExpr *exprs = NULL; // TODO - return u->vtbl->dtyp(NULL, n_hypos, hypos, cat, n_exprs, exprs); + return u->vtbl->dtyp(u, n_hypos, hypos, cat, n_exprs, exprs); } static PgfMarshallerVtbl marshallerVtbl = diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index e04ce4076..cc8219d62 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -1740,7 +1740,7 @@ typedef struct { // } static PyObject* -PGF_repr(PGFObject *self) +PGF_str(PGFObject *self) { // GuPool* tmp_pool = gu_local_pool(); // @@ -2369,7 +2369,7 @@ static PyTypeObject pgf_PGFType = { 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ - (reprfunc) PGF_repr, /*tp_str*/ + (reprfunc) PGF_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ @@ -2476,35 +2476,27 @@ pgf_readNGF(PyObject *self, PyObject *args) return py_pgf; } -// static ExprObject* -// pgf_readExpr(PyObject *self, PyObject *args) { -// Py_ssize_t len; -// const uint8_t *buf; -// if (!PyArg_ParseTuple(args, "s#", &buf, &len)) -// return NULL; -// -// ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); -// if (pyexpr == NULL) -// return NULL; -// -// GuPool* tmp_pool = gu_local_pool(); -// GuIn* in = gu_data_in(buf, len, tmp_pool); -// GuExn* err = gu_new_exn(tmp_pool); -// -// pyexpr->pool = gu_new_pool(); -// pyexpr->expr = pgf_read_expr(in, pyexpr->pool, tmp_pool, err); -// pyexpr->master = NULL; -// -// if (!gu_ok(err) || gu_variant_is_null(pyexpr->expr)) { -// PyErr_SetString(PGFError, "The expression cannot be parsed"); -// Py_DECREF(pyexpr); -// gu_pool_free(tmp_pool); -// return NULL; -// } -// -// gu_pool_free(tmp_pool); -// return pyexpr; -// } +static ExprObject* +pgf_readExpr(PyObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "s#", &s, &size)) + return NULL; + + PgfText *input = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1); + memcpy(input->text, s, size+1); + input->size = size; + + PgfExpr expr = pgf_read_expr(input, &unmarshaller); + PyMem_Free(input); + if (expr == 0) { + PyErr_SetString(PGFError, "expression cannot be parsed"); + return NULL; + } + + return (ExprObject *)expr; +} static TypeObject * pgf_readType(PyObject *self, PyObject *args) @@ -2535,8 +2527,8 @@ static PyMethodDef module_methods[] = { "Reads a PGF file into memory and stores the unpacked data in an NGF file"}, {"readNGF", (void*)pgf_readNGF, METH_VARARGS, "Reads an NGF file into memory"}, - // {"readExpr", (void*)pgf_readExpr, METH_VARARGS, - // "Parses a string as an abstract tree"}, + {"readExpr", (void*)pgf_readExpr, METH_VARARGS, + "Parses a string as an abstract tree"}, {"readType", (void*)pgf_readType, METH_VARARGS, "Parses a string as an abstract type"}, {NULL, NULL, 0, NULL} /* Sentinel */ @@ -2564,6 +2556,7 @@ MOD_INIT(pgf) if (PyType_Ready(&pgf_PGFType) < 0) return MOD_ERROR_VAL; + // if (PyType_Ready(&pgf_ConcrType) < 0) // return MOD_ERROR_VAL; // @@ -2572,9 +2565,12 @@ MOD_INIT(pgf) // // if (PyType_Ready(&pgf_BINDType) < 0) // return MOD_ERROR_VAL; - // - // if (PyType_Ready(&pgf_ExprType) < 0) - // return MOD_ERROR_VAL; + + if (PyType_Ready(&pgf_ExprType) < 0) + return MOD_ERROR_VAL; + + if (PyType_Ready(&pgf_ExprLitType) < 0) + return MOD_ERROR_VAL; if (PyType_Ready(&pgf_TypeType) < 0) return MOD_ERROR_VAL; @@ -2601,8 +2597,11 @@ MOD_INIT(pgf) // PyModule_AddObject(m, "TypeError", TypeError); // Py_INCREF(TypeError); - // PyModule_AddObject(m, "Expr", (PyObject *) &pgf_ExprType); - // Py_INCREF(&pgf_ExprType); + PyModule_AddObject(m, "Expr", (PyObject *) &pgf_ExprType); + Py_INCREF(&pgf_ExprType); + + PyModule_AddObject(m, "ExprLit", (PyObject *) &pgf_ExprLitType); + Py_INCREF(&pgf_ExprType); PyModule_AddObject(m, "Type", (PyObject *) &pgf_TypeType); Py_INCREF(&pgf_TypeType); diff --git a/src/runtime/python/setup.py b/src/runtime/python/setup.py index a07cb17f7..940ae8f50 100644 --- a/src/runtime/python/setup.py +++ b/src/runtime/python/setup.py @@ -10,7 +10,7 @@ if libraries==['']: pgf_module = Extension('pgf', sources = ['pypgf.c', 'marshaller.c', 'expr.c'], - extra_compile_args = ['-std=c99', '-Werror', '-Wno-comment'], + extra_compile_args = ['-std=c99', '-Werror', '-Wno-error=int-conversion', '-Wno-comment'], include_dirs = includes, library_dirs = libraries, libraries = ['pgf']) diff --git a/src/runtime/python/test_suite.py b/src/runtime/python/test_suite.py index 60ffbeee0..c3007fedb 100644 --- a/src/runtime/python/test_suite.py +++ b/src/runtime/python/test_suite.py @@ -64,7 +64,7 @@ def test_readNGF(NGF): pgf.readNGF("./basic.ngf") # TODO assert read actually worked -# abstract expressions +# abstract syntax def test_abstractName(PGF): assert PGF.abstractName == "basic" @@ -84,6 +84,8 @@ def test_functionsByCat_2(PGF): def test_functionsByCat_non_existant(PGF): assert PGF.functionsByCat("X") == [] +# types + def test_readType_invalid(): with pytest.raises(pgf.PGFError): pgf.readType("->") @@ -103,7 +105,7 @@ def test_readType_inequality_1(): def test_readType_inequality_2(): assert pgf.readType("A -> B") != pgf.readType("B->B") -# def test_Type_str_1(): +# def test_readType_str(): # assert str(pgf.readType("A-> B")) == "A -> B" def test_functionType_1(PGF): @@ -123,6 +125,31 @@ 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 assert PGF.startCat == pgf.readType("S") + +# expressions + +def test_readExpr_invalid(): + with pytest.raises(pgf.PGFError): + pgf.readExpr("->") + +def test_readExpr_equality_int(): + assert pgf.readExpr("123") == pgf.readExpr("123") + +def test_readExpr_inequality_int(): + assert pgf.readExpr("123") != pgf.readExpr("456") + +def test_readExpr_equality_float(): + assert pgf.readExpr("3.142") == pgf.readExpr("3.142") + +def test_readExpr_inequality_float(): + assert pgf.readExpr("3.142") != pgf.readExpr("3") + +def test_readExpr_equality_string(): + assert pgf.readExpr("\"abc\"") == pgf.readExpr("\"abc\"") + +def test_readExpr_inequality_string(): + assert pgf.readExpr("\"abc\"") != pgf.readExpr("\"def\"") + +# def test_readExpr_str_int(): +# assert str(pgf.readExpr("123")) == "123"