123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- /*
- * 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_rpnexpr.h"
-
- PyMethodDef RPNExpr_methods[] = {
- {"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"},
- {"reset_stack", (PyCFunction)rpnexpr_reset_stack, METH_NOARGS,
- "Reset stack memory storage (set all items to 0)"},
- {"__getstate__", (PyCFunction)rpnexpr_getstate, METH_NOARGS,
- "Pickling method. Return a bytes repr of tokenized expression \
- and the stack state."},
- {"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O,
- "Unpickling method"},
- {NULL} //Sentinel
- };
-
- PyMemberDef RPNExpr_members[] = {
- {NULL}
- };
-
- PyTypeObject RPNExprType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "pyrpn.RPNExpr", /* tp_name */
- sizeof(PyRPNExpr_t), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)rpnexpr_del, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- rpnexpr_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- rpnexpr_str, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT |
- Py_TPFLAGS_BASETYPE, /* tp_flags */
- "RPN expression evaluator", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- RPNExpr_methods, /* tp_methods */
- RPNExpr_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- rpnexpr_init, /* tp_init */
- 0, /* tp_alloc */
- rpnexpr_new, /* tp_new */
- };
-
- PyObject* rpnexpr_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
- {
- PyObject *ret, *err;
- PyRPNExpr_t *expr;
- ret = PyType_GenericNew(subtype, args, kwds);
- if((err = PyErr_Occurred()))
- {
- Py_DECREF(err);
- return ret;
- }
- expr = (PyRPNExpr_t*)ret;
- expr->rpn = NULL;
- expr->args = NULL;
- return ret;
- }
-
- int rpnexpr_init(PyObject *self, PyObject *args, PyObject *kwds)
- {
- PyRPNExpr_t *expr_self;
- char *names[] = {"expression", "args_count", "stack_size", NULL};
- char err_str[256];
- const char *expr;
- long long int args_count, stack_size;
-
- expr_self = (PyRPNExpr_t*)self;
-
- stack_size = 16;
- expr_self->rpn = NULL;
-
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "sL|L:RPNExpr.__init__", names, &expr,
- &args_count, &stack_size))
- {
- return -1;
- }
-
- if(strlen(expr) == 0)
- {
- PyErr_SetString(PyExc_ValueError,
- "RpnExpr.__init__() expect expression argument to be not empty");
- return -1;
- }
-
- if(args_count < 0 || args_count > 255)
- {
- snprintf(err_str, 128,
- "Argument count should be in [4..255] but %lld given",
- args_count);
- PyErr_SetString(PyExc_ValueError, err_str);
- return -1;
- }
-
- if(stack_size < 4 || stack_size > 255)
- {
- snprintf(err_str, 128,
- "Stack size should be in [0..255] but %lld given",
- stack_size);
- PyErr_SetString(PyExc_ValueError, err_str);
- return -1;
- }
-
- expr_self->rpn = malloc(sizeof(rpn_expr_t));
- if(!expr_self->rpn)
- {
- snprintf(err_str, 256,
- "Expression memory allocation error : %s",
- strerror(errno));
- }
- bzero(expr_self->rpn, sizeof(rpn_expr_t));
-
- if(rpn_expr_init(expr_self->rpn, stack_size, args_count) < 0)
- {
- snprintf(err_str, 256,
- "Expression init error : %s",
- expr_self->rpn->err_reason);
- PyErr_SetString(PyExc_ValueError, err_str);
- return -1;
- }
-
- expr_self->args = malloc(sizeof(rpn_value_t) * args_count);
- if(!expr_self->args)
- {
- snprintf(err_str, 256,
- "Error allocating arguments memory : %s",
- strerror(errno));
- return -1;
- }
-
- if(rpn_expr_compile(expr_self->rpn, expr))
- {
- PyErr_SetString(PyExc_ValueError, expr_self->rpn->err_reason);
- return -1;
- }
-
- return 0;
- }
-
- void rpnexpr_del(PyObject *self)
- {
- PyRPNExpr_t *expr_self;
-
- expr_self = (PyRPNExpr_t*)self;
- if(expr_self->rpn)
- {
- rpn_expr_close(expr_self->rpn);
- free(expr_self->rpn);
- expr_self->rpn = NULL;
- }
- if(expr_self->args)
- {
- free(expr_self->args);
- expr_self->args = NULL;
- }
- }
-
-
- PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
- {
- PyObject *res, *part;
- PyRPNExpr_state_t resbuf;
- PyRPNExpr_t *expr_self;
- size_t total_sz;
- char err_str[128];
-
- expr_self = (PyRPNExpr_t*)self;
-
- if(expr_self->rpn->state != RPN_READY)
- {
- snprintf(err_str, 128,
- "RPNExpr.__getstate__() instance in bad state : %s",
- expr_self->rpn->state==RPN_ERROR?"error":"init");
- PyErr_SetString(PyExc_ValueError, err_str);
- return NULL;
- }
-
- total_sz = sizeof(PyRPNExpr_state_t);
- total_sz += expr_self->rpn->toks.tokens_sz * sizeof(rpn_token_t);
- total_sz += expr_self->rpn->stack_sz * sizeof(rpn_value_t);
-
- resbuf.total_sz = total_sz;
- resbuf.argc = expr_self->rpn->args_count;
- resbuf.stack_sz = expr_self->rpn->stack_sz;
- resbuf.token_sz = expr_self->rpn->toks.tokens_sz;
-
- if(!(res = PyBytes_FromStringAndSize((char*)&resbuf, sizeof(resbuf))))
- {
- return NULL;
- }
- if(resbuf.stack_sz)
- {
- if(!(part=PyBytes_FromStringAndSize(
- (char*)expr_self->rpn->stack,
- sizeof(rpn_value_t) * resbuf.stack_sz)))
- {
- return NULL;
- }
- PyBytes_ConcatAndDel(&res, part);
- if(!res)
- {
- return NULL;
- }
- }
- if(resbuf.token_sz)
- {
- if(!(part=PyBytes_FromStringAndSize(
- (char*)expr_self->rpn->toks.tokens,
- sizeof(rpn_token_t) * resbuf.token_sz)))
- {
- return NULL;
- }
- PyBytes_ConcatAndDel(&res, part);
- if(!res)
- {
- return NULL;
- }
- }
- return res;
- }
-
- PyObject* rpnexpr_setstate(PyObject *self, PyObject *state_bytes)
- {
- PyObject *tmp, *tmp2;
- PyRPNExpr_state_t *state;
- PyRPNExpr_t *expr_self;
- rpn_value_t *stack;
- rpn_tokenized_t toks;
- const char *data;
- size_t bsize, csize;
- int err;
- char err_str[256];
- size_t i;
-
- expr_self = (PyRPNExpr_t*)self;
-
- if(!PyBytes_Check(state_bytes)) /* Arg check */
- {
- tmp2 = NULL;
- tmp = PyObject_Type(state_bytes);
- if(tmp)
- {
- tmp2 = PyObject_Str(tmp);
- }
- if(tmp2)
- {
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() expected a bytes as \
- argument but %s found",
- PyUnicode_AsUTF8(tmp2));
- PyErr_SetString(PyExc_ValueError, err_str);
- }
- else
- {
- PyErr_SetString(PyExc_RuntimeError,
- "Failing to fetch arguments type will \
- generating exception message !");
- }
- return NULL;
- }
- if(expr_self->rpn || expr_self->args) /* checking instance state */
- {
- PyErr_SetString(PyExc_ValueError,
- "RPNExpr.__getstate__() instance in bad state : \
- should not be initialized");
- return NULL;
- }
-
- /* Checking data size */
- bsize = PyBytes_GET_SIZE(state_bytes);
- data = PyBytes_AS_STRING(state_bytes);
- state = (PyRPNExpr_state_t*)data;
-
- if(bsize < sizeof(size_t))
- {
- PyErr_SetString(PyExc_ValueError, "Invalid argument");
- }
- if(bsize != state->total_sz)
- {
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() error : expected state to \
- contains %ld bytes but %ld found",
- state->total_sz, bsize);
- PyErr_SetString(PyExc_ValueError, err_str);
- }
-
- /* Checking data "integrity" */
- csize = sizeof(PyRPNExpr_state_t) +
- state->token_sz * sizeof(rpn_token_t) +
- state->stack_sz * sizeof(rpn_value_t);
- if(state->total_sz != csize)
- {
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() error : should have %ld as \
- total size but %ld found",
- csize, state->total_sz);
- PyErr_SetString(PyExc_ValueError, err_str);
- return NULL;
- }
-
-
- /* Alloc and init rpn expression & args buffer*/
- if(!(expr_self->rpn = malloc(sizeof(rpn_expr_t))))
- {
- err = errno;
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() failed to allocate memory for \
- rpn_expr_t : %s",
- strerror(err));
- PyErr_SetString(PyExc_MemoryError, err_str);
- return NULL;
- }
- bzero(expr_self->rpn, sizeof(rpn_expr_t));
- if(!(expr_self->args = malloc(sizeof(rpn_value_t)*state->argc)))
- {
- err = errno;
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() failed to allocate memory for \
- args buffer : %s",
- strerror(err));
- PyErr_SetString(PyExc_MemoryError, err_str);
- return NULL;
- }
-
- if(rpn_expr_init(expr_self->rpn, state->stack_sz, state->argc) < 0)
- {
- snprintf(err_str, 256,
- "RPNExpr.__setstate__() failed to init RPN expression \
- : %s",
- expr_self->rpn->err_reason);
- PyErr_SetString(PyExc_RuntimeError, err_str);
- goto free_err;
- }
-
- /* restore stack & untokenize expression */
- stack = (rpn_value_t*)(state+1);
- memcpy(expr_self->rpn->stack, stack,
- sizeof(rpn_value_t)*state->stack_sz);
-
- toks.argc = state->argc;
- toks.tokens_sz = state->token_sz;
- toks.tokens = malloc(sizeof(rpn_token_t)*state->token_sz);
- if(!toks.tokens)
- {
- snprintf(err_str, 128,
- "RPNExpr.__setstate__() failed to allocate tokens \
- : %s",
- strerror(errno));
- PyErr_SetString(PyExc_RuntimeError, err_str);
- goto close_err;
- }
- memcpy(toks.tokens, (rpn_token_t*)(stack+state->stack_sz),
- sizeof(rpn_token_t)*state->token_sz);
-
- for(i=0; i<toks.tokens_sz;i++)
- {
- // restore op pointers
- toks.tokens[i].op = &(rpn_ops[toks.tokens[i].op_n]);
- }
-
-
- if(rpn_expr_untokenize(expr_self->rpn, &toks, 0) < 0)
- {
- snprintf(err_str, 256,
- "RPNExpr.__setstate__() unable to untokenize : %s",
- expr_self->rpn->err_reason);
- PyErr_SetString(PyExc_RuntimeError, err_str);
- goto close_err;
- }
-
- Py_RETURN_NONE;
- close_err:
- rpn_expr_close(expr_self->rpn);
- free_err:
- return NULL;
- }
-
- PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
- {
- PyRPNExpr_t *expr_self;
- unsigned long res;
- char err_str[128];
- Py_ssize_t i;
- PyObject *cur, *ret;
-
-
- expr_self = (PyRPNExpr_t*)self;
-
- if((unsigned long)argc != expr_self->rpn->args_count)
- {
- snprintf(err_str, 128,
- "RPNExpr expected %ld arguments but %ld given",
- expr_self->rpn->args_count,
- argc);
- PyErr_SetString(PyExc_ValueError, err_str);
- return NULL;
- }
-
- for(i=0; i<argc; i++)
- {
- cur = argv[i];
- if(!PyLong_Check(cur))
- {
- snprintf(err_str, 128,
- "RpnExpr.__call__ expect int as arguments but argument %ld is not",
- i+1);
- PyErr_SetString(PyExc_ValueError, err_str);
- return NULL;
- }
- expr_self->args[i] = PyLong_AsUnsignedLong(argv[i]);
- if((ret = PyErr_Occurred()))
- {
- Py_DECREF(ret);
- return NULL;
- }
- }
-
- res = rpn_expr_eval(expr_self->rpn, expr_self->args);
- //dprintf(2, "[RES=%lu]\n", res);
-
- return PyLong_FromUnsignedLong(res);
- }
-
- PyObject* rpnexpr_reset_stack(PyObject *self, PyObject *noargs)
- {
- rpn_expr_reset_stack(((PyRPNExpr_t*)self)->rpn);
- Py_RETURN_NONE;
- }
-
- PyObject* rpnexpr_str(PyObject *self)
- {
- PyRPNExpr_t *expr_self;
- PyObject *res;
-
- expr_self = (PyRPNExpr_t*)self;
- res = Py_BuildValue("s", expr_self->rpn->expr);
- return res;
- }
-
- PyObject* rpnexpr_repr(PyObject *self)
- {
- PyRPNExpr_t *expr_self;
- PyObject *res;
- size_t sz;
- char *buff, err_str[128];
-
- expr_self = (PyRPNExpr_t*)self;
- sz = snprintf(NULL, 0, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
- expr_self->rpn->args_count, expr_self->rpn->stack_sz,
- expr_self->rpn->expr);
- buff = malloc(sizeof(char) * (sz + 1));
- if(!buff)
- {
- snprintf(err_str, 128,
- "Error allocating repr : %s",
- strerror(errno));
- PyErr_SetString(PyExc_RuntimeError, err_str);
- return NULL;
- }
- snprintf(buff, sz+1, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
- expr_self->rpn->args_count, expr_self->rpn->stack_sz,
- expr_self->rpn->expr);
- res = Py_BuildValue("s", buff);
- free(buff);
- return res;
- }
|