from ..utils import compare from functools import cmp_to_key from ..tree import Tree, Visitor_NoRecurse # Standard ambiguity resolver (uses comparison) # # Author: Erez Sh def _compare_rules(rule1, rule2): if rule1.origin != rule2.origin: if rule1.options and rule2.options: if rule1.options.priority is not None and rule2.options.priority is not None: assert rule1.options.priority != rule2.options.priority, "Priority is the same between both rules: %s == %s" % (rule1, rule2) return -compare(rule1.options.priority, rule2.options.priority) return 0 c = compare( len(rule1.expansion), len(rule2.expansion)) if rule1.origin.startswith('__'): # XXX hack! We need to set priority in parser, not here c = -c return c def _compare_drv(tree1, tree2): if not (isinstance(tree1, Tree) and isinstance(tree2, Tree)): try: return -compare(tree1, tree2) except TypeError: return 0 try: rule1, rule2 = tree1.rule, tree2.rule except AttributeError: # Probably trees that don't take part in this parse (better way to distinguish?) return -compare(tree1, tree2) # XXX These artifacts can appear due to imperfections in the ordering of Visitor_NoRecurse, # when confronted with duplicate (same-id) nodes. Fixing this ordering is possible, but would be # computationally inefficient. So we handle it here. if tree1.data == '_ambig': _standard_resolve_ambig(tree1) if tree2.data == '_ambig': _standard_resolve_ambig(tree2) c = _compare_rules(tree1.rule, tree2.rule) if c: return c # rules are "equal", so compare trees for t1, t2 in zip(tree1.children, tree2.children): c = _compare_drv(t1, t2) if c: return c return compare(len(tree1.children), len(tree2.children)) def _standard_resolve_ambig(tree): assert tree.data == '_ambig' best = min(tree.children, key=cmp_to_key(_compare_drv)) assert best.data == 'drv' tree.set('drv', best.children) tree.rule = best.rule # needed for applying callbacks def standard_resolve_ambig(tree): for ambig in tree.find_data('_ambig'): _standard_resolve_ambig(ambig) return tree # Anti-score Sum # # Author: Uriva (https://github.com/uriva) def _antiscore_sum_drv(tree): if not isinstance(tree, Tree): return 0 # XXX These artifacts can appear due to imperfections in the ordering of Visitor_NoRecurse, # when confronted with duplicate (same-id) nodes. Fixing this ordering is possible, but would be # computationally inefficient. So we handle it here. if tree.data == '_ambig': _antiscore_sum_resolve_ambig(tree) try: priority = tree.rule.options.priority except AttributeError: # Probably trees that don't take part in this parse (better way to distinguish?) priority = None return (priority or 0) + sum(map(_antiscore_sum_drv, tree.children), 0) def _antiscore_sum_resolve_ambig(tree): assert tree.data == '_ambig' best = min(tree.children, key=_antiscore_sum_drv) assert best.data == 'drv' tree.set('drv', best.children) tree.rule = best.rule # needed for applying callbacks def antiscore_sum_resolve_ambig(tree): for ambig in tree.find_data('_ambig'): _antiscore_sum_resolve_ambig(ambig) return tree