make sure apply() only hits each pattern one

This commit is contained in:
jan 2018-04-15 16:34:52 -07:00
parent 52adb582dc
commit f875ae89d7

View File

@ -98,16 +98,30 @@ class Pattern:
func: Callable[['Pattern'], 'Pattern'] func: Callable[['Pattern'], 'Pattern']
) -> 'Pattern': ) -> 'Pattern':
""" """
Recursively apply func() to this pattern and its subpatterns. Recursively apply func() to this pattern and any pattern it references.
func() is expected to take and return a Pattern. func() is expected to take and return a Pattern.
func() is first applied to the pattern as a whole, then the subpatterns. func() is first applied to the pattern as a whole, then the referenced patterns.
It is only applied to any given pattern once, regardless of how many times it is
referenced.
:param func: Function which accepts a Pattern, and returns a pattern. :param func: Function which accepts a Pattern, and returns a pattern.
:return: The result of applying func() to this pattern and all subpatterns. :return: The result of applying func() to this pattern and all subpatterns.
:raises: PatternError if called on a pattern containing a circular reference.
""" """
pat_map = {id(self): None}
pat = func(self) pat = func(self)
pat_map[id(self)] = pat
for subpat in pat.subpatterns: for subpat in pat.subpatterns:
ref_pat_id = id(subpat.pattern)
if ref_pat_id not in pat_map:
pat_map[ref_pat_id] = None
subpat.pattern = subpat.pattern.apply(func) subpat.pattern = subpat.pattern.apply(func)
pat_map[ref_pat_id] = subpat.pattern
elif pat_map[ref_pat_id] is None:
raise PatternError('.apply() called on pattern with circular reference')
else:
subpat.pattern = pat_map[ref_pat_id]
return pat return pat
def polygonize(self, def polygonize(self,