|
""" See readme for documentation """ |
|
_none = object() |
|
|
|
class _MObject: |
|
def __call__(self, arg=_none): |
|
if isinstance(arg, list): |
|
return self[list]([self(a) for a in arg]) |
|
elif isinstance(arg, tuple): |
|
return self[tuple](tuple([self(a) for a in arg])) |
|
elif isinstance(arg, (_MatchBase, _StarMatcher)): |
|
return arg |
|
else: |
|
return _Exactly(arg) |
|
|
|
def __getitem__(self, cls): |
|
def f(*args, **kwargs): |
|
return _ClassMatcher(cls, *args, **kwargs) |
|
return f |
|
|
|
@property |
|
def _(self): |
|
return _Any() |
|
|
|
|
|
M = _MObject() |
|
|
|
|
|
class _MatchBase: |
|
def __or__(self, other): |
|
return _Either(self, other) |
|
|
|
|
|
class _ClassMatcher(_MatchBase): |
|
_known = {} |
|
|
|
@classmethod |
|
def register(cls, c): |
|
def decorator(f): |
|
cls._known[c] = f |
|
return f |
|
return decorator |
|
|
|
def __init__(self, cls, *args, **kwargs): |
|
self._cls = cls |
|
self._args = args |
|
self._kwargs = kwargs |
|
|
|
def __contains__(self, other): |
|
try: |
|
m = type(self)._known[self._cls] |
|
except: |
|
m = self._cls.__match__ |
|
if m(other, *self._args, **self._kwargs): |
|
self.value = other |
|
return True |
|
return False |
|
|
|
|
|
class _StarMatcher: |
|
def __init__(self, any): |
|
self._any = any |
|
def __contains__(self, other): |
|
raise TypeError("Can't be used directly") |
|
|
|
|
|
def _register_sequence(t): |
|
@_ClassMatcher.register(t) |
|
def _t_matcher(other, arg): |
|
assert isinstance(arg, t) |
|
|
|
if not isinstance(other, t): |
|
return False |
|
|
|
n_arg = len(arg) |
|
|
|
star = None |
|
for i, v in enumerate(arg): |
|
if isinstance(v, _StarMatcher): |
|
star = (i, v) |
|
if star: |
|
i, v = star |
|
arg_begin, arg_end = arg[:i], arg[i+1:] |
|
if other[:i] not in M(arg_begin): |
|
return False |
|
if other[len(other)-len(arg_end):] not in M(arg_end): |
|
return False |
|
v._any.value = other[i:len(other)-len(arg_end)] |
|
return True |
|
|
|
else: |
|
if len(arg) != len(other): |
|
return False |
|
return all( |
|
oi in M(ai) for oi, ai in zip(other, arg) |
|
) |
|
return arg == other |
|
|
|
_register_sequence(list) |
|
_register_sequence(tuple) |
|
|
|
|
|
class _Either(_MatchBase): |
|
def __init__(self, *options): |
|
self._options = options |
|
def __contains__(self, other): |
|
if any(other in o for o in self._options): |
|
self.value = other |
|
return True |
|
return False |
|
|
|
|
|
class _Any(_MatchBase): |
|
def __contains__(self, other): |
|
self.value = other |
|
return True |
|
|
|
def __iter__(self): |
|
yield _StarMatcher(self) |
|
|
|
|
|
class _Exactly(_MatchBase): |
|
def __init__(self, value): |
|
self.value = value |
|
|
|
def __contains__(self, other): |
|
return self.value == other |