@@ -40,13 +40,45 @@ export Empty, IfElse, If, Chain, RestartedChain, Fixpoint, Postwalk, Prewalk, Pa
4040const repr_cache = IdDict ()
4141cached_repr (x) = Base. get! (()-> repr (x), repr_cache, x)
4242
43+ """
44+ Empty()
45+
46+ A rewriter that always returns `nothing`, indicating no rewrite occurred.
47+
48+ This is useful as a placeholder or for conditional rewriting patterns.
49+
50+ # Examples
51+ ```julia
52+ julia> Empty()(x)
53+ nothing
54+ ```
55+ """
4356struct Empty end
4457
4558(rw:: Empty )(x) = nothing
4659
4760instrument (x, f) = f (x)
4861instrument (x:: Empty , f) = x
4962
63+ """
64+ IfElse(cond, yes, no)
65+
66+ A conditional rewriter that applies `yes` if `cond(x)` is true, otherwise applies `no`.
67+
68+ # Arguments
69+ - `cond`: A function that returns true or false for the input
70+ - `yes`: The rewriter to apply if the condition is true
71+ - `no`: The rewriter to apply if the condition is false
72+
73+ # Examples
74+ ```julia
75+ julia> r = IfElse(x -> x > 0, x -> -x, x -> x)
76+ julia> r(5) # Returns -5
77+ julia> r(-3) # Returns -3
78+ ```
79+
80+ See also: [`If`](@ref)
81+ """
5082struct IfElse{F, A, B}
5183 cond:: F
5284 yes:: A
@@ -59,8 +91,46 @@ function (rw::IfElse)(x)
5991 rw. cond (x) ? rw. yes (x) : rw. no (x)
6092end
6193
94+ """
95+ If(cond, yes)
96+
97+ A conditional rewriter that applies `yes` if `cond(x)` is true, otherwise returns the input unchanged.
98+
99+ This is equivalent to `IfElse(cond, yes, Empty())`.
100+
101+ # Arguments
102+ - `cond`: A function that returns true or false for the input
103+ - `yes`: The rewriter to apply if the condition is true
104+
105+ # Examples
106+ ```julia
107+ julia> r = If(x -> x > 0, x -> -x)
108+ julia> r(5) # Returns -5
109+ julia> r(-3) # Returns -3 (unchanged)
110+ ```
111+ """
62112If (f, x) = IfElse (f, x, Empty ())
63113
114+ """
115+ Chain(rws; stop_on_match=false)
116+
117+ Apply a sequence of rewriters to an expression, chaining the results.
118+
119+ Each rewriter in the chain receives the result of the previous rewriter.
120+ If a rewriter returns `nothing`, the input is passed unchanged to the next rewriter.
121+
122+ # Arguments
123+ - `rws`: A collection of rewriters to apply in sequence
124+ - `stop_on_match`: If true, stop at the first rewriter that produces a change
125+
126+ # Examples
127+ ```julia
128+ julia> r1 = @rule sin(~x)^2 + cos(~x)^2 => 1
129+ julia> r2 = @rule sin(2*(~x)) => 2*sin(~x)*cos(~x)
130+ julia> chain = Chain([r1, r2])
131+ julia> chain(sin(x)^2 + cos(x)^2) # Returns 1
132+ ```
133+ """
64134struct Chain
65135 rws
66136 stop_on_match:: Bool
@@ -83,6 +153,25 @@ function (rw::Chain)(x)
83153end
84154instrument (c:: Chain , f) = Chain (map (x-> instrument (x,f), c. rws))
85155
156+ """
157+ RestartedChain(rws)
158+
159+ Apply rewriters in sequence, restarting the chain when any rewriter produces a change.
160+
161+ When any rewriter in the chain produces a non-nothing result, the entire chain
162+ is restarted with that result as the new input.
163+
164+ # Arguments
165+ - `rws`: A collection of rewriters to apply
166+
167+ # Examples
168+ ```julia
169+ julia> r1 = @rule ~x + ~x => 2 * ~x
170+ julia> r2 = @rule 2 * ~x => ~x * 2
171+ julia> chain = RestartedChain([r1, r2])
172+ julia> chain(x + x) # Applies r1, then restarts and applies r2
173+ ```
174+ """
86175struct RestartedChain{Cs}
87176 rws:: Cs
88177end
114203end
115204
116205
206+ """
207+ Fixpoint(rw)
208+
209+ Apply a rewriter repeatedly until a fixed point is reached.
210+
211+ The rewriter is applied repeatedly until the output equals the input
212+ (either by identity or by `isequal`), indicating a fixed point has been reached.
213+
214+ # Arguments
215+ - `rw`: The rewriter to apply repeatedly
216+
217+ # Examples
218+ ```julia
219+ julia> r = @rule ~x + ~x => 2 * ~x
220+ julia> fp = Fixpoint(r)
221+ julia> fp(x + x + x + x) # Keeps applying until no more changes
222+ ```
223+
224+ See also: [`FixpointNoCycle`](@ref)
225+ """
117226struct Fixpoint{C}
118227 rw:: C
119228end
@@ -180,14 +289,80 @@ end
180289using . Threads
181290
182291
292+ """
293+ Postwalk(rw; threaded=false, thread_cutoff=100, maketerm=maketerm)
294+
295+ Apply a rewriter to a symbolic expression tree in post-order (bottom-up).
296+
297+ Post-order traversal visits child nodes before their parents, allowing for
298+ simplification of subexpressions before the containing expression.
299+
300+ # Arguments
301+ - `rw`: The rewriter to apply at each node
302+ - `threaded`: If true, use multi-threading for large expressions
303+ - `thread_cutoff`: Minimum node count to trigger threading
304+ - `maketerm`: Function to construct terms (defaults to `maketerm`)
305+
306+ # Examples
307+ ```julia
308+ julia> r = @rule ~x + ~x => 2 * ~x
309+ julia> pw = Postwalk(r)
310+ julia> pw((x + x) * (y + y)) # Simplifies both additions
311+ 2x * 2y
312+ ```
313+
314+ See also: [`Prewalk`](@ref)
315+ """
183316function Postwalk (rw; threaded:: Bool = false , thread_cutoff= 100 , maketerm= maketerm)
184317 Walk {:post, typeof(rw), typeof(maketerm), threaded} (rw, thread_cutoff, maketerm)
185318end
186319
320+ """
321+ Prewalk(rw; threaded=false, thread_cutoff=100, maketerm=maketerm)
322+
323+ Apply a rewriter to a symbolic expression tree in pre-order (top-down).
324+
325+ Pre-order traversal visits parent nodes before their children, allowing for
326+ transformation of the overall structure before processing subexpressions.
327+
328+ # Arguments
329+ - `rw`: The rewriter to apply at each node
330+ - `threaded`: If true, use multi-threading for large expressions
331+ - `thread_cutoff`: Minimum node count to trigger threading
332+ - `maketerm`: Function to construct terms (defaults to `maketerm`)
333+
334+ # Examples
335+ ```julia
336+ julia> r = @rule sin(~x) => cos(~x)
337+ julia> pw = Prewalk(r)
338+ julia> pw(sin(sin(x))) # Transforms outer sin first
339+ cos(cos(x))
340+ ```
341+
342+ See also: [`Postwalk`](@ref)
343+ """
187344function Prewalk (rw; threaded:: Bool = false , thread_cutoff= 100 , maketerm= maketerm)
188345 Walk {:pre, typeof(rw), typeof(maketerm), threaded} (rw, thread_cutoff, maketerm)
189346end
190347
348+ """
349+ PassThrough(rw)
350+
351+ A rewriter that returns the input unchanged if the wrapped rewriter returns `nothing`.
352+
353+ This is useful for making rewriters that preserve the input when no rule applies.
354+
355+ # Arguments
356+ - `rw`: The rewriter to wrap
357+
358+ # Examples
359+ ```julia
360+ julia> r = @rule sin(~x) => cos(~x)
361+ julia> pt = PassThrough(r)
362+ julia> pt(sin(x)) # Returns cos(x)
363+ julia> pt(tan(x)) # Returns tan(x) unchanged
364+ ```
365+ """
191366struct PassThrough{C}
192367 rw:: C
193368end
0 commit comments