@@ -22,14 +22,23 @@ struct Segment{F}
2222 predicate:: F
2323end
2424
25- ismatch (s:: Segment , t) = s. predicate (t)
26-
2725Segment (s) = Segment (s, alwaystrue)
2826
2927Base. show (io:: IO , s:: Segment ) = (print (io, " ~~" ); print (io, s. name))
3028
3129makesegment (s:: Symbol , keys) = (push! (keys, s); Segment (s))
3230
31+ """
32+ A wrapper for slot and segment predicates which allows them to
33+ take two arguments: the value and a Context
34+ """
35+ struct Contextual{F}
36+ f:: F
37+ end
38+ (c:: Contextual )(args... ) = c. f (args... )
39+
40+ ctxcall (f, x, ctx) = f isa Contextual ? f (x, ctx) : f (x)
41+
3342function makesegment (s:: Expr , keys)
3443 if ! (s. head == :(:: ))
3544 error (" Syntax for specifying a segment is ~~x::\$ predicate, where predicate is a boolean function" )
@@ -91,6 +100,16 @@ function makeconsequent(expr)
91100 return Expr (:call , map (makeconsequent, expr. args)... )
92101 end
93102 else
103+ if expr. head == :macrocall
104+ if expr. args[1 ] === Symbol (" @ctx" )
105+ if length (filter (x-> ! (x isa LineNumberNode), expr. args)) != 1
106+ error (" @ctx takes no arguments. try (@ctx)" )
107+ end
108+ return :__CTX__
109+ else
110+ return esc (expr)
111+ end
112+ end
94113 return Expr (expr. head, map (makeconsequent, expr. args)... )
95114 end
96115 else
@@ -106,21 +125,21 @@ end
106125# 3. Callback: takes arguments Dictionary × Number of elements matched
107126#
108127function matcher (val:: Any )
109- function literal_matcher (data, bindings, next )
128+ function literal_matcher (next, data, bindings, ctx )
110129 ! isempty (data) && isequal (car (data), val) ? next (bindings, 1 ) : nothing
111130 end
112131end
113132
114133function matcher (slot:: Slot )
115- function slot_matcher (data, bindings, next )
134+ function slot_matcher (next, data, bindings, ctx )
116135 isempty (data) && return
117136 val = get (bindings, slot. name, nothing )
118137 if val != = nothing
119138 if isequal (val, car (data))
120139 return next (bindings, 1 )
121140 end
122141 else
123- if slot. predicate ( car (data))
142+ if ctxcall ( slot. predicate, car (data), ctx )
124143 next (assoc (bindings, slot. name, car (data)), 1 )
125144 end
126145 end
@@ -156,7 +175,7 @@ function trymatchexpr(data, value, n)
156175end
157176
158177function matcher (segment:: Segment )
159- function segment_matcher (data, bindings, success )
178+ function segment_matcher (success, data, bindings, ctx )
160179 val = get (bindings, segment. name, nothing )
161180
162181 if val != = nothing
@@ -170,7 +189,7 @@ function matcher(segment::Segment)
170189 for i= length (data): - 1 : 0
171190 subexpr = take_n (data, i)
172191
173- if segment. predicate ( subexpr)
192+ if ctxcall ( segment. predicate, subexpr, ctx )
174193 res = success (assoc (bindings, segment. name, subexpr), i)
175194 if res != = nothing
176195 break
185204
186205function matcher (term:: Term )
187206 matchers = (matcher (operation (term)), map (matcher, arguments (term))... ,)
188- function term_matcher (data, bindings, success )
207+ function term_matcher (success, data, bindings, ctx )
189208
190209 isempty (data) && return nothing
191210 ! (car (data) isa Term) && return nothing
@@ -197,8 +216,9 @@ function matcher(term::Term)
197216 end
198217 return nothing
199218 end
200- res = car (matchers′)(term, bindings′,
201- (b, n) -> loop (drop_n (term, n), b, cdr (matchers′)))
219+ car (matchers′)(term, bindings′, ctx) do b, n
220+ loop (drop_n (term, n), b, cdr (matchers′))
221+ end
202222 end
203223
204224 loop (car (data), bindings, matchers) # Try to eat exactly one term
0 commit comments