rpnifs/python_pyrpn.c
2023-09-11 14:36:08 +02:00

244 lines
5.4 KiB
C

/*
* Copyright (C) 2020 Weber Yann
*
* This file is part of pyrpn.
*
* pyrpn is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* pyrpn is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pyrpn. If not, see <http://www.gnu.org/licenses/>.
*/
#include "python_pyrpn.h"
/**@file python_pyrpn.c
* @brief Python module & type definition
* @ingroup python_ext
* @ingroup python_pyrpn
*
* This file contains pyrpn Python module definition
*/
/**@brief pyrpn module's method definition */
static PyMethodDef rpnmodule_methods[] = {
PYRPN_method("get_ops", pyrpn_ops,
METH_NOARGS,
"/",
"Return a dict with valid operands"),
PYRPN_method("random_expr", pyrpn_random,
METH_VARARGS | METH_KEYWORDS,
"args_count, token_count",
"Return a random RPN expression string"),
{NULL} // Sentinel
};
PyModuleDef rpnmodule = {
PyModuleDef_HEAD_INIT,
"pyrpn",
"Python librarie for RPN evaluation",
-1, // module size
rpnmodule_methods,
NULL, // m_slots
NULL, // m_traverse
NULL, // m_clear
NULL // m_free
};
PyObject *mmap_module = NULL;
PyObject *mmap_cls = NULL;
PyMODINIT_FUNC
PyInit_pyrpn(void)
{
if(mmap_module == NULL)
{
mmap_module = PyImport_ImportModule("mmap");
if(PyErr_Occurred()) { return NULL; }
else if(!mmap_module)
{
PyErr_Format(PyExc_ImportError, "Unable to import mmap module");
return NULL;
}
}
if(mmap_cls == NULL)
{
mmap_cls = PyObject_GetAttrString(mmap_module, "mmap");
if(PyErr_Occurred()) { return NULL; }
else if (!mmap_cls)
{
PyErr_Format(PyExc_ImportError, "Unable to import mmap.mmap");
return NULL;
}
}
PyObject *mod, *const_mod, *tokens_mod;
// init module & globals
mod = PyModule_Create(&rpnmodule);
if(mod == NULL) { return NULL; }
//init constants module
const_mod = rpnconst_init();
if(const_mod == NULL)
{
goto fail_init;
}
Py_INCREF(const_mod);
if(PyModule_AddObject(mod, "const", const_mod) < 0)
{
goto fail_add_const;
}
//init tokens module
tokens_mod = rpntokens_module_init();
if(tokens_mod == NULL)
{
goto fail_add_const;
}
Py_INCREF(tokens_mod);
if(PyModule_AddObject(mod, "tokens", tokens_mod) < 0)
{
goto fail_add_tokens;
}
// Init RPNExpr type
if(PyType_Ready(&RPNExprType) < 0)
{
goto fail_expr_type_ready;
}
// Add type to module
Py_INCREF(&RPNExprType);
if(PyModule_AddObject(mod, "RPNExpr", (PyObject*)&RPNExprType) < 0)
{
goto fail_add_rpnexpr;
}
// Init RPNIterExpr type
if(PyType_Ready(&RPNIterExprType) < 0)
{
goto fail_iter_type_ready;
}
Py_INCREF(&RPNIterExprType);
if(PyModule_AddObject(mod, "RPNIterExpr", (PyObject*)&RPNIterExprType) < 0)
{
goto fail_add_iter;
}
// Named tuple for RPNIterExpr's params
PyStructSequence_InitType(&rpnif_params_SeqDesc,&rpnif_params_desc);
Py_INCREF(&rpnif_params_SeqDesc);
/*
PyObject_SetAttrString((PyObject*)rpnif_params_SeqDesc, "__module__",
mod);
*/
if(PyModule_AddObject(mod, "RPNIterExprParams",
(PyObject*)&rpnif_params_SeqDesc) < 0)
{
goto fail_add_iter_expr_params;
}
// Named tuple for token types
PyStructSequence_InitType(&rpn_token_types_SeqDesc,
&rpn_token_types_desc);
Py_INCREF(&rpn_token_types_SeqDesc);
if(PyModule_AddObject(mod, "RPNTokenTypesTuple",
(PyObject*)&rpn_token_types_SeqDesc) < 0)
{
goto fail_add_token_types_tuple;
}
// Named tuple for mutation parameters
PyStructSequence_InitType(&rpn_mutation_params_SeqDesc,
&rpn_mutation_params_desc);
Py_INCREF(&rpn_mutation_params_SeqDesc);
if(PyModule_AddObject(mod, "RPNMutationParamsTuple",
(PyObject*)&rpn_mutation_params_SeqDesc) < 0)
{
goto fail_add_mutation_params_tuple;
}
return mod;
fail_add_mutation_params_tuple:
Py_DECREF(&rpn_token_types_SeqDesc);
fail_add_token_types_tuple:
Py_DECREF(&rpnif_params_SeqDesc);
fail_add_iter_expr_params:
fail_add_iter:
Py_DECREF(&RPNIterExprType);
fail_iter_type_ready:
fail_add_rpnexpr:
Py_DECREF(&RPNExprType);
fail_expr_type_ready:
fail_add_tokens:
Py_DECREF(tokens_mod);
fail_add_const:
Py_DECREF(const_mod);
fail_init:
Py_DECREF(mod);
return NULL;
}
PyObject* pyrpn_ops(PyObject* mod, PyObject* noargs)
{
PyObject *ret, *value;
const rpn_op_t *op;
size_t i;
ret = PyDict_New();
if(!ret)
{
return ret;
}
foreach_rpn_ops(i)
{
op = &rpn_ops[i];
value = Py_BuildValue("C", op->chr);
if(PyDict_SetItemString(ret, op->str, value))
{
Py_DECREF(value);
Py_DECREF(ret);
return NULL;
}
Py_DECREF(value);
}
return ret;
}
PyObject* pyrpn_random(PyObject *mod, PyObject *args, PyObject *kwds)
{
long long int args_count, expr_sz;
char *expr, err_str[128];
PyObject *res;
char *names[] = {"args_count", "token_count", NULL};
expr_sz = 10;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "L|L:pyrpn.random_expr", names,
&args_count, &expr_sz))
{
return NULL;
}
expr = expr_sz?rpn_random(expr_sz, args_count):"";
if(!expr)
{
snprintf(err_str, 128,
"Error generating random expression : %s",
strerror(errno));
PyErr_SetString(PyExc_RuntimeError, err_str);
return NULL;
}
res = Py_BuildValue("s", expr);
return res;
}