Source code for modeci_mdf.functions.actr.ccm.pattern

import re

basestring = str


[docs]class PatternException(Exception): pass
[docs]def get(obj, name, key): if name is None: a = obj else: a = obj[name] while type(key) == str and "." in key: key1, key = key.split(".", 1) try: a = a[key1] except AttributeError: a = getattr(a, key1) try: x = a[key] except AttributeError: x = getattr(a, key) if isinstance(x, float): x = "%g" % x if not isinstance(x, str): x = repr(x) return x
[docs]def partialmatch(obj, name, key, b, value): if type(key) == str and key[0] == "?": key = b[key[1:]] v = get(obj, name, key) if v == value: return True # fix for early Python versions where True and False are actually 1 and 0 if value in ["True", "False"] and type(True) == int: if v == str(bool(value)): return True pm = b.get("_partial", None) if pm is not None: x = pm.match(key, value, v) obj._partial += x return True else: return False
[docs]class Pattern: def __init__(self, patterns, bound=None, partial=None): self.funcs = parse(patterns, bound) self.partial = partial def match(self, obj): b = {} b["_partial"] = self.partial if self.partial is not None: obj._partial = 0.0 try: for f in self.funcs: if f(obj, b) == False: return None except (AttributeError, TypeError, KeyError): return None del b["_partial"] return b
[docs]def parse(patterns, bound=None): if not hasattr(patterns, "items"): patterns = {None: patterns} funcs = [] vars = {} funcs2 = [] for name, pattern in patterns.items(): if not isinstance(pattern, (list, tuple)): pattern = [pattern] for p in pattern: if p is None: if name is None: funcs.append(lambda x, b: x == None) else: funcs.append( lambda x, b, name=name: x[name] == None or len(x[name]) == 0 ) elif callable(p): if name is None: def callfunc(x, b, name=name, p=p): return p(x, b) else: def callfunc(x, b, name=name, p=p): return p(x[name], b) funcs2.append(callfunc) elif isinstance(p, basestring): namedSlots = False for j, text in enumerate(p.split()): key = j m = re.match(r"([?]?[\w\.]+):", text) if m != None: key = m.group(1) try: key = int(key) except ValueError: pass text = text[m.end() :] if len(text) == 0: raise PatternException( "No value for slot '%s' in pattern '%s'" % (key, pattern) ) namedSlots = True else: if namedSlots != False: raise PatternException( "Found unnamed slot '%s' after named slot in pattern '%s'" % (text, pattern) ) if text == "?": continue while len(text) > 0: m = re.match(r"([\w\.-]+)", text) if m != None: text = text[m.end() :] t = m.group(1) funcs.append( lambda x, b, name=name, key=key, t=t: partialmatch( x, name, key, b, t ) ) continue m = re.match(r"!([\w\.-]+)", text) if m != None: text = text[m.end() :] t = m.group(1) funcs.append( lambda x, b, name=name, key=key, t=t: get(x, name, key) != t ) continue m = re.match(r"\?(\w+)", text) if m != None: text = text[m.end() :] v = m.group(1) if bound is not None and v in bound: funcs.append( lambda x, b, name=name, key=key, t=bound[ v ]: partialmatch(x, name, key, b, t) ) elif v in vars: funcs2.append( lambda x, b, name=name, key=key, v=v: partialmatch( x, name, key, b, b[v] ) ) else: vars[v] = (name, key) def setfunc(x, b, name=name, key=key, v=v): b[v] = get(x, name, key) return True funcs.append(setfunc) continue m = re.match(r"!\?(\w+)", text) if m != None: text = text[m.end() :] v = m.group(1) if bound is not None and v in bound: funcs.append( lambda x, b, name=name, key=key, t=bound[v]: get( x, name, key ) != t ) else: funcs2.append( lambda x, b, name=name, key=key, v=v: get( x, name, key ) != b[v] ) continue raise PatternException( f"Unknown text '{text}' in pattern '{pattern}'" ) return funcs + funcs2