Preparing mutation with bugfix & enhancement in jit & parse
This commit is contained in:
parent
3097c98237
commit
fb42b293e8
9 changed files with 78 additions and 150 deletions
|
|
@ -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);
|
||||
|
|
|
|||
43
rpn_jit.c
43
rpn_jit.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
14
rpn_jit.h
14
rpn_jit.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue