Compare commits

...
Sign in to create a new pull request.

23 commits

Author SHA1 Message Date
eb3feb7705 Commenting libs/cturmit.h 2018-09-03 12:42:49 +02:00
733743ba57 Adds an autostep limits to 0x40000 steps 2018-09-03 11:47:55 +02:00
3f5adeedc4 Add auto steps + correcting fractdim target
Now turmit can run to limit fractdim (when it stop raising)
The fractdim score is calculated given the target
2018-08-29 09:25:31 +02:00
ab7876e8d9 Fixing memory usage when writting animations
The options -b and -B specify a buffer size for images waiting to we writtent
on disk
2018-08-28 15:37:36 +02:00
fff97816aa Bugfixing wrong errno on constant parsing 2018-08-27 17:06:51 +02:00
a7ff0da428 Add explicit stack size limit in python turmit 2018-08-26 22:06:56 +02:00
4915e15893 New test on sub 2018-08-26 22:06:41 +02:00
a43466c4ef Turmit stack enhancement & bugfixes
Now stack reallocate blocs of stack. If no new block needed just set new
stack_sz
2018-08-26 22:05:20 +02:00
bf6a13f14a Bugfixes
Memory leak : now free stack
mem_sz op : bad size was given to bzero
sub op : handling underflow case and preparing signed int handling
2018-08-26 21:05:18 +02:00
dc51926e28 Bugfix + changing cflags 2018-08-26 16:01:45 +02:00
545d33cd76 Fixing jmp operations 2018-08-26 15:26:57 +02:00
70f9880af3 Better argument forwarding for gte.sh 2018-08-26 15:26:31 +02:00
50d59eddd0 Try to solve memory leak problems 2018-08-26 15:25:59 +02:00
c55918fd09 Bugfixes & enhancement in CTurmit init
Allowing copy
2018-08-25 23:43:09 +02:00
4e74e8909c Almost working commit 2018-08-25 22:46:06 +02:00
74db399337 Bugfixes to make all tests pass on cturmit 2018-08-25 21:56:53 +02:00
dc1311ad36 More test & more bugfixes
Now have separated tests for CTurmit and Turmit
2018-08-25 21:18:31 +02:00
10af037382 Add more methods, more tests passes 2018-08-25 18:55:31 +02:00
d01186c773 Make some test pass with CTurmit 2018-08-25 18:28:59 +02:00
5a4095e666 Continuing implementation of cturmit 2018-08-25 15:55:26 +02:00
f2f8341291 Start implementing a c library for turmits 2018-08-24 17:46:39 +02:00
4861d470d4 Starting cturmit implementation & tests 2018-08-24 14:59:01 +02:00
f4581b0023 Bugfix in argparsing 2018-08-24 14:48:44 +02:00
13 changed files with 1678 additions and 30 deletions

9
Makefile Normal file
View file

@ -0,0 +1,9 @@
all: libs
libs:
make -C libs
.PHONY: libs clean
clean:
make -C libs clean

3
gte.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
PYTHONPATH=":`pwd`/libs" /usr/bin/env python3 -m gte "$@"

View file

@ -16,18 +16,22 @@ logger = logging.getLogger()
logger.debug('Logger started')
from . import turmit, rpnlib
from .turmit import Turmit
#from .turmit import Turmit
from cturmit import CTurmit as Turmit
from .world import World, LivingTurmit, eval_prog
from .mutator import mutate
parser = argparse.ArgumentParser(description='Genetic Turmit Evolver')
parser.add_argument('-L', '--list-op', action="store_const", default=False,
const=True, help="List operations and exit")
subparsers = parser.add_subparsers(help='sub-commands help')
parser_evolve = subparsers.add_parser('evolve', help='evolving help')
parser_evolve.add_argument('--steps', '-s', type=int, metavar='N',
default=30000, help="Number of steps")
default=None, help="Number of steps")
parser_evolve.add_argument('--repeat-eval', '-R', type=int, metavar='N',
default=5)
@ -109,10 +113,26 @@ parser_gen.add_argument('--no-diagonals', '-d', action='store_const',
parser_gen.add_argument('--threads', '-t', type=int, metavar='N',
default=os.cpu_count()-1,
help="Animation writting threads")
parser_gen.add_argument('--buffer-min', '-b', type=int, metavar='N',
default=10,
help="Start populating animation buffer when this \
amount of images are in the buffer")
parser_gen.add_argument('--buffer-max', '-B', type=int, metavar='N',
default=100,
help="Start a buffer flush when this amount of images \
are in the buffer")
args = parser.parse_args()
if 'pool_size' in args:
if args.list_op:
from . import rpnlib
print("Operations list & aliases :")
for i, opname in enumerate(rpnlib._op_list):
alias = rpnlib._op_alias[opname] if opname in rpnlib._op_alias else ""
print("\t%02X: %8s\t%s" % (i, opname, alias))
exit(0)
elif 'pool_size' in args:
# Evolver
if args.prog is None:
prog = rpnlib.RpnExpr.random(args.prog_size)
@ -184,10 +204,8 @@ if 'pool_size' in args:
# Displaying eval results
logger.info('Generation evaluating ended in %.2fs' % (genstop - genstart))
if args.target is None:
scores = sorted(scores, key=lambda x: x[0], reverse=True)
else:
scores = sorted(scores, key=lambda x: abs(x[0] - args.target),)
scores = sorted(scores, key=lambda x: x[0], reverse=True)
for i, (score, prog, sinfo) in enumerate(scores):
logger.info('P%d %.3f:(D:%.3f,F:%.3f) : "%s"' % (i, score,
sinfo['D'],
@ -224,7 +242,7 @@ if 'pool_size' in args:
logger.debug('P%d : %s' % (pid, str(prog)))
generation += 1
exit(0)
else:
elif 'output_dir' in args:
# Generate
if args.output_dir is not None:
from PIL import Image
@ -233,10 +251,12 @@ else:
im.save(fname)
logger.debug('Image %s saved in %.3fs' % (fname,
time.time() - st1))
del(im)
write_pool = Pool(args.threads)
async_res = []
img_count = 0
img_total = args.steps if args.anim_div <=1 else args.steps / (args.anim_div - 1)
w = World(args.world_height, args.world_width, gray=args.gray)
prog = rpnlib.RpnExpr.from_string(args.prog)
turmits = [LivingTurmit(world=w, prog=prog, diag=not args.no_diagonals)
@ -246,7 +266,7 @@ else:
start = time.time()
for step in range(args.steps):
if step % 512 == 1:
msg = 'Step %d/%d %dus/step fractdim=%.3f'
msg = 'Step %d/%d avg: %dus/step fractdim=%.3f'
msg %= (step, args.steps,
((time.time() - start)*1000000)//step//len(turmits),
w.fractdim())
@ -261,14 +281,23 @@ else:
fname = os.path.join(args.output_dir, fname)
im = Image.fromarray(np.uint8(w._val))
async_res.append(write_pool.apply_async(save_pool, (im, fname)))
while async_res[0].ready():
async_res[0].get()
async_res.pop(0)
if len(async_res) > args.buffer_max:
logger.debug('Flushing animation on disk to empty RAM')
while len(async_res) > args.buffer_min:
while async_res[0].ready():
async_res[0].get()
async_res.pop(0)
msg = '%d/%d images written at avg %.0f img/s ETL : %ds'
img_prog = img_count - args.buffer_min
img_pers = img_prog/((time.time() - start))
etl = (img_total - img_prog) // img_pers
msg %= (img_prog, img_total, img_pers, etl)
logger.info(msg)
if args.output_dir is not None:
while async_res[0].ready():
while len(async_res) and async_res[0].ready():
async_res[0].get()
sync_res.pop(0)
async_res.pop(0)
write_pool.close()
logger.info('Waiting for animation to be written on disk')
img_st1 = None
@ -318,5 +347,8 @@ else:
w.save(args.output)
logger.info('Image saved in %s' % args.output)
else:
parser.print_help()
exit(1)
exit(0)

View file

@ -42,6 +42,8 @@ class Turmit(object):
# @note This limit is handled by @ref rpnlib.RpnOp()
self._signed_int = True
self._stack_max = 0xFFF
if 'max_int' in kwargs:
v = kwargs['max_int']
if v < 1:
@ -273,7 +275,7 @@ class Turmit(object):
'''
stksz = len(self._stack)
new_sz %= 0xFFF
new_sz %= self._stack_max
if new_sz < 2:
new_sz = 2
if new_sz > stksz:
@ -424,11 +426,11 @@ class Turmit(object):
Condition type is encoded on an int :
- 0b0000 : je
- 0b0001 : jne
- 0b0010 : jle
- 0b0011 : jl
- 0b0010 : jl
- 0b0011 : jle
- 0b0100 : jg
- 0b0101 : jge
- 0b0110 : jne
- 0b0110 : jmp
- 0b0111 : jmp
@param a int : operand

View file

@ -12,7 +12,8 @@ import time
import numpy as np
from random import randint
from .turmit import Turmit
#from .turmit import Turmit
from cturmit import CTurmit as Turmit
logger = logging.getLogger()
@ -25,7 +26,8 @@ def eval_prog(args):
w = World(args.world_height, args.world_width, gray=True)
logger.debug('Running P%d run#%d %s' % (progid, trynum, prog))
w.raz()
turmits = [LivingTurmit(world=w, prog=prog, diag=not args.no_diagonals)
base = LivingTurmit(world=w, prog=prog, diag=not args.no_diagonals)
turmits = [ LivingTurmit(world=w, turmit=base)
for _ in range(args.turmit_count)]
start = time.time()
@ -33,24 +35,49 @@ def eval_prog(args):
steps = args.steps
else:
steps = args.steps - int((args.steps / 1.5) // (args.repeat_eval - trynum))
for step in range(steps):
for turmit in turmits:
turmit()
if not steps: # 0 or None
pfdim = 0
dfdim = 1
steps = 0
lim_reach = 0
retry_lim = 0
while lim_reach < 2 and steps < 0x40000:
for _ in range(3000):
for turmit in turmits:
turmit()
steps += 0x1000
cfdim = w.fractdim() # delta fdim on not targeted dim
dfdim = cfdim - pfdim
pfdim = cfdim
if abs(dfdim) < 0.001:
lim_reach += 1
else:
retry_lim += 1
if retry_lim < 3:
lim_reach = 0
else:
for step in range(steps):
for turmit in turmits:
turmit()
stop = time.time()
score_dir = sum([t.dirvar() for t in turmits]) / len(turmits)
score_deter = sum([t.determinist() for t in turmits]) / len(turmits)
score_fract = w.fractdim()
score_fract, raw_fract = w.fractdim_target(args.target)
score = (score_dir * score_fract) * (score_deter * 0.2 + 0.8)
sinfo = {'F':score_fract, 'D':score_dir}
#score = sum([score_fract] + [score_dir] * 4) / 5
if not args.quiet:
tall = time.time() - startall
msg = 'G%d P%d R%d: %d steps scores %.3f:(D:%.3f,F:%.3f,Dtr:%.3f) in %.3fs (%dus per step)\t%s'
msg = 'G%d P%d R%d: %d steps scores %.3f:(D:%.3f,F:%.3f,'
msg %= (generation, progid, trynum, steps, score, score_dir,
score_fract, score_deter, tall,
((stop - start)*1000000)//steps//len(turmits),
str(prog))
score_fract)
if args.target:
msg += 'RawF:%.3f,' % raw_fract
msg += 'Dtr:%.3f) in %.3fs (%dus per step)\t%s'
msg %= (score_deter, tall,
((stop - start)*1000000)//steps//len(turmits), str(prog))
logger.info(msg)
return progid, score, sinfo
@ -98,6 +125,16 @@ class World(object):
''' @brief Save as an image '''
scipy.misc.imsave(filename, self._val)
def fractdim_target(self, target, threshold=None):
res = self.fractdim(threshold)
if target:
ret = (2.0 - (abs(target - res))*5)
if ret < 0:
ret = 0.0
return (ret, res)
else:
return (res, res)
def fractdim(self, threshold=None):
''' @return Minkowski–Bouligand dimension (computed) '''
if not self._gray:
@ -169,6 +206,8 @@ class LivingTurmit(Turmit):
''' @brief Represent a Turmit with coordinates in a world '''
def __init__(self, world, color = None, x=None, y=None, diag=True, **kwargs):
if 'prog' in kwargs:
kwargs['prog'] = str(kwargs['prog']).lower()
super().__init__(**kwargs)
if not isinstance(world, World):
@ -228,6 +267,7 @@ class LivingTurmit(Turmit):
r = g = b = self._world[self._y][self._x]
else:
r,g,b = self._world[self._y][self._x]
r = int(r); g=int(g); b=int(b)
tdir = super().__call__(x=self._x, y=self._y, r=r, g=g, b=b)
self.move(tdir)
@ -253,7 +293,10 @@ class LivingTurmit(Turmit):
''' @brief Process a determinit score : determinist_expr / total expr
@return float in [0.0..1.0]
'''
return (self._determin_score + 1) / self._steps
try:
return (self._determin_score + 1) / self._steps
except AttributeError:
return 1
def dirvar(self):
''' @brief Process @ref _dirvar to return a direction variation

17
libs/Makefile Normal file
View file

@ -0,0 +1,17 @@
PYTHON=/usr/bin/python3
#CFLAGS=-Wall -Werror -O0 -g
CFLAGS=-Wall -Werror
CC=gcc $(CFLAGS)
all: cturmit*.so
cturmit*.so: setup.py build/lib.*/cturmit*.so
cp build/lib.*/cturmit*.so ./
build/lib.*/cturmit*.so: cturmit.c cturmit.h turmit.c turmit.h
make clean; CFLAGS="$(CFLAGS)" $(PYTHON) setup.py --verbose build
.PHONY: clean
clean:
-rm -Rf build cturmit*.so

352
libs/cturmit.c Normal file
View file

@ -0,0 +1,352 @@
#include "cturmit.h"
PyMODINIT_FUNC
PyInit_cturmit(void)
{
PyObject* m;
CTurmitType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CTurmitType) < 0)
return NULL;
m = PyModule_Create(&cturmitmodule);
if (m == NULL)
return NULL;
Py_INCREF(&CTurmitType);
PyModule_AddObject(m, "CTurmit", (PyObject *)&CTurmitType);
return m;
}
static int
CTurmit_init(CTurmit *self, PyObject *args, PyObject *kwds)
{
size_t sz;
char err_msg[128];
ssize_t arg_stk_sz, arg_int_max;
char *arg_expr;
int i, ret;
CTurmit *turmit;
PyObject *stack_size, *int_max, *expr, *keys, *asc_str;
PyObject *errtype, *errvalue, *errbck;
PyErr_Fetch(&errtype, &errvalue, &errbck);
turmit = (CTurmit*)PyMapping_GetItemString(kwds, "turmit");
if(turmit)
{
Py_XDECREF(errtype);
Py_XDECREF(errvalue);
Py_XDECREF(errbck);
ret = _CTurmit_copy_init(self, turmit);
Py_DECREF(turmit);
return ret;
}
PyErr_Restore(errtype, errvalue, errbck);
stack_size = int_max = expr = NULL;
self->turmit = NULL;
//Checking arguments
if((sz = PySequence_Length(args)) >= 0)
{
if(sz > 1)
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128, "1 positional argument expected \
but %ld found", sz);
PyErr_SetString(PyExc_TypeError,
err_msg);
goto cturmit_init_error;
}
stack_size = PySequence_GetItem(args, 0);
}
if(!stack_size)
{
stack_size = PyMapping_GetItemString(kwds, "stack_size");
PyMapping_DelItemString(kwds, "stack_size");
}
if(stack_size)
{
if(!PyLong_CheckExact(stack_size))
{
PyErr_Restore(errtype, errvalue, errbck);
Py_DECREF(stack_size);
snprintf(err_msg, 128,
"stack_size expected to be an integer");
PyErr_SetString(PyExc_TypeError,
err_msg);
goto cturmit_init_error;
}
arg_stk_sz = PyLong_AsSsize_t(stack_size);
Py_DECREF(stack_size);
if(arg_stk_sz == (size_t)-1 && PyErr_Occurred())
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"size_t overflow with stack_size");
PyErr_SetString(PyExc_ValueError,
err_msg);
goto cturmit_init_error;
}
}
else
{
arg_stk_sz = 8;
}
int_max = PyMapping_GetItemString(kwds, "max_int");
PyMapping_DelItemString(kwds, "max_int");
if(int_max)
{
if(!PyLong_CheckExact(int_max))
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"int_max expected to be an integer");
PyErr_SetString(PyExc_TypeError,
err_msg);
goto cturmit_init_error;
}
arg_int_max = PyLong_AsSsize_t(int_max);
Py_DECREF(int_max);
if(arg_int_max == (size_t)-1 && PyErr_Occurred())
{
PyErr_Restore(errtype, errvalue, errbck);
PyErr_SetString(PyExc_TypeError,
"size_t overflow with stack_size");
PyErr_SetString(PyExc_ValueError,
err_msg);
goto cturmit_init_error;
}
}
else
{
arg_int_max = 0x10000;
}
expr = PyMapping_GetItemString(kwds, "prog");
PyMapping_DelItemString(kwds, "prog");
if(expr)
{
if(!PyUnicode_Check(expr) && !(expr = PyObject_Str(expr)))
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"prog expected to be a string !");
PyErr_SetString(PyExc_TypeError,
err_msg);
goto cturmit_init_error;
}
asc_str = PyUnicode_AsASCIIString(expr);
Py_DECREF(expr);
if(!asc_str)
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"prog expected to be an ASCII string");
PyErr_SetString(PyExc_ValueError,
err_msg);
goto cturmit_init_error;
}
arg_expr = (char*)PyBytes_AsString(asc_str);
Py_DECREF(asc_str);
if(!arg_expr)
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"Unable to convert prog to Cstring");
PyErr_SetString(PyExc_RuntimeError,
err_msg);
goto cturmit_init_error;
}
}
else
{
arg_expr = "";
}
if(PyMapping_Length(kwds) > 0)
{
keys = PyMapping_Keys(kwds);
strncpy(err_msg, "Unrecognized arguments : '", 128);
for(i=0; i<PyList_Size(keys); i++)
{
asc_str = PyUnicode_AsASCIIString(
PyList_GetItem(keys, i));
strncat(err_msg,
(char*)PyBytes_AsString(asc_str),127);
strncat(err_msg, "', '", 127);
}
Py_DECREF(keys);
strncat(err_msg, "'", 128);
PyErr_Restore(errtype, errvalue, errbck);
PyErr_SetString(PyExc_RuntimeError,
err_msg);
goto cturmit_init_error;
}
PyErr_Restore(errtype, errvalue, errbck);
self->turmit = turmit_alloc(arg_stk_sz, arg_int_max, arg_expr,
TURMIT_AUTOCOMP);
if(self->turmit->err)
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128,
"Unable to compile '%s' err : %s", arg_expr,
self->turmit->err_str);
PyErr_SetString(PyExc_ValueError,
err_msg);
goto cturmit_init_error;
}
Py_XDECREF(errtype);
Py_XDECREF(errvalue);
Py_XDECREF(errbck);
return 0;
cturmit_init_error:
Py_XDECREF(errtype);
Py_XDECREF(errvalue);
Py_XDECREF(errbck);
return -1;
}
static PyObject *
CTurmit_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CTurmit *self;
self = (CTurmit *)type->tp_alloc(type, 0);
if(self != NULL) {
//do stuff
}
return (PyObject *)self;
}
void
CTurmit_dealloc(CTurmit *self)
{
if(self->turmit) { turmit_free(self->turmit); }
Py_TYPE(self)->tp_free((PyObject*)self);
}
static int _CTurmit_copy_init(CTurmit *self, CTurmit *t)
{
self->turmit = turmit_copy(t->turmit);
if(!self->turmit)
{
//set error
return -1;
}
return 0;
}
PyObject* CTurmit_call(PyObject *func, PyObject *args, PyObject *kwds)
{
turmit_int res;
PyObject *arg;
CTurmit *self;
turmit_int exec_args[5];
char *argsname[5] = {"x", "y", "r", "g", "b"}; // see TURMIT_VAR_L
char err_msg[64];
int i;
PyObject *errtype, *errvalue, *errbck;
self = (CTurmit*)func;
PyErr_Fetch(&errtype, &errvalue, &errbck);
for(i=0; i<5; i++)
{
arg = PyMapping_GetItemString(kwds, argsname[i]);
if(PyErr_Occurred())
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 64, "Argument %s missing",
argsname[i]);
PyErr_SetString(PyExc_TypeError,
err_msg);
Py_RETURN_NONE;
}
exec_args[i] = PyLong_AsUnsignedLongLong(arg);
if(PyErr_Occurred())
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 64, "An integer is required for %s",
argsname[i]);
PyErr_SetString(PyExc_TypeError,
err_msg);
Py_RETURN_NONE;
}
Py_DECREF(arg);
}
res = turmit_exec(self->turmit, exec_args);
return PyLong_FromUnsignedLongLong(res);
}
PyObject* CTurmit__push(CTurmit* self, PyObject *args)
{
char err_msg[128];
size_t sz;
turmit_int ival;
PyObject *val;
PyObject *errtype, *errvalue, *errbck;
PyErr_Fetch(&errtype, &errvalue, &errbck);
if((sz = PySequence_Length(args)) >= 0)
{
if(sz > 1)
{
PyErr_Restore(errtype, errvalue, errbck);
snprintf(err_msg, 128, "1 positional argument expected \
but %ld found", sz);
PyErr_SetString(PyExc_TypeError, err_msg);
Py_RETURN_NONE;
}
val = PySequence_GetItem(args, 0);
}
if(!val)
{
PyErr_Restore(errtype, errvalue, errbck);
PyErr_SetString(PyExc_TypeError,
"Argument val is missing");
Py_RETURN_NONE;
}
ival = PyLong_AsSize_t(val);
if(ival == (size_t)-1 && PyErr_Occurred()) { Py_RETURN_NONE; }
SPUSH(self->turmit, ival);
PyErr_Restore(errtype, errvalue, errbck);
Py_RETURN_NONE;
}
PyObject* CTurmit__pop(CTurmit* self)
{
return PyLong_FromUnsignedLongLong(SPOP(self->turmit));
}
PyObject* CTurmit_get_shead(CTurmit *self, void *ref)
{
return PyLong_FromUnsignedLongLong(SCUR(self->turmit));
}
PyObject* CTurmit_get__cur(CTurmit *self, void *ref)
{
return PyLong_FromSsize_t(self->turmit->stack_cur);
}
PyObject* CTurmit_get__stack(CTurmit *self, void *ref)
{
size_t i;
PyObject *res;
res = PyList_New(self->turmit->stack_sz);
for(i=0; i<self->turmit->stack_sz;i++)
{
PyList_SET_ITEM(res, i,
PyLong_FromUnsignedLongLong(self->turmit->stack[i]));
}
return res;
}

205
libs/cturmit.h Normal file
View file

@ -0,0 +1,205 @@
#include<Python.h>
#include"structmember.h"
#include "turmit.h"
/** @brief Python module containing CTurmit python class */
static PyModuleDef cturmitmodule = {
PyModuleDef_HEAD_INIT,
"cturmit",
"Module implementing turmits in C",
-1,
NULL, NULL, NULL, NULL, NULL
}; /*<! Module description */
/*
class CTurmit definitions
*/
typedef struct
{
PyObject VAR_HEAD;
turmit_t *turmit; /*<! Ref to a turmit_t from libs/turmit.h */
} CTurmit; /*<! CTurmit struct */
static PyMemberDef CTurmit_members[] = {
{NULL} /* Sentinel */
}; /*<! CTurmit member attribute description */
/* Other methods */
#define TURMIT_PYOP(NAME) PyObject* CTurmit_op_##NAME(CTurmit* self) {\
turmit_op_##NAME(self->turmit);\
Py_RETURN_NONE;\
}
#define TURMIT_PYOPDEF(NAME) {#NAME, (PyCFunction)CTurmit_op_##NAME, \
METH_NOARGS, NULL}
/** @brief Push a python integer on the CTurmit stack
* @param self the CTurmit instance
* @param PyObject* list of *args arguments. Should contain a single integer
* argument to be pushed on the stack
* @return Python None
* @throws TypeError if bad arguments
*/
PyObject* CTurmit__push(CTurmit* self, PyObject *args);
/**@brief Pop a python integer from the CTurmit stack
* @return a python integer returned from PyLong_FromUnsignedLongLong()
*/
PyObject* CTurmit__pop(CTurmit* self);
/* Adding method to call turmit_t operations on the stack
* @param self CTurmit* (see TURMIT_PYOP macro) the method takes no args
* except self
*/
TURMIT_PYOP(mem_sz)
TURMIT_PYOP(add)
TURMIT_PYOP(sub)
TURMIT_PYOP(bin_and)
TURMIT_PYOP(dup)
TURMIT_PYOP(lshift)
TURMIT_PYOP(mod)
TURMIT_PYOP(mul)
TURMIT_PYOP(div)
TURMIT_PYOP(bin_or)
TURMIT_PYOP(bin_xor)
TURMIT_PYOP(pop)
TURMIT_PYOP(swp)
TURMIT_PYOP(jmp)
TURMIT_PYOP(jz)
TURMIT_PYOP(jcmp)
static PyMethodDef CTurmit_methods[] = {
{"_push", (PyCFunction)CTurmit__push, METH_KEYWORDS | METH_VARARGS,
"Push a value on the stack"},
{"_pop", (PyCFunction)CTurmit__pop, METH_NOARGS,
"Pop a value from the stack"},
TURMIT_PYOPDEF(mem_sz),
TURMIT_PYOPDEF(add),
TURMIT_PYOPDEF(sub),
TURMIT_PYOPDEF(bin_and),
TURMIT_PYOPDEF(dup),
TURMIT_PYOPDEF(lshift),
TURMIT_PYOPDEF(mod),
TURMIT_PYOPDEF(mul),
TURMIT_PYOPDEF(div),
TURMIT_PYOPDEF(bin_or),
TURMIT_PYOPDEF(bin_xor),
TURMIT_PYOPDEF(pop),
TURMIT_PYOPDEF(swp),
TURMIT_PYOPDEF(jmp),
TURMIT_PYOPDEF(jz),
TURMIT_PYOPDEF(jcmp),
{NULL} /* Sentinel */
}; /*<! Static CTurmit method mapping */
/*
Getter & setter definition
Note : no setter, this methods are implemented for read only access
to some @ref turmit_t attributes
*/
/**@brief Returns current value on the top of the stack
* @note mapped as "shead" attribute
* @retrun a python int
*/
PyObject* CTurmit_get_shead(CTurmit *self, void *ref);
/**@brief Returns current position of the stack head
* @note mapped as "_cur" attribute
* @retrun a python int
*/
PyObject* CTurmit_get__cur(CTurmit *self, void *ref);
/**@brief Returns a python representation of the stack
*@return a python list containing python int
*/
PyObject* CTurmit_get__stack(CTurmit *self, void *ref);
static struct PyGetSetDef CTurmit_getset[] = {
{"shead", (getter)CTurmit_get_shead, NULL, NULL, NULL},
{"_cur", (getter)CTurmit_get__cur, NULL, NULL, NULL},
{"_stack", (getter)CTurmit_get__stack, NULL, NULL, NULL},
{NULL} /* Sentinel */
};/*<! Getter mapping */
/**@brief Utility method that handle CTurmit instanciation copying an existing
* CTurmit instance
* @param self Python self CTurmit, the CTurmit to copy
* @param t the destination CTurmit
* @return 0 if no error else -1
* @todo set error to throw python exception if error
*/
static int _CTurmit_copy_init(CTurmit *self, CTurmit *t);
/**@brief Python CTurmit.__new__() method
* @param type Python type
* @param args Python *args positional args list
* @param kwds Python **kwargs named args dict
* @return a CTurmit with memory allocated for the instance
*/
static PyObject *
CTurmit_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
/**@brief CTurmit.__init__(self, stack_size=8, max_int=0x10000, prog="", turmit=None) method
* @param CTurmit* self
* @param PyObject* can contain an interger representing stack size
* @param Pyobject* contains kwargs. Can be : stack_size, max_int, prog
*/
static int
CTurmit_init(CTurmit *self, PyObject *args, PyObject *kwds);
/**@brief CTurmit.__del__(self) method
* @param self The CTurmit instance
*/
void
CTurmit_dealloc(CTurmit *self);
/**@brief CTurmit.__call__(self, x, y, r, g, b) method
* @param args python positional arguments list
* @param kwds python named arguments dict
*/
PyObject* CTurmit_call(PyObject *func, PyObject *args, PyObject *kwds);
static PyTypeObject CTurmitType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cturmit.CTurmit", /* tp_name */
sizeof(CTurmit), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)CTurmit_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
CTurmit_call, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
"CTurmit objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
CTurmit_methods, /* tp_methods */
CTurmit_members, /* tp_members */
CTurmit_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)CTurmit_init, /* tp_init */
0, /* tp_alloc */
CTurmit_new, /* tp_new */
}; /*<! CTurmit object mapping */

12
libs/setup.py Normal file
View file

@ -0,0 +1,12 @@
from distutils.core import setup, Extension
module1 = Extension('cturmit',
sources = ['cturmit.c', 'turmit.c'])
setup(
name = "Cturmit",
version = '1.0',
description = 'Turmit implementation in c',
ext_modules = [module1]
)

458
libs/turmit.c Normal file
View file

@ -0,0 +1,458 @@
#include "turmit.h"
TURMIT_OP(mem_sz)
{
turmit_int *new;
turmit_int new_sz, old_sz, new_blc, old_blc;
old_sz = turmit->stack_sz;
old_blc = (old_sz / TURMIT_STACK_GROW) + 1;
new_sz = SPOP(turmit);
new_sz %= TURMIT_STACK_MAX;
new_sz = new_sz<2?2:new_sz;
new_blc = (new_sz / TURMIT_STACK_GROW) + 1;
if(new_blc != old_blc)
{
new = realloc(turmit->stack,
sizeof(turmit_int) * (new_blc * TURMIT_STACK_GROW));
if(!new) {
perror("Unable to reallocate memory for stack");
return;
}
turmit->stack = new;
}
turmit->stack_sz = new_sz;
turmit->stack_cur %= new_sz;
if(old_sz < new_sz)
{
bzero(turmit->stack + old_sz,
sizeof(turmit_int) * (new_sz - old_sz));
}
}
TURMIT_OP(add)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
SPUSH(turmit, a+b);
}
TURMIT_OP(sub)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
if(turmit->flags & TURMIT_SIGNED)
{
fprintf(stderr, "Signed int not implemented\n");
}
else
{
SPUSH(turmit, a>b?(turmit->int_max - a) + b:b - a);
}
}
TURMIT_OP(bin_and)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
SPUSH(turmit, b & a);
}
TURMIT_OP(dup)
{
turmit_int a = SCUR(turmit);
SPUSH(turmit, a);
}
TURMIT_OP(lshift)
{
turmit_int a,b;
a = SPOP(turmit); b = SPOP(turmit);
SPUSH(turmit, b << a);
}
TURMIT_OP(mod)
{
turmit_int a,b;
a = SPOP(turmit); b = SPOP(turmit);
a = !a?0:b%a;
SPUSH(turmit, a);
}
TURMIT_OP(mul)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
SPUSH(turmit, a*b);
}
TURMIT_OP(div)
{
turmit_int a, b;
a = SPOP(turmit);
b = SPOP(turmit);
SPUSH(turmit, a==0?0:b/a);
}
TURMIT_OP(bin_or)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
SPUSH(turmit, a | b);
}
TURMIT_OP(bin_xor)
{
turmit_int a = SPOP(turmit), b = SPOP(turmit);
SPUSH(turmit, a ^ b);
}
TURMIT_OP(pop)
{
SPOP(turmit);
}
TURMIT_OP(swp)
{
turmit_int a, b;
a = SPOP(turmit);
b = SPOP(turmit);
SPUSH(turmit, a);
SPUSH(turmit, b);
}
TURMIT_OP(jmp)
{
turmit_int a;
a = SPOP(turmit);
TURMIT_JMP(turmit, a);
}
TURMIT_OP(jz)
{
turmit_int a, b;
a = SPOP(turmit);
b = SPOP(turmit);
if(b == 0)
{
TURMIT_JMP(turmit, a);
}
}
TURMIT_OP(jcmp)
{
turmit_int a, b, cnd, offset;
offset = SPOP(turmit);
cnd = SPOP(turmit);
b = SPOP(turmit);
a = SPOP(turmit);
if(((cnd & 7) == 0 && a != b) || (cnd > 6) || ((cnd & 1) && a == b) ||
((cnd & 7) > 2 && a < b) || ((cnd & 7) > 4 && a > b))
{
TURMIT_JMP(turmit, offset);
}
}
turmit_t *turmit_alloc(ssize_t stack_sz, ssize_t int_max, const char *expr,
unsigned char flags)
{
turmit_t *res;
res = malloc(sizeof(struct turmit_s));
if(!res)
{
perror("Unable to allocate memory for turmit");
return NULL;
}
return turmit_init(res, stack_sz, int_max, expr, flags);
}
turmit_t *turmit_init(turmit_t *turmit, ssize_t stack_sz, ssize_t int_max,
const char *expr, unsigned char flags)
{
turmit->expr = strndup(expr, TURMIT_EXPR_MAX_SZ);
turmit->flags = flags;
turmit->int_max = int_max;
turmit->op_expr = NULL;
turmit->op_expr_sz = 0;
turmit->op_cur = 0;
turmit->op_end = 0;
turmit->stack_sz = stack_sz;
turmit->stack_cur = turmit->stack_sz - 1;
turmit->err = 0;
turmit->err_str = NULL;
turmit->stack = malloc(sizeof(turmit_int) *
((turmit->stack_sz / TURMIT_STACK_GROW)+1) * TURMIT_STACK_GROW);
if(!turmit->stack)
{
perror("Unable to allocate turmit's stack's memory");
return turmit;
}
bzero(turmit->stack, sizeof(turmit_int) * turmit->stack_sz);
if(turmit->flags & TURMIT_AUTOCOMP)
{
turmit_compile(turmit);
}
return turmit;
}
turmit_t *turmit_copy(turmit_t *turmit)
{
turmit_t *res;
turmit_int stack_blck;
res = malloc(sizeof(turmit_t));
if(!res)
{
perror("Unable to allocate memory for copy");
return NULL;
}
memcpy(res, turmit, sizeof(turmit_t));
if(turmit->expr)
{
res->expr = strdup(turmit->expr);
}
if(turmit->stack)
{
stack_blck = (res->stack_sz / TURMIT_STACK_GROW) + 1;
res->stack = malloc(
sizeof(turmit_int) * stack_blck * TURMIT_STACK_GROW);
memcpy(res->stack, turmit->stack,
sizeof(turmit_int) * stack_blck * TURMIT_STACK_GROW);
}
if(turmit->op_expr)
{
res->op_expr = malloc(sizeof(turmit_op_t) * res->op_expr_sz);
if(!res->op_expr)
{
perror("Unable to allocate memory for expression");
return res;
}
memcpy(res->op_expr, turmit->op_expr,
sizeof(turmit_op_t) * res->op_expr_sz);
}
return res;
}
void turmit_clean(turmit_t *turmit)
{
if(turmit->stack) { free(turmit->stack); }
if(turmit->err_str) { free(turmit->err_str); }
if(turmit->expr) { free(turmit->expr); }
if(turmit->op_expr) { free(turmit->op_expr); }
}
void turmit_free(turmit_t *turmit)
{
turmit_clean(turmit);
free(turmit);
}
turmit_int turmit_exec(turmit_t *turmit, const turmit_int args[5])
{
turmit_op_t *op;
turmit->op_cur = 0;
turmit->op_end = 0;
while(!turmit->op_end && turmit->op_cur < turmit->op_expr_sz)
{
op = &(turmit->op_expr[turmit->op_cur]);
switch(op->value)
{
case TURMIT_SYM_OP:
op->op.op(turmit);
break;
case TURMIT_SYM_VAL:
SPUSH(turmit, op->op.val);
break;
case TURMIT_SYM_VAR:
SPUSH(turmit, args[op->op.var]);
break;
default:
// Null sym encountered. This sould NOT append
fprintf(stderr, "Warning NULL sym encountered\n");
turmit->op_cur = turmit->op_expr_sz;
break;
}
//_turmit_stack_dump(turmit);
turmit->op_cur++;
}
return SCUR(turmit);
}
int turmit_compile(turmit_t *turmit)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-braces"
turmit_sym_t tsym[] = TURMIT_OP_LST;
#pragma GCC diagnostic pop
char *cur, *endptr;
turmit_sym_t *isym;
ssize_t opcur;
turmit_op_t *pret;
long int iret;
int err;
int i;
turmit->op_expr_sz = 64;
turmit->op_expr = malloc(sizeof(turmit_op_t) * turmit->op_expr_sz);
bzero(turmit->op_expr, sizeof(turmit_op_t) * turmit->op_expr_sz);
opcur = 0;
cur = turmit->expr;
while(*cur != '\0')
{
if(opcur >= turmit->op_expr_sz - 1)
{ //more space needed
turmit->op_expr_sz += 64;
pret = realloc(turmit->op_expr,
sizeof(turmit_op_t) * turmit->op_expr_sz);
if(!pret)
{
perror("Unable to allocate memory");
goto turmit_compile_err;
}
bzero(pret + opcur - 1,
64 * sizeof(turmit_op_t));
turmit->op_expr = pret;
}
//Checking for separators
if(*cur == ' ' || *cur == '\t' || *cur == ' ')
{
cur++;
continue;
}
//Checking for variables
for(i=0; TURMIT_VAR_L[i] != '\0'; i++)
{
if(tolower(*cur) == TURMIT_VAR_L[i])
{
turmit->op_expr[opcur].op.var = i;
turmit->op_expr[opcur].value = TURMIT_SYM_VAR;
opcur++;
cur++;
break;
}
}
if(TURMIT_VAR_L[i] != '\0') { continue; }
//Checking for values
//hex
if(strncasecmp("0x", cur, 2) == 0)
{
cur+= 2;
errno = 0;
iret = strtol(cur, &endptr, 16);
err = errno;
if(err || endptr == cur)
{
fprintf(stderr, "Invalid constant %s : %s\n",
cur-2, strerror(err));
goto turmit_compile_err;
}
turmit->op_expr[opcur].op.val = iret;
turmit->op_expr[opcur].value = TURMIT_SYM_VAL;
opcur++;
cur = endptr;
continue;
}
//decimal
if(*cur <= '9' && *cur >= '0')
{
iret = strtol(cur, &endptr, 10);
err = errno;
if(err || endptr == cur)
{
fprintf(stderr, "Invalid constant %s : %s\n",
cur, strerror(err));
goto turmit_compile_err;
}
turmit->op_expr[opcur].op.val = iret;
turmit->op_expr[opcur].value = TURMIT_SYM_VAL;
opcur++;
cur = endptr;
continue;
}
//Checking for op
isym = tsym;
while(isym->str != NULL)
{
endptr = cur;
if(strncasecmp(isym->str, cur, strlen(isym->str)) == 0)
{
endptr = cur+strlen(isym->str);
}
else if(isym->alias && strncmp(cur, isym->alias,
strlen(isym->alias)) == 0)
{
endptr = cur+strlen(isym->alias);
}
if(cur != endptr)
{
cur = endptr;
turmit->op_expr[opcur].op.op = isym->op_fun;
turmit->op_expr[opcur].value = TURMIT_SYM_OP;
opcur++;
break;
}
isym++;
}
if(isym->str != NULL)
{
continue;
}
//unrecognized symbol :'(
turmit->err = 1;
if(turmit->err_str) { free(turmit->err_str); }
turmit->err_str = malloc(sizeof(char) * 256);
if(!turmit->err_str)
{
perror("Unable to allocate memory for error string");
return -1;
}
snprintf(turmit->err_str, 256,
"Error compiling prog starting at : '%s'", cur);
goto turmit_compile_err;
}
if(!opcur)
{ //empty expression
turmit->op_expr_sz = 0;
free(turmit->op_expr);
turmit->op_expr = NULL;
return 0;
}
turmit->op_expr_sz = opcur;
pret = realloc(turmit->op_expr,
sizeof(turmit_op_t) * turmit->op_expr_sz);
if(!pret)
{
perror("Unable to shrink op_expr");
return 1;
}
else
{
turmit->op_expr = pret;
}
return 0;
turmit_compile_err:
free(turmit->op_expr);
turmit->op_expr = NULL;
turmit->op_expr_sz = 0;
turmit->op_cur = 0;
return 1;
}
void _turmit_stack_dump(turmit_t *turmit)
{
int i;
fprintf(stderr, "Stack cur = %lu\n[", turmit->stack_cur);
for(i=0; i<turmit->stack_sz; i++)
{
fprintf(stderr,"%llu, ", turmit->stack[i]);
}
fprintf(stderr, "]\n");
}

196
libs/turmit.h Normal file
View file

@ -0,0 +1,196 @@
#ifndef _TURMIT_H_
#define _TURMIT_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
/**@Todo For the moment there is no way to track wether a variable is used
* or not in result processing */
typedef unsigned long long int turmit_int;
typedef struct turmit_op_s turmit_op_t;
typedef struct turmit_s turmit_t;
typedef struct turmit_sym_s turmit_sym_t;
typedef void (*turmit_op_f)(turmit_t*);
#define SCUR(t) (t->stack[t->stack_cur])
#define SDEC(t) (t->stack_cur = (t->stack_cur>0?t->stack_cur:t->stack_sz) -1)
#define SINC(t) (t->stack_cur = (t->stack_cur + 1) % t->stack_sz)
#define SPOP(t) (__SPOP(t))
#define SPUSH(t, v) (t->stack[SINC(t)] = v % t->int_max)
#define TURMIT_JMP(t, v) (((t->op_expr_sz - t->op_cur) <= v)?\
(t->op_end=1):\
(t->op_cur += (v>0?v-1:0) ))
#define TURMIT_STACK_GROW 0xFF
#define TURMIT_STACK_MAX 0xFFF
#define TURMIT_EXPR_MAX_SZ 0xFFFFFFFF
#define TURMIT_LAZY 0
#define TURMIT_AUTOCOMP 1
#define TURMIT_UNSIGNED 0
#define TURMIT_SIGNED 2
#define TURMIT_OK 0
#define TURMIT_ERROR -1
#define TURMIT_SYM_OP 1
#define TURMIT_SYM_VAL 2
#define TURMIT_SYM_VAR 3
#define TURMIT_VAR_L "xyrgb"
#define TURMIT_OPSYM(NAME) {#NAME, NULL, turmit_op_##NAME}
#define TURMIT_OPSYMALIAS(NAME, alias) {#NAME, alias, turmit_op_##NAME}
// OPSYMALIAS has to be first !
#define TURMIT_OP_LST {\
TURMIT_OPSYMALIAS(add, "+"),\
TURMIT_OPSYMALIAS(sub, "-"),\
TURMIT_OPSYMALIAS(mul, "*"),\
TURMIT_OPSYMALIAS(div, "/"),\
TURMIT_OPSYMALIAS(mod, "%"),\
TURMIT_OPSYMALIAS(bin_or, "|"),\
TURMIT_OPSYMALIAS(bin_and, "&"),\
TURMIT_OPSYMALIAS(bin_xor, "^"),\
TURMIT_OPSYMALIAS(lshift, "<<"),\
TURMIT_OPSYM(mem_sz),\
TURMIT_OPSYM(dup),\
TURMIT_OPSYM(pop),\
TURMIT_OPSYM(swp),\
TURMIT_OPSYM(jmp),\
TURMIT_OPSYM(jz),\
TURMIT_OPSYM(jcmp),\
NULL,\
}
struct turmit_sym_s
{
char *str;
char *alias;
turmit_op_f op_fun;
};
union turmit_op_u
{
turmit_op_f op;
turmit_int val;
short var; /*!< interpreted % 5 */
};
struct turmit_op_s
{
union turmit_op_u op;
/** 0 for NULL, 1 if operation pointer, 2 if value, 3 if variable */
short value;
};
struct turmit_s
{
char *expr;
unsigned char flags;
ssize_t int_max;
turmit_op_t *op_expr;
ssize_t op_expr_sz;
ssize_t op_cur;
short op_end;
ssize_t stack_sz;
turmit_int *stack;
ssize_t stack_cur;
/**@brief 0 if no error
* @note only for compilation error for the moment
*/
char err;
char *err_str;
};
inline static turmit_int __SPOP(turmit_t *t) {
turmit_int r = t->stack[t->stack_cur];
SDEC(t);
return r;
}
#define TURMIT_OP(NAME) void turmit_op_##NAME (turmit_t *turmit)
/**@brief Allocate memory and initialise a turmit
* @param const char* The turmit expression
* @param unsigned char One of TURMIT_LAZY or TURMIT_AUTOCOMP.
* @return A pointer on the new turmit
*/
turmit_t *turmit_alloc(ssize_t stack_sz, ssize_t int_max, const char *expr,
unsigned char flags);
/**@brief Initialize a turmit
* @param turmit_t* The turmit to initialize
* @param const char* The turmit expression
* @param unsigned char One of TURMIT_LAZY or TURMIT_AUTOCOMP.
* @return The pointer on the turmit
*/
turmit_t *turmit_init(turmit_t *turmit, ssize_t stack_sz, ssize_t int_max,
const char *expr, unsigned char flags);
turmit_t *turmit_copy(turmit_t *turmit);
void turmit_clean(turmit_t *turmit);
/**@brief Free memory of a turmit
* @param turmit the turmit to free
*/
void turmit_free(turmit_t *turmit);
/**@brief Exec a turmit expr
* @param turmit_t* Concerned turmit
* @param turmit_int* Arguments ( see @ref TURMIT_VAL_L )
* @return Processed value
*/
turmit_int turmit_exec(turmit_t *turmit, const turmit_int args[5]);
/**@brief Populate turmit_t.op_expr and set op_expr_sz
* @return 0 if no errors
*/
int turmit_compile(turmit_t *turmit);
void _turmit_stack_dump(turmit_t *turmit);
TURMIT_OP(mem_sz);
TURMIT_OP(add);
TURMIT_OP(sub);
TURMIT_OP(bin_and);
TURMIT_OP(dup);
TURMIT_OP(lshift);
TURMIT_OP(mod);
TURMIT_OP(mul);
TURMIT_OP(div);
TURMIT_OP(bin_or);
TURMIT_OP(bin_xor);
TURMIT_OP(pop);
TURMIT_OP(swp);
TURMIT_OP(jmp);
TURMIT_OP(jz);
TURMIT_OP(jcmp);
#endif

View file

@ -1,3 +1,3 @@
#!/bin/sh
python3 -m unittest $@
PYTHONPATH=":`pwd`/libs" python3 -m unittest $@

319
tests/test_cturmit.py Normal file
View file

@ -0,0 +1,319 @@
import unittest
import inspect
from cturmit import CTurmit as Turmit
from gte.rpnlib import _op_list
class TurmitTestCase(unittest.TestCase):
def test_init(self):
''' Test Turmit class __init__ '''
t = Turmit(42)
self.assertEqual(len(t._stack), 42)
self.assertEqual(t.shead, 0)
self.assertEqual(len(t._stack) - 1 , t._cur)
def test_init_args(self):
''' Test Turmit __init__ arguments '''
t = Turmit()
t = Turmit(prog = 'G R B 44 MOD ADD 43 MOD ADD 42 MOD')
t = Turmit(prog = 'G R B ADD ADD 42 MOD', max_int = 0xFFFF,
stack_size=42)
def test_call(self):
''' Test Turmit.__call__ '''
t = Turmit(prog = 'G R B ADD ADD 42 MOD', max_int = 0xFFFF,
stack_size=42)
r = t(x=1, y=2, r=255, g=255, b=255)
self.assertEqual(r, 9)
r = t(x=2, y=2, r=255, g=0, b=0)
self.assertEqual(r, 3)
def test_copy(self):
t = Turmit(prog = 'G R B ADD ADD 42 MOD', max_int = 0xFFFF,
stack_size=42)
t2 = Turmit(turmit=t)
r = t2(x=1, y=2, r=255, g=255, b=255)
self.assertEqual(r, 9)
r = t2(x=2, y=2, r=255, g=0, b=0)
self.assertEqual(r, 3)
def test_init_badargs(self):
''' Test Turmit __init__ bad arguments '''
with self.assertRaises(RuntimeError):
t = Turmit(foobar=42)
with self.assertRaises(ValueError):
t = Turmit(prog='foobar')
class TurmitExprCompileTestCase(unittest.TestCase):
''' Tests compilatin capabilities of cturmit '''
def test_values(self):
progs = ('1', '0x1', '9', '0x9', '0xf', '0xF', '0x1FFF', '0xFFF1',
'12345');
for prog in progs:
t = Turmit(prog=prog)
def test_var(self):
progs = ('x', 'y', 'r', 'g', 'b')
for prog in progs:
t = Turmit(prog=prog)
class TurmitOperationTestCase(unittest.TestCase):
def test_push(self):
''' Test Turmit _push() method '''
t = Turmit()
t._push(1)
self.assertEqual(t.shead, 1)
t._push(2)
self.assertEqual(t.shead, 2)
def _rpn(self, rpn, narg = 2):
if rpn not in _op_list:
raise unittest.SkipTest('"%s" not implemented' % rpn)
method, wrapped = _op_list[rpn]
if narg != len(inspect.signature(method).parameters) - 1:
self.fail('Expected %s to take %d arguments, but Turmit.%s() takes \
%d arguments' % (rpn, narg, rpn, len(inspect.signature(method).parameters) - 1))
def test_add(self):
''' Test turmit add method '''
self._rpn('add')
t = Turmit()
t._push(42)
t._push(8)
t.add()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 50)
t._push(42)
t._push(8)
t.add()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 50)
t.add()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 100)
def test_mem_sz(self):
''' Test turmit mem_sz() operation '''
self._rpn('mem_sz', 1)
t = Turmit(8)
self.assertEqual(len(t._stack), 8)
t._push(42)
t.mem_sz()
self.assertEqual(len(t._stack), 42)
self.assertEqual(t._cur, 7)
t._push(42)
t._push(8)
t.mem_sz()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 42)
def test_sub(self):
''' Test turmit sub() method '''
self._rpn('sub')
t = Turmit(max_int=0xFFFF)
t._push(50)
t._push(8)
t.sub()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 42)
t._push(50)
t._push(8)
t.sub()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 42)
t.sub()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 0)
t._push(8)
t._push(50)
t.sub()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 0xFFFF + (8 - 50))
def test_mul(self):
''' Test turmit mul() method '''
self._rpn('mul')
t = Turmit()
t._push(7)
t._push(6)
t.mul()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 42)
t._push(7)
t._push(6)
t.mul()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 42)
t.mul()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 42 *42)
def test_div(self):
''' Test turmit division capabilities '''
self._rpn('div')
t = Turmit()
t._push(43)
t._push(7)
t.div()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 6)
def test_mod(self):
''' Test turmit mod() method '''
self._rpn('mod')
t = Turmit()
t._push(42)
t._push(4)
t.mod()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 2)
def test_pow(self):
''' Test turmit pow() method '''
self._rpn('pow')
t = Turmit()
t._push(2)
t._push(4)
t.pow()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 16)
def test_sqrt(self):
''' Test turmit sqrt() method '''
self._rpn('sqrt', 1)
t = Turmit()
t._push(42)
t.sqrt()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 6)
def test_and(self):
''' Test turmit binary and() method '''
self._rpn('bin_and')
t = Turmit()
t._push(10)
t._push(42)
t.bin_and()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 10)
def test_or(self):
''' Test turmit binary or() method '''
self._rpn('bin_or')
t = Turmit()
t._push(42)
t._push(7)
t.bin_or()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 47)
def test_xor(self):
''' Test turmit binary xor() method '''
self._rpn('bin_xor')
t = Turmit()
t._push(42)
t._push(11)
t.bin_xor()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 33)
def test_rshift(self):
''' Test turmit rshift method '''
self._rpn('rshift')
t = Turmit()
t._push(42)
t._push(2)
t.rshift()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 10)
def test_lshift(self):
''' Test turmit lshift method '''
self._rpn('lshift')
t = Turmit()
t._push(10)
t._push(2)
t.lshift()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 40)
def test_dup(self):
''' Test turmit dup() method '''
self._rpn('dup', 1)
t = Turmit()
t._push(42)
t.dup()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 42)
def test_pop(self):
''' Test turmit pop() method '''
self._rpn('pop', 1)
t = Turmit()
t._push(10)
t._push(2)
t.pop()
self.assertEqual(t._cur, 0)
self.assertEqual(t.shead, 10)
t.pop()
self.assertEqual(t._cur, len(t._stack) - 1)
def test_swp(self):
''' Test turmit swp() method '''
self._rpn('swp', 2)
t = Turmit()
t._push(42)
t._push(1337)
t.swp()
self.assertEqual(t._cur, 1)
self.assertEqual(t.shead, 42)
t._pop()
self.assertEqual(t.shead, 1337)