forked from GitHub/gf-core
constant time and space grammar embedding
This commit is contained in:
@@ -100,6 +100,8 @@ public:
|
|||||||
|
|
||||||
PGF_INTERNAL_DECL static txn_t get_txn_id();
|
PGF_INTERNAL_DECL static txn_t get_txn_id();
|
||||||
|
|
||||||
|
PGF_INTERNAL_DECL const char *get_file_path() { return filepath; };
|
||||||
|
|
||||||
template<class A>
|
template<class A>
|
||||||
static ref<A> malloc(size_t extra_bytes=0) {
|
static ref<A> malloc(size_t extra_bytes=0) {
|
||||||
return current_db->malloc_internal(sizeof(A)+extra_bytes);
|
return current_db->malloc_internal(sizeof(A)+extra_bytes);
|
||||||
|
|||||||
@@ -265,7 +265,13 @@ end:
|
|||||||
fclose(out);
|
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)
|
void pgf_free_revision(PgfDB *db, PgfRevision revision)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -281,7 +287,7 @@ void pgf_free_revision(PgfDB *db, PgfRevision revision)
|
|||||||
delete db;
|
delete db;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_API_DECL
|
PGF_API
|
||||||
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision)
|
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name,
|
|||||||
PgfRevision *revision,
|
PgfRevision *revision,
|
||||||
PgfExn* err);
|
PgfExn* err);
|
||||||
|
|
||||||
PGF_API
|
PGF_API_DECL
|
||||||
void pgf_merge_pgf(PgfDB *db, PgfRevision revision,
|
void pgf_merge_pgf(PgfDB *db, PgfRevision revision,
|
||||||
const char* fpath,
|
const char* fpath,
|
||||||
PgfExn* err);
|
PgfExn* err);
|
||||||
@@ -277,6 +277,9 @@ void pgf_write_pgf(const char* fpath,
|
|||||||
PgfDB *db, PgfRevision revision,
|
PgfDB *db, PgfRevision revision,
|
||||||
PgfExn* err);
|
PgfExn* err);
|
||||||
|
|
||||||
|
PGF_API_DECL
|
||||||
|
const char *pgf_file_path(PgfDB *db);
|
||||||
|
|
||||||
/* Release a revision. If this is the last revision for the given
|
/* Release a revision. If this is the last revision for the given
|
||||||
* database, then the database is released as well. */
|
* database, then the database is released as well. */
|
||||||
PGF_API_DECL
|
PGF_API_DECL
|
||||||
|
|||||||
@@ -630,67 +630,155 @@ static PyGetSetDef PGF_getseters[] = {
|
|||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
typedef struct {
|
||||||
pgf_embed_funs(PgfItor* fn, PgfText* name, object value, PgfExn* err)
|
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 *)
|
PgfExn err;
|
||||||
pgf_ExprFunType.tp_alloc(&pgf_ExprFunType, 0);
|
prob_t prob = pgf_function_prob(self->grammar->db, self->grammar->revision, name, &err);
|
||||||
if (pyexpr == NULL) {
|
PyMem_RawFree(name);
|
||||||
err->type = PGF_EXN_OTHER_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pyexpr->name = PyUnicode_FromStringAndSize(name->text, name->size);
|
if (handleError(err) != PGF_EXN_NONE)
|
||||||
if (pyexpr->name == NULL) {
|
return NULL;
|
||||||
Py_DECREF(pyexpr);
|
|
||||||
err->type = PGF_EXN_OTHER_ERROR;
|
if (prob != INFINITY) {
|
||||||
return;
|
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) {
|
return PyObject_GenericGetAttr((PyObject*) self, py_attr);
|
||||||
Py_DECREF(pyexpr);
|
|
||||||
err->type = PGF_EXN_OTHER_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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*
|
static PyObject*
|
||||||
PGF_embed(PGFObject* self, PyObject *modname)
|
PGF_embed(PGFObject* self, PyObject *modname)
|
||||||
{
|
{
|
||||||
PyObject *m = PyImport_Import(modname);
|
PyObject *module = PyImport_Import(modname);
|
||||||
if (m == NULL) {
|
if (module == NULL) {
|
||||||
PyObject *globals = PyEval_GetBuiltins();
|
PyObject *globals = PyEval_GetBuiltins();
|
||||||
if (globals != NULL) {
|
if (globals == NULL)
|
||||||
PyObject *exc = PyDict_GetItemString(globals, "ModuleNotFoundError");
|
return NULL;
|
||||||
if (exc != NULL) {
|
|
||||||
if (PyErr_ExceptionMatches(exc)) {
|
|
||||||
PyErr_Clear();
|
|
||||||
m = PyImport_AddModuleObject(modname);
|
|
||||||
Py_INCREF(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(self);
|
PyObject *exc = PyDict_GetItemString(globals, "ModuleNotFoundError");
|
||||||
if (PyModule_AddObject(m, "__pgf__", (PyObject*) self) != 0) {
|
if (exc == NULL)
|
||||||
Py_DECREF(self);
|
return NULL;
|
||||||
Py_DECREF(m);
|
|
||||||
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PgfExn err;
|
return (PyObject*) py_embedding;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef PGF_methods[] = {
|
static PyMethodDef PGF_methods[] = {
|
||||||
@@ -1087,6 +1175,7 @@ MOD_INIT(pgf)
|
|||||||
TYPE_READY(pgf_ExprTypedType);
|
TYPE_READY(pgf_ExprTypedType);
|
||||||
TYPE_READY(pgf_ExprImplArgType);
|
TYPE_READY(pgf_ExprImplArgType);
|
||||||
TYPE_READY(pgf_TypeType);
|
TYPE_READY(pgf_TypeType);
|
||||||
|
TYPE_READY(pgf_EmbeddedGrammarType);
|
||||||
|
|
||||||
MOD_DEF(m, "pgf", "The Runtime for Portable Grammar Format in Python", module_methods);
|
MOD_DEF(m, "pgf", "The Runtime for Portable Grammar Format in Python", module_methods);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
|
|||||||
Reference in New Issue
Block a user