1
0
forked from GitHub/gf-core

constant time and space grammar embedding

This commit is contained in:
Krasimir Angelov
2022-11-16 09:43:09 +01:00
parent 045f708a76
commit a6aa6c2a5a
4 changed files with 149 additions and 49 deletions

View File

@@ -100,6 +100,8 @@ public:
PGF_INTERNAL_DECL static txn_t get_txn_id();
PGF_INTERNAL_DECL const char *get_file_path() { return filepath; };
template<class A>
static ref<A> malloc(size_t extra_bytes=0) {
return current_db->malloc_internal(sizeof(A)+extra_bytes);

View File

@@ -265,7 +265,13 @@ end:
fclose(out);
}
PGF_API_DECL
PGF_API
const char *pgf_file_path(PgfDB *db)
{
return db->get_file_path();
}
PGF_API
void pgf_free_revision(PgfDB *db, PgfRevision revision)
{
try {
@@ -281,7 +287,7 @@ void pgf_free_revision(PgfDB *db, PgfRevision revision)
delete db;
}
PGF_API_DECL
PGF_API
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision)
{
try {

View File

@@ -267,7 +267,7 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name,
PgfRevision *revision,
PgfExn* err);
PGF_API
PGF_API_DECL
void pgf_merge_pgf(PgfDB *db, PgfRevision revision,
const char* fpath,
PgfExn* err);
@@ -277,6 +277,9 @@ void pgf_write_pgf(const char* fpath,
PgfDB *db, PgfRevision revision,
PgfExn* err);
PGF_API_DECL
const char *pgf_file_path(PgfDB *db);
/* Release a revision. If this is the last revision for the given
* database, then the database is released as well. */
PGF_API_DECL

View File

@@ -630,67 +630,155 @@ static PyGetSetDef PGF_getseters[] = {
{NULL} /* Sentinel */
};
static void
pgf_embed_funs(PgfItor* fn, PgfText* name, object value, PgfExn* err)
typedef struct {
PyObject_HEAD
PyObject* dict;
PyObject* modname;
PGFObject* grammar;
} EmbeddedGrammarObject;
static PyObject *EmbeddedGrammar_getattro(EmbeddedGrammarObject *self, PyObject *py_attr)
{
PyPGFClosure *clo = (PyPGFClosure*) fn;
PgfText *name = PyUnicode_AsPgfText(py_attr);
if (!name)
return NULL;
ExprFunObject *pyexpr = (ExprFunObject *)
pgf_ExprFunType.tp_alloc(&pgf_ExprFunType, 0);
if (pyexpr == NULL) {
err->type = PGF_EXN_OTHER_ERROR;
return;
}
PgfExn err;
prob_t prob = pgf_function_prob(self->grammar->db, self->grammar->revision, name, &err);
PyMem_RawFree(name);
pyexpr->name = PyUnicode_FromStringAndSize(name->text, name->size);
if (pyexpr->name == NULL) {
Py_DECREF(pyexpr);
err->type = PGF_EXN_OTHER_ERROR;
return;
if (handleError(err) != PGF_EXN_NONE)
return NULL;
if (prob != INFINITY) {
ExprFunObject *pyexpr = (ExprFunObject *)
pgf_ExprFunType.tp_alloc(&pgf_ExprFunType, 0);
if (pyexpr == NULL)
return NULL;
pyexpr->name = py_attr; Py_INCREF(py_attr);
return (PyObject*) pyexpr;
}
if (PyModule_AddObject(clo->collection, name->text, (PyObject*) pyexpr) != 0) {
Py_DECREF(pyexpr);
err->type = PGF_EXN_OTHER_ERROR;
}
return PyObject_GenericGetAttr((PyObject*) self, py_attr);
}
static PyObject *
EmbeddedGrammar_getFilePath(EmbeddedGrammarObject *self, void *closure)
{
return PyUnicode_FromString(pgf_file_path(self->grammar->db));
}
static PyObject*
EmbeddedGrammar_str(EmbeddedGrammarObject *self)
{
return PyUnicode_FromFormat("<embedded grammar '%U' from '%s'>", self->modname, pgf_file_path(self->grammar->db));
}
static void
EmbeddedGrammar_dealloc(EmbeddedGrammarObject* self)
{
Py_XDECREF(self->dict);
Py_XDECREF(self->modname);
Py_XDECREF(self->grammar);
}
static PyMemberDef EmbeddedGrammar_members[] = {
{"__name__", T_OBJECT, offsetof(EmbeddedGrammarObject, modname), READONLY, NULL},
{"__dict__", T_OBJECT, offsetof(EmbeddedGrammarObject, dict), READONLY, NULL},
{"__pgf__", T_OBJECT, offsetof(EmbeddedGrammarObject, grammar), READONLY, NULL},
{NULL}
};
static PyGetSetDef EmbeddedGrammar_getseters[] = {
{"__file__",
(getter)EmbeddedGrammar_getFilePath, NULL,
"the path to the grammar file",
NULL},
{NULL} /* Sentinel */
};
static PyTypeObject pgf_EmbeddedGrammarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"pgf.EmbeddedGrammar", /*tp_name*/
sizeof(EmbeddedGrammarObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)EmbeddedGrammar_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc) EmbeddedGrammar_str, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
(reprfunc) EmbeddedGrammar_str, /*tp_str*/
(getattrofunc) EmbeddedGrammar_getattro, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"a grammar embeded in Python as a module",/*tp_doc*/
0, /*tp_traverse */
0, /*tp_clear */
0, /*tp_richcompare */
0, /*tp_weaklistoffset */
0, /*tp_iter */
0, /*tp_iternext */
0, /*tp_methods */
EmbeddedGrammar_members, /*tp_members */
EmbeddedGrammar_getseters, /*tp_getset */
0, /*tp_base */
0, /*tp_dict */
0, /*tp_descr_get */
0, /*tp_descr_set */
offsetof(EmbeddedGrammarObject,dict), /*tp_dictoffset */
0, /*tp_init */
0, /*tp_alloc */
0, /*tp_new */
};
static PyObject*
PGF_embed(PGFObject* self, PyObject *modname)
{
PyObject *m = PyImport_Import(modname);
if (m == NULL) {
PyObject *module = PyImport_Import(modname);
if (module == NULL) {
PyObject *globals = PyEval_GetBuiltins();
if (globals != NULL) {
PyObject *exc = PyDict_GetItemString(globals, "ModuleNotFoundError");
if (exc != NULL) {
if (PyErr_ExceptionMatches(exc)) {
PyErr_Clear();
m = PyImport_AddModuleObject(modname);
Py_INCREF(m);
}
}
}
}
if (m == NULL)
return NULL;
if (globals == NULL)
return NULL;
Py_INCREF(self);
if (PyModule_AddObject(m, "__pgf__", (PyObject*) self) != 0) {
Py_DECREF(self);
Py_DECREF(m);
PyObject *exc = PyDict_GetItemString(globals, "ModuleNotFoundError");
if (exc == NULL)
return NULL;
if (!PyErr_ExceptionMatches(exc))
return NULL;
PyErr_Clear();
}
EmbeddedGrammarObject *py_embedding =
(EmbeddedGrammarObject *) pgf_EmbeddedGrammarType.tp_alloc(&pgf_EmbeddedGrammarType, 0);
if (py_embedding == NULL) {
return NULL;
}
py_embedding->modname = modname; Py_INCREF(modname);
py_embedding->grammar = self; Py_INCREF(self);
if (module == NULL) {
py_embedding->dict = PyDict_New();
} else {
py_embedding->dict = PyModule_GetDict(module);
Py_INCREF(py_embedding->dict);
}
if (_PyImport_SetModule(modname, (PyObject*) py_embedding) < 0) {
return NULL;
}
PgfExn err;
PyPGFClosure clo = { { pgf_embed_funs }, self, m };
pgf_iter_functions(self->db, self->revision, &clo.fn, &err);
if (handleError(err) != PGF_EXN_NONE) {
Py_DECREF(m);
return NULL;
}
return m;
return (PyObject*) py_embedding;
}
static PyMethodDef PGF_methods[] = {
@@ -1087,6 +1175,7 @@ MOD_INIT(pgf)
TYPE_READY(pgf_ExprTypedType);
TYPE_READY(pgf_ExprImplArgType);
TYPE_READY(pgf_TypeType);
TYPE_READY(pgf_EmbeddedGrammarType);
MOD_DEF(m, "pgf", "The Runtime for Portable Grammar Format in Python", module_methods);
if (m == NULL)