/// <summary> /// Yields all of the nodes in the tree represented by <paramref name="value"/>, starting at the bottom. /// /// <para> /// This is a depth-first post-order traversal. /// </para> /// /// <seealso cref="SelfAndDescendants"/> /// </summary> /// <example> /// <code> /// 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)); /// </code> /// </example> /// <typeparam name="T">The rewritable tree type</typeparam> /// <param name="rewriter">The rewriter</param> /// <param name="value">The value to traverse</param> /// <returns>An enumerable containing all of the nodes in the tree represented by <paramref name="value"/>, starting at the bottom.</returns> public static IEnumerable <T> DescendantsAndSelf <T>(this IRewriter <T> rewriter, T value) { if (rewriter == null) { throw new ArgumentNullException(nameof(rewriter)); } IEnumerable <T> Iterator() { var stack = new Stack <DescendantsAndSelfFrame <T> >(); var initialArray = ArrayPool <T> .Shared.Rent(1); initialArray[0] = value; var enumerator = new DescendantsAndSelfFrame <T>(initialArray, 1); do { while (enumerator.MoveNext()) { stack.Push(enumerator); var count = rewriter.CountChildren(enumerator.Current); var array = ArrayPool <T> .Shared.Rent(count); rewriter.GetChildren(array.AsSpan()[..count], enumerator.Current);
/// <summary> /// Yields all of the nodes in the tree represented by <paramref name="value"/> in a breadth-first traversal order. /// /// <para> /// This is a breadth-first pre-order traversal. /// </para> /// /// </summary> /// <typeparam name="T">The rewritable tree type</typeparam> /// <param name="rewriter">The rewriter</param> /// <param name="value">The value to traverse</param> /// <returns>An enumerable containing all of the nodes in the tree represented by <paramref name="value"/> in a breadth-first traversal order.</returns> public static IEnumerable <T> SelfAndDescendantsBreadthFirst <T>(this IRewriter <T> rewriter, T value) { if (rewriter == null) { throw new ArgumentNullException(nameof(rewriter)); } IEnumerable <T> Iterator() { var queue = new PooledQueue <T>(); queue.AllocateRight(1)[0] = value; try { while (queue.Count != 0) { var x = queue.PopLeft(); yield return(x); var count = rewriter.CountChildren(x); var span = queue.AllocateRight(count); rewriter.GetChildren(span, x); } } finally { queue.Dispose(); } } return(Iterator()); }
/// <summary> /// Yields all of the nodes in the tree represented by <paramref name="value"/>, starting at the top. /// /// <para> /// This is a depth-first pre-order traversal. /// </para> /// /// <seealso cref="DescendantsAndSelf"/> /// </summary> /// <example> /// <code> /// 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)); /// </code> /// </example> /// <typeparam name="T">The rewritable tree type</typeparam> /// <param name="rewriter">The rewriter</param> /// <param name="value">The value to traverse</param> /// <returns>An enumerable containing all of the nodes in the tree represented by <paramref name="value"/>, starting at the top.</returns> public static IEnumerable <T> SelfAndDescendants <T>(this IRewriter <T> rewriter, T value) { if (rewriter == null) { throw new ArgumentNullException(nameof(rewriter)); } IEnumerable <T> Iterator() { var stack = new ChunkStack <T>(); stack.Allocate(1)[0] = value; try { while (!stack.IsEmpty) { var x = stack.Pop(); yield return(x); var count = rewriter.CountChildren(x); var span = stack.Allocate(count); rewriter.GetChildren(span, x); span.Reverse(); // pop them in left to right order } } finally { stack.Dispose(); } } return(Iterator()); }
/// <summary> /// Get the immediate children of the value. /// <seealso cref="IRewritable{T}.GetChildren"/> /// </summary> /// <example> /// Given a representation of the expression <c>(1+2)+3</c>, /// <code> /// Expr expr = new Add( /// new Add( /// new Lit(1), /// new Lit(2) /// ), /// new Lit(3) /// ); /// </code> /// <see cref="GetChildren"/> returns the immediate children of the topmost node. /// <code> /// Expr[] expected = new[] /// { /// new Add( /// new Lit(1), /// new Lit(2) /// ), /// new Lit(3) /// }; /// Assert.Equal(expected, rewriter.GetChildren(expr)); /// </code> /// </example> /// <typeparam name="T">The rewritable tree type</typeparam> /// <param name="rewriter">The rewriter</param> /// <param name="value">The value</param> /// <returns>The immediate children of <paramref name="value"/></returns> public static T[] GetChildren <T>(this IRewriter <T> rewriter, T value) { if (rewriter == null) { throw new ArgumentNullException(nameof(rewriter)); } var count = rewriter.CountChildren(value); var array = new T[count]; rewriter.GetChildren(array, value); return(array); }
internal static async ValueTask <R> WithChildren <T, R>( this IRewriter <T> rewriter, Func <Memory <T>, ValueTask <R> > action, T value, Box <ChunkStack <T> > chunks ) { var count = rewriter.CountChildren(value); var memory = chunks.Value.AllocateMemory(count); rewriter.GetChildren(memory.Span, value); var result = await action(memory).ConfigureAwait(false); chunks.Value.Free(memory); return(result); }
internal static R WithChildren <T, R>( this IRewriter <T> rewriter, SpanFunc <T, R> action, T value, ref ChunkStack <T> chunks ) { var count = rewriter.CountChildren(value); if (count <= 4) { return(WithChildren_Fast(rewriter, action, value, count)); } var span = chunks.Allocate(count); rewriter.GetChildren(span, value); var result = action(span); chunks.Free(span); return(result); }