Browse Source

Continue implementation of RPNExprIter & sequences/mapping methods

Yann Weber 1 year ago
parent
commit
8a3bf95172
17 changed files with 943 additions and 73 deletions
  1. 2
    0
      python_const.c
  2. 456
    49
      python_if.c
  3. 20
    0
      python_if.h
  4. 75
    0
      python_rpnexpr.c
  5. 1
    2
      python_rpnexpr.h
  6. 56
    0
      python_rpntoken.c
  7. 1
    0
      python_rpntoken.h
  8. 6
    5
      rpn_if.c
  9. 1
    0
      rpn_if.h
  10. 20
    4
      rpn_jit.c
  11. 7
    0
      rpn_jit.h
  12. 3
    2
      tests/tests_pyrpn.py
  13. 66
    11
      tests/tests_rpn_sequence.py
  14. 0
    0
      tests/tests_rpn_tokens.py
  15. 37
    0
      tests/tests_rpniter.py
  16. 100
    0
      tests/tests_rpniter_seq.py
  17. 92
    0
      tests/tests_tokens.py

+ 2
- 0
python_const.c View File

@@ -1,5 +1,6 @@
1 1
 #include "python_const.h"
2 2
 
3
+/** @todo implement GC with m_clear */
3 4
 PyModuleDef rpnconstmodule = {
4 5
 	PyModuleDef_HEAD_INIT,
5 6
 	"pyrpn.const",
@@ -114,6 +115,7 @@ int Py_rpnconst_add(PyObject* mod, const char* name, int value)
114 115
 	return 0;
115 116
 }
116 117
 
118
+/** @todo rename this function ! (bad prefix) */
117 119
 PyObject *Py_rpnconst_init(void)
118 120
 {
119 121
 	PyObject *mod;

+ 456
- 49
python_if.c View File

@@ -3,6 +3,14 @@
3 3
 PyMethodDef RPNIterExpr_methods[] = {
4 4
 	{"get_params", (PyCFunction)rpnif_get_params, METH_NOARGS,
5 5
 		"Get a named tuple with parameters"},
6
+	{"keys", (PyCFunction)rpnif_keys, METH_NOARGS,
7
+		"Get the list of keys identifing the expressions"},
8
+	{"values", (PyCFunction)rpnif_values, METH_NOARGS,
9
+		"Get the list of expressions"},
10
+	{"items", (PyCFunction)rpnif_items, METH_NOARGS,
11
+		"Iterate on couple of (key, expr)"},
12
+	{"step", (PyCFunction)rpnif_step, METH_O,
13
+		"Run an IF given a position and return the new position"},
6 14
 	{"__getstate__", (PyCFunction)rpnif_getstate, METH_NOARGS,
7 15
 		"Pickling method. Return a bytes repr of tokenized expression \
8 16
 and the stack state."},
@@ -17,6 +25,18 @@ PyMemberDef RPNIterExpr_members[] = {
17 25
 	{NULL}
18 26
 };
19 27
 
28
+PySequenceMethods RPNIterExpr_seq_methods = {
29
+	.sq_length = rpnif_len,
30
+	.sq_item = rpnif_expr_item,
31
+	.sq_ass_item = rpnif_expr_ass_item,
32
+};
33
+
34
+PyMappingMethods RPNIterExpr_mapping_methods = {
35
+	.mp_length = rpnif_len,
36
+	.mp_subscript = rpnif_subscript,
37
+	.mp_ass_subscript = rpnif_ass_subscript,
38
+};
39
+
20 40
 PyGetSetDef RPNIterExpr_getset[] = {
21 41
 	{NULL}
22 42
 };
@@ -29,44 +49,22 @@ static PyBufferProcs RPNIterExpr_as_buffer = {
29 49
 
30 50
 PyTypeObject RPNIterExprType = {
31 51
 	PyVarObject_HEAD_INIT(NULL, 0)
32
-	"pyrpn.RPNIterExpr",                     /* tp_name */
33
-	sizeof(PyRPNIterExpr_t),                        /* tp_basicsize */
34
-	0,                                               /* tp_itemsize */
35
-	(destructor)rpnif_del, /* tp_dealloc */
36
-	0,                                               /* tp_print */
37
-	0,                                               /* tp_getattr */
38
-	0,                                               /* tp_setattr */
39
-	0,                                               /* tp_reserved */
40
-	rpnif_repr,                                    /* tp_repr */
41
-	0,                                               /* tp_as_number */
42
-	0,                                               /* tp_as_sequence */
43
-	0,                              /* tp_as_mapping */
44
-	0,                                               /* tp_hash  */
45
-	0,                                               /* tp_call */
46
-	rpnif_str,                                               /* tp_str */
47
-	0,                                               /* tp_getattro */
48
-	0,                                               /* tp_setattro */
49
-	&RPNIterExpr_as_buffer,                           /* tp_as_buffer */
50
-	Py_TPFLAGS_DEFAULT |
51
-	Py_TPFLAGS_BASETYPE,   /* tp_flags */
52
-	"RPN expression evaluator",                /* tp_doc */
53
-	0,                                               /* tp_traverse */
54
-	0,                                               /* tp_clear */
55
-	0,                                               /* tp_richcompare */
56
-	0,                                               /* tp_weaklistoffset */
57
-	0,                                               /* tp_iter */
58
-	0,                                               /* tp_iternext */
59
-	RPNIterExpr_methods,                        /* tp_methods */
60
-	RPNIterExpr_members,                        /* tp_members */
61
-	RPNIterExpr_getset,                              /* tp_getset */
62
-	0,                                               /* tp_base */
63
-	0,                                               /* tp_dict */
64
-	0,                                               /* tp_descr_get */
65
-	0,                                               /* tp_descr_set */
66
-	0,                                               /* tp_dictoffset */
67
-	rpnif_init,          /* tp_init */
68
-	0,                                               /* tp_alloc */
69
-	rpnif_new,                            /* tp_new */
52
+	.tp_name = "pyrpn.RPNIterExpr",
53
+	.tp_basicsize = sizeof(PyRPNIterExpr_t),
54
+	.tp_itemsize = 0,
55
+	.tp_del = rpnif_del,
56
+	.tp_repr = rpnif_repr,
57
+	.tp_as_sequence = &RPNIterExpr_seq_methods,
58
+	.tp_as_mapping = &RPNIterExpr_mapping_methods,
59
+	.tp_str = rpnif_str,
60
+	.tp_as_buffer = &RPNIterExpr_as_buffer,
61
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
62
+	.tp_doc = "RPN expression evaluator",
63
+	.tp_methods = RPNIterExpr_methods,
64
+	.tp_members = RPNIterExpr_members,
65
+	.tp_getset = RPNIterExpr_getset,
66
+	.tp_init = rpnif_init,
67
+	.tp_new = rpnif_new,
70 68
 };
71 69
 
72 70
 PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
@@ -337,11 +335,157 @@ PyObject *rpnif_get_params(PyObject *self)
337 335
 	return res;
338 336
 }
339 337
 
340
-void rpnif_del(PyObject *self)
338
+
339
+PyObject *rpnif_step(PyObject *self, PyObject* opos)
341 340
 {
342
-	PyRPNIterExpr_t *expr_self;
341
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
342
+	if(!PyLong_Check(opos))
343
+	{
344
+		PyErr_SetString(PyExc_TypeError, "Expected position to be an int");
345
+		return NULL;
346
+	}
347
+	size_t pos = PyLong_AsSize_t(opos);
348
+	if(PyErr_Occurred())
349
+	{
350
+		return NULL;
351
+	}
343 352
 
344
-	expr_self = (PyRPNIterExpr_t*)self;
353
+	pos = rpn_if_step(expr_self->rif, pos);
354
+
355
+	return PyLong_FromSize_t(pos);
356
+}
357
+
358
+
359
+PyObject *rpnif_keys(PyObject *self)
360
+{
361
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
362
+	rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
363
+
364
+	Py_ssize_t ret_idx = 0;
365
+	char xdim_key[64];
366
+
367
+	PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
368
+	if(PyErr_Occurred())
369
+	{
370
+		return NULL;
371
+	}
372
+
373
+#define _ret_append(key) PyTuple_SET_ITEM(ret, ret_idx++, \
374
+		PyUnicode_FromString(key))
375
+
376
+	switch(rif_data->pos_flag)
377
+	{
378
+		case RPN_IF_POSITION_XY:
379
+			_ret_append("X");
380
+			_ret_append("Y");
381
+			break;
382
+		case RPN_IF_POSITION_LINEAR:
383
+			_ret_append("X");
384
+			break;
385
+		case RPN_IF_POSITION_XDIM:
386
+			for(size_t i=0; i<rif_data->size_lim[0];i++)
387
+			{
388
+				snprintf(xdim_key, 64, "P%ld", i);
389
+				_ret_append(xdim_key);
390
+			}
391
+			break;
392
+		default:
393
+			PyErr_SetString(PyExc_RuntimeError,
394
+					"UNKOWN POS_FLAG3");
395
+			return NULL;
396
+	}
397
+	switch(rif_data->res_flag)
398
+	{
399
+		case RPN_IF_RES_BOOL:
400
+		case RPN_IF_RES_XFUN:
401
+			_ret_append("R");
402
+			break;
403
+		case RPN_IF_RES_RGB:
404
+			_ret_append("R");
405
+			_ret_append("G");
406
+			_ret_append("B");
407
+			break;
408
+		case RPN_IF_RES_RGBA:
409
+			_ret_append("R");
410
+			_ret_append("G");
411
+			_ret_append("B");
412
+			_ret_append("A");
413
+			break;
414
+		default:
415
+			break;
416
+	}
417
+
418
+	if(PyErr_Occurred())
419
+	{
420
+		return NULL;
421
+	}
422
+
423
+	return ret;
424
+
425
+#undef _ret_append
426
+}
427
+
428
+
429
+PyObject *rpnif_values(PyObject *self)
430
+{
431
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
432
+	Py_INCREF(expr_self->expr);
433
+	return expr_self->expr;
434
+}
435
+
436
+
437
+PyObject *rpnif_items(PyObject *self)
438
+{
439
+	size_t i;
440
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
441
+	PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
442
+	if(PyErr_Occurred())
443
+	{
444
+		return NULL;
445
+	}
446
+	PyObject *keys = rpnif_keys(self);
447
+	for(i=0; i<expr_self->rif->params->rpn_sz; i++)
448
+	{
449
+		PyObject *tmp = PyTuple_New(2);
450
+		if(PyErr_Occurred())
451
+		{
452
+			goto err_loop_newtuple;
453
+		}
454
+		PyObject *key = PyTuple_GET_ITEM(keys, i);
455
+		PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
456
+		Py_INCREF(key);
457
+		Py_INCREF(value);
458
+		PyTuple_SET_ITEM(tmp, 0, key);
459
+		PyTuple_SET_ITEM(tmp, 1, value);
460
+		PyTuple_SET_ITEM(ret, i, tmp);
461
+		if(PyErr_Occurred())
462
+		{
463
+			goto err_loop_setitem;
464
+		}
465
+
466
+				 
467
+	}
468
+	
469
+	return ret;
470
+
471
+	/** @todo cleanup seems wrong... */
472
+	for(i=i; i>=0; i--)
473
+	{
474
+err_loop_setitem:
475
+		PyObject *key = PyTuple_GET_ITEM(keys, i);
476
+		PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
477
+		Py_DECREF(key);
478
+		Py_DECREF(value);
479
+err_loop_newtuple:
480
+	}
481
+	Py_DECREF(ret);
482
+	return NULL;
483
+}
484
+
485
+
486
+void rpnif_del(PyObject *self)
487
+{
488
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
345 489
 	if(expr_self->rif)
346 490
 	{
347 491
 		rpn_if_free(expr_self->rif);
@@ -349,6 +493,201 @@ void rpnif_del(PyObject *self)
349 493
 	}
350 494
 }
351 495
 
496
+
497
+Py_ssize_t rpnif_len(PyObject *self)
498
+{
499
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
500
+	return expr_self->rif->params->rpn_sz;
501
+}
502
+
503
+PyObject* rpnif_expr_item(PyObject *self, Py_ssize_t idx)
504
+{
505
+	Py_ssize_t _idx = idx;
506
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
507
+
508
+	if(idx < 0)
509
+	{
510
+		idx = expr_self->rif->params->rpn_sz - 1 + idx;
511
+	}
512
+	if(idx < 0 || idx >= expr_self->rif->params->rpn_sz)
513
+	{
514
+		PyErr_Format(PyExc_IndexError,
515
+				"No expression %ld with given options",
516
+				_idx);
517
+		return NULL;
518
+	}
519
+	PyObject *ret = PyTuple_GET_ITEM(expr_self->expr, idx);
520
+	Py_INCREF(ret);
521
+	return ret;
522
+}
523
+
524
+
525
+int rpnif_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
526
+{
527
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
528
+	
529
+	if(!PyUnicode_Check(elt))
530
+	{
531
+		PyErr_SetString(PyExc_TypeError, "RPNExpr expected");
532
+		return -1;
533
+	}
534
+
535
+	PyObject *bytes_str = PyUnicode_AsASCIIString(elt);
536
+	if(PyErr_Occurred())
537
+	{
538
+		return -1;
539
+	}
540
+	const char *code = PyBytes_AS_STRING(bytes_str);
541
+
542
+	rpn_expr_t *expr = &(expr_self->rif->rpn[idx]);
543
+
544
+	if(rpn_expr_recompile(expr, code) < 0)
545
+	{
546
+		PyErr_Format(PyExc_ValueError,
547
+				"Error during expression '%s' compilation : %s",
548
+				code, expr->err_reason);
549
+		return -1;
550
+	}
551
+
552
+	return 0;
553
+}
554
+
555
+static Py_ssize_t _rpnif_subscript_idx(PyObject *self, PyObject *_key)
556
+{
557
+	if(!PyUnicode_Check(_key))
558
+	{
559
+		PyErr_SetString(PyExc_TypeError, "Key should be a str");
560
+		return -1;
561
+	}
562
+	PyObject *bytes_str = PyUnicode_AsASCIIString(_key);
563
+	if(PyErr_Occurred())
564
+	{
565
+		return -1;
566
+	}
567
+	const char *key = PyBytes_AS_STRING(bytes_str);
568
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
569
+	rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
570
+
571
+	Py_ssize_t idx = -1;
572
+	Py_ssize_t res_idx = -1;
573
+
574
+	switch(rif_data->pos_flag)
575
+	{
576
+		case RPN_IF_POSITION_XY:
577
+			res_idx = 2;
578
+			if(key[1] != '\0') { break; }
579
+			switch(key[0])
580
+			{
581
+				case 'X':
582
+					idx=0;
583
+					break;
584
+				case 'Y':
585
+					idx=1;
586
+					break;
587
+			}
588
+			break;
589
+		case RPN_IF_POSITION_LINEAR:
590
+			res_idx = 1;
591
+			if(!strcmp("X", key))
592
+			{
593
+				idx = 0;
594
+			}
595
+			break;
596
+		case RPN_IF_POSITION_XDIM:
597
+			size_t ndim = rif_data->size_lim[0];
598
+			res_idx = ndim;
599
+			char possible_key[64];
600
+			for(size_t i=0; i<ndim; i++)
601
+			{
602
+				snprintf(possible_key, 64, "P%ld", i);
603
+				if(!strcmp(possible_key, key))
604
+				{
605
+					idx = i;
606
+					break;
607
+				}
608
+			}
609
+			break;
610
+		default:
611
+			PyErr_SetString(PyExc_RuntimeError,
612
+					"UNKOWN POS_FLAG");
613
+			return -1;
614
+	}
615
+	if(idx < 0)
616
+	{
617
+		// not found yet, looking for result key
618
+		switch(rif_data->res_flag)
619
+		{
620
+			case RPN_IF_RES_BOOL:
621
+			case RPN_IF_RES_XFUN:
622
+				if(!strcmp("R", key))
623
+				{
624
+					idx = res_idx;
625
+				}
626
+				break;
627
+			case RPN_IF_RES_RGBA:
628
+				if(!strcmp("A", key))
629
+				{
630
+					idx = res_idx + 3;
631
+				}
632
+			case RPN_IF_RES_RGB:
633
+				if(key[1] != '\0')
634
+				{
635
+					break;
636
+				}
637
+				switch(key[0])
638
+				{
639
+					case 'R':
640
+						idx=res_idx;
641
+						break;
642
+					case 'G':
643
+						idx=res_idx+1;
644
+						break;
645
+					case 'B':
646
+						idx=res_idx+2;
647
+						break;
648
+				}
649
+				break;
650
+			default:
651
+				// not implemented, not unknown....
652
+				PyErr_SetString(PyExc_RuntimeError,
653
+						"UNKOWN RES_FLAG");
654
+				return -1;
655
+		}
656
+	}
657
+	return idx;
658
+}
659
+
660
+PyObject* rpnif_subscript(PyObject *self, PyObject *key)
661
+{
662
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
663
+	
664
+	Py_ssize_t idx = _rpnif_subscript_idx(self, key);
665
+	if(idx < 0)
666
+	{
667
+		PyErr_Format(PyExc_IndexError,
668
+				"No expression '%s' with given parameters",
669
+				key);
670
+		return NULL;
671
+	}
672
+	PyObject *expr = PyTuple_GET_ITEM(expr_self->expr, idx);
673
+	Py_INCREF(expr);
674
+	return expr;
675
+}
676
+
677
+int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt)
678
+{
679
+	Py_ssize_t idx = _rpnif_subscript_idx(self, key);
680
+	if(idx < 0)
681
+	{
682
+		PyErr_Format(PyExc_IndexError,
683
+				"Cannot set expression '%s' that do not exists with this parameters",
684
+				key);
685
+		return -1;
686
+	}
687
+
688
+	return rpnif_expr_ass_item(self, idx, elt);
689
+}
690
+
352 691
 int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
353 692
 {
354 693
 	PyRPNIterExpr_t *expr_self;
@@ -412,7 +751,7 @@ void rpnif_releasebuffer(PyObject *self, Py_buffer *view)
412 751
 PyObject* rpnif_str(PyObject *self)
413 752
 {
414 753
 	PyErr_SetString(PyExc_NotImplementedError,
415
-		"Not implemented");
754
+		"str Not implemented");
416 755
 	return NULL;
417 756
 	/**@todo TODO write the function */
418 757
 	Py_RETURN_NONE;
@@ -420,17 +759,85 @@ PyObject* rpnif_str(PyObject *self)
420 759
 
421 760
 PyObject* rpnif_repr(PyObject *self)
422 761
 {
423
-	PyErr_SetString(PyExc_NotImplementedError,
424
-		"Not implemented");
425
-	return NULL;
426
-	/**@todo TODO write the function */
427
-	Py_RETURN_NONE;
762
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
763
+	char *buff;
764
+	size_t sz;
765
+	rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
766
+
767
+	char *str_pos, *str_res;
768
+	char tmp[64];
769
+
770
+	switch(rif_data->pos_flag)
771
+	{
772
+		case RPN_IF_POSITION_XY:
773
+			str_pos = "XY";
774
+			break;
775
+		case RPN_IF_POSITION_LINEAR:
776
+			str_pos = "LINEAR";
777
+			break;
778
+		case RPN_IF_POSITION_XDIM:
779
+			snprintf(tmp, 64, "XDIM[%ld]", rif_data->size_lim[0]);
780
+			str_pos = tmp;
781
+			break;
782
+		default:
783
+			PyErr_SetString(PyExc_RuntimeError,
784
+					"UNKOWN POS_FLAG2");
785
+			return NULL;
786
+	}
787
+
788
+	switch(rif_data->res_flag)
789
+	{
790
+		case RPN_IF_RES_BOOL:
791
+			str_res = "BOOL";
792
+			break;
793
+		case RPN_IF_RES_CONST:
794
+			str_res = "CONST";
795
+			break;
796
+		case RPN_IF_RES_CONST_RGBA:
797
+			str_res = "CONST_RGBA";
798
+			break;
799
+		case RPN_IF_RES_COUNT:
800
+			str_res = "COUNT";
801
+			break;
802
+		case RPN_IF_RES_XFUN:
803
+			str_res = "XFUN";
804
+			break;
805
+		case RPN_IF_RES_RGB:
806
+			str_res = "RGB";
807
+			break;
808
+		case RPN_IF_RES_RGBA:
809
+			str_res = "RGBA";
810
+			break;
811
+		default:
812
+			PyErr_SetString(PyExc_RuntimeError,
813
+					"UNKOWN RES_FLAG2");
814
+			return NULL;
815
+	}
816
+
817
+	sz = snprintf(NULL, 0,
818
+			"<RPNIterExpr pos_flag:%s res_flag:%s expr_sz:%ld>",
819
+			str_pos, str_res, expr_self->rif->params->rpn_sz);
820
+	
821
+	buff = malloc(sizeof(char) * (sz + 1));
822
+	if(!buff)
823
+	{
824
+		PyErr_Format(PyExc_RuntimeError, "Error allocating RPNIterExpr repr : ",
825
+				strerror(errno));
826
+		return NULL;
827
+	}
828
+
829
+	sz = snprintf(buff, sz+1,
830
+			"<RPNIterExpr pos_flag:%s res_flag:%s expr_sz:%ld>",
831
+			str_pos, str_res, expr_self->rif->params->rpn_sz);
832
+	PyObject *res = Py_BuildValue("s", buff);
833
+	free(buff);
834
+	return res;
428 835
 }
429 836
 
430 837
 PyObject* rpnif_getstate(PyObject *self, PyObject *noargs)
431 838
 {
432 839
 	PyErr_SetString(PyExc_NotImplementedError,
433
-		"Not implemented");
840
+		"getstate Not implemented");
434 841
 	return NULL;
435 842
 	/**@todo TODO write the function */
436 843
 	Py_RETURN_NONE;
@@ -439,7 +846,7 @@ PyObject* rpnif_getstate(PyObject *self, PyObject *noargs)
439 846
 PyObject* rpnif_setstate(PyObject *self, PyObject *state_bytes)
440 847
 {
441 848
 	PyErr_SetString(PyExc_NotImplementedError,
442
-		"Not implemented");
849
+		"setstate Not implemented");
443 850
 	return NULL;
444 851
 	/**@todo TODO write the function */
445 852
 	Py_RETURN_NONE;

+ 20
- 0
python_if.h View File

@@ -108,6 +108,9 @@ void rpnif_releasebuffer(PyObject *self, Py_buffer *view);
108 108
 /**@brief Return a named tuple of custom rif data */
109 109
 PyObject *rpnif_get_params(PyObject *self);
110 110
 
111
+/**@brief Runs an if on given */
112
+PyObject *rpnif_step(PyObject *self, PyObject* pos);
113
+
111 114
 /**@brief Return the list of expressions */
112 115
 PyObject *rpnif_get_expr(PyObject *self);
113 116
 
@@ -140,5 +143,22 @@ PyObject* rpnif_repr(PyObject *self);
140 143
  */
141 144
 PyObject* rpnif_str(PyObject *self);
142 145
 
146
+/**@brief RPNExpr.__len__() method
147
+ * @return A integer with the number of tokens in expression
148
+ */
149
+Py_ssize_t rpnif_len(PyObject *self);
150
+
151
+PyObject* rpnif_expr_item(PyObject *self, Py_ssize_t);
152
+int rpnif_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt);
153
+
154
+
155
+PyObject* rpnif_subscript(PyObject *self, PyObject *key);
156
+int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt);
157
+
158
+PyObject *rpnif_keys(PyObject *self);
159
+PyObject *rpnif_values(PyObject *self);
160
+PyObject *rpnif_items(PyObject *self);
161
+
162
+
143 163
 #endif
144 164
 

+ 75
- 0
python_rpnexpr.c View File

@@ -46,9 +46,11 @@ PyMemberDef RPNExpr_members[] = {
46 46
 	{NULL}
47 47
 };
48 48
 
49
+/**@todo Continue sequence implementation with contains, concat, repeat etc. */
49 50
 PySequenceMethods RPNExpr_seq_methods = {
50 51
 	.sq_length = rpnexpr_len,
51 52
 	.sq_item = rpnexpr_token_item,
53
+	.sq_ass_item = rpnexpr_token_ass_item,
52 54
 };
53 55
 
54 56
 PyTypeObject RPNExprType = {
@@ -536,6 +538,79 @@ PyObject* rpnexpr_token_item(PyObject *self, Py_ssize_t idx)
536 538
 }
537 539
 
538 540
 
541
+int rpnexpr_token_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
542
+{
543
+	PyRPNExpr_t *expr_self = (PyRPNExpr_t*)self;
544
+	Py_ssize_t _idx = idx;
545
+	if(idx < 0)
546
+	{
547
+		idx = expr_self->rpn->toks.tokens_sz - 1 + idx;
548
+	}
549
+	if(idx < 0 || idx > expr_self->rpn->toks.tokens_sz)
550
+	{
551
+		PyErr_Format(PyExc_IndexError,
552
+			"Cannot set token %ld in expression of size %ld",
553
+			_idx, expr_self->rpn->toks.tokens_sz);
554
+		return -1;
555
+	}
556
+
557
+	if(!PyObject_IsInstance(elt, (PyObject*)&RPNTokenType))
558
+	{
559
+		PyErr_Format(PyExc_TypeError,
560
+				"Given element in not RPNToken subtype");
561
+		return -1;
562
+	}
563
+
564
+	short new_elt = 0;
565
+	if(idx == expr_self->rpn->toks.tokens_sz)
566
+	{
567
+		new_elt = 1;
568
+		expr_self->rpn->toks.tokens_sz++;
569
+		size_t new_sz = expr_self->rpn->toks.tokens_sz*sizeof(rpn_token_t);
570
+		rpn_token_t *tmp = realloc(expr_self->rpn->toks.tokens, new_sz);
571
+		if(!tmp)
572
+		{
573
+			PyErr_Format(PyExc_MemoryError,
574
+					"Error reallocation tokenized expression : %s",
575
+					strerror(errno));
576
+			return -1;
577
+		}
578
+		expr_self->rpn->toks.tokens = tmp;
579
+	}
580
+
581
+	rpn_token_t original = expr_self->rpn->toks.tokens[idx];
582
+
583
+	RPNToken_t *token = (RPNToken_t*)elt;
584
+	expr_self->rpn->toks.tokens[idx] = token->value;
585
+	if(rpn_expr_tokens_updated(expr_self->rpn) < 0)
586
+	{
587
+		PyErr_Format(PyExc_ValueError,
588
+				"Unable to update expression : %s",
589
+				strerror(errno));
590
+		goto rollback;
591
+	}
592
+	return 0;
593
+
594
+rollback:
595
+	if(new_elt)
596
+	{
597
+		expr_self->rpn->toks.tokens_sz--;
598
+	}
599
+	else
600
+	{
601
+		expr_self->rpn->toks.tokens[idx] = original;
602
+		if(rpn_expr_tokens_updated(expr_self->rpn) < 0)
603
+		{
604
+			PyErr_Format(PyExc_RuntimeError,
605
+					"Unable to rollback expression : %s",
606
+					strerror(errno));
607
+			goto rollback;
608
+		}
609
+	}
610
+	return -1;
611
+}
612
+
613
+
539 614
 PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
540 615
 {
541 616
 	PyRPNExpr_t *expr_self;

+ 1
- 2
python_rpnexpr.h View File

@@ -43,8 +43,6 @@
43 43
  *
44 44
  * This file is the header of the RPNExpr Python class
45 45
  *
46
- * @todo implements tp_as_sequence in order to give access to tokens from
47
- * expr. To do this we have to implement a python module representing tokens.
48 46
  */
49 47
 
50 48
 /**@brief RPNExpr Python class methods list
@@ -154,6 +152,7 @@ PyObject* rpnexpr_copy(PyObject *cls, PyObject *noargs);
154 152
 Py_ssize_t rpnexpr_len(PyObject *self);
155 153
 
156 154
 PyObject* rpnexpr_token_item(PyObject *self, Py_ssize_t);
155
+int rpnexpr_token_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt);
157 156
 
158 157
 /**@brief Eval an RPN expression given arguments and return the
159 158
  * value

+ 56
- 0
python_rpntoken.c View File

@@ -13,6 +13,7 @@ PyTypeObject RPNTokenType = {
13 13
 	.tp_basicsize = sizeof(RPNToken_t),
14 14
 	.tp_itemsize = 0,
15 15
 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
16
+	.tp_richcompare = rpntoken_richcompare,
16 17
 	.tp_init = rpntoken_init,
17 18
 	.tp_new = PyType_GenericNew,
18 19
 	.tp_str = rpntoken_str,
@@ -210,6 +211,61 @@ int rpntoken_init(PyObject *_self, PyObject *args, PyObject *kwds)
210 211
 	return -1;
211 212
 }
212 213
 
214
+PyObject* rpntoken_richcompare(PyObject *_self, PyObject *_other, int op)
215
+{
216
+	RPNToken_t *self, *other;
217
+	self = (RPNToken_t*)_self;
218
+	other = (RPNToken_t*)_other;
219
+
220
+	int cmp = self->value.type - other->value.type;
221
+	if(cmp == 0)
222
+	{
223
+		switch(self->value.type)
224
+		{
225
+			case RPN_op:
226
+				cmp = self->value.op_n - other->value.op_n;
227
+				break;
228
+			case RPN_arg:
229
+				cmp = self->value.arg_n - other->value.arg_n;
230
+				break;
231
+			case RPN_val:
232
+				cmp = self->value.value - other->value.value;
233
+				break;
234
+			default:
235
+				PyErr_Format(PyExc_RuntimeError,
236
+						"Unknown token type %d",
237
+						self->value.type);
238
+				return NULL;
239
+		}
240
+	}
241
+
242
+	switch(op)
243
+	{
244
+		case Py_LT:
245
+			if(cmp < 0) { Py_RETURN_TRUE; }
246
+			Py_RETURN_FALSE;
247
+		case Py_LE:
248
+			if(cmp <= 0) { Py_RETURN_TRUE; }
249
+			Py_RETURN_FALSE;
250
+		case Py_EQ:
251
+			if(cmp == 0) { Py_RETURN_TRUE; }
252
+			Py_RETURN_FALSE;
253
+		case Py_NE:
254
+			if(cmp != 0) { Py_RETURN_TRUE; }
255
+			Py_RETURN_FALSE;
256
+		case Py_GT:
257
+			if(cmp > 0) { Py_RETURN_TRUE; }
258
+			Py_RETURN_FALSE;
259
+		case Py_GE:
260
+			if(cmp >= 0) { Py_RETURN_TRUE; }
261
+			Py_RETURN_FALSE;
262
+		default:
263
+			PyErr_Format(PyExc_NotImplementedError,
264
+					"Unknown comparison %d",
265
+					self->value.type);
266
+			return NULL;
267
+	}
268
+}
213 269
 
214 270
 PyObject* rpntoken_repr(PyObject *_self)
215 271
 {

+ 1
- 0
python_rpntoken.h View File

@@ -66,6 +66,7 @@ PyObject* rpntoken_from_str(PyObject *_self, PyObject *arg);
66 66
 PyObject* rpntoken_from_token(const rpn_token_t *token);
67 67
 
68 68
 int rpntoken_init(PyObject *_self, PyObject *args, PyObject *kwds);
69
+PyObject* rpntoken_richcompare(PyObject *_self, PyObject *other, int op);
69 70
 PyObject* rpntoken_str(PyObject *_self);
70 71
 PyObject* rpntoken_repr(PyObject *_self);
71 72
 

+ 6
- 5
rpn_if.c View File

@@ -95,6 +95,7 @@ rpn_if_t* rpn_if_new(const rpn_if_param_t *params, rpn_value_t *memmap)
95 95
 			#endif
96 96
 			goto rpn_init_error;
97 97
 		}
98
+		rpn_expr_compile(&(res->rpn[i]), "");
98 99
 	}
99 100
 
100 101
 	return res;
@@ -113,7 +114,7 @@ rpn_if_t* rpn_if_new(const rpn_if_param_t *params, rpn_value_t *memmap)
113 114
 		err = errno;
114 115
 		if(res->self_mem)
115 116
 		{
116
-			munmap(res->mem, params->mem_sz);
117
+			munmap(res->mem, params->mem_sz * params->value_sz);
117 118
 		}
118 119
 	mmap_err:
119 120
 		err = errno;
@@ -135,19 +136,19 @@ void rpn_if_free(rpn_if_t* rif)
135 136
 	free(rif->rpn_res);
136 137
 	if(rif->self_mem)
137 138
 	{
138
-		munmap(rif->mem, rif->params->mem_sz);
139
+		munmap(rif->mem, rif->params->mem_sz * rif->params->value_sz);
139 140
 	}
140 141
 	free(rif);
141 142
 }
142 143
 
143 144
 size_t rpn_if_step(rpn_if_t *rif, size_t pos)
144 145
 {
145
-	size_t i;
146 146
 	size_t newpos;
147 147
 	rif->params->getarg_f(rif, pos);
148
-	for(i=0; i<rif->params->rpn_sz; i++)
148
+	for(size_t i=0; i<rif->params->rpn_sz; i++)
149 149
 	{
150
-		rif->rpn_res[i] = rpn_expr_eval(&(rif->rpn[i]), rif->rpn_args);
150
+		rpn_value_t res = rpn_expr_eval(&(rif->rpn[i]), rif->rpn_args);
151
+		rif->rpn_res[i] = res;
151 152
 	}
152 153
 	rif->params->setres_f(rif, &newpos);
153 154
 	return newpos;

+ 1
- 0
rpn_if.h View File

@@ -126,6 +126,7 @@ size_t rpn_if_step(rpn_if_t *rif, size_t pos);
126 126
  */
127 127
 rpn_expr_t **rpn_if_rpn_get(rpn_if_t *rif);
128 128
 
129
+
129 130
 /**@brief New @ref rpn_if_s and partial initialisation
130 131
  * @param mem_sz memory size in bytes
131 132
  * @param rpn_argc number of arguments taken by @ref rpn_expr_s

+ 20
- 4
rpn_jit.c View File

@@ -87,6 +87,16 @@ int rpn_expr_reinit(rpn_expr_t* expr)
87 87
 	return 0;
88 88
 }
89 89
 
90
+
91
+int rpn_expr_recompile(rpn_expr_t *expr, const char *code)
92
+{
93
+	if(rpn_expr_reinit(expr) < 0)
94
+	{
95
+		return -1;
96
+	}
97
+	return rpn_expr_compile(expr, code);
98
+}
99
+
90 100
 int rpn_expr_tokens_updated(rpn_expr_t* expr)
91 101
 {
92 102
 	if(rpn_expr_reinit(expr) < 0)
@@ -103,6 +113,7 @@ int rpn_expr_tokens_updated(rpn_expr_t* expr)
103 113
 		free(expr->expr);
104 114
 	}
105 115
 	expr->expr = rpn_tokenized_expr(&expr->toks, 0);
116
+	expr->state = RPN_READY;
106 117
 	return 0;
107 118
 }
108 119
 
@@ -165,7 +176,7 @@ int rpn_expr_untokenize(rpn_expr_t *expr, rpn_tokenized_t *tokens, char long_op)
165 176
 		if(_rpn_expr_token_copy(expr, &(tokens->tokens[i])) < 0)
166 177
 		{
167 178
 			err = errno;
168
-			if(errno == EINVAL)
179
+			if(errno == EUCLEAN)
169 180
 			{
170 181
 				dprintf(2,
171 182
 "Fatal error, unknown token type : %d.\nMemory corruption ?\n",
@@ -311,7 +322,7 @@ int _rpn_expr_compile_expr(rpn_expr_t* expr)
311 322
 	{
312 323
 		if(_rpn_expr_token_copy(expr, token) < 0)
313 324
 		{
314
-			if(errno == EINVAL)
325
+			if(errno == EUCLEAN)
315 326
 			{
316 327
 				dprintf(2,
317 328
 "Fatal error, unknown token type : %d chr %ld.\nMemory corruption ?\n",
@@ -357,7 +368,7 @@ int _rpn_expr_compile_tokens(rpn_expr_t* expr)
357 368
 		token = &(expr->toks.tokens[i]);
358 369
 		if(_rpn_expr_token_copy(expr, token) < 0)
359 370
 		{
360
-			if(errno == EINVAL)
371
+			if(errno == EUCLEAN)
361 372
 			{
362 373
 				dprintf(2,
363 374
 "Fatal error, unknown token type : %d\nMemory corruption ?\n",
@@ -438,6 +449,11 @@ int _rpn_expr_token_copy(rpn_expr_t *expr, rpn_token_t *token)
438 449
 			value = NULL;
439 450
 			break;
440 451
 		case RPN_arg:
452
+			if(expr->args_count <= token->arg_n)
453
+			{
454
+				errno = EINVAL;
455
+				return -1;
456
+			}
441 457
 			local_op.fun = &rpn_arg;
442 458
 			local_op.fun_sz = &(CODE_SZ(rpn_arg));
443 459
 			value = &(token->arg_n);
@@ -448,7 +464,7 @@ int _rpn_expr_token_copy(rpn_expr_t *expr, rpn_token_t *token)
448 464
 			value = &(token->value);
449 465
 			break;
450 466
 		default:
451
-			errno = EINVAL;
467
+			errno = EUCLEAN;
452 468
 			return -1;
453 469
 	}
454 470
 	if(_rpn_code_part_cpy(expr, local_op.fun, *(local_op.fun_sz),

+ 7
- 0
rpn_jit.h View File

@@ -152,6 +152,13 @@ int rpn_expr_init(rpn_expr_t* expr, const unsigned char stack_sz,
152 152
  */
153 153
 int rpn_expr_reinit(rpn_expr_t* expr);
154 154
 
155
+/**@brief Recompile an existing, allready initialized, expression
156
+ * @param rpn_expr_t* The expression
157
+ * @param const char * The code to compile
158
+ * @return 0 if no error else -1
159
+ */
160
+int rpn_expr_recompile(rpn_expr_t *expr, const char *code);
161
+
155 162
 /**@brief Takes into account modifications in token representation
156 163
  * @param rpn_expr_t*
157 164
  * @return 0 if no error else -1

+ 3
- 2
tests/tests_pyrpn.py View File

@@ -126,10 +126,11 @@ class Test0RpnModule(unittest.TestCase):
126 126
                         if tok not in counters:
127 127
                             counters[tok] = 0
128 128
                         counters[tok] += 1
129
-        all_ops = len(pyrpn.get_ops()) + 2
129
+        all_ops = len(pyrpn.get_ops()) + 1
130 130
         entropy = 1-sum([(n/all_count)**2
131 131
                           for _, n in counters.items()])
132 132
         self.assertGreater(entropy, 1-(1/all_ops), "Low entropy !")
133
-   
133
+ 
134
+
134 135
 if __name__ == '__main__':
135 136
     unittest.main()

+ 66
- 11
tests/tests_rpn_sequence.py View File

@@ -1,20 +1,20 @@
1 1
 #!/usr/bin/python3
2
-# Copyright 2023 Weber Yann
2
+# copyright 2023 weber yann
3 3
 #
4
-# This file is part of rpnifs.
4
+# this file is part of rpnifs.
5 5
 #
6 6
 #        geneifs is free software: you can redistribute it and/or modify
7
-#        it under the terms of the GNU General Public License as published by
8
-#        the Free Software Foundation, either version 3 of the License, or
7
+#        it under the terms of the gnu general public license as published by
8
+#        the free software foundation, either version 3 of the license, or
9 9
 #        (at your option) any later version.
10 10
 #
11 11
 #        geneifs is distributed in the hope that it will be useful,
12
-#        but WITHOUT ANY WARRANTY; without even the implied warranty of
13
-#        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
-#        GNU General Public License for more details.
12
+#        but without any warranty; without even the implied warranty of
13
+#        merchantability or fitness for a particular purpose.  see the
14
+#        gnu general public license for more details.
15 15
 #
16
-#        You should have received a copy of the GNU General Public License
17
-#        along with geneifs.  If not, see <http://www.gnu.org/licenses/>.
16
+#        you should have received a copy of the gnu general public license
17
+#        along with geneifs.  if not, see <http://www.gnu.org/licenses/>.
18 18
 #
19 19
 
20 20
 import copy
@@ -26,8 +26,8 @@ import unittest
26 26
 
27 27
 try:
28 28
     import pyrpn
29
-except (ImportError, NameError) as e:
30
-    print("Error importing pyrpn. Try to run make.",
29
+except (importerror, nameerror) as e:
30
+    print("error importing pyrpn. try to run make.",
31 31
           file=sys.stderr)
32 32
     raise e
33 33
 
@@ -60,6 +60,61 @@ class TestRpnExprCopy(unittest.TestCase):
60 60
             with self.subTest(expr=expr, expected_len=elen):
61 61
                 self.assertEqual(len(expr), elen)
62 62
 
63
+    def test_getter(self):
64
+        """ Test __getitem__ """
65
+        tests = ((['0x42', '+', 'A0'], 1),
66
+                 (['A0'], 1))
67
+        for test in tests:
68
+            elts, nargs = test
69
+            expr_str = ' '.join(elts)
70
+            expr = pyrpn.RPNExpr(expr_str, nargs)
71
+            with self.subTest(expr=expr):
72
+                for i in range(len(expr)):
73
+                    self.assertEqual(expr[i],
74
+                            pyrpn.tokens.Token.from_str(elts[i]))
75
+
76
+    def test_setter(self):
77
+        """ Testing __setitem__ """
78
+        expr = pyrpn.RPNExpr('A0 A1 +', 2)
79
+        for _ in range(1024):
80
+            a0, a1 = (random.randint(0, 0x10000) for _ in range(2))
81
+            res = expr.eval(a0, a1)
82
+            self.assertEqual(res, a0+a1)
83
+
84
+        expr[2] = pyrpn.tokens.Operand('*')
85
+        self.assertEqual(str(expr), 'A0 A1 *')
86
+        for _ in range(1024):
87
+            a0, a1 = (random.randint(0, 0x1000) for _ in range(2))
88
+            res = expr.eval(a0, a1)
89
+            self.assertEqual(res, a0*a1)
90
+
91
+    def test_setter_append(self):
92
+        """ Testing __setitem__ to append new token """
93
+        expr = pyrpn.RPNExpr('A0 A1', 2)
94
+        expr[2] = pyrpn.tokens.Operand('+')
95
+        for _ in range(1024):
96
+            a0, a1 = (random.randint(0, 0x10000) for _ in range(2))
97
+            res = expr.eval(a0, a1)
98
+            self.assertEqual(res, a0+a1)
99
+
100
+    def test_setter_err_check_arg(self):
101
+        """ Testing __setitem__ errors on invalid argument number"""
102
+        for argcnt in range(1,10):
103
+            expr = pyrpn.RPNExpr('0x0', argcnt)
104
+            for argno in range(argcnt):
105
+                expr[0] = pyrpn.tokens.Argument(argno)
106
+            for argno in range(argcnt, 0x100):
107
+                with self.assertRaises(ValueError):
108
+                    expr[0] = pyrpn.tokens.Argument(argno)
109
+
110
+    def test_setter_err_check_idx(self):
111
+        """ Testing __setitem__ errors on invalid index"""
112
+        for elen in range(100):
113
+            expr = pyrpn.RPNExpr(pyrpn.random_expr(2, elen), 2)
114
+            for pos in range(len(expr)+1, 0x100):
115
+                with self.assertRaises(IndexError):
116
+                    expr[pos] = pyrpn.tokens.Value(0x1)
117
+
63 118
 
64 119
 if __name__ == '__main__':
65 120
     unittest.main()

+ 0
- 0
tests/tests_rpn_tokens.py View File


+ 37
- 0
tests/tests_rpniter.py View File

@@ -1,4 +1,41 @@
1 1
 #!/usr/bin/python3
2
+# copyright 2023 weber yann
3
+#
4
+# this file is part of rpnifs.
5
+#
6
+#        geneifs is free software: you can redistribute it and/or modify
7
+#        it under the terms of the gnu general public license as published by
8
+#        the free software foundation, either version 3 of the license, or
9
+#        (at your option) any later version.
10
+#
11
+#        geneifs is distributed in the hope that it will be useful,
12
+#        but without any warranty; without even the implied warranty of
13
+#        merchantability or fitness for a particular purpose.  see the
14
+#        gnu general public license for more details.
15
+#
16
+#        you should have received a copy of the gnu general public license
17
+#        along with geneifs.  if not, see <http://www.gnu.org/licenses/>.
18
+#
19
+
20
+import copy
21
+import pickle
22
+import random
23
+import sys
24
+
25
+import unittest
26
+
27
+try:
28
+    import pyrpn
29
+except (importerror, nameerror) as e:
30
+    print("error importing pyrpn. try to run make.",
31
+          file=sys.stderr)
32
+    raise e
33
+
34
+
35
+class TestRpnExprCopy(unittest.TestCase):
36
+    """ Testing RPNExpr sequence method """
37
+
38
+
2 39
 import unittest
3 40
 import warnings
4 41
 

+ 100
- 0
tests/tests_rpniter_seq.py View File

@@ -0,0 +1,100 @@
1
+#!/usr/bin/python3
2
+# copyright 2023 weber yann
3
+#
4
+# this file is part of rpnifs.
5
+#
6
+#        geneifs is free software: you can redistribute it and/or modify
7
+#        it under the terms of the gnu general public license as published by
8
+#        the free software foundation, either version 3 of the license, or
9
+#        (at your option) any later version.
10
+#
11
+#        geneifs is distributed in the hope that it will be useful,
12
+#        but without any warranty; without even the implied warranty of
13
+#        merchantability or fitness for a particular purpose.  see the
14
+#        gnu general public license for more details.
15
+#
16
+#        you should have received a copy of the gnu general public license
17
+#        along with geneifs.  if not, see <http://www.gnu.org/licenses/>.
18
+#
19
+
20
+import copy
21
+import pickle
22
+import random
23
+import sys
24
+
25
+import unittest
26
+
27
+try:
28
+    import pyrpn
29
+except (importerror, nameerror) as e:
30
+    print("error importing pyrpn. try to run make.",
31
+          file=sys.stderr)
32
+    raise e
33
+
34
+
35
+class TestRpnIterSequence(unittest.TestCase):
36
+    """ Testing RPNIterExpr sequence methods """
37
+
38
+    def test_len(self):
39
+        """ Testing RPNIterExpr.__len__ with various values/constants """
40
+        tests = [([pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (1024,1024)],
41
+                   5),
42
+                 ([pyrpn.const.POS_LINEAR, pyrpn.const.RESULT_CONST_RGBA, (1024,), (255,0,0,255)],
43
+                   1),
44
+                 ([pyrpn.const.POS_XY, pyrpn.const.RESULT_CONST_RGBA, (640,480), (255,0,0,255)],
45
+                   2),
46
+                 ([pyrpn.const.POS_LINEAR, pyrpn.const.RESULT_RGBA, (1024,)],
47
+                   5),
48
+                 ([pyrpn.const.POS_XDIM, pyrpn.const.RESULT_RGB, (4, 2, 2, 640, 480)],
49
+                  7),
50
+        ]
51
+        for args, expt_len in tests:
52
+            rif=pyrpn.RPNIterExpr(*args)
53
+            with self.subTest(rif=rif, expt_len=expt_len, args=args):
54
+                self.assertEqual(expt_len, len(rif))
55
+
56
+
57
+
58
+class TestRPNIterMapping(unittest.TestCase):
59
+    """ Testing RPNIterExpr mapping methods """
60
+
61
+
62
+    def test_keys(self):
63
+        """ Testing RPNIterExpr.__getitem__ with various values/constants """
64
+        tests = [([pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (1024,1024)],
65
+                  ['X', 'Y', 'R', 'G', 'B']),
66
+                 ([pyrpn.const.POS_LINEAR, pyrpn.const.RESULT_CONST_RGBA, (1024,), (255,0,0,255)],
67
+                   ['X']),
68
+                 ([pyrpn.const.POS_XY, pyrpn.const.RESULT_CONST_RGBA, (640,480), (255,0,0,255)],
69
+                   ['X', 'Y']),
70
+                 ([pyrpn.const.POS_LINEAR, pyrpn.const.RESULT_RGBA, (1024,)],
71
+                   ['X', 'R', 'G', 'B', 'A']),
72
+                 ([pyrpn.const.POS_XDIM, pyrpn.const.RESULT_RGB, (4, 2, 2, 640, 480)],
73
+                     ['P0', 'P1', 'P2', 'P3', 'R', 'G', 'B']),
74
+        ]
75
+        for args, keys in tests:
76
+            rif=pyrpn.RPNIterExpr(*args)
77
+            for curkey in keys:
78
+                with self.subTest(rif=rif, key=curkey):
79
+                    expr = rif[curkey]
80
+            expt = set(keys)
81
+            self.assertEqual(set(rif.keys()), expt)
82
+            for key, value in rif.items():
83
+                with self.subTest(item=(key, value), id1=id(rif[key]),
84
+                        id2=id(value), rif=rif):
85
+                    self.assertEqual(rif[key], value)
86
+
87
+    def test_assignement(self):
88
+        """ Testing RPNIterExpr.__setitem__ """
89
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, (1024,1024))
90
+        rif['X'] = 'A0 A1 +'
91
+        for _ in range(1000):
92
+            a, b = [random.randint(0,0xFFFF) for _  in range(2)]
93
+            args = (a,b, 0,0,0)
94
+            self.assertEqual(a+b, rif['X'].eval(*args))
95
+            self.assertEqual(0, rif['Y'].eval(*args))
96
+
97
+
98
+if __name__ == '__main__':
99
+    unittest.main()
100
+

+ 92
- 0
tests/tests_tokens.py View File

@@ -0,0 +1,92 @@
1
+#!/usr/bin/python3
2
+# copyright 2023 weber yann
3
+#
4
+# this file is part of rpnifs.
5
+#
6
+#        geneifs is free software: you can redistribute it and/or modify
7
+#        it under the terms of the gnu general public license as published by
8
+#        the free software foundation, either version 3 of the license, or
9
+#        (at your option) any later version.
10
+#
11
+#        geneifs is distributed in the hope that it will be useful,
12
+#        but without any warranty; without even the implied warranty of
13
+#        merchantability or fitness for a particular purpose.  see the
14
+#        gnu general public license for more details.
15
+#
16
+#        you should have received a copy of the gnu general public license
17
+#        along with geneifs.  if not, see <http://www.gnu.org/licenses/>.
18
+#
19
+import random
20
+import sys
21
+
22
+import unittest
23
+
24
+try:
25
+    import pyrpn
26
+except (importerror, nameerror) as e:
27
+    print("error importing pyrpn. try to run make.",
28
+          file=sys.stderr)
29
+    raise e
30
+
31
+
32
+class TestTokens(unittest.TestCase):
33
+    """ Testing tokens module """
34
+
35
+    def test_argument(self):
36
+        """ Testing tokens.Argument type  init """
37
+        for argno in range(1024):
38
+            arg = pyrpn.tokens.Argument(argno)
39
+            with self.subTest(argno=argno, arg=arg):
40
+                self.assertEqual(arg.argno, argno)
41
+
42
+    def test_value(self):
43
+        """ Testing tokens.Value type init """
44
+        for _ in range(1024):
45
+            v = random.randint(0, 0xFFFFFFFF)
46
+            val = pyrpn.tokens.Value(v)
47
+            with self.subTest(val=v, token_value=val):
48
+                self.assertEqual(val.value, v)
49
+
50
+    def test_op(self):
51
+        """ Testing tokens.Operand type init """
52
+        for opcode in range(pyrpn.tokens.Operand.opcode_max()+1):
53
+            operand = pyrpn.tokens.Operand(opcode)
54
+            with self.subTest(opcode=opcode, operand=operand):
55
+                self.assertEqual(opcode, operand.opcode)
56
+
57
+            op_fromstr = pyrpn.tokens.Operand(str(operand))
58
+            with self.subTest(from_str=op_fromstr, opcode=opcode):
59
+                self.assertEqual(opcode, op_fromstr.opcode)
60
+
61
+    def test_cmp(self):
62
+        """ Testing token comparison """
63
+        tests = {
64
+                'lt': ([('A0', 'A1'), ('0x10', '0x11'), ('-', '/'),
65
+                        ('-', 'A0'), ('-', '0x1'), ('A0', '0x1')],
66
+                       [('A1', 'A0'), ('0x11', '0x10'), ('/', '-'),
67
+                        ('A0', '-'), ('0x1000', '+'), ('0x0', 'A1')]),
68
+                'eq': [[('A0', 'A0'), ('0x1', '0x1'), ('+', '+')],
69
+                       []]
70
+        }
71
+        tests['gt'] = (tests['lt'][1], tests['lt'][0])
72
+        tests['le'] = [tests['lt'][i] + tests['eq'][i] for i in range(2)]
73
+        tests['ge'] = [tests['gt'][i] + tests['eq'][i] for i in range(2)]
74
+        tests['eq'][1] = [('A0', '0x0'), ('A0', '+'), ('0x0', '+')] 
75
+
76
+        assertions = {'lt': (self.assertLess, self.assertGreaterEqual),
77
+                'le': (self.assertLessEqual, self.assertGreater),
78
+                'eq': (self.assertEqual, self.assertNotEqual),
79
+                'gt': (self.assertGreater, self.assertLessEqual),
80
+                'ge': (self.assertGreaterEqual, self.assertLess)}
81
+
82
+        for comparison, (cmp_true, cmp_false) in tests.items():
83
+            assert_true, assert_false = assertions[comparison]
84
+            lst = [(assert_true, cmp_true), (assert_false, cmp_false)]
85
+            for assertion, cmplist in lst:
86
+                for test in cmplist:
87
+                    a=pyrpn.tokens.Token.from_str(test[0])
88
+                    b=pyrpn.tokens.Token.from_str(test[1])
89
+                    with self.subTest(assertion=assertion, a=a, b=b):
90
+                        assertion(a, b)
91
+
92
+

Loading…
Cancel
Save