Skip to content

Commit 48cc5ff

Browse files
authored
Merge pull request #343 from peterahrens/pja/capture-macro
2 parents 95ddcce + 162d419 commit 48cc5ff

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

src/SymbolicUtils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ include("rewriters.jl")
3535
using .Rewriters
3636

3737
using Combinatorics: permutations, combinations
38-
export @rule, @acrule, RuleSet
38+
export @rule, @acrule, RuleSet, @capture
3939

4040
# Rule type and @rule macro
4141
include("rule.jl")

src/rule.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,49 @@ macro rule(expr)
316316
end
317317
end
318318

319+
"""
320+
@capture ex pattern
321+
322+
Uses a `Rule` object to capture an expression if it matches the `pattern`. Returns `true` and injects
323+
slot variable match results into the calling scope when the `pattern` matches, otherwise returns false. The
324+
rule language for specifying the `pattern` is the same in @capture as it is in `@rule`. Contextual matching
325+
is not yet supported
326+
327+
```julia
328+
julia> @syms a; ex = a^a;
329+
330+
julia> if @capture ex (~x)^(~x)
331+
@show x
332+
elseif @capture ex 2(~y)
333+
@show y
334+
end;
335+
x = a
336+
```
337+
338+
See also: [`@rule`](@ref)
339+
"""
340+
macro capture(ex, lhs)
341+
keys = Symbol[]
342+
lhs_term = makepattern(lhs, keys)
343+
unique!(keys)
344+
bind = Expr(:block, map(key-> :($(esc(key)) = getindex(__MATCHES__, $(QuoteNode(key)))), keys)...)
345+
quote
346+
$(__source__)
347+
lhs_pattern = $(lhs_term)
348+
__MATCHES__ = Rule($(QuoteNode(lhs)),
349+
lhs_pattern,
350+
matcher(lhs_pattern),
351+
identity,
352+
rule_depth($lhs_term))($(esc(ex)))
353+
if __MATCHES__ !== nothing
354+
$bind
355+
true
356+
else
357+
false
358+
end
359+
end
360+
end
361+
319362
#-----------------------------
320363
#### Associative Commutative Rules
321364

test/rewrite.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,34 @@ end
4242
@eqtest @rule(+(~~x,~y, ~~x) => (~~x, ~y, ~~x))(term(+,9,8,9,9,8,type=Any)) == ([9,8], 9, [9,8])
4343
@eqtest @rule(+(~~x,~y,~~x) => (~~x, ~y, ~~x))(term(+,6,type=Any)) == ([], 6, [])
4444
end
45+
46+
@testset "Capture form" begin
47+
ex = a^a
48+
49+
#note that @test inserts a soft local scope (try-catch) that would gobble
50+
#the matches from assignment statements in @capture macro, so we call it
51+
#outside the test macro
52+
ret = @capture ex (~x)^(~x)
53+
@test ret
54+
@test @isdefined x
55+
@test x === a
56+
57+
ex = b^a
58+
ret = @capture ex (~y)^(~y)
59+
@test !ret
60+
@test !(@isdefined y)
61+
62+
ret = @capture (a + b) (+)(~~z)
63+
@test ret
64+
@test @isdefined z
65+
@test all(z .=== arguments(a + b))
66+
67+
#a more typical way to use the @capture macro
68+
69+
f(x) = if @capture x (~w)^(~w)
70+
w
71+
end
72+
73+
@eqtest f(b^b) == b
74+
@test f(b+b) == nothing
75+
end

0 commit comments

Comments
 (0)