# type util
class PistonTypeError(Exception):pass
def _get_ptn_parent_type(t):return t._t()
def _get_type(t):return _get_ptn_parent_type(t)if(isinstance(t,_ptn_type)or issubclass(t if isinstance(t,type)else type(t), _ptn_type))else t if isinstance(t,type)else type(t)
def _cmp_type(t,o):return _get_type(t)==_get_type(o)
def _ensure_iterable(o):return o if isinstance(o,(list,tuple))else[o]
def _type_of(t,o):print([_get_type(e)for e in _ensure_iterable(o)]);return _get_type(t)in[_get_type(e)for e in _ensure_iterable(o)]
def _type_mismatch(t,o):raise PistonTypeError("type mismatch. expected "+("|".join([_get_type(e).__name__ for e in _ensure_iterable(o)])+" but got "+_get_type(t).__name__))
def _assert_type(t,o):_type_mismatch(t,o)if not _type_of(t,o)else None
def _cast_type(v,t):ns=dict(v=v,t=t);exec("try:t(v);r=False\nexcept:r=True",ns);return _type_mismatch(v,t)if(ns["r"])else t(v)
def _length_error(e,l):raise ValueError("expected length "+str(len(e))+" but got "+str(l))
def _assert_length(e,l):_length_error(e,l)if len(e)!=l else None
# match util
def _value_cb(v):return lambda:v
def _call_fn(cb,args,n):
n_args=cb.__code__.co_argcount
if n_args<=0:return cb()
else:
template="res=call({args})";str_args=[f'"{arg}"'if isinstance(arg,str)else str(arg)for arg in args];arg_dif=n_args-n
if arg_dif<=0:str_args=str_args[:arg_dif]
else:str_args.extend(["None"]*arg_dif)
f_call=template.format(args=",".join(str_args));ns=dict(__name__="match");ns["call"]=cb;exec(f_call,ns);return ns["res"]
class _Matchable(object):
def get_values(self):raise NotImplementedError
def get_n_values(self):return len(self.get_values())
def match(self,*cases,default):
for case in cases:
_assert_type(case,(tuple,list));_assert_length(case,2);comp,call=case;call=call if callable(call)else _value_cb(call);
if self.__eq__(comp):return _call_fn(call,self.get_values(),self.get_n_values())
if default:
call=default if callable(default)else _value_cb(default);return _call_fn(call,self.get_values(),self.get_n_values())
# types
class _ptn_type(object):pass
class _ptn_t_integer(_ptn_type):
def __init__(s,v):s.v=_cast_type(v,int)
def __str__(s):return str(s.v)
def __repr__(s):return str(s)
def __len__(s):return len(s.v)
@staticmethod
def _t():return int
def __lt__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v<o.v
if isinstance(o,(int,float)):return s.v<o
else:return False
def __gt__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v>o.v
if isinstance(o,(int,float)):return s.v>o
else:return False
def __le__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v<=o.v
if isinstance(o,(int,float)):return s.v<=o
else:return False
def __ge__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v>=o.v
if isinstance(o,(int,float)):return s.v>=o
else:return False
def __eq__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v==o.v
if isinstance(o,(int,float)):return s.v==o
else:return False
def __ne__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v!=o.v
if isinstance(o,(int,float)):return s.v!=o
else:return False
def __add__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v+o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v+o)
else:_type_mismatch(o,(int,float))
def __iadd__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v+o.v;return s
if isinstance(o,(int,float)):s.v=s.v+o;return s
else:_type_mismatch(o,(int,float))
# TODO: radd, rsub, rmul, etc. https://python-course.eu/oop/magic-methods.php
def __sub__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v-o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v-o)
else:_type_mismatch(o,(int,float))
def __isub__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v-o.v;return s
if isinstance(o,(int,float)):s.v=s.v-o;return s
else:_type_mismatch(o,(int,float))
def __mul__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v*o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v*o)
else:_type_mismatch(o,(int,float))
def __imul__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v*o.v;return s
if isinstance(o,(int,float)):s.v=s.v*o;return s
else:_type_mismatch(o,(int,float))
def __floordiv__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v//o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v//o)
else:_type_mismatch(o,(int,float))
def __ifloordiv__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v//o.v;return s
if isinstance(o,(int,float)):s.v=s.v//o;return s
else:_type_mismatch(o,(int,float))
def __truediv__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v/o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v/o)
else:_type_mismatch(o,(int,float))
def __idiv__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v/o.v;return s
if isinstance(o,(int,float)):s.v=s.v/o;return s
else:_type_mismatch(o,(int,float))
def __mod__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v%o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v%o)
else:_type_mismatch(o,(int,float))
def __imod__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v%o.v;return s
if isinstance(o,(int,float)):s.v=s.v%o;return s
else:_type_mismatch(o,(int,float))
def __pow__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v**o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v**o)
else:_type_mismatch(o,(int,float))
def __ipow__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v**o.v;return s
if isinstance(o,(int,float)):s.v=s.v**o;return s
else:_type_mismatch(o,(int,float))
def __lshift__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v<<o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v<<o)
else:_type_mismatch(o,(int,float))
def __ilshift__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v<<o.v;return s
if isinstance(o,(int,float)):s.v=s.v<<o;return s
else:_type_mismatch(o,(int,float))
def __rshift__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v>>o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v>>o)
else:_type_mismatch(o,(int,float))
def __irshift__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v>>o.v;return s
if isinstance(o,(int,float)):s.v=s.v>>o;return s
else:_type_mismatch(o,(int,float))
def __and__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v&o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v&o)
else:_type_mismatch(o,(int,float))
def __iand__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v&o.v;return s
if isinstance(o,(int,float)):s.v=s.v&o;return s
else:_type_mismatch(o,(int,float))
def __xor__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v^o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v^o)
else:_type_mismatch(o,(int,float))
def __ixor__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v^o.v;return s
if isinstance(o,(int,float)):s.v=s.v^o;return s
else:_type_mismatch(o,(int,float))
def __or__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return _ptn_t_integer(s.v|o.v)
if isinstance(o,(int,float)):return _ptn_t_integer(s.v|o)
else:_type_mismatch(o,(int,float))
def __ior__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):s.v=s.v|o.v;return s
if isinstance(o,(int,float)):s.v=s.v|o;return s
else:_type_mismatch(o,(int,float))
def __neg__(s):return _ptn_t_integer(-s.v)
def __pos__(s):return _ptn_t_integer(+s.v)
def __invert__(s):return _ptn_t_integer(~s.v)
def __int__(s):return _ptn_t_integer(int(s.v))
def __float__(s):return _ptn_t_float(float(s.v))
def __abs__(s):return _ptn_t_integer(abs(s.v))
def __complex__(s):return _ptn_t_integer(complex(s.v))
def __oct__(s):return _ptn_t_integer(oct(s.v))
def __hex__(s):return _ptn_t_integer(hex(s.v))
class _ptn_t_float(_ptn_type):
def __init__(s,v):s.v=_cast_type(v,float)
def __str__(s):return str(s.v)
def __repr__(s):return str(s)
def __len__(s):return len(s.v)
@staticmethod
def _t():return float
def __lt__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v<o.v
if isinstance(o,(int,float)):return s.v<o
else:return False
def __gt__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v>o.v
if isinstance(o,(int,float)):return s.v>o
else:return False
def __le__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v<=o.v
if isinstance(o,(int,float)):return s.v<=o
else:return False
def __ge__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v>=o.v
if isinstance(o,(int,float)):return s.v>=o
else:return False
def __eq__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v==o.v
if isinstance(o,(int,float)):return s.v==o
else:return False
def __ne__(s,o):
if isinstance(o,(_ptn_t_integer,_ptn_t_float)):return s.v!=o.v
if isinstance(o,(int,float)):return s.v!=o
else:return False
class _ptn_t_string(_ptn_type):
def __init__(s,v):s.v=_cast_type(v,str)
def __str__(s):return str(s.v)
def __repr__(s):return str(s)
def __len__(s):return len(s.v)
@staticmethod
def _t():return str
def __eq__(s,o):
if isinstance(o,_ptn_t_string):return s.v==o.v
if isinstance(o,str):return s.v==o
else:return False
def __ne__(s,o):
if isinstance(o,_ptn_t_string):return s.v!=o.v
if isinstance(o,str):return s.v!=o
else:return False
def __contains__(s,o):return o in s.v
def __iter__(s):
for e in s.v:yield e
class _ptn_t_bool(_ptn_type):
def __init__(s,v):s.v=_cast_type(v,bool)
def __str__(s):return str(s.v)
def __repr__(s):return str(s)
def __len__(s):return len(s.v)
@staticmethod
def _t():return bool
def __eq__(s,o):
if isinstance(o,_ptn_t_bool):return s.v==o.v
if isinstance(o,bool):return s.v==o
else:return False
def __ne__(s,o):
if isinstance(o,_ptn_t_bool):return s.v!=o.v
if isinstance(o,bool):return s.v!=o
else:return False
if __name__ == '__main__':
val = _ptn_t_integer(1.0)
print(val.v)
print(val.v == _ptn_t_float(1))
print(_type_of(1,_ptn_t_integer))