From 05cb74d14aef10c86038c516791ca2692ca6e801 Mon Sep 17 00:00:00 2001 From: "kr.angelov" Date: Tue, 29 Jan 2013 09:20:32 +0000 Subject: the Python binding is in pure C again --- src/runtime/python/pgf/__init__.py | 3 - src/runtime/python/pgf/binding.c | 1247 ------------------------------------ src/runtime/python/pgf/expr.py | 169 ----- src/runtime/python/pypgf.c | 1247 ++++++++++++++++++++++++++++++++++++ src/runtime/python/setup.py | 5 +- 5 files changed, 1249 insertions(+), 1422 deletions(-) delete mode 100644 src/runtime/python/pgf/__init__.py delete mode 100644 src/runtime/python/pgf/binding.c delete mode 100644 src/runtime/python/pgf/expr.py create mode 100644 src/runtime/python/pypgf.c (limited to 'src/runtime/python') diff --git a/src/runtime/python/pgf/__init__.py b/src/runtime/python/pgf/__init__.py deleted file mode 100644 index 07e164093..000000000 --- a/src/runtime/python/pgf/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import pgf.expr -from pgf.binding import * -from pgf.expr import (readExpr_py) diff --git a/src/runtime/python/pgf/binding.c b/src/runtime/python/pgf/binding.c deleted file mode 100644 index 3b97b6367..000000000 --- a/src/runtime/python/pgf/binding.c +++ /dev/null @@ -1,1247 +0,0 @@ -#include -#include "structmember.h" - -#include -#include -#include -#include - -static PyObject* PGFError; - -static PyObject* ParseError; - -static PyObject* -gu2py_string(GuString s) { - GuWord w = s.w_; - uint8_t buf[sizeof(GuWord)]; - - char* src; - size_t len; - if (w & 1) { - len = (w & 0xff) >> 1; - gu_assert(len <= sizeof(GuWord)); - size_t i = len; - while (i > 0) { - w >>= 8; - buf[--i] = w & 0xff; - } - src = (char*) buf; - } else { - uint8_t* p = (void*) w; - len = (p[0] == 0) ? ((size_t*) p)[-1] : p[0]; - src = (char*) &p[1]; - } - - return PyString_FromStringAndSize(src, len); -} - -typedef struct { - PyObject_HEAD - PyObject* master; - GuPool* pool; - PgfExpr expr; -} ExprObject; - -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); - } - - self->ob_type->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 PyObject* -Expr_unpack(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)", tuple_size); - return -1; - } - - return 0; -} - -static PyObject * -Expr_repr(ExprObject *self) -{ - GuPool* tmp_pool = gu_local_pool(); - - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - GuStringBuf* sbuf = gu_string_buf(tmp_pool); - GuWriter* wtr = gu_string_buf_writer(sbuf); - - pgf_print_expr(self->expr, 0, wtr, err); - - GuString str = gu_string_buf_freeze(sbuf, tmp_pool); - PyObject* pystr = gu2py_string(str); - - gu_pool_free(tmp_pool); - return pystr; -} - -static PyMethodDef Expr_methods[] = { - {"unpack", (PyCFunction)Expr_unpack, METH_VARARGS, - "Decomposes an expression into its components" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject pgf_ExprType = { - PyObject_HEAD_INIT(NULL) - 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*/ - 0, /*tp_hash */ - 0, /*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 */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - Expr_methods, /*tp_methods */ - 0, /*tp_members */ - 0, /*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)) { - PgfLiteralStr* slit = - gu_new_variant(PGF_LITERAL_STR, - PgfLiteralStr, - &e->lit, self->pool); - slit->val = gu_str_string(PyString_AsString(lit), self->pool); - } 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_variant(PGF_EXPR_FUN, - PgfExprFun, - &self->expr, self->pool); - e->fun = gu_str_string(fname, self->pool); - - 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 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_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 = 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 gu2py_string(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: { - Py_DECREF(args); - return Py_None; - } - case PGF_EXPR_FUN: { - PgfExprFun* efun = i.data; - PyObject* fun = gu2py_string(efun->fun); - PyObject* res = Py_BuildValue("OO", fun, args); - Py_DECREF(fun); - Py_DECREF(args); - return res; - } - default: - gu_impossible(); - return NULL; - } - } - return NULL; -} - -static PyObject* -Expr_getattro(ExprObject *self, PyObject *attr_name) { - const char* name = PyString_AsString(attr_name); - - GuVariantInfo i = gu_variant_open(self->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 (strcmp(name, "fun") == 0) { - pyexpr->expr = eapp->fun; - return ((PyObject*) pyexpr); - } else if (strcmp(name, "arg") == 0) { - pyexpr->expr = eapp->arg; - return ((PyObject*) pyexpr); - } else { - Py_DECREF(pyexpr); - } - break; - } - case PGF_EXPR_LIT: { - PgfExprLit* elit = i.data; - - if (strcmp(name, "val") == 0) { - 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 gu2py_string(lstr->val); - } - } - } - break; - } - case PGF_EXPR_META: { - PgfExprMeta* emeta = i.data; - if (strcmp(name, "id") == 0) - return PyInt_FromLong(emeta->id); - break; - } - case PGF_EXPR_FUN: { - PgfExprFun* efun = i.data; - if (strcmp(name, "name") == 0) { - return gu2py_string(efun->fun); - } - break; - } - default: - gu_impossible(); - } - - return PyObject_GenericGetAttr((PyObject*)self, attr_name); -} - -typedef struct { - PyObject_HEAD - GuPool* pool; - int max_count; - int counter; - GuEnum* res; -} ExprIterObject; - -static ExprIterObject* -ExprIter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - ExprIterObject* self = (ExprIterObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->pool = NULL; - self->max_count = -1; - self->counter = 0; - self->res = NULL; - } - - return self; -} - -static void -ExprIter_dealloc(ExprIterObject* self) -{ - if (self->pool != NULL) - gu_pool_free(self->pool); - - self->ob_type->tp_free((PyObject*)self); -} - -static int -ExprIter_init(ExprIterObject *self, PyObject *args, PyObject *kwds) -{ - return -1; -} - -static PyObject* -ExprIter_iter(ExprIterObject *self) -{ - Py_INCREF(self); - return (PyObject*) self; -} - -static PyObject* -ExprIter_iternext(ExprIterObject *self) -{ - if (self->max_count >= 0 && self->counter >= self->max_count) { - return NULL; - } - self->counter++; - - PgfExprProb* ep = gu_next(self->res, PgfExprProb*, self->pool); - if (ep == NULL) - return NULL; - - ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); - if (pyexpr == NULL) - return NULL; - pyexpr->pool = NULL; - pyexpr->expr = ep->expr; - pyexpr->master = (PyObject*) self; - Py_INCREF(self); - - PyObject* res = Py_BuildValue("(f,O)", ep->prob, pyexpr); - Py_DECREF(pyexpr); - - return res; -} - -static PyMethodDef ExprIter_methods[] = { - {NULL} /* Sentinel */ -}; - -static PyTypeObject pgf_ExprIterType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pgf.ExprIter", /*tp_name*/ - sizeof(ExprIterObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)ExprIter_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, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "an iterator over a sequence of expressions",/*tp_doc*/ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - (getiterfunc) ExprIter_iter, /*tp_iter */ - (iternextfunc) ExprIter_iternext, /*tp_iternext */ - ExprIter_methods, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - (initproc)ExprIter_init, /*tp_init */ - 0, /*tp_alloc */ - (newfunc) ExprIter_new, /*tp_new */ -}; - -typedef struct { - PyObject_HEAD - GuPool* pool; - PgfPGF* pgf; -} PGFObject; - -typedef struct { - PyObject_HEAD - PGFObject* grammar; - PgfConcr* concr; -} ConcrObject; - -static ConcrObject* -Concr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - ConcrObject* self = (ConcrObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->grammar = NULL; - self->concr = NULL; - } - - return self; -} - -static void -Concr_dealloc(ConcrObject* self) -{ - Py_XDECREF(self->grammar); - self->ob_type->tp_free((PyObject*)self); -} - -static int -Concr_init(ConcrObject *self, PyObject *args, PyObject *kwds) -{ - return -1; -} - -static PyObject* -Concr_printName(ConcrObject* self, PyObject *args) -{ - const char *name_s; - if (!PyArg_ParseTuple(args, "s", &name_s)) - return NULL; - - GuPool *tmp_pool = gu_local_pool(); - GuString name = gu_str_string(name_s, tmp_pool); - PyObject* pyname = gu2py_string(pgf_print_name(self->concr, name)); - gu_pool_free(tmp_pool); - - return pyname; -} - -static ExprIterObject* -Concr_parse(ConcrObject* self, PyObject *args, PyObject *keywds) -{ - static char *kwlist[] = {"sentence", "cat", "n", NULL}; - - size_t len; - const uint8_t *buf; - const char *catname_s = NULL; - int max_count = -1; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#|si", kwlist, - &buf, &len, &catname_s, &max_count)) - return NULL; - - ExprIterObject* pyres = (ExprIterObject*) - pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); - if (pyres == NULL) { - return NULL; - } - - pyres->pool = gu_new_pool(); - pyres->max_count = max_count; - pyres->counter = 0; - - GuPool *tmp_pool = gu_local_pool(); - GuString catname = - (catname_s == NULL) ? pgf_start_cat(self->grammar->pgf, tmp_pool) - : gu_str_string(catname_s, tmp_pool); - GuIn* in = gu_data_in(buf, len, tmp_pool); - GuReader* rdr = gu_new_utf8_reader(in, tmp_pool); - PgfLexer *lexer = - pgf_new_lexer(rdr, tmp_pool); - - pyres->res = - pgf_parse(self->concr, catname, lexer, pyres->pool); - if (pyres->res == NULL) { - Py_DECREF(pyres); - - PgfToken tok = - pgf_lexer_current_token(lexer); - - if (gu_string_eq(tok, gu_empty_string)) - PyErr_SetString(PGFError, "The sentence cannot be parsed"); - else { - PyObject* py_tok = gu2py_string(tok); - PyObject_SetAttrString(ParseError, "token", py_tok); - PyErr_Format(ParseError, "Unexpected token: \"%s\"", - PyString_AsString(py_tok)); - Py_DECREF(py_tok); - } - - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - - return pyres; -} - -// Concr_parse_tokens is the same as the above function but -// instead of a string it expect a sequence of tokens as argument. -// This is usefull if you want to implement your own tokenizer in -// python. -static ExprIterObject* -Concr_parse_tokens(ConcrObject* self, PyObject *args, PyObject *keywds) -{ - static char *kwlist[] = {"tokens", "cat", "n", NULL}; - // Variable for the input list of tokens - PyObject* obj; - PyObject* seq; - int len; - const char *catname_s = NULL; - int max_count = -1; - - // Parsing arguments: the tokens is a python object (O), - // cat is a string (s) and n an integer (i) - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|si", kwlist, - &obj, &catname_s, &max_count)) - return NULL; - // The python object should be a sequence - seq = PySequence_Fast(obj, "expected a sequence"); - len = PySequence_Size(obj); - - ExprIterObject* pyres = (ExprIterObject*) - pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); - if (pyres == NULL) { - return NULL; - } - - pyres->pool = gu_new_pool(); - pyres->max_count = max_count; - pyres->counter = 0; - - GuPool *tmp_pool = gu_local_pool(); - GuString catname = - (catname_s == NULL) ? pgf_start_cat(self->grammar->pgf, tmp_pool) - : gu_str_string(catname_s, tmp_pool); - - // turn the (python) list of tokens into a string array - char* tokens[len]; - for (int i = 0; i < len; i++) { - tokens[i] = PyString_AsString(PySequence_Fast_GET_ITEM(seq, i)); - if (tokens[i] == NULL) { - // Note: if the list item is not a string, - // PyString_AsString raises TypeError itself - // so we just have to return - gu_pool_free(tmp_pool); - return NULL; - } - } - Py_DECREF(seq); - - pyres->res = - pgf_parse_tokens(self->concr, catname, tokens, len, pyres->pool); - - if (pyres->res == NULL) { - Py_DECREF(pyres); - - PyErr_SetString(PGFError, "Something went wrong during parsing"); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - return pyres; -} - -static PyObject* -Concr_linearize(ConcrObject* self, PyObject *args) -{ - ExprObject* pyexpr; - if (!PyArg_ParseTuple(args, "O!", &pgf_ExprType, &pyexpr)) - return NULL; - - GuPool* tmp_pool = gu_local_pool(); - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - GuStringBuf* sbuf = gu_string_buf(tmp_pool); - GuWriter* wtr = gu_string_buf_writer(sbuf); - - pgf_linearize(self->concr, pyexpr->expr, wtr, err); - if (!gu_ok(err)) { - PyErr_SetString(PGFError, "The abstract tree cannot be linearized"); - return NULL; - } - - GuString str = gu_string_buf_freeze(sbuf, tmp_pool); - PyObject* pystr = gu2py_string(str); - - gu_pool_free(tmp_pool); - return pystr; -} - -static PyMethodDef Concr_methods[] = { - {"printName", (PyCFunction)Concr_printName, METH_VARARGS, - "Returns the print name of a function or category" - }, - {"parse", (PyCFunction)Concr_parse, METH_VARARGS | METH_KEYWORDS, - "Parses a string and returns an iterator over the abstract trees for this sentence" - }, - {"parse_tokens", (PyCFunction)Concr_parse_tokens, METH_VARARGS | METH_KEYWORDS, - "Parses list of tokens and returns an iterator over the abstract trees for this sentence. Allows you to write your own tokenizer in python." - }, - {"linearize", (PyCFunction)Concr_linearize, METH_VARARGS, - "Takes an abstract tree and linearizes it to a sentence" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject pgf_ConcrType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pgf.Concr", /*tp_name*/ - sizeof(ConcrObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Concr_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, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "concrete syntax", /*tp_doc*/ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - Concr_methods, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - (initproc)Concr_init, /*tp_init */ - 0, /*tp_alloc */ - (newfunc)Concr_new, /*tp_new */ -}; - -static PGFObject* -PGF_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PGFObject* self = (PGFObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->pool = NULL; - self->pgf = NULL; - } - - return self; -} - -static void -PGF_dealloc(PGFObject* self) -{ - if (self->pool != NULL) - gu_pool_free(self->pool); - self->ob_type->tp_free((PyObject*)self); -} - -static int -PGF_init(PGFObject *self, PyObject *args, PyObject *kwds) -{ - return -1; -} - -static PyObject* -PGF_getAbstractName(PGFObject *self, void *closure) -{ - return gu2py_string(pgf_abstract_name(self->pgf)); -} - -typedef struct { - GuMapItor fn; - PGFObject* grammar; - PyObject* object; -} PyPGFClosure; - -static void -pgf_collect_langs(GuMapItor* fn, const void* key, void* value, GuExn* err) -{ - PgfCId name = *((PgfCId*) key); - PgfConcr* concr = *((PgfConcr**) value); - PyPGFClosure* clo = (PyPGFClosure*) fn; - - PyObject* py_name = NULL; - PyObject* py_lang = NULL; - - py_name = gu2py_string(name); - if (py_name == NULL) { - gu_raise(err, PgfExn); - goto end; - } - - py_lang = pgf_ConcrType.tp_alloc(&pgf_ConcrType, 0); - if (py_lang == NULL) { - gu_raise(err, PgfExn); - goto end; - } - - ((ConcrObject *) py_lang)->concr = concr; - ((ConcrObject *) py_lang)->grammar = clo->grammar; - Py_INCREF(clo->grammar); - - if (PyDict_SetItem(clo->object, py_name, py_lang) != 0) { - gu_raise(err, PgfExn); - goto end; - } - -end: - Py_XDECREF(py_lang); - Py_XDECREF(py_name); -} - -static PyObject* -PGF_getLanguages(PGFObject *self, void *closure) -{ - PyObject* languages = PyDict_New(); - if (languages == NULL) - return NULL; - - GuPool* tmp_pool = gu_local_pool(); - - // Create an exception frame that catches all errors. - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - PyPGFClosure clo = { { pgf_collect_langs }, self, languages }; - pgf_iter_languages(self->pgf, &clo.fn, err); - if (!gu_ok(err)) { - Py_DECREF(languages); - gu_pool_free(tmp_pool); - return NULL; - } - - PyObject* proxy = PyDictProxy_New(languages); - - Py_DECREF(languages); - gu_pool_free(tmp_pool); - - return proxy; -} - -static void -pgf_collect_cats(GuMapItor* fn, const void* key, void* value, GuExn* err) -{ - PgfCId name = *((PgfCId*) key); - PyPGFClosure* clo = (PyPGFClosure*) fn; - - PyObject* py_name = NULL; - - py_name = gu2py_string(name); - if (py_name == NULL) { - gu_raise(err, PgfExn); - goto end; - } - - if (PyList_Append(clo->object, py_name) != 0) { - gu_raise(err, PgfExn); - goto end; - } - -end: - Py_XDECREF(py_name); -} - -static PyObject* -PGF_getCategories(PGFObject *self, void *closure) -{ - PyObject* categories = PyList_New(0); - if (categories == NULL) - return NULL; - - GuPool* tmp_pool = gu_local_pool(); - - // Create an exception frame that catches all errors. - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - PyPGFClosure clo = { { pgf_collect_cats }, self, categories }; - pgf_iter_categories(self->pgf, &clo.fn, err); - if (!gu_ok(err)) { - Py_DECREF(categories); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - return categories; -} - -static PyObject* -PGF_getStartCat(PGFObject *self, void *closure) -{ - GuPool* tmp_pool = gu_local_pool(); - PyObject* pyname = gu2py_string(pgf_start_cat(self->pgf, tmp_pool)); - gu_pool_free(tmp_pool); - return pyname; -} - -static void -pgf_collect_funs(GuMapItor* fn, const void* key, void* value, GuExn* err) -{ - PgfCId name = *((PgfCId*) key); - PyPGFClosure* clo = (PyPGFClosure*) fn; - - PyObject* py_name = NULL; - - py_name = gu2py_string(name); - if (py_name == NULL) { - gu_raise(err, PgfExn); - goto end; - } - - if (PyList_Append(clo->object, py_name) != 0) { - gu_raise(err, PgfExn); - goto end; - } - -end: - Py_XDECREF(py_name); -} - -static PyObject* -PGF_getFunctions(PGFObject *self, void *closure) -{ - PyObject* functions = PyList_New(0); - if (functions == NULL) - return NULL; - - GuPool* tmp_pool = gu_local_pool(); - - // Create an exception frame that catches all errors. - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - PyPGFClosure clo = { { pgf_collect_funs }, self, functions }; - pgf_iter_functions(self->pgf, &clo.fn, err); - if (!gu_ok(err)) { - Py_DECREF(functions); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - return functions; -} - -static PyObject* -PGF_functionsByCat(PGFObject* self, PyObject *args) -{ - const char *catname_s; - if (!PyArg_ParseTuple(args, "s", &catname_s)) - return NULL; - - GuPool *tmp_pool = gu_local_pool(); - GuString catname = gu_str_string(catname_s, tmp_pool); - - PyObject* functions = PyList_New(0); - if (functions == NULL) { - gu_pool_free(tmp_pool); - return NULL; - } - - // Create an exception frame that catches all errors. - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - PyPGFClosure clo = { { pgf_collect_funs }, self, functions }; - pgf_iter_functions_by_cat(self->pgf, catname, &clo.fn, err); - if (!gu_ok(err)) { - Py_DECREF(functions); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - return functions; -} - -static ExprIterObject* -PGF_generate(PGFObject* self, PyObject *args, PyObject *keywds) -{ - static char *kwlist[] = {"cat", "n", NULL}; - - const char *catname_s; - int max_count = -1; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|i", kwlist, - &catname_s, &max_count)) - return NULL; - - ExprIterObject* pyres = (ExprIterObject*) - pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); - if (pyres == NULL) { - return NULL; - } - - pyres->pool = gu_new_pool(); - pyres->max_count = max_count; - pyres->counter = 0; - - GuPool *tmp_pool = gu_local_pool(); - GuString catname = gu_str_string(catname_s, tmp_pool); - - pyres->res = - pgf_generate(self->pgf, catname, pyres->pool); - if (pyres->res == NULL) { - Py_DECREF(pyres); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - - return pyres; -} - -static PyGetSetDef PGF_getseters[] = { - {"abstractName", - (getter)PGF_getAbstractName, NULL, - "the abstract syntax name", - NULL}, - {"languages", - (getter)PGF_getLanguages, NULL, - "a map containing all concrete languages in the grammar", - NULL}, - {"categories", - (getter)PGF_getCategories, NULL, - "a list containing all categories in the grammar", - NULL}, - {"startCat", - (getter)PGF_getStartCat, NULL, - "the start category for the grammar", - NULL}, - {"functions", - (getter)PGF_getFunctions, NULL, - "a list containing all functions in the grammar", - NULL}, - {NULL} /* Sentinel */ -}; - -static PyMemberDef PGF_members[] = { - {NULL} /* Sentinel */ -}; - -static PyMethodDef PGF_methods[] = { - {"functionsByCat", (PyCFunction)PGF_functionsByCat, METH_VARARGS, - "Returns the list of functions for a given category" - }, - {"generate", (PyCFunction)PGF_generate, METH_VARARGS | METH_KEYWORDS, - "Generates abstract syntax trees of given category in decreasing probability order" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject pgf_PGFType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pgf.PGF", /*tp_name*/ - sizeof(PGFObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)PGF_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, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "PGF object", /*tp_doc*/ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - PGF_methods, /*tp_methods */ - PGF_members, /*tp_members */ - PGF_getseters, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - (initproc)PGF_init, /*tp_init */ - 0, /*tp_alloc */ - (newfunc)PGF_new, /*tp_new */ -}; - -static PGFObject* -pgf_readPGF(PyObject *self, PyObject *args) -{ - const char *fpath; - if (!PyArg_ParseTuple(args, "s", &fpath)) - return NULL; - - PGFObject* py_pgf = (PGFObject*) pgf_PGFType.tp_alloc(&pgf_PGFType, 0); - py_pgf->pool = gu_new_pool(); - - GuPool* tmp_pool = gu_local_pool(); - - // Create an exception frame that catches all errors. - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - // Read the PGF grammar. - py_pgf->pgf = pgf_read(fpath, py_pgf->pool, err); - if (!gu_ok(err)) { - PyErr_SetString(PGFError, "The grammar cannot be loaded"); - Py_DECREF(py_pgf); - gu_pool_free(tmp_pool); - return NULL; - } - - gu_pool_free(tmp_pool); - return py_pgf; -} - -static ExprObject* -pgf_readExpr(PyObject *self, PyObject *args) { - size_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); - GuReader* rdr = gu_new_utf8_reader(in, tmp_pool); - GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); - - pyexpr->pool = gu_new_pool(); - pyexpr->expr = pgf_read_expr(rdr, pyexpr->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 PyMethodDef module_methods[] = { - {"readPGF", (void*)pgf_readPGF, METH_VARARGS, - "Reads a PGF file in the memory"}, - {"readExpr", (void*)pgf_readExpr, METH_VARARGS, - "Parses a string as an abstract tree"}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - -PyMODINIT_FUNC -initbinding(void) -{ - PyObject *m; - - if (PyType_Ready(&pgf_PGFType) < 0) - return; - - if (PyType_Ready(&pgf_ConcrType) < 0) - return; - - if (PyType_Ready(&pgf_ExprType) < 0) - return; - - if (PyType_Ready(&pgf_ExprIterType) < 0) - return; - - m = Py_InitModule("binding", module_methods); - if (m == NULL) - return; - - PGFError = PyErr_NewException("pgf.PGFError", NULL, NULL); - PyModule_AddObject(m, "PGFError", PGFError); - Py_INCREF(PGFError); - - PyObject *dict = PyDict_New(); - PyDict_SetItemString(dict, "token", PyString_FromString("")); - ParseError = PyErr_NewException("pgf.ParseError", NULL, dict); - PyModule_AddObject(m, "ParseError", ParseError); - Py_INCREF(ParseError); - - PyModule_AddObject(m, "Expr", (PyObject *) &pgf_ExprType); - Py_INCREF(&pgf_ExprType); - - Py_INCREF(&pgf_PGFType); - Py_INCREF(&pgf_ConcrType); - Py_INCREF(&pgf_ExprIterType); -} diff --git a/src/runtime/python/pgf/expr.py b/src/runtime/python/pgf/expr.py deleted file mode 100644 index 83cccd39f..000000000 --- a/src/runtime/python/pgf/expr.py +++ /dev/null @@ -1,169 +0,0 @@ -import pgf.binding -import StringIO - -class App: - """An application of a function to an argument""" - - def __init__(self, fun, arg): - self.fun = fun - self.arg = arg - - def showExpr(self, prec): - s = self.fun.showExpr(3) + " " + self.arg.showExpr(4) - if prec > 3: - s = "(" + s + ")" - return s - - def __str__(self): - return self.showExpr(0) - -class Lit: - """A literal value""" - - def __init__(self, value): - self.value = value - - def showExpr(self, prec): - if isinstance(self.value, str): - return '"' + self.value + '"' - else: - return str(self.value) - - def __str__(self): - return self.showExpr(0) - -class Meta: - """A meta variable""" - - def __init__(self, metaid): - self.metaid = metaid - - def showExpr(self, prec): - return "?" - - def __str__(self): - return self.showExpr(0) - -class Fun: - """A function name""" - - def __init__(self, name): - self.name = name - - def showExpr(self, prec): - return self.name - - def __str__(self): - return self.showExpr(0) - -class __ExprParser: - # token types - TOKEN_UNKNOWN = 0 - TOKEN_LPARENT = 1 - TOKEN_RPARENT = 2 - TOKEN_QUESTION = 3 - TOKEN_IDENT = 4 - TOKEN_STRING = 5 - TOKEN_INT = 6 - TOKEN_FLOAT = 7 - TOKEN_EOF = 8 - - def __init__(self, fh): - self.ch = ' ' - self.fh = fh - self.token = self.TOKEN_UNKNOWN - self.token_value = "" - self.readToken() - - def readToken(self): - while self.ch.isspace(): - self.ch = self.fh.read(1); - - self.token_value = "" - - if self.ch == '(': - self.ch = self.fh.read(1); - self.token = self.TOKEN_LPARENT - elif self.ch == ')': - self.ch = self.fh.read(1); - self.token = self.TOKEN_RPARENT - elif self.ch == '?': - self.ch = self.fh.read(1); - self.token = self.TOKEN_QUESTION - elif (self.ch.isalpha() or self.ch == '_'): - self.token = self.TOKEN_IDENT - while (self.ch.isalnum() or self.ch == '_' or self.ch == "'"): - self.token_value = self.token_value + self.ch - self.ch = self.fh.read(1) - elif self.ch == '"': - self.ch = self.fh.read(1) - self.token = self.TOKEN_STRING - while self.ch != '"': - if self.ch == '': - raise pgf.ParseError("Missing quotation mark") - self.token_value = self.token_value + self.ch - self.ch = self.fh.read(1) - self.ch = self.fh.read(1) - elif self.ch.isdigit(): - self.token = self.TOKEN_INT - while self.ch.isdigit(): - self.token_value = self.token_value + self.ch - self.ch = self.fh.read(1) - - if self.ch == '.': - self.token = self.TOKEN_FLOAT - - self.token_value = self.token_value + self.ch - self.ch = self.fh.read(1) - - while self.ch.isdigit(): - self.token_value = self.token_value + self.ch - self.ch = self.fh.read(1) - - elif self.ch == '': - self.token = self.TOKEN_EOF - else: - self.token = self.TOKEN_UNKNOWN - - def parseTerm(self): - if self.token == self.TOKEN_IDENT: - e = Fun(self.token_value) - self.readToken() - return e - elif self.token == self.TOKEN_LPARENT: - self.readToken() - e = self.parseExpr() - if self.token == self.TOKEN_RPARENT: - self.readToken() - return e; - else: - raise pgf.ParseError("Missing right parenthesis") - elif self.token == self.TOKEN_QUESTION: - e = Meta(0) - self.readToken() - return e - elif self.token == self.TOKEN_STRING: - e = Lit(self.token_value) - self.readToken() - return e - elif self.token == self.TOKEN_INT: - e = Lit(int(self.token_value)) - self.readToken() - return e - elif self.token == self.TOKEN_FLOAT: - e = Lit(float(self.token_value)) - self.readToken() - return e - else: - raise pgf.ParseError("Unknown token") - - def parseExpr(self): - e = self.parseTerm() - while (self.token != self.TOKEN_EOF and - self.token != self.TOKEN_RPARENT): - e = App(e, self.parseTerm()) - return e - -def readExpr_py(str): - parser = __ExprParser(StringIO.StringIO(str)) - return parser.parseExpr() diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c new file mode 100644 index 000000000..98ca25e3a --- /dev/null +++ b/src/runtime/python/pypgf.c @@ -0,0 +1,1247 @@ +#include +#include "structmember.h" + +#include +#include +#include +#include + +static PyObject* PGFError; + +static PyObject* ParseError; + +static PyObject* +gu2py_string(GuString s) { + GuWord w = s.w_; + uint8_t buf[sizeof(GuWord)]; + + char* src; + size_t len; + if (w & 1) { + len = (w & 0xff) >> 1; + gu_assert(len <= sizeof(GuWord)); + size_t i = len; + while (i > 0) { + w >>= 8; + buf[--i] = w & 0xff; + } + src = (char*) buf; + } else { + uint8_t* p = (void*) w; + len = (p[0] == 0) ? ((size_t*) p)[-1] : p[0]; + src = (char*) &p[1]; + } + + return PyString_FromStringAndSize(src, len); +} + +typedef struct { + PyObject_HEAD + PyObject* master; + GuPool* pool; + PgfExpr expr; +} ExprObject; + +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); + } + + self->ob_type->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 PyObject* +Expr_unpack(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)", tuple_size); + return -1; + } + + return 0; +} + +static PyObject * +Expr_repr(ExprObject *self) +{ + GuPool* tmp_pool = gu_local_pool(); + + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + GuStringBuf* sbuf = gu_string_buf(tmp_pool); + GuWriter* wtr = gu_string_buf_writer(sbuf); + + pgf_print_expr(self->expr, 0, wtr, err); + + GuString str = gu_string_buf_freeze(sbuf, tmp_pool); + PyObject* pystr = gu2py_string(str); + + gu_pool_free(tmp_pool); + return pystr; +} + +static PyMethodDef Expr_methods[] = { + {"unpack", (PyCFunction)Expr_unpack, METH_VARARGS, + "Decomposes an expression into its components" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject pgf_ExprType = { + PyObject_HEAD_INIT(NULL) + 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*/ + 0, /*tp_hash */ + 0, /*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 */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + Expr_methods, /*tp_methods */ + 0, /*tp_members */ + 0, /*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)) { + PgfLiteralStr* slit = + gu_new_variant(PGF_LITERAL_STR, + PgfLiteralStr, + &e->lit, self->pool); + slit->val = gu_str_string(PyString_AsString(lit), self->pool); + } 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_variant(PGF_EXPR_FUN, + PgfExprFun, + &self->expr, self->pool); + e->fun = gu_str_string(fname, self->pool); + + 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 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_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 = 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 gu2py_string(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: { + Py_DECREF(args); + return Py_None; + } + case PGF_EXPR_FUN: { + PgfExprFun* efun = i.data; + PyObject* fun = gu2py_string(efun->fun); + PyObject* res = Py_BuildValue("OO", fun, args); + Py_DECREF(fun); + Py_DECREF(args); + return res; + } + default: + gu_impossible(); + return NULL; + } + } + return NULL; +} + +static PyObject* +Expr_getattro(ExprObject *self, PyObject *attr_name) { + const char* name = PyString_AsString(attr_name); + + GuVariantInfo i = gu_variant_open(self->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 (strcmp(name, "fun") == 0) { + pyexpr->expr = eapp->fun; + return ((PyObject*) pyexpr); + } else if (strcmp(name, "arg") == 0) { + pyexpr->expr = eapp->arg; + return ((PyObject*) pyexpr); + } else { + Py_DECREF(pyexpr); + } + break; + } + case PGF_EXPR_LIT: { + PgfExprLit* elit = i.data; + + if (strcmp(name, "val") == 0) { + 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 gu2py_string(lstr->val); + } + } + } + break; + } + case PGF_EXPR_META: { + PgfExprMeta* emeta = i.data; + if (strcmp(name, "id") == 0) + return PyInt_FromLong(emeta->id); + break; + } + case PGF_EXPR_FUN: { + PgfExprFun* efun = i.data; + if (strcmp(name, "name") == 0) { + return gu2py_string(efun->fun); + } + break; + } + default: + gu_impossible(); + } + + return PyObject_GenericGetAttr((PyObject*)self, attr_name); +} + +typedef struct { + PyObject_HEAD + GuPool* pool; + int max_count; + int counter; + GuEnum* res; +} ExprIterObject; + +static ExprIterObject* +ExprIter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + ExprIterObject* self = (ExprIterObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->pool = NULL; + self->max_count = -1; + self->counter = 0; + self->res = NULL; + } + + return self; +} + +static void +ExprIter_dealloc(ExprIterObject* self) +{ + if (self->pool != NULL) + gu_pool_free(self->pool); + + self->ob_type->tp_free((PyObject*)self); +} + +static int +ExprIter_init(ExprIterObject *self, PyObject *args, PyObject *kwds) +{ + return -1; +} + +static PyObject* +ExprIter_iter(ExprIterObject *self) +{ + Py_INCREF(self); + return (PyObject*) self; +} + +static PyObject* +ExprIter_iternext(ExprIterObject *self) +{ + if (self->max_count >= 0 && self->counter >= self->max_count) { + return NULL; + } + self->counter++; + + PgfExprProb* ep = gu_next(self->res, PgfExprProb*, self->pool); + if (ep == NULL) + return NULL; + + ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0); + if (pyexpr == NULL) + return NULL; + pyexpr->pool = NULL; + pyexpr->expr = ep->expr; + pyexpr->master = (PyObject*) self; + Py_INCREF(self); + + PyObject* res = Py_BuildValue("(f,O)", ep->prob, pyexpr); + Py_DECREF(pyexpr); + + return res; +} + +static PyMethodDef ExprIter_methods[] = { + {NULL} /* Sentinel */ +}; + +static PyTypeObject pgf_ExprIterType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pgf.ExprIter", /*tp_name*/ + sizeof(ExprIterObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)ExprIter_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, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "an iterator over a sequence of expressions",/*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + (getiterfunc) ExprIter_iter, /*tp_iter */ + (iternextfunc) ExprIter_iternext, /*tp_iternext */ + ExprIter_methods, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)ExprIter_init, /*tp_init */ + 0, /*tp_alloc */ + (newfunc) ExprIter_new, /*tp_new */ +}; + +typedef struct { + PyObject_HEAD + GuPool* pool; + PgfPGF* pgf; +} PGFObject; + +typedef struct { + PyObject_HEAD + PGFObject* grammar; + PgfConcr* concr; +} ConcrObject; + +static ConcrObject* +Concr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + ConcrObject* self = (ConcrObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->grammar = NULL; + self->concr = NULL; + } + + return self; +} + +static void +Concr_dealloc(ConcrObject* self) +{ + Py_XDECREF(self->grammar); + self->ob_type->tp_free((PyObject*)self); +} + +static int +Concr_init(ConcrObject *self, PyObject *args, PyObject *kwds) +{ + return -1; +} + +static PyObject* +Concr_printName(ConcrObject* self, PyObject *args) +{ + const char *name_s; + if (!PyArg_ParseTuple(args, "s", &name_s)) + return NULL; + + GuPool *tmp_pool = gu_local_pool(); + GuString name = gu_str_string(name_s, tmp_pool); + PyObject* pyname = gu2py_string(pgf_print_name(self->concr, name)); + gu_pool_free(tmp_pool); + + return pyname; +} + +static ExprIterObject* +Concr_parse(ConcrObject* self, PyObject *args, PyObject *keywds) +{ + static char *kwlist[] = {"sentence", "cat", "n", NULL}; + + size_t len; + const uint8_t *buf; + const char *catname_s = NULL; + int max_count = -1; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#|si", kwlist, + &buf, &len, &catname_s, &max_count)) + return NULL; + + ExprIterObject* pyres = (ExprIterObject*) + pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); + if (pyres == NULL) { + return NULL; + } + + pyres->pool = gu_new_pool(); + pyres->max_count = max_count; + pyres->counter = 0; + + GuPool *tmp_pool = gu_local_pool(); + GuString catname = + (catname_s == NULL) ? pgf_start_cat(self->grammar->pgf, tmp_pool) + : gu_str_string(catname_s, tmp_pool); + GuIn* in = gu_data_in(buf, len, tmp_pool); + GuReader* rdr = gu_new_utf8_reader(in, tmp_pool); + PgfLexer *lexer = + pgf_new_lexer(rdr, tmp_pool); + + pyres->res = + pgf_parse(self->concr, catname, lexer, pyres->pool); + if (pyres->res == NULL) { + Py_DECREF(pyres); + + PgfToken tok = + pgf_lexer_current_token(lexer); + + if (gu_string_eq(tok, gu_empty_string)) + PyErr_SetString(PGFError, "The sentence cannot be parsed"); + else { + PyObject* py_tok = gu2py_string(tok); + PyObject_SetAttrString(ParseError, "token", py_tok); + PyErr_Format(ParseError, "Unexpected token: \"%s\"", + PyString_AsString(py_tok)); + Py_DECREF(py_tok); + } + + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + + return pyres; +} + +// Concr_parse_tokens is the same as the above function but +// instead of a string it expect a sequence of tokens as argument. +// This is usefull if you want to implement your own tokenizer in +// python. +static ExprIterObject* +Concr_parse_tokens(ConcrObject* self, PyObject *args, PyObject *keywds) +{ + static char *kwlist[] = {"tokens", "cat", "n", NULL}; + // Variable for the input list of tokens + PyObject* obj; + PyObject* seq; + int len; + const char *catname_s = NULL; + int max_count = -1; + + // Parsing arguments: the tokens is a python object (O), + // cat is a string (s) and n an integer (i) + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|si", kwlist, + &obj, &catname_s, &max_count)) + return NULL; + // The python object should be a sequence + seq = PySequence_Fast(obj, "expected a sequence"); + len = PySequence_Size(obj); + + ExprIterObject* pyres = (ExprIterObject*) + pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); + if (pyres == NULL) { + return NULL; + } + + pyres->pool = gu_new_pool(); + pyres->max_count = max_count; + pyres->counter = 0; + + GuPool *tmp_pool = gu_local_pool(); + GuString catname = + (catname_s == NULL) ? pgf_start_cat(self->grammar->pgf, tmp_pool) + : gu_str_string(catname_s, tmp_pool); + + // turn the (python) list of tokens into a string array + char* tokens[len]; + for (int i = 0; i < len; i++) { + tokens[i] = PyString_AsString(PySequence_Fast_GET_ITEM(seq, i)); + if (tokens[i] == NULL) { + // Note: if the list item is not a string, + // PyString_AsString raises TypeError itself + // so we just have to return + gu_pool_free(tmp_pool); + return NULL; + } + } + Py_DECREF(seq); + + pyres->res = + pgf_parse_tokens(self->concr, catname, tokens, len, pyres->pool); + + if (pyres->res == NULL) { + Py_DECREF(pyres); + + PyErr_SetString(PGFError, "Something went wrong during parsing"); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return pyres; +} + +static PyObject* +Concr_linearize(ConcrObject* self, PyObject *args) +{ + ExprObject* pyexpr; + if (!PyArg_ParseTuple(args, "O!", &pgf_ExprType, &pyexpr)) + return NULL; + + GuPool* tmp_pool = gu_local_pool(); + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + GuStringBuf* sbuf = gu_string_buf(tmp_pool); + GuWriter* wtr = gu_string_buf_writer(sbuf); + + pgf_linearize(self->concr, pyexpr->expr, wtr, err); + if (!gu_ok(err)) { + PyErr_SetString(PGFError, "The abstract tree cannot be linearized"); + return NULL; + } + + GuString str = gu_string_buf_freeze(sbuf, tmp_pool); + PyObject* pystr = gu2py_string(str); + + gu_pool_free(tmp_pool); + return pystr; +} + +static PyMethodDef Concr_methods[] = { + {"printName", (PyCFunction)Concr_printName, METH_VARARGS, + "Returns the print name of a function or category" + }, + {"parse", (PyCFunction)Concr_parse, METH_VARARGS | METH_KEYWORDS, + "Parses a string and returns an iterator over the abstract trees for this sentence" + }, + {"parse_tokens", (PyCFunction)Concr_parse_tokens, METH_VARARGS | METH_KEYWORDS, + "Parses list of tokens and returns an iterator over the abstract trees for this sentence. Allows you to write your own tokenizer in python." + }, + {"linearize", (PyCFunction)Concr_linearize, METH_VARARGS, + "Takes an abstract tree and linearizes it to a sentence" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject pgf_ConcrType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pgf.Concr", /*tp_name*/ + sizeof(ConcrObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Concr_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, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "concrete syntax", /*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + Concr_methods, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)Concr_init, /*tp_init */ + 0, /*tp_alloc */ + (newfunc)Concr_new, /*tp_new */ +}; + +static PGFObject* +PGF_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PGFObject* self = (PGFObject *)type->tp_alloc(type, 0); + if (self != NULL) { + self->pool = NULL; + self->pgf = NULL; + } + + return self; +} + +static void +PGF_dealloc(PGFObject* self) +{ + if (self->pool != NULL) + gu_pool_free(self->pool); + self->ob_type->tp_free((PyObject*)self); +} + +static int +PGF_init(PGFObject *self, PyObject *args, PyObject *kwds) +{ + return -1; +} + +static PyObject* +PGF_getAbstractName(PGFObject *self, void *closure) +{ + return gu2py_string(pgf_abstract_name(self->pgf)); +} + +typedef struct { + GuMapItor fn; + PGFObject* grammar; + PyObject* object; +} PyPGFClosure; + +static void +pgf_collect_langs(GuMapItor* fn, const void* key, void* value, GuExn* err) +{ + PgfCId name = *((PgfCId*) key); + PgfConcr* concr = *((PgfConcr**) value); + PyPGFClosure* clo = (PyPGFClosure*) fn; + + PyObject* py_name = NULL; + PyObject* py_lang = NULL; + + py_name = gu2py_string(name); + if (py_name == NULL) { + gu_raise(err, PgfExn); + goto end; + } + + py_lang = pgf_ConcrType.tp_alloc(&pgf_ConcrType, 0); + if (py_lang == NULL) { + gu_raise(err, PgfExn); + goto end; + } + + ((ConcrObject *) py_lang)->concr = concr; + ((ConcrObject *) py_lang)->grammar = clo->grammar; + Py_INCREF(clo->grammar); + + if (PyDict_SetItem(clo->object, py_name, py_lang) != 0) { + gu_raise(err, PgfExn); + goto end; + } + +end: + Py_XDECREF(py_lang); + Py_XDECREF(py_name); +} + +static PyObject* +PGF_getLanguages(PGFObject *self, void *closure) +{ + PyObject* languages = PyDict_New(); + if (languages == NULL) + return NULL; + + GuPool* tmp_pool = gu_local_pool(); + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + PyPGFClosure clo = { { pgf_collect_langs }, self, languages }; + pgf_iter_languages(self->pgf, &clo.fn, err); + if (!gu_ok(err)) { + Py_DECREF(languages); + gu_pool_free(tmp_pool); + return NULL; + } + + PyObject* proxy = PyDictProxy_New(languages); + + Py_DECREF(languages); + gu_pool_free(tmp_pool); + + return proxy; +} + +static void +pgf_collect_cats(GuMapItor* fn, const void* key, void* value, GuExn* err) +{ + PgfCId name = *((PgfCId*) key); + PyPGFClosure* clo = (PyPGFClosure*) fn; + + PyObject* py_name = NULL; + + py_name = gu2py_string(name); + if (py_name == NULL) { + gu_raise(err, PgfExn); + goto end; + } + + if (PyList_Append(clo->object, py_name) != 0) { + gu_raise(err, PgfExn); + goto end; + } + +end: + Py_XDECREF(py_name); +} + +static PyObject* +PGF_getCategories(PGFObject *self, void *closure) +{ + PyObject* categories = PyList_New(0); + if (categories == NULL) + return NULL; + + GuPool* tmp_pool = gu_local_pool(); + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + PyPGFClosure clo = { { pgf_collect_cats }, self, categories }; + pgf_iter_categories(self->pgf, &clo.fn, err); + if (!gu_ok(err)) { + Py_DECREF(categories); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return categories; +} + +static PyObject* +PGF_getStartCat(PGFObject *self, void *closure) +{ + GuPool* tmp_pool = gu_local_pool(); + PyObject* pyname = gu2py_string(pgf_start_cat(self->pgf, tmp_pool)); + gu_pool_free(tmp_pool); + return pyname; +} + +static void +pgf_collect_funs(GuMapItor* fn, const void* key, void* value, GuExn* err) +{ + PgfCId name = *((PgfCId*) key); + PyPGFClosure* clo = (PyPGFClosure*) fn; + + PyObject* py_name = NULL; + + py_name = gu2py_string(name); + if (py_name == NULL) { + gu_raise(err, PgfExn); + goto end; + } + + if (PyList_Append(clo->object, py_name) != 0) { + gu_raise(err, PgfExn); + goto end; + } + +end: + Py_XDECREF(py_name); +} + +static PyObject* +PGF_getFunctions(PGFObject *self, void *closure) +{ + PyObject* functions = PyList_New(0); + if (functions == NULL) + return NULL; + + GuPool* tmp_pool = gu_local_pool(); + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + PyPGFClosure clo = { { pgf_collect_funs }, self, functions }; + pgf_iter_functions(self->pgf, &clo.fn, err); + if (!gu_ok(err)) { + Py_DECREF(functions); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return functions; +} + +static PyObject* +PGF_functionsByCat(PGFObject* self, PyObject *args) +{ + const char *catname_s; + if (!PyArg_ParseTuple(args, "s", &catname_s)) + return NULL; + + GuPool *tmp_pool = gu_local_pool(); + GuString catname = gu_str_string(catname_s, tmp_pool); + + PyObject* functions = PyList_New(0); + if (functions == NULL) { + gu_pool_free(tmp_pool); + return NULL; + } + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + PyPGFClosure clo = { { pgf_collect_funs }, self, functions }; + pgf_iter_functions_by_cat(self->pgf, catname, &clo.fn, err); + if (!gu_ok(err)) { + Py_DECREF(functions); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return functions; +} + +static ExprIterObject* +PGF_generate(PGFObject* self, PyObject *args, PyObject *keywds) +{ + static char *kwlist[] = {"cat", "n", NULL}; + + const char *catname_s; + int max_count = -1; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|i", kwlist, + &catname_s, &max_count)) + return NULL; + + ExprIterObject* pyres = (ExprIterObject*) + pgf_ExprIterType.tp_alloc(&pgf_ExprIterType, 0); + if (pyres == NULL) { + return NULL; + } + + pyres->pool = gu_new_pool(); + pyres->max_count = max_count; + pyres->counter = 0; + + GuPool *tmp_pool = gu_local_pool(); + GuString catname = gu_str_string(catname_s, tmp_pool); + + pyres->res = + pgf_generate(self->pgf, catname, pyres->pool); + if (pyres->res == NULL) { + Py_DECREF(pyres); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + + return pyres; +} + +static PyGetSetDef PGF_getseters[] = { + {"abstractName", + (getter)PGF_getAbstractName, NULL, + "the abstract syntax name", + NULL}, + {"languages", + (getter)PGF_getLanguages, NULL, + "a map containing all concrete languages in the grammar", + NULL}, + {"categories", + (getter)PGF_getCategories, NULL, + "a list containing all categories in the grammar", + NULL}, + {"startCat", + (getter)PGF_getStartCat, NULL, + "the start category for the grammar", + NULL}, + {"functions", + (getter)PGF_getFunctions, NULL, + "a list containing all functions in the grammar", + NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef PGF_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef PGF_methods[] = { + {"functionsByCat", (PyCFunction)PGF_functionsByCat, METH_VARARGS, + "Returns the list of functions for a given category" + }, + {"generate", (PyCFunction)PGF_generate, METH_VARARGS | METH_KEYWORDS, + "Generates abstract syntax trees of given category in decreasing probability order" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject pgf_PGFType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pgf.PGF", /*tp_name*/ + sizeof(PGFObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)PGF_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, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "PGF object", /*tp_doc*/ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + PGF_methods, /*tp_methods */ + PGF_members, /*tp_members */ + PGF_getseters, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)PGF_init, /*tp_init */ + 0, /*tp_alloc */ + (newfunc)PGF_new, /*tp_new */ +}; + +static PGFObject* +pgf_readPGF(PyObject *self, PyObject *args) +{ + const char *fpath; + if (!PyArg_ParseTuple(args, "s", &fpath)) + return NULL; + + PGFObject* py_pgf = (PGFObject*) pgf_PGFType.tp_alloc(&pgf_PGFType, 0); + py_pgf->pool = gu_new_pool(); + + GuPool* tmp_pool = gu_local_pool(); + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + // Read the PGF grammar. + py_pgf->pgf = pgf_read(fpath, py_pgf->pool, err); + if (!gu_ok(err)) { + PyErr_SetString(PGFError, "The grammar cannot be loaded"); + Py_DECREF(py_pgf); + gu_pool_free(tmp_pool); + return NULL; + } + + gu_pool_free(tmp_pool); + return py_pgf; +} + +static ExprObject* +pgf_readExpr(PyObject *self, PyObject *args) { + size_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); + GuReader* rdr = gu_new_utf8_reader(in, tmp_pool); + GuExn* err = gu_new_exn(NULL, gu_kind(type), tmp_pool); + + pyexpr->pool = gu_new_pool(); + pyexpr->expr = pgf_read_expr(rdr, pyexpr->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 PyMethodDef module_methods[] = { + {"readPGF", (void*)pgf_readPGF, METH_VARARGS, + "Reads a PGF file in the memory"}, + {"readExpr", (void*)pgf_readExpr, METH_VARARGS, + "Parses a string as an abstract tree"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initpgf(void) +{ + PyObject *m; + + if (PyType_Ready(&pgf_PGFType) < 0) + return; + + if (PyType_Ready(&pgf_ConcrType) < 0) + return; + + if (PyType_Ready(&pgf_ExprType) < 0) + return; + + if (PyType_Ready(&pgf_ExprIterType) < 0) + return; + + m = Py_InitModule("pgf", module_methods); + if (m == NULL) + return; + + PGFError = PyErr_NewException("pgf.PGFError", NULL, NULL); + PyModule_AddObject(m, "PGFError", PGFError); + Py_INCREF(PGFError); + + PyObject *dict = PyDict_New(); + PyDict_SetItemString(dict, "token", PyString_FromString("")); + ParseError = PyErr_NewException("pgf.ParseError", NULL, dict); + PyModule_AddObject(m, "ParseError", ParseError); + Py_INCREF(ParseError); + + PyModule_AddObject(m, "Expr", (PyObject *) &pgf_ExprType); + Py_INCREF(&pgf_ExprType); + + Py_INCREF(&pgf_PGFType); + Py_INCREF(&pgf_ConcrType); + Py_INCREF(&pgf_ExprIterType); +} diff --git a/src/runtime/python/setup.py b/src/runtime/python/setup.py index 6f908cfe1..cac6f7409 100644 --- a/src/runtime/python/setup.py +++ b/src/runtime/python/setup.py @@ -1,7 +1,7 @@ from distutils.core import setup, Extension -pgf_module = Extension('pgf.binding', - sources = ['pgf/binding.c'], +pgf_module = Extension('pgf', + sources = ['pypgf.c'], extra_compile_args = ['-std=c99'], libraries = ['gu', 'pgf']) @@ -11,5 +11,4 @@ setup (name = 'pgf', author='Krasimir Angelov', author_email='kr.angelov@gmail.com', license='BSD', - packages=['pgf'], ext_modules = [pgf_module]) -- cgit v1.2.3