def _(rep: FixedStitchRepeat, unroll: bool = False) -> Node: # Cases where the only node a fixed stitch repeat contains is another fixed # stitch repeat should be flattened by multiplying the repeat times # together. if (rep.times.value != 1 and len(rep.stitches) == 1 and isinstance(rep.stitches[0], FixedStitchRepeat)): first = rep.stitches[0] assert isinstance(first, FixedStitchRepeat) # noinspection PyTypeChecker return ast_map( replace(rep, stitches=first.stitches, times=NaturalLit.of(first.times.value * rep.times.value), consumes=first.consumes * rep.times.value, produces=first.produces * rep.times.value), partial(_flatten, unroll=unroll)) else: stitches = [] # noinspection PyTypeChecker for stitch in map(partial(_flatten, unroll=unroll), rep.stitches): if (isinstance(stitch, FixedStitchRepeat) and stitch.times.value == 1): # Un-nest fixed stitch repeats that only repeat once. stitches.extend(stitch.stitches) else: stitches.append(stitch) return replace(rep, stitches=stitches)
def reflect(node: Node) -> Node: """ Reflects the AST horizontally. :param node: the AST to reflect :return: the reflected AST """ return ast_map(node, reflect)
def enclose(node: Node, env: Mapping[str, Node]) -> Node: """ Encloses patterns in environment, in order to achieve lexical scoping. :param node: the AST node to enclose :param env: the environment that the pattern should form a closure with :return: an AST with environments baked into the patterns """ # noinspection PyTypeChecker return ast_map(node, partial(enclose, env=env))
def substitute(node: Node, env: Mapping[str, Node]) -> Node: """ Substitutes all variables and calls in the AST with their equivalent expressions. :param node: the AST to transform :param env: the environment :return: the transformed expression with all variables and calls substituted out """ # noinspection PyTypeChecker return ast_map(node, partial(substitute, env=env))
def _alternate_sides(node: Node, side: Side = Side.Right) -> Node: """ Ensures that every row alternates between right and wrong side, starting from the given side. :param node: the AST to alternate the sides of :param side: the side of the first row :return: (1) the AST with every row alternating sides, and (2) the side that the next row should be on """ # noinspection PyTypeChecker return ast_map(node, partial(_alternate_sides, side=side))
def _flatten(node: Node, unroll: bool = False) -> Node: """ Flattens blocks, nested patterns, and nested fixed stitch repeats. :param node: the AST to transform :param unroll: whether to unroll row repeat expressions into a sequence of repeated rows :return: the flattened AST """ # noinspection PyTypeChecker return ast_map(node, partial(_flatten, unroll=unroll))
def infer_counts(node: Node, available: Optional[int] = None) -> Node: """ Tries to count the number of stitches that each node consumes and produces. If not enough information is available for a particular node, its stitch counts are not updated. :param node: the AST to count stitches in :param available: the number of stitches remaining in the current row, if known :return: an AST with as many stitch counts (consumes and produces) as possible filled in """ # noinspection PyTypeChecker return ast_map(node, partial(infer_counts, available=available))
def _roll_repeated_rows(node: Node) -> Node: """ Tries to find repeated sequences of rows to roll up into a row repeat. It uses a naive algorithm that can give weird output in cases where multiple overlapping sequences could be rolled up, but should work OK in most cases. **Note:** This ignores sides when comparing rows for equality (so RS: K and WS: K are considered equal), which mimics the way odd-numbered row repeats are knitted, but this means that :ref:`alternate_sides` must be run before this function. :param node: the AST to search for repeated rows :return: the AST with repeated rows rolled up """ return ast_map(node, _roll_repeated_rows)
def all_to_rs(node: Node) -> Node: return ast_map(node, all_to_rs)
def _combine_stitches(node: Node) -> Node: return ast_map(node, _combine_stitches)
def _increase_expanding_repeats(node: Node, n: int) -> Node: # noinspection PyTypeChecker return ast_map(node, partial(_increase_expanding_repeats, n=n))
def _repeat_across(node: Node, times: int) -> Node: # noinspection PyTypeChecker return ast_map(node, partial(_repeat_across, times=times))