738 lines
17 KiB
C
738 lines
17 KiB
C
/*
|
|
* Copyright (C) 2020,2023 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"
|
|
|
|
/**@file python_rpnexpr.c
|
|
* @brief Python module & type definition
|
|
* @ingroup python_ext
|
|
* @ingroup python_pyrpn_RPNExpr
|
|
*/
|
|
|
|
/**@brief @ref pymod_pyrpn_RPNExpr methods definition
|
|
* @ingroup python_pyrpn_RPNExpr */
|
|
static PyMethodDef RPNExpr_methods[] = {
|
|
PYRPN_method("random", rpnexpr_random,
|
|
METH_CLASS | METH_VARARGS | METH_KEYWORDS,
|
|
"cls, args_count, token_count=10",
|
|
"Return a new random RPN expression string"),
|
|
PYRPN_method("default_mutation_params", rpnexpr_default_mutation_params,
|
|
METH_CLASS | METH_FASTCALL,
|
|
"cls, /",
|
|
"Return the default mutation parameters"),
|
|
PYRPN_method("eval", rpnexpr_eval, METH_FASTCALL,
|
|
"self, /, *args",
|
|
"Evaluate an expression"),
|
|
PYRPN_method("mutate", rpnexpr_mutate,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
"self, n_mutations=1, params=None",
|
|
"Mutate an expression"),
|
|
PYRPN_method("reset_stack", rpnexpr_reset_stack,
|
|
METH_NOARGS,
|
|
"self, /",
|
|
"Reset the stack (set all items to 0)"),
|
|
PYRPN_method("__getstate__", rpnexpr_getstate,
|
|
METH_NOARGS,
|
|
"self, /",
|
|
"Pickling method (see pickle module).\n"
|
|
"Return a bytes representation of the expression state."),
|
|
PYRPN_method("__setstate__", rpnexpr_setstate,
|
|
METH_O,
|
|
"self, state, /",
|
|
"Unpickling method (see pickle module)."),
|
|
PYRPN_method("__copy__", rpnexpr_copy,
|
|
METH_NOARGS,
|
|
"self, /",
|
|
"Return a new equivalent instance (see copy module)"),
|
|
PYRPN_method("uid", rpnexpr_getexprstate,
|
|
METH_NOARGS,
|
|
"self, /",
|
|
"Return a base64 uid for expression"),
|
|
{NULL} //Sentinel
|
|
};
|
|
|
|
/**@brief @ref pymod_pyrpn_RPNExpr members definition
|
|
* @ingroup python_pyrpn_RPNExpr */
|
|
static PyMemberDef RPNExpr_members[] = {
|
|
{NULL}
|
|
};
|
|
|
|
/**@brief @ref pymod_pyrpn_RPNExpr methods definition
|
|
* @todo Continue sequence implementation with contains, concat, repeat etc.
|
|
* @ingroup python_pyrpn_RPNExpr */
|
|
static PySequenceMethods RPNExpr_seq_methods = {
|
|
.sq_length = rpnexpr_len,
|
|
.sq_item = rpnexpr_token_item,
|
|
.sq_ass_item = rpnexpr_token_ass_item,
|
|
};
|
|
|
|
|
|
PyTypeObject RPNExprType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "pyrpn.RPNExpr",
|
|
.tp_doc = "RPN expression evaluator\n\
|
|
\n\
|
|
Instanciation :\n\
|
|
RPNExpr(expression:str, args_count:int, stack_size:int=16)",
|
|
.tp_basicsize = sizeof(PyRPNExpr_t),
|
|
.tp_itemsize = 0,
|
|
.tp_del = rpnexpr_del,
|
|
.tp_repr = rpnexpr_repr,
|
|
.tp_str = rpnexpr_str,
|
|
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
.tp_richcompare = rpnexpr_richcompare,
|
|
.tp_methods = RPNExpr_methods,
|
|
.tp_as_sequence = &RPNExpr_seq_methods,
|
|
.tp_members = RPNExpr_members,
|
|
.tp_init = rpnexpr_init,
|
|
.tp_new = rpnexpr_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;
|
|
expr->borrowed_expr = 0;
|
|
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(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;
|
|
}
|
|
|
|
PyObject* rpnexpr_init_borrowing(rpn_expr_t *borrowed)
|
|
{
|
|
PyObject *args, *ret;
|
|
PyRPNExpr_t *instance;
|
|
|
|
args = Py_BuildValue("sLL", "", borrowed->args_count,
|
|
borrowed->stack_sz);
|
|
if(!args || PyErr_Occurred())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = PyObject_CallObject((PyObject*)&RPNExprType, args);
|
|
if(!ret || PyErr_Occurred())
|
|
{
|
|
Py_DECREF(args);
|
|
return NULL;
|
|
}
|
|
|
|
Py_DECREF(args);
|
|
|
|
instance = (PyRPNExpr_t*)ret;
|
|
|
|
rpn_expr_close(instance->rpn);
|
|
free(instance->rpn);
|
|
|
|
instance->borrowed_expr = 1;
|
|
instance->rpn = borrowed;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void rpnexpr_del(PyObject *self)
|
|
{
|
|
PyRPNExpr_t *expr_self;
|
|
|
|
expr_self = (PyRPNExpr_t*)self;
|
|
if(expr_self->rpn && !expr_self->borrowed_expr)
|
|
{
|
|
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_getexprstate(PyObject *self, PyObject *noargs)
|
|
{
|
|
/**@todo check if usefull */
|
|
PyErr_SetString(PyExc_NotImplementedError, "Not implemented...");
|
|
return NULL;
|
|
}
|
|
|
|
PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
|
|
{
|
|
PyObject *res;
|
|
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 = rpn_expr_serialize(expr_self->rpn, NULL, 0);
|
|
|
|
char serial[total_sz];
|
|
|
|
rpn_expr_serialize(expr_self->rpn, serial, total_sz);
|
|
if(!(res = PyBytes_FromStringAndSize(serial, total_sz)))
|
|
{
|
|
return NULL;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
PyObject* rpnexpr_setstate(PyObject *self, PyObject *state_bytes)
|
|
{
|
|
PyObject *tmp, *tmp2;
|
|
PyRPNExpr_t *expr_self;
|
|
const char *data;
|
|
size_t bsize;
|
|
int err;
|
|
char err_str[256];
|
|
|
|
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.__setstate__() 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);
|
|
|
|
if(bsize < sizeof(size_t))
|
|
{
|
|
PyErr_SetString(PyExc_ValueError, "Invalid argument");
|
|
return NULL;
|
|
}
|
|
|
|
//alloc & init
|
|
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(rpn_expr_deserialize(expr_self->rpn, data, bsize) < 0)
|
|
{
|
|
PyErr_Format(PyExc_ValueError,
|
|
"RPNExpr.__setstate__() fails to deserialize (%s)) %s",
|
|
strerror(errno), expr_self->rpn->err_reason);
|
|
return NULL;
|
|
}
|
|
|
|
if(!(expr_self->args = malloc(sizeof(rpn_value_t)*expr_self->rpn->args_count)))
|
|
{
|
|
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;
|
|
}
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
PyObject* rpnexpr_copy(PyObject *self, PyObject *noargs)
|
|
{
|
|
PyRPNExpr_t *copy;
|
|
PyObject *ret, *state, *setret;
|
|
|
|
ret = PyObject_CallMethod((PyObject*)&RPNExprType, "__new__", "O", &RPNExprType);
|
|
copy = (PyRPNExpr_t*)ret;
|
|
|
|
state = PyObject_CallMethod(self, "__getstate__", NULL);
|
|
if(PyErr_Occurred()) {
|
|
goto err;
|
|
}
|
|
setret = PyObject_CallMethod(ret, "__setstate__", "O", state);
|
|
if(PyErr_Occurred()) {
|
|
Py_DECREF(state);
|
|
goto err;
|
|
}
|
|
|
|
Py_DECREF(state);
|
|
Py_DECREF(setret);
|
|
|
|
return ret;
|
|
err:
|
|
PyObject_Del(copy);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Py_ssize_t rpnexpr_len(PyObject *self)
|
|
{
|
|
PyRPNExpr_t *expr_self = (PyRPNExpr_t*)self;
|
|
return (Py_ssize_t)expr_self->rpn->toks.tokens_sz;
|
|
}
|
|
|
|
|
|
PyObject* rpnexpr_token_item(PyObject *self, Py_ssize_t idx)
|
|
{
|
|
PyRPNExpr_t *expr_self = (PyRPNExpr_t*)self;
|
|
Py_ssize_t _idx = idx;
|
|
if(idx < 0)
|
|
{
|
|
idx = expr_self->rpn->toks.tokens_sz - 1 + idx;
|
|
}
|
|
if(idx < 0 || (size_t)idx >= expr_self->rpn->toks.tokens_sz)
|
|
{
|
|
PyErr_Format(PyExc_IndexError,
|
|
"No token %ld in expression of size %ld",
|
|
_idx, expr_self->rpn->toks.tokens_sz);
|
|
return NULL;
|
|
|
|
}
|
|
return rpntoken_from_token(&expr_self->rpn->toks.tokens[idx]);
|
|
}
|
|
|
|
|
|
int rpnexpr_token_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
|
|
{
|
|
PyRPNExpr_t *expr_self = (PyRPNExpr_t*)self;
|
|
Py_ssize_t _idx = idx;
|
|
if(idx < 0)
|
|
{
|
|
idx = expr_self->rpn->toks.tokens_sz - 1 + idx;
|
|
}
|
|
if(idx < 0 || (size_t)idx > expr_self->rpn->toks.tokens_sz)
|
|
{
|
|
PyErr_Format(PyExc_IndexError,
|
|
"Cannot set token %ld in expression of size %ld",
|
|
_idx, expr_self->rpn->toks.tokens_sz);
|
|
return -1;
|
|
}
|
|
|
|
if(!PyObject_IsInstance(elt, (PyObject*)&RPNTokenType))
|
|
{
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Given element in not RPNToken subtype");
|
|
return -1;
|
|
}
|
|
|
|
short new_elt = 0;
|
|
if((size_t)idx == expr_self->rpn->toks.tokens_sz)
|
|
{
|
|
new_elt = 1;
|
|
expr_self->rpn->toks.tokens_sz++;
|
|
size_t new_sz = expr_self->rpn->toks.tokens_sz*sizeof(rpn_token_t);
|
|
rpn_token_t *tmp = realloc(expr_self->rpn->toks.tokens, new_sz);
|
|
if(!tmp)
|
|
{
|
|
PyErr_Format(PyExc_MemoryError,
|
|
"Error reallocation tokenized expression : %s",
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
expr_self->rpn->toks.tokens = tmp;
|
|
}
|
|
|
|
rpn_token_t original = expr_self->rpn->toks.tokens[idx];
|
|
|
|
RPNToken_t *token = (RPNToken_t*)elt;
|
|
expr_self->rpn->toks.tokens[idx] = token->value;
|
|
if(rpn_expr_tokens_updated(expr_self->rpn) < 0)
|
|
{
|
|
PyErr_Format(PyExc_ValueError,
|
|
"Unable to update expression : %s",
|
|
strerror(errno));
|
|
goto rollback;
|
|
}
|
|
return 0;
|
|
|
|
rollback:
|
|
if(new_elt)
|
|
{
|
|
expr_self->rpn->toks.tokens_sz--;
|
|
}
|
|
else
|
|
{
|
|
expr_self->rpn->toks.tokens[idx] = original;
|
|
if(rpn_expr_tokens_updated(expr_self->rpn) < 0)
|
|
{
|
|
PyErr_Format(PyExc_RuntimeError,
|
|
"Unable to rollback expression : %s",
|
|
strerror(errno));
|
|
goto rollback;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
return PyLong_FromUnsignedLong(res);
|
|
}
|
|
|
|
|
|
PyObject* rpnexpr_mutate(PyObject* slf, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyRPNExpr_t *self = (PyRPNExpr_t*)slf;
|
|
|
|
char *str_args = "|IO:RPNExpr.mutate";
|
|
char *names[] = {"n_mutations", "params", NULL};
|
|
|
|
PyObject *py_params = NULL;
|
|
unsigned int n_mutations = 1;
|
|
rpn_mutation_params_t params;
|
|
|
|
if(!PyArg_ParseTupleAndKeywords(args, kwds, str_args, names,
|
|
&n_mutations, &py_params))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if(!py_params || py_params == Py_None)
|
|
{
|
|
if(py_params == Py_None) { Py_DECREF(Py_None); }
|
|
memcpy(¶ms, &rpn_mutation_params_default,
|
|
sizeof(rpn_mutation_params_t));
|
|
}
|
|
else
|
|
{
|
|
if(pyrpn_pyobj_to_mutation_params(py_params, ¶ms) < 0)
|
|
{
|
|
PyErr_SetString(PyExc_ValueError, "Bad value for params arguments");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
for(size_t i=0; i<n_mutations; i++)
|
|
{
|
|
if(rpn_mutation(&(self->rpn->toks), ¶ms) < 0)
|
|
{
|
|
PyErr_Format(PyExc_RuntimeError, "Mutation failed : %s",
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
rpn_expr_tokens_updated(self->rpn);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
PyObject* rpnexpr_richcompare(PyObject *_self, PyObject *other, int op)
|
|
{
|
|
PyObject *sta, *stb, *res;
|
|
|
|
if(!PyObject_IsInstance(other, (PyObject*)&RPNExprType))
|
|
{
|
|
PyErr_Format(PyExc_TypeError,
|
|
"Can only be compared with RPNExpr");
|
|
return NULL;
|
|
}
|
|
|
|
sta = rpnexpr_getstate(_self, NULL);
|
|
stb = rpnexpr_getstate(other, NULL);
|
|
|
|
res = PyObject_RichCompare(sta, stb, op);
|
|
|
|
Py_DECREF(sta);
|
|
Py_DECREF(stb);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
PyObject* rpnexpr_random(PyObject *cls, 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 = 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);
|
|
//free(expr);
|
|
return res;
|
|
}
|
|
|
|
PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssize_t argc)
|
|
{
|
|
PyObject *res, *wtypes;
|
|
|
|
if(!(wtypes = PyStructSequence_New(&rpn_token_types_SeqDesc)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if(!(res = PyStructSequence_New(&rpn_mutation_params_SeqDesc)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// wtypes filled with 1.0
|
|
PyObject *one = PyFloat_FromDouble(1.0);
|
|
for(size_t i=0; i<3; i++)
|
|
{
|
|
PyStructSequence_SET_ITEM(wtypes, i, one);
|
|
}
|
|
|
|
|
|
// max_len
|
|
PyStructSequence_SET_ITEM(res, 0,
|
|
PyLong_FromLong(rpn_mutation_params_default.min_len));
|
|
// weight_add
|
|
PyStructSequence_SET_ITEM(res, 1,
|
|
PyFloat_FromDouble(rpn_mutation_params_default.w_add));
|
|
// weight_del
|
|
PyStructSequence_SET_ITEM(res, 2,
|
|
PyFloat_FromDouble(rpn_mutation_params_default.w_del));
|
|
// weight_mut
|
|
PyStructSequence_SET_ITEM(res, 3,
|
|
PyFloat_FromDouble(rpn_mutation_params_default.w_mut));
|
|
// weight_mut_soft
|
|
PyStructSequence_SET_ITEM(res, 4,
|
|
PyFloat_FromDouble(rpn_mutation_params_default.w_mut_soft));
|
|
|
|
/** TODO use rpn_mutation_params_default instead of wtypes [1,1,1] */
|
|
// weight_add_elt
|
|
PyStructSequence_SET_ITEM(res, 5, wtypes);
|
|
Py_INCREF(wtypes);
|
|
// weight_mut_elt
|
|
PyStructSequence_SET_ITEM(res, 6, wtypes);
|
|
Py_INCREF(wtypes);
|
|
|
|
return res;
|
|
|
|
}
|
|
|