Preparing mutation with bugfix & enhancement in jit & parse

This commit is contained in:
Yann Weber 2023-06-08 11:15:24 +02:00
commit fb42b293e8
9 changed files with 78 additions and 150 deletions

View file

@ -182,7 +182,7 @@ PyObject* rpnexpr_init_borrowing(rpn_expr_t *borrowed)
return NULL;
}
ret = PyObject_CallObject(&RPNExprType, args);
ret = PyObject_CallObject((PyObject*)&RPNExprType, args);
if(!ret || PyErr_Occurred())
{
Py_DECREF(args);

View file

@ -68,7 +68,13 @@ int rpn_expr_reinit(rpn_expr_t* expr)
return -1;
}
#endif
bzero(expr->code_map, expr->code_map_sz);
if(_rpn_expr_reset_map(expr) < 0)
{
snprintf(expr->err_reason, 128,
"Unable to re-init code map : %s", strerror(errno));
expr->state = RPN_ERROR;
return -1;
}
bzero(expr->stack, sizeof(unsigned long) * expr->stack_sz);
if(_rpn_expr_init_map(expr) < 0)
{
@ -81,6 +87,26 @@ int rpn_expr_reinit(rpn_expr_t* expr)
return 0;
}
int rpn_expr_tokens_updated(rpn_expr_t* expr)
{
if(rpn_expr_reinit(expr) < 0)
{
return -1;
}
if(_rpn_expr_compile_tokens(expr) < 0)
{
expr->state = RPN_ERROR;
return -1;
}
if(expr->expr)
{
free(expr->expr);
}
expr->expr = rpn_tokenized_expr(&expr->toks, 0);
return 0;
}
int rpn_expr_compile(rpn_expr_t *expr, const char *code)
{
#ifdef DEBUG
@ -502,3 +528,18 @@ int _rpn_expr_end_map(rpn_expr_t *expr)
return 0;
}
int _rpn_expr_reset_map(rpn_expr_t *expr)
{
if(!expr->code_map_sz)
{
return _rpn_expr_init_map(expr);
}
if(mprotect(expr->code_map, expr->code_map_sz,
PROT_READ | PROT_WRITE))
{
return -1;
}
bzero(expr->code_map, expr->code_map_sz);
return 0;
}

View file

@ -152,6 +152,12 @@ int rpn_expr_init(rpn_expr_t* expr, const unsigned char stack_sz,
*/
int rpn_expr_reinit(rpn_expr_t* expr);
/**@brief Takes into account modifications in token representation
* @param rpn_expr_t*
* @return 0 if no error else -1
*/
int rpn_expr_tokens_updated(rpn_expr_t* expr);
/**@brief Starts a new initialized expression from an expression string
* @param expr Pointer on an intialized expression ( see @ref rpn_expr_init )
* @param code '\0' terminated string representing the RPN expr
@ -190,7 +196,7 @@ char* rpn_random(size_t op_sz, size_t args_count);
* @ingroup rpn_compile
*/
int _rpn_expr_compile_expr(rpn_expr_t* expr);
/**@brief Compile an new RPN expression from string expression
/**@brief Compile an new RPN expression from tokens
* @param expr Pointer on @ref rpn_expr_s
* @return 0 if no error else -1 and set @ref rpn_expr_s err_reason
* @ingroup rpn_compile
@ -255,4 +261,10 @@ int _rpn_expr_init_map(rpn_expr_t* expr);
*/
int _rpn_expr_end_map(rpn_expr_t *expr);
/**@brief Reset the memory map, filling it with zeroes and reseting permissions
* @param rpn_expr_t*
* @return 0 if no error else -1
*/
int _rpn_expr_reset_map(rpn_expr_t *expr);
#endif

View file

@ -1,58 +0,0 @@
/*
* 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 "rpn_mutation.h"
/**@file rpn_mutation.c
* @todo continue implementation */
const rpn_mutation_profile_t rpn_default_mutprof = {16,
{ RPN_del, RPN_del,
RPN_add, RPN_add,
RPN_chg, RPN_chg, RPN_chg, RPN_chg, RPN_chg, RPN_chg,
RPN_upd, RPN_upd, RPN_upd, RPN_upd, RPN_upd, RPN_upd}
};
rpn_expr_t* rpn_expr_mutation(rpn_expr_t *src, size_t mutations)
{
return rpn_expr_mutation_p(src, mutations, &rpn_default_mutprof);
}
rpn_expr_t* rpn_expr_mutation_p(rpn_expr_t *src, size_t mutations,
const rpn_mutation_profile_t *prof)
{
unsigned char op;
prof = prof?prof:&rpn_default_mutprof;
op = prof->mods[(int)(drand48() / (1.0 / prof->mods_sz))];
switch(op)
{
case 0: // add a token
break;
case 1: // delete a token
break;
case 2: // update token type
break;
default: // update token, same type
break;
}
return NULL;
}

View file

@ -1,83 +0,0 @@
/*
* 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/>.
*/
#ifndef __rpn_mutation__h__
#define __rpn_mutation__h__
#include <stddef.h>
#include "rpn_jit.h"
/**@defgroup mutation RPN expression mutation
* @ingroup rpn
*/
/**@file rpn_mutation.h
* @brief Contains structures and function to mutate RPN epxressions
*/
/**@brief Defines mutation actions types */
enum rpn_mutation_op_e {
/**@brief Mutation action : delete a token */
RPN_del,
/**@brief Mutation action : add a token */
RPN_add,
/**@brief Mutation action : change a token */
RPN_chg,
/**@brief Mutation action : update a token (same type, different value) */
RPN_upd
};
/**@brief Shortcut for struct @ref rpn_mutation_profile_s */
typedef struct rpn_mutation_profile_s rpn_mutation_profile_t;
/**@brief Stores mutation informations
* @ingroup mutation
*/
struct rpn_mutation_profile_s
{
/**@brief Size of @ref rpn_mutation_profile_s::mods attribute */
size_t mods_sz;
/**@brief Modification possibilities
*
* One value is picked up randomly from this list to determine
* the type of mutation : addition, deletion, modification, value change
*/
unsigned char mods[];
};
/**@brief Default mutation profile */
extern const rpn_mutation_profile_t rpn_default_mutprof;
/**@brief Shortcut for @ref rpn_expr_mutation_p with a @ref rpn_default_mutprof
* @ingroup mutation */
rpn_expr_t* rpn_expr_mutation(rpn_expr_t *src, size_t mutations);
/**@brief Generate a new expression by applying mutations to a source
* expression
* @param src Source expression
* @param mutations number of mutations
* @param prof Mutation profile
* @return A new instance of rpn_expr_t ready to be evaluate
* @ingroup mutation
*/
rpn_expr_t* rpn_expr_mutation_p(rpn_expr_t *src, size_t mutations,
const rpn_mutation_profile_t *prof);
#endif

View file

@ -42,6 +42,7 @@ const rpn_op_t rpn_ops[] = {\
__op(rpn_pop_op, 'p', "pop"),\
};
#undef __op
const size_t RPN_OP_SZ = (sizeof(rpn_ops) / sizeof(rpn_op_t));
int rpn_tokenizer_start(rpn_tokenizer_t *tokenizer, rpn_tokenized_t *dst,
const char* expr, size_t argc)

View file

@ -49,7 +49,7 @@
*/
/**@brief Shortcut for loop on all operations list */
#define foreach_rpn_ops(IDX) for(IDX=0; IDX<rpn_op_sz(); IDX++)
#define foreach_rpn_ops(IDX) for(IDX=0; IDX<RPN_OP_SZ; IDX++)
/**@brief Check if a tokenizer is in error state
* @param tokenizer Pointer on a @ref rpn_tokenizer_s
@ -92,7 +92,7 @@ enum rpn_token_type_e {
/**@brief The token is an argument */
RPN_arg,
/**@brief The token is a value */
RPN_val
RPN_val,
};
/**@brief Represent an expression token (value, argument or operation)
@ -164,6 +164,8 @@ struct rpn_tokenizer_s
* Stores operation identification informations
* @ingroup rpn_tokenize */
extern const rpn_op_t rpn_ops[];
extern const size_t RPN_OP_SZ;
/**@brief Initialize a tokenizer and a tokenized representation
* @param tokenizer Pointer on a new tokenizer
@ -205,7 +207,7 @@ void rpn_tokenizer_free(rpn_tokenizer_t *tokenizer);
*/
int rpn_tokenize(const char *token, rpn_token_t *dst, char error[64]);
/**@brief Represented a tokenized expression in a string
/**@brief Represent a tokenized expression in a string
* @param tokens Tokenized expression
* @param long_op If true uses @ref rpn_op_s::str else @ref rpn_op_s::chr
* @return A newly allocated char* that should be deallocated using free()

View file

@ -113,6 +113,18 @@ int test_add()
res);
return 2;
}
// test token update
expr.toks.tokens[0].value = 15;
rpn_expr_tokens_updated(&expr);
res = rpn_expr_eval(&expr, NULL);
//printf("Result = %ld\n", res);
if(res != 41)
{
dprintf(2, "Error : expected 42 but %ld received\n",
res);
return 3;
}
rpn_expr_close(&expr);
return 0;
}

View file

@ -65,10 +65,11 @@ class Test0RpnModule(unittest.TestCase):
def test_init_badargs(self):
""" RPNExpr instanciation with bad arguments """
badargs = [('', 2), (), ('ab+',), ('ab+',300), (42, 42), ('ab', '42')]
badargs = [(), ('ab+',), ('ab+',300), (42, 42), ('ab', '42')]
for badarg in badargs:
with self.assertRaises((ValueError, TypeError)):
expr = pyrpn.RPNExpr(*badarg)
with self.subTest(badargs=badarg):
with self.assertRaises((ValueError, TypeError)):
expr = pyrpn.RPNExpr(*badarg)
def test_init_loop(self):
""" Testing pyrpn.RPNExpr multiple instanciation """