Fixed match tree merges creating ambiguous trees
Now match tree merging favors the most specific match possible
This commit is contained in:
parent
88399fff69
commit
666488ce0f
|
@ -35,6 +35,9 @@ class LeafNode(Generic[A]):
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '{..}' if len(self.matches) else 'X'
|
return '{..}' if len(self.matches) else 'X'
|
||||||
|
|
||||||
|
def fill_empty_leaves(self, with_values: Sequence[A]) -> MatchTree:
|
||||||
|
return self if len(self.matches) else LeafNode(with_values)
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class IntNode(Generic[A]):
|
class IntNode(Generic[A]):
|
||||||
location: StructurePath
|
location: StructurePath
|
||||||
|
@ -48,6 +51,13 @@ class IntNode(Generic[A]):
|
||||||
merge_trees(self.fallback_tree, other)
|
merge_trees(self.fallback_tree, other)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def fill_empty_leaves(self, with_values: Sequence[A]) -> MatchTree:
|
||||||
|
return IntNode(
|
||||||
|
self.location,
|
||||||
|
{i: tree.fill_empty_leaves(with_values) for (i, tree) in self.specific_trees.items()},
|
||||||
|
self.fallback_tree.fill_empty_leaves(with_values)
|
||||||
|
)
|
||||||
|
|
||||||
def is_complete(self) -> bool:
|
def is_complete(self) -> bool:
|
||||||
return all(
|
return all(
|
||||||
subtree.is_complete() for subtree in self.specific_trees.values()
|
subtree.is_complete() for subtree in self.specific_trees.values()
|
||||||
|
@ -58,6 +68,10 @@ class IntNode(Generic[A]):
|
||||||
|
|
||||||
def merge_trees(t1: 'MatchTree[A]', t2: 'MatchTree[A]') -> 'MatchTree[A]':
|
def merge_trees(t1: 'MatchTree[A]', t2: 'MatchTree[A]') -> 'MatchTree[A]':
|
||||||
match (t1, t2):
|
match (t1, t2):
|
||||||
|
case (LeafNode(matches1), LeafNode(matches2)):
|
||||||
|
return LeafNode((*matches1, *matches2))
|
||||||
|
case (LeafNode(matches), other_node) | (other_node, LeafNode(matches)):
|
||||||
|
return other_node.fill_empty_leaves(matches)
|
||||||
case (IntNode(location1, specific_trees1, fallback_tree1) as tree1, IntNode(location2, specific_trees2, fallback_tree2) as tree2):
|
case (IntNode(location1, specific_trees1, fallback_tree1) as tree1, IntNode(location2, specific_trees2, fallback_tree2) as tree2):
|
||||||
if location1 == location2:
|
if location1 == location2:
|
||||||
return IntNode(
|
return IntNode(
|
||||||
|
@ -81,10 +95,6 @@ def merge_trees(t1: 'MatchTree[A]', t2: 'MatchTree[A]') -> 'MatchTree[A]':
|
||||||
return tree1.merge_each_child(tree2)
|
return tree1.merge_each_child(tree2)
|
||||||
else:
|
else:
|
||||||
return tree2.merge_each_child(tree1)
|
return tree2.merge_each_child(tree1)
|
||||||
case (IntNode() as int_node, match_node) | (match_node, IntNode() as int_node):
|
|
||||||
return int_node.merge_each_child(match_node)
|
|
||||||
case (LeafNode(matches1), LeafNode(matches2)):
|
|
||||||
return LeafNode((*matches1, *matches2))
|
|
||||||
raise Exception('Unreachable')
|
raise Exception('Unreachable')
|
||||||
|
|
||||||
def merge_all_trees(trees: 'Iterable[MatchTree[A]]') -> 'MatchTree[A]':
|
def merge_all_trees(trees: 'Iterable[MatchTree[A]]') -> 'MatchTree[A]':
|
||||||
|
|
Loading…
Reference in New Issue