153 lines
4.5 KiB
Python
153 lines
4.5 KiB
Python
# from smnp.type.model import Type
|
|
#
|
|
from smnp.type.model import Type
|
|
|
|
|
|
class Matcher:
|
|
def __init__(self, objectType, matcher, string):
|
|
self.type = objectType
|
|
self.matcher = matcher
|
|
self.string = string
|
|
|
|
def match(self, value):
|
|
if self.type is not None and self.type != value.type:
|
|
return False
|
|
return self.matcher(value)
|
|
|
|
def andWith(self, matcher):
|
|
if self.type != matcher.type:
|
|
raise RuntimeError("Support types of matches are not the same")
|
|
string = f"[{self.string} and {matcher.string}]"
|
|
return Matcher(self.type, lambda x: self.match(x) and matcher.match(x), string)
|
|
|
|
def orWith(self, matcher):
|
|
string = f"[{self.string} or {matcher.string}]"
|
|
return Matcher(None, lambda x: self.match(x) or matcher.match(x), string)
|
|
|
|
def __eq__(self, other):
|
|
return self.type == other.type and self.string == other.string
|
|
|
|
|
|
|
|
def __str__(self):
|
|
return self.string
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
|
|
class Signature:
|
|
def __init__(self, check, string, matchers):
|
|
self.check = check
|
|
self.string = string
|
|
self.matchers = matchers
|
|
|
|
|
|
def varargSignature(varargMatcher, *basicSignature):
|
|
def check(args):
|
|
if len(basicSignature) > len(args):
|
|
return doesNotMatchVararg(basicSignature)
|
|
|
|
for i in range(len(basicSignature)):
|
|
if not basicSignature[i].match(args[i]):
|
|
return doesNotMatchVararg(basicSignature)
|
|
|
|
for i in range(len(basicSignature), len(args)):
|
|
if not varargMatcher.match(args[i]):
|
|
return doesNotMatchVararg(basicSignature)
|
|
|
|
return True, (*args[:len(basicSignature)]), args[len(basicSignature):]
|
|
|
|
string = f"({', '.join([str(m) for m in basicSignature])}{', ' if len(basicSignature) > 0 else ''}{str(varargMatcher)}...)"
|
|
|
|
return Signature(check, string, [varargMatcher, *basicSignature])
|
|
|
|
|
|
def doesNotMatchVararg(basicSignature):
|
|
return (False, *[None for n in basicSignature], None)
|
|
#
|
|
|
|
|
|
def signature(*signature):
|
|
def check(args):
|
|
if len(signature) != len(args):
|
|
return doesNotMatch(signature)
|
|
|
|
for s, a in zip(signature, args):
|
|
if not s.match(a):
|
|
return doesNotMatch(signature)
|
|
|
|
return (True, *args)
|
|
|
|
string = f"({', '.join([str(m) for m in signature])})"
|
|
|
|
return Signature(check, string, signature)
|
|
|
|
|
|
def doesNotMatch(sign):
|
|
return (False, *[None for n in sign])
|
|
|
|
|
|
def allTypes():
|
|
allowedTypes = [t for t in Type if t != Type.VOID]
|
|
return ofTypes(*allowedTypes)
|
|
|
|
|
|
def ofTypes(*types):
|
|
def check(value):
|
|
return value.type in types
|
|
return Matcher(None, check, f"<{', '.join([t.name.lower() for t in types])}>")
|
|
|
|
def ofType(type):
|
|
def check(value):
|
|
return value.type == type
|
|
|
|
return Matcher(None, check, type.name.lower())
|
|
|
|
def listOf(*types):
|
|
def check(value):
|
|
return len([item for item in value.value if not item.type in types]) == 0
|
|
|
|
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([t.name.lower() for t in types])}>")
|
|
|
|
def listOfMatchers(*matchers):
|
|
def check(value):
|
|
matched = 0
|
|
for item in value.value:
|
|
matched += 1 if any(matcher.match(item) for matcher in matchers) else 0
|
|
|
|
return matched == len(value.value)
|
|
|
|
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([m.string for m in matchers])}>")
|
|
|
|
def mapOfMatchers(keyMatchers, valueMatchers):
|
|
def check(map):
|
|
matched = 0
|
|
for key, value in map.value.items():
|
|
matched += 1 if any(matcher.match(key) for matcher in keyMatchers) \
|
|
and any(matcher.match(value) for matcher in valueMatchers) else 0
|
|
|
|
return matched == len(map.value)
|
|
|
|
return Matcher(Type.MAP, check, f"{Type.MAP.name.lower()}<{', '.join([m.string for m in keyMatchers])}><{', '.join([m.string for m in valueMatchers])}>")
|
|
|
|
|
|
def listMatches(*pattern):
|
|
def check(value):
|
|
return signature(*pattern).check(value.value)[0]
|
|
|
|
return Matcher(Type.LIST, check, f"({', '.join([str(m) for m in pattern])})")
|
|
|
|
def recursiveListMatcher(matcher):
|
|
if matcher.type == Type.LIST:
|
|
raise RuntimeError(f"Passed matcher will be handling non-list types, so it cannot have type set to {Type.LIST}")
|
|
|
|
def check(value):
|
|
if value.type != Type.LIST:
|
|
return matcher.match(value)
|
|
for item in value.value:
|
|
return check(item)
|
|
|
|
return Matcher(Type.LIST, check, f"[LISTS OF {str(matcher)}]")
|
|
|