Sawmill

Class XmlNodeExtensions

Extension methods for XmlNodes.

Inheritance
Declaration
public static class XmlNodeExtensions : Object

Methods

ChildrenInContext(XmlNode)

Returns an array containing each immediate child of value paired with a function to replace the child. This is typically useful when you need to replace a node's children one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the child; calling the function with a new child "plugs the hole" in the context.

SelfAndDescendantsInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static (XmlNode, Func<XmlNode, XmlNode>)[] ChildrenInContext(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to get the contexts for the immediate children

Returns
Type Description

(, )<XmlNode, Func<XmlNode, XmlNode>>[]

See Also
ChildrenInContext<T>(IRewriter<T>, T)

CountChildren(XmlNode)

Count the immediate children of the value. CountChildren()

Declaration
public static int CountChildren(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value

Returns
Type Description

Int32

value's number of immediate children

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
CountChildren(T) counts the immediate children of the topmost (Add) node.
Assert.Equal(2, rewriter.CountChildren(expr));
See Also
CountChildren(T)

Cursor(XmlNode)

Create a Cursor<T>(IRewriter<T>, T) focused on the root node of value.

Declaration
public static Cursor<XmlNode> Cursor(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The root node on which the newly created Cursor<T>(IRewriter<T>, T) should be focused

Returns
Type Description

Cursor<XmlNode>

A Cursor<T>(IRewriter<T>, T) focused on the root node of value

See Also
Cursor<T>(IRewriter<T>, T)

DescendantAt(XmlNode, IEnumerable<Direction>)

Returns the descendant at a particular location in value

Declaration
public static XmlNode DescendantAt(this XmlNode value, IEnumerable<Direction> path)
Parameters
Type Name Description

XmlNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

Returns
Type Description

XmlNode

The descendant found by following the directions in path

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
DescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, T)

DescendantsAndSelf(XmlNode)

Yields all of the nodes in the tree represented by value, starting at the bottom.

This is a depth-first post-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<XmlNode> DescendantsAndSelf(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to traverse

Returns
Type Description

IEnumerable<XmlNode>

An enumerable containing all of the nodes in the tree represented by value, starting at the bottom.

Examples
  Expr expr = new Add(
      new Add(
          new Lit(1),
          new Lit(2)
      ),
      new Lit(3)
  );
  Expr[] expected = new[]
      {
          new Lit(1),
          new Lit(2),
          new Add(new Lit(1), new Lit(2)),
          new Lit(3),
          expr    
      };
  Assert.Equal(expected, rewriter.DescendantsAndSelf(expr));
See Also
DescendantsAndSelf<T>(IRewriter<T>, T)

DescendantsAndSelfInContext(XmlNode)

Yields each node in the tree represented by value paired with a function to replace the node, starting at the bottom. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a depth-first post-order traversal.

DescendantsAndSelf<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)SelfAndDescendantsInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<(XmlNode, Func<XmlNode, XmlNode>)> DescendantsAndSelfInContext(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<(, )<XmlNode, Func<XmlNode, XmlNode>>>

See Also
DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Fold<T>(XmlNode, SpanFunc<T, XmlNode, T>)

Flattens all the nodes in the tree represented by value into a single result, using an aggregation function to combine each node with the results of folding its children.

Declaration
public static T Fold<T>(this XmlNode value, SpanFunc<T, XmlNode, T> func)
Parameters
Type Name Description

XmlNode

value

The value to fold

SpanFunc<T, XmlNode, T>

func

The aggregation function

Returns
Type Description

T

The result of aggregating the tree represented by value.

Type Parameters
Name Description

T

See Also
Fold<T, U>(IRewriter<T>, SpanFunc<U, T, U>, T)
Fold<T, U>(T, SpanFunc<U, T, U>)

Fold<T>(XmlNode, Func<Memory<T>, XmlNode, ValueTask<T>>)

Flattens all the nodes in the tree represented by value into a single result, using an asynchronous aggregation function to combine each node with the results of folding its children.

Declaration
public static ValueTask<T> Fold<T>(this XmlNode value, Func<Memory<T>, XmlNode, ValueTask<T>> func)
Parameters
Type Name Description

XmlNode

value

The value to fold

Func<Memory<T>, XmlNode, ValueTask<T>>

func

The asynchronous aggregation function

Returns
Type Description

ValueTask<T>

The result of aggregating the tree represented by value.

Type Parameters
Name Description

T

Remarks

This method is not available on platforms which do not support ValueTask.

See Also
Fold<T, U>(IRewriter<T>, Func<Memory<U>, T, ValueTask<U>>, T)
Fold<T, U>(T, Func<Memory<U>, T, ValueTask<U>>)

GetChildren(XmlNode)

Get the immediate children of the value. GetChildren(Span<T>)

Declaration
public static XmlNode[] GetChildren(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value

Returns
Type Description

XmlNode[]

The immediate children of value

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
GetChildren<T>(IRewriter<T>, T) returns the immediate children of the topmost node.
Expr[] expected = new[]
    {
        new Add(
            new Lit(1),
            new Lit(2)
        ),
        new Lit(3)
    };
Assert.Equal(expected, rewriter.GetChildren(expr));
See Also
GetChildren<T>(IRewriter<T>, T)

GetChildren(XmlNode, Span<XmlNode>)

Copy the immediate children of the value into childrenReceiver. GetChildren(Span<T>)

Declaration
public static void GetChildren(this XmlNode value, Span<XmlNode> childrenReceiver)
Parameters
Type Name Description

XmlNode

value

The value

Span<XmlNode>

childrenReceiver

A Span<T> to copy value's immediate children into. The Span<T>'s Length will be equal to the number returned by CountChildren(T).

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
GetChildren(Span<T>, T) copies the immediate children of the topmost node into the span.
Expr[] expected = new[]
    {
        new Add(
            new Lit(1),
            new Lit(2)
        ),
        new Lit(3)
    };
var array = new Expr[rewriter.CountChildren(expr)];
rewriter.GetChildren(array, expr);
Assert.Equal(expected, array);
See Also
GetChildren(Span<T>, T)

ReplaceDescendantAt<T>(XmlNode, IEnumerable<Direction>, XmlNode)

Replaces the descendant at a particular location in value

Declaration
public static XmlNode ReplaceDescendantAt<T>(this XmlNode value, IEnumerable<Direction> path, XmlNode newDescendant)
Parameters
Type Name Description

XmlNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

XmlNode

newDescendant

The replacement descendant

Returns
Type Description

XmlNode

A copy of value with newDescendant placed at the location indicated by path

Type Parameters
Name Description

T

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
ReplaceDescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, T, T)

Rewrite(XmlNode, Func<XmlNode, ValueTask<XmlNode>>)

Rebuild a tree by applying an asynchronous transformation function to every node from bottom to top.

Declaration
public static ValueTask<XmlNode> Rewrite(this XmlNode value, Func<XmlNode, ValueTask<XmlNode>> transformer)
Parameters
Type Name Description

XmlNode

value

The value to rewrite

Func<XmlNode, ValueTask<XmlNode>>

transformer

The asynchronous transformation function to apply to every node in the tree

Returns
Type Description

ValueTask<XmlNode>

The result of applying transformer to every node in the tree represented by value.

Remarks

This method is not available on platforms which do not support ValueTask.

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
Rewrite<T>(IRewriter<T>, Func<T, ValueTask<T>>, T) replaces the leaves of the tree with the result of calling transformer,

then replaces their parents with the result of calling transformer, and so on. By the end, Rewrite<T>(IRewriter<T>, Func<T, ValueTask<T>>, T) has traversed the whole tree.

Expr expected = await transformer(new Add(
    await transformer(new Add(
        await transformer(new Lit(1)),
        await transformer(new Lit(2))
    )),
    await transformer(new Lit(3))
));
Assert.Equal(expected, await rewriter.Rewrite(transformer, expr));
See Also
Rewrite<T>(IRewriter<T>, Func<T, ValueTask<T>>, T)

Rewrite(XmlNode, Func<XmlNode, XmlNode>)

Rebuild a tree by applying a transformation function to every node from bottom to top.

Declaration
public static XmlNode Rewrite(this XmlNode value, Func<XmlNode, XmlNode> transformer)
Parameters
Type Name Description

XmlNode

value

The value to rewrite

Func<XmlNode, XmlNode>

transformer

The transformation function to apply to every node in the tree

Returns
Type Description

XmlNode

The result of applying transformer to every node in the tree represented by value.

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
Rewrite<T>(IRewriter<T>, Func<T, T>, T) replaces the leaves of the tree with the result of calling transformer,

then replaces their parents with the result of calling transformer, and so on. By the end, Rewrite<T>(IRewriter<T>, Func<T, T>, T) has traversed the whole tree.

Expr expected = transformer(new Add(
    transformer(new Add(
        transformer(new Lit(1)),
        transformer(new Lit(2))
    )),
    transformer(new Lit(3))
));
Assert.Equal(expected, rewriter.Rewrite(transformer, expr));
See Also
Rewrite<T>(IRewriter<T>, Func<T, T>, T)

RewriteChildren(XmlNode, Func<XmlNode, ValueTask<XmlNode>>)

Update the immediate children of the value by applying an asynchronous transformation function to each one.

Declaration
public static ValueTask<XmlNode> RewriteChildren(this XmlNode value, Func<XmlNode, ValueTask<XmlNode>> transformer)
Parameters
Type Name Description

XmlNode

value

The old value, whose immediate children should be transformed by transformer.

Func<XmlNode, ValueTask<XmlNode>>

transformer

An asynchronous transformation function to apply to each of value's immediate children.

Returns
Type Description

ValueTask<XmlNode>

A copy of value with updated children.

Remarks

This method is not available on platforms which do not support ValueTask.

See Also
RewriteChildren<T>(IRewriter<T>, Func<T, ValueTask<T>>, T)

RewriteChildren(XmlNode, Func<XmlNode, XmlNode>)

Update the immediate children of the value by applying a transformation function to each one.

Declaration
public static XmlNode RewriteChildren(this XmlNode value, Func<XmlNode, XmlNode> transformer)
Parameters
Type Name Description

XmlNode

value

The old value, whose immediate children should be transformed by transformer.

Func<XmlNode, XmlNode>

transformer

A transformation function to apply to each of value's immediate children.

Returns
Type Description

XmlNode

A copy of value with updated children.

See Also
RewriteChildren<T>(IRewriter<T>, Func<T, T>, T)

RewriteDescendantAt<T>(XmlNode, IEnumerable<Direction>, Func<XmlNode, ValueTask<XmlNode>>)

Apply an asynchronous function at a particular location in value

Declaration
public static ValueTask<XmlNode> RewriteDescendantAt<T>(this XmlNode value, IEnumerable<Direction> path, Func<XmlNode, ValueTask<XmlNode>> transformer)
Parameters
Type Name Description

XmlNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

Func<XmlNode, ValueTask<XmlNode>>

transformer

An asynchronous function to calculate a replacement for the descendant

Returns
Type Description

ValueTask<XmlNode>

A copy of value with the result of transformer placed at the location indicated by path

Type Parameters
Name Description

T

Remarks

This method is not available on platforms which do not support ValueTask.

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
RewriteDescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, Func<T, ValueTask<T>>, T)

RewriteDescendantAt<T>(XmlNode, IEnumerable<Direction>, Func<XmlNode, XmlNode>)

Apply a function at a particular location in value

Declaration
public static XmlNode RewriteDescendantAt<T>(this XmlNode value, IEnumerable<Direction> path, Func<XmlNode, XmlNode> transformer)
Parameters
Type Name Description

XmlNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

Func<XmlNode, XmlNode>

transformer

A function to calculate a replacement for the descendant

Returns
Type Description

XmlNode

A copy of value with the result of transformer placed at the location indicated by path

Type Parameters
Name Description

T

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
RewriteDescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, Func<T, T>, T)

RewriteIter(XmlNode, Func<XmlNode, ValueTask<XmlNode>>)

Rebuild a tree by repeatedly applying an asynchronous transformation function to every node in the tree, until a fixed point is reached. transformer should always eventually return its argument unchanged, or this method will loop. That is, x.RewriteIter(transformer).SelfAndDescendants().All(x => await transformer(x) == x).

This is typically useful when you want to put your tree into a normal form by applying a collection of rewrite rules until none of them can fire any more.

Declaration
public static ValueTask<XmlNode> RewriteIter(this XmlNode value, Func<XmlNode, ValueTask<XmlNode>> transformer)
Parameters
Type Name Description

XmlNode

value

The value to rewrite

Func<XmlNode, ValueTask<XmlNode>>

transformer

An asynchronous transformation function to apply to every node in value repeatedly.

Returns
Type Description

ValueTask<XmlNode>

The result of applying transformer to every node in the tree represented by value repeatedly until a fixed point is reached.

Remarks

This method is not available on platforms which do not support ValueTask.

See Also
RewriteIter<T>(IRewriter<T>, Func<T, ValueTask<T>>, T)

RewriteIter(XmlNode, Func<XmlNode, XmlNode>)

Rebuild a tree by repeatedly applying a transformation function to every node in the tree, until a fixed point is reached. transformer should always eventually return its argument unchanged, or this method will loop. That is, x.RewriteIter(transformer).SelfAndDescendants().All(x => transformer(x) == x).

This is typically useful when you want to put your tree into a normal form by applying a collection of rewrite rules until none of them can fire any more.

Declaration
public static XmlNode RewriteIter(this XmlNode value, Func<XmlNode, XmlNode> transformer)
Parameters
Type Name Description

XmlNode

value

The value to rewrite

Func<XmlNode, XmlNode>

transformer

A transformation function to apply to every node in value repeatedly.

Returns
Type Description

XmlNode

The result of applying transformer to every node in the tree represented by value repeatedly until a fixed point is reached.

See Also
RewriteIter<T>(IRewriter<T>, Func<T, T>, T)

SelfAndDescendants(XmlNode)

Yields all of the nodes in the tree represented by value, starting at the top.

This is a depth-first pre-order traversal.

DescendantsAndSelf<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<XmlNode> SelfAndDescendants(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to traverse

Returns
Type Description

IEnumerable<XmlNode>

An enumerable containing all of the nodes in the tree represented by value, starting at the top.

Examples
  Expr expr = new Add(
      new Add(
          new Lit(1),
          new Lit(2)
      ),
      new Lit(3)
  );
  Expr[] expected = new[]
      {
          expr,
          new Add(new Lit(1), new Lit(2)),
          new Lit(1),
          new Lit(2),
          new Lit(3),
      };
  Assert.Equal(expected, rewriter.SelfAndDescendants(expr));
See Also
SelfAndDescendants<T>(IRewriter<T>, T)

SelfAndDescendantsBreadthFirst(XmlNode)

Yields all of the nodes in the tree represented by value in a breadth-first traversal order.

This is a breadth-first pre-order traversal.

Declaration
public static IEnumerable<XmlNode> SelfAndDescendantsBreadthFirst(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to traverse

Returns
Type Description

IEnumerable<XmlNode>

An enumerable containing all of the nodes in the tree represented by value in a breadth-first traversal order.

See Also
SelfAndDescendantsBreadthFirst<T>(IRewriter<T>, T)

SelfAndDescendantsInContext(XmlNode)

Yields each node in the tree represented by value paired with a function to replace the node, starting at the top. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a depth-first pre-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<(XmlNode, Func<XmlNode, XmlNode>)> SelfAndDescendantsInContext(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<(, )<XmlNode, Func<XmlNode, XmlNode>>>

See Also
SelfAndDescendantsInContext<T>(IRewriter<T>, T)

SelfAndDescendantsInContextBreadthFirst(XmlNode)

Yields each node in the tree represented by value paired with a function to replace the node, in a breadth-first traversal order. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a breadth-first pre-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<(XmlNode, Func<XmlNode, XmlNode>)> SelfAndDescendantsInContextBreadthFirst(this XmlNode value)
Parameters
Type Name Description

XmlNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<(, )<XmlNode, Func<XmlNode, XmlNode>>>

See Also
SelfAndDescendantsInContextBreadthFirst<T>(IRewriter<T>, T)

SetChildren(XmlNode, ReadOnlySpan<XmlNode>)

Set the immediate children of the value.

Callers should ensure that newChildren contains the same number of children as was returned by GetChildren(Span<T>, T).

SetChildren(ReadOnlySpan<T>)

Declaration
public static XmlNode SetChildren(this XmlNode value, ReadOnlySpan<XmlNode> newChildren)
Parameters
Type Name Description

XmlNode

value

The old value, whose immediate children should be replaced

ReadOnlySpan<XmlNode>

newChildren

The new children

Returns
Type Description

XmlNode

A copy of value with updated children.

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
SetChildren(ReadOnlySpan<T>, T) replaces the immediate children of the topmost node.
Expr expected = new Add(
    new Lit(4),
    new Lit(5)
);
Assert.Equal(expected, rewriter.SetChildren(Children.Two(new Lit(4), new Lit(5)), expr));
See Also
SetChildren(ReadOnlySpan<T>, T)

ZipFold<U>(XmlNode, XmlNode, Func<XmlNode, XmlNode, IAsyncEnumerable<U>, ValueTask<U>>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static ValueTask<U> ZipFold<U>(this XmlNode value1, XmlNode value2, Func<XmlNode, XmlNode, IAsyncEnumerable<U>, ValueTask<U>> func)
Parameters
Type Name Description

XmlNode

value1

XmlNode

value2

Func<XmlNode, XmlNode, IAsyncEnumerable<U>, ValueTask<U>>

func

The aggregation function

Returns
Type Description

ValueTask<U>

The result of aggregating the two trees

Type Parameters
Name Description

U

Remarks

This method is not available on platforms which do not support ValueTask and IAsyncEnumerable<T>.

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IAsyncEnumerable<U>, ValueTask<U>>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IAsyncEnumerable<U>, ValueTask<U>>, T[])

ZipFold<U>(XmlNode, XmlNode, Func<XmlNode, XmlNode, IEnumerable<U>, U>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static U ZipFold<U>(this XmlNode value1, XmlNode value2, Func<XmlNode, XmlNode, IEnumerable<U>, U> func)
Parameters
Type Name Description

XmlNode

value1

XmlNode

value2

Func<XmlNode, XmlNode, IEnumerable<U>, U>

func

The aggregation function

Returns
Type Description

U

The result of aggregating the two trees

Type Parameters
Name Description

U

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[])

ZipFold<U>(XmlNode[], Func<XmlNode[], IAsyncEnumerable<U>, ValueTask<U>>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static ValueTask<U> ZipFold<U>(this XmlNode[] values, Func<XmlNode[], IAsyncEnumerable<U>, ValueTask<U>> func)
Parameters
Type Name Description

XmlNode[]

values

The trees to fold

Func<XmlNode[], IAsyncEnumerable<U>, ValueTask<U>>

func

The aggregation function

Returns
Type Description

ValueTask<U>

The result of aggregating the two trees

Type Parameters
Name Description

U

Remarks

This method is not available on platforms which do not support ValueTask and IAsyncEnumerable<T>.

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IAsyncEnumerable<U>, ValueTask<U>>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IAsyncEnumerable<U>, ValueTask<U>>, T[])

ZipFold<U>(XmlNode[], Func<XmlNode[], IEnumerable<U>, U>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static U ZipFold<U>(this XmlNode[] values, Func<XmlNode[], IEnumerable<U>, U> func)
Parameters
Type Name Description

XmlNode[]

values

The trees to fold

Func<XmlNode[], IEnumerable<U>, U>

func

The aggregation function

Returns
Type Description

U

The result of aggregating the two trees

Type Parameters
Name Description

U

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[])