123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- import collections
- import inspect
- import random
-
- _op_list = collections.OrderedDict()
- _var_list = collections.OrderedDict()
-
- _op_alias = collections.OrderedDict()
- _op_alias['add'] = '+'
- _op_alias['sub'] = '-'
- _op_alias['mul'] = '*'
- _op_alias['div'] = '/'
- _op_alias['mod'] = '%'
- _op_alias['bin_and'] = '&'
- _op_alias['bin_or'] = '|'
- _op_alias['bin_xor'] = '^'
- _op_alias['lshift'] = '<<'
- _op_alias['rshift'] = '>>'
- _op_alias['pow'] = '**'
-
- _var_list['x'] = 0
- _var_list['y'] = 0
- _var_list['r'] = 0
- _var_list['g'] = 0
- _var_list['b'] = 0
-
- def RpnOpNoMod(method):
- return RpnOp(method, True)
-
- def RpnOp(method, nomod = False):
- ''' @brief Decorator for RPN operation that autodetect argument count
-
- Autodetect argument count and pop them from the stack. Then attempt
- to push values from result as an array. If it fails result is push
- as it.
-
- @warning if result is None nothing is push
- '''
- narg = len(inspect.signature(method).parameters)-1
- def wrapped(self):
- args = [ self._pop() for _ in range(narg) ]
- determinist = True
- if not nomod:
- for arg in args:
- if isinstance(arg, IntVar):
- determinist = False
- break
- args.reverse()
- try:
- res = method(self, *args)
- except ZeroDivisionError:
- res = None
- if res is None:
- return determinist
- try:
- for topush in res:
- if not isinstance(topush, int):
- raise ValueError('Turmit.%s() returned a list containing a\
- %s : %s' % (method.__name__, type(topush), topush))
- topush = self._cast_int(topush)
- self._push(topush)
- except TypeError:
- if not isinstance(res, int):
- raise ValueError('Turmit.%s() returned a list containing a\
- %s : %s' % (method.__name__, type(res), res))
- self._push(res)
- return determinist
- _op_list[method.__name__] = (method, wrapped)
- return wrapped
-
- class RpnExpr(list):
- ''' @brief Extended list that only contains RpnSymbol '''
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- for i, item in enumerate(self):
- if not isinstance(item, RpnSymbol):
- raise TypeError('Item %d is %s but RpnSymbol expected' % (i,
- item))
- def __setitem__(self, idx, val):
- if not isinstance(val, RpnSymbol):
- raise TypeError('RpnSymbol expected but got %s' % type(val))
- super().__setitem__(idx, val)
-
- def __str__(self, small=True):
- if small:
- return ' '.join([_op_alias[str(sym).lower()]
- if str(sym).lower() in _op_alias
- else str(sym)
- for sym in self])
- return ' '.join([str(sym) for sym in self])
-
- def __eq__(self, b):
- if len(self) != len(b):
- return False
- for i in range(len(self)):
- if self[i] != b[i]:
- return False
- return True
-
- @classmethod
- def random(cls, sz):
- return cls([RpnSymbol.random() for _ in range(sz)])
-
- @classmethod
- def from_string(cls, val):
- ''' @brief generate an expr from a string
- @param val str : expression
- @return RpnExpr
- '''
- return cls([RpnSymbol.from_string(s.strip())
- for s in val.split()
- if len(s.strip()) > 0])
-
- class RpnSymbol(object):
- ''' @brief Designed to handle operation and operand for Turmit expr '''
-
- OPERATION = 0x0
- VALUE = 0x1
- VARIABLE = 0x3
-
-
- def __init__(self, value, optype = VALUE):
- ''' @brief RpnSymbol constructor
- @param value int : positiv integer moded given optype
- @param optype int : one of @ref OPERATION @ref VALUE @ref VARIABLE
- '''
- self.optype = optype
- self.value = value
-
- err = False
- err_type = 'Unknown'
- if optype == self.OPERATION:
- if isinstance(value, str):
- if self.value.lower() in _op_alias.values():
- idx = list(_op_alias.values()).index(self.value.lower())
- self.value = list(_op_alias.keys())[idx]
- if not value in _op_list:
- err = True
- err_type = 'operation'
- else:
- self.value = value
- else:
- self.value = list(_op_list.keys())[value % len(_op_list)]
- self.value = self.value.lower()
- elif optype == self.VARIABLE:
- if isinstance(value, str):
- if not value in _var_list:
- err = True
- err_type = 'variable'
- else:
- self.value = value
- else:
- self.value = list(_var_list.keys())[value % len(_var_list)]
- self.value = self.value.lower()
- if err:
- msg = 'Invalid %s : "%s"' % (err_type, value.upper())
-
- def __str__(self, small=True):
- ''' @brief Return a string representation of current symbol '''
- if self.optype == self.OPERATION:
- return _op_list[self.value][0].__name__.upper()
- elif self.optype == self.VALUE:
- if small:
- return '0x%X' % self.value
- else:
- return '0x%04X' % self.value
- else:
- return self.value.upper()
-
- def __repr__(self):
- if self.optype == self.OPERATION:
- optype = 'OPE'
- elif self.optype == self.VALUE:
- optype = 'VAL'
- elif self.optype == self.VARIABLE:
- optype = 'VAR'
- name = '%s.%s' % (self.__class__.__module__,
- self.__class__.__name__)
- return '<%s %s(%s)>' % (name, optype, self.value)
-
- def __eq__(self, b):
- if not isinstance(b, RpnSymbol):
- return False
- return b.optype == self.optype and b.value == self.value
-
- def __copy__(self):
- return self.__class__(self.value, self.optype)
-
- @classmethod
- def from_string(cls, val):
- try:
- val = int(val, base=0)
- return cls(val, cls.VALUE)
- except Exception:
- pass
- if val.lower() in _op_list.keys() or val.lower() in _op_alias.values():
- return cls(val, cls.OPERATION)
- elif val.lower() in _var_list.keys():
- return cls(val, cls.VARIABLE)
-
- raise ValueError('Unrecognized symbol "%s"' % val)
-
- @classmethod
- def random(cls, optype=None):
- ''' @brief Return a randomly generated symbol '''
- if optype is None:
- optype = [cls.OPERATION, cls.VALUE, cls.VARIABLE]
- optype = optype[random.randint(0,2)]
- if optype == cls.VALUE:
- vals = [(0,0xF), (0, 0xFF), (0,0xFFFF)]
- return cls(random.randint(*vals[random.randint(0,2)]), optype)
- else:
- return cls(random.randint(0, 0xFFFF), optype)
-
- @classmethod
- def rand_op(cls):
- ''' @return Random operation '''
- return cls.random(cls.OPERATION)
-
- @classmethod
- def rand_var(cls):
- ''' @retrun Random variable '''
- return cls.random(cls.VARIABLE)
-
- @classmethod
- def rand_value(cls):
- ''' @return Random value '''
- return cls.random(cls.VALUE)
-
-
- class IntVar(int):
- pass
|