from attrs import Attrs from log import log from rule import Rule class Edge(Rule): def __init__(self, rule, begin=0, end=0, point=0, left=None, right=None, real_offset=0, parents=()): self.rule = rule self.left = dict(rule.left if left is None else left) self.right = ([dict(token) for token in rule.right] if right is None else [dict(token) for token in right]) self.begin = begin self.end = end self.point = point self.real_offset = real_offset # parent edges can be none (initial agenda), one (terminal rule, # prediction), or two (fundamental rule, closed edges rule) self.parents = parents # set of parent edges; since it can be created # by various means we want to record not only # the first successful attempt, but all # (previously, we would just discard duplicate # edges, now we add parent edges to the set) # můžou mít stejné pravidlo, stejný začátek i konec i tečku, # ale mohly vzniknout z jiných pravidel (ovšem i dřívějších), # takže porovnávat (i) rodiče – ale to už stačí, protože jejich # historie bude unikátní def __eq__(self, other): return (self.rule is other.rule and self.begin == other.begin and self.end == other.end and self.point == other.point) # def __hash__(self): # return id(self.rule) ^ self.begin ^ self.end ^ self.point @property def complete(self): # TODO: nesmysl, tohle stačí nastavit při vytvoření hrany return self.point == len(self.right) @property def next_token(self): return None if self.complete else self.right[self.point] @property def next_rule_token(self): return None if self.complete else self.rule.right[self.point] def copy_attributes(self, update=None): if update: current = self.right[self.point - 1] for attr, value in sorted(update.items()): if attr not in current or current[attr] is None: log.debug('move %s=%s → %s', attr, value, Attrs(current)) current[attr] = value elif current[attr] != value: log.warning('update %s=%s → %s', attr, value, Attrs(current)) current[attr] = value for attr, match_on_indexes in sorted(self.rule.attr_matches.items()): copy_to_head = False value = None for index in match_on_indexes: if index == -1: copy_to_head = True continue elif index == self.point - 1: # nemá smysl kopírovat znovu if attr not in self.right[index]: log.warning('no attr %s %s', attr, Attrs(self.right[index])) # if attr in ('g',): continue value = self.right[index][attr] if copy_to_head: if attr in self.left and self.left[attr] is not None: if self.left[attr] != value: log.critical(' '*13 + 'měla selhat shoda!' ' %s=%s %s', attr, value, Attrs(self.left)) continue log.debug('copy %s=%s → head', attr, value) self.left[attr] = value elif value is not None and index >= self.point: log.debug('copy %s=%s → %s', attr, value, Attrs(self.right[index])) self.right[index][attr] = value def predict_attributes(self, attrs): for attr, value in self.rule.left.items(): if value is None and attr in attrs: self.left[attr] = attrs[attr] # log.debug('copy %s=%s → head', attr, attrs[attr]) for attr, match_on_indexes in sorted(self.rule.attr_matches.items()): if -1 in match_on_indexes and attr in self.left: value = self.left[attr] for index in match_on_indexes[1:]: self.right[index][attr] = value # log.debug('copy head → %s=%s', attr, value)