mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-23 19:42:50 -06:00
an API for visitor patterns on abstract syntax trees from Python. This makes the embedded grammars especially pleasing
This commit is contained in:
@@ -71,6 +71,9 @@ Expr_call(ExprObject* e, PyObject* args, PyObject* kw);
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
Expr_unpack(ExprObject* self, PyObject *args);
|
Expr_unpack(ExprObject* self, PyObject *args);
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
Expr_visit(ExprObject* self, PyObject *args);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
Expr_init(ExprObject *self, PyObject *args, PyObject *kwds)
|
Expr_init(ExprObject *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
@@ -140,6 +143,13 @@ static PyMethodDef Expr_methods[] = {
|
|||||||
{"unpack", (PyCFunction)Expr_unpack, METH_VARARGS,
|
{"unpack", (PyCFunction)Expr_unpack, METH_VARARGS,
|
||||||
"Decomposes an expression into its components"
|
"Decomposes an expression into its components"
|
||||||
},
|
},
|
||||||
|
{"visit", (PyCFunction)Expr_visit, METH_VARARGS,
|
||||||
|
"Implementation of the visitor pattern for abstract syntax trees. "
|
||||||
|
"If e is an expression equal to f a1 .. an then "
|
||||||
|
"e.visit(self) calls method self.on_f(a1,..an). "
|
||||||
|
"If the method doesn't exist then the method self.default(e) "
|
||||||
|
"is called."
|
||||||
|
},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -363,8 +373,10 @@ Expr_unpack(ExprObject* self, PyObject *fargs)
|
|||||||
PgfExprAbs* eabs = i.data;
|
PgfExprAbs* eabs = i.data;
|
||||||
|
|
||||||
ExprObject* py_body = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0);
|
ExprObject* py_body = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0);
|
||||||
if (py_body == NULL)
|
if (py_body == NULL) {
|
||||||
|
Py_DECREF(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
py_body->pool = NULL;
|
py_body->pool = NULL;
|
||||||
py_body->master = (self->master) ? self->master : (PyObject*) self;
|
py_body->master = (self->master) ? self->master : (PyObject*) self;
|
||||||
py_body->expr = eabs->body;
|
py_body->expr = eabs->body;
|
||||||
@@ -385,8 +397,10 @@ Expr_unpack(ExprObject* self, PyObject *fargs)
|
|||||||
PgfExprApp* eapp = i.data;
|
PgfExprApp* eapp = i.data;
|
||||||
|
|
||||||
ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0);
|
ExprObject* pyexpr = (ExprObject*) pgf_ExprType.tp_alloc(&pgf_ExprType, 0);
|
||||||
if (pyexpr == NULL)
|
if (pyexpr == NULL) {
|
||||||
|
Py_DECREF(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
pyexpr->pool = NULL;
|
pyexpr->pool = NULL;
|
||||||
pyexpr->master = (self->master) ? self->master : (PyObject*) self;
|
pyexpr->master = (self->master) ? self->master : (PyObject*) self;
|
||||||
pyexpr->expr = eapp->arg;
|
pyexpr->expr = eapp->arg;
|
||||||
@@ -463,6 +477,67 @@ Expr_unpack(ExprObject* self, PyObject *fargs)
|
|||||||
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*
|
static PyObject*
|
||||||
Expr_getattro(ExprObject *self, PyObject *attr_name) {
|
Expr_getattro(ExprObject *self, PyObject *attr_name) {
|
||||||
const char* name = PyString_AsString(attr_name);
|
const char* name = PyString_AsString(attr_name);
|
||||||
|
|||||||
Reference in New Issue
Block a user