@@ -3,7 +3,7 @@ module Breakpoints
3
3
using .. JuliaInterpreter
4
4
using JuliaInterpreter: JuliaFrameCode, JuliaStackFrame, BreakpointState,
5
5
truecondition, falsecondition, prepare_framecode, get_framecode,
6
- sparam_syms, linenumber
6
+ sparam_syms, linenumber, statementnumber
7
7
using Base. Meta: isexpr
8
8
using InteractiveUtils
9
9
@@ -91,18 +91,22 @@ function prepare_slotfunction(framecode::JuliaFrameCode, body::Union{Symbol,Expr
91
91
return Expr (:function , Expr (:call , funcname, framename), Expr (:block , assignments... , body))
92
92
end
93
93
94
+ const Condition = Union{Nothing,Expr,Tuple{Module,Expr}}
95
+ _unpack (condition) = isa (condition, Expr) ? (Main, condition) : condition
96
+
94
97
# # The fundamental implementations of breakpoint-setting
95
- function breakpoint! (framecode:: JuliaFrameCode , pc, condition:: Union{Bool,Expr} = true )
98
+ function breakpoint! (framecode:: JuliaFrameCode , pc, condition:: Condition = nothing )
96
99
stmtidx = convert (Int, pc)
97
- if isa ( condition, Bool)
98
- framecode. breakpoints[stmtidx] = BreakpointState (condition )
100
+ if condition === nothing
101
+ framecode. breakpoints[stmtidx] = BreakpointState ()
99
102
else
100
- fex = prepare_slotfunction (framecode, condition)
101
- framecode. breakpoints[stmtidx] = BreakpointState (true , eval (fex))
103
+ mod, cond = _unpack (condition)
104
+ fex = prepare_slotfunction (framecode, cond)
105
+ framecode. breakpoints[stmtidx] = BreakpointState (true , Core. eval (mod, fex))
102
106
end
103
107
return add_breakpoint (framecode, stmtidx)
104
108
end
105
- breakpoint! (frame:: JuliaStackFrame , pc= frame. pc[], condition:: Union{Bool,Expr} = true ) =
109
+ breakpoint! (frame:: JuliaStackFrame , pc= frame. pc[], condition:: Condition = nothing ) =
106
110
breakpoint! (frame. code, pc, condition)
107
111
108
112
enable (bp:: BreakpointRef ) = bp[] = true
@@ -126,11 +130,16 @@ end
126
130
127
131
"""
128
132
breakpoint(f, sig)
133
+ breakpoint(f, sig, line)
129
134
breakpoint(f, sig, condition)
135
+ breakpoint(f, sig, line, condition)
130
136
breakpoint(...; enter_generated=false)
131
137
132
- Add a breakpoint upon entry to `f` with the specified argument types `sig`.
133
- The first will break unconditionally, the second only if `condition` evaluates to `true`.
138
+ Add a breakpoint to `f` with the specified argument types `sig`.
139
+ Optionally specify an absolute line number `line` in the source file; the default
140
+ is to break upon entry at the first line of the body.
141
+ Without `condition`, the breakpoint will be triggered every time it is encountered;
142
+ the second only if `condition` evaluates to `true`.
134
143
`condition` should be written in terms of the arguments and local variables of `f`.
135
144
136
145
# Example
@@ -142,19 +151,33 @@ end
142
151
breakpoint(radius2, Tuple{Int,Int}, :(y > x))
143
152
```
144
153
"""
145
- function breakpoint (f, sig:: Type , condition:: Union{Bool,Expr} = true ; enter_generated= false )
154
+ function breakpoint (f, sig:: Type , line:: Integer , condition:: Condition = nothing ; enter_generated= false )
155
+ method = which (f, sig)
156
+ framecode, _ = prepare_framecode (method, sig; enter_generated= enter_generated)
157
+ # Don't use statementnumber(method, line) in case it's enter_generated
158
+ linec = line - whereis (method)[2 ] + method. line
159
+ stmtidx = statementnumber (framecode, linec)
160
+ breakpoint! (framecode, stmtidx, condition)
161
+ end
162
+ function breakpoint (f, sig:: Type , condition:: Condition = nothing ; enter_generated= false )
146
163
method = which (f, sig)
147
164
framecode, _ = prepare_framecode (method, sig; enter_generated= enter_generated)
148
165
breakpoint! (framecode, 1 , condition)
149
166
end
150
167
151
168
"""
152
169
breakpoint(method::Method)
170
+ breakpoint(method::Method, line)
153
171
breakpoint(method::Method, condition::Expr)
172
+ breakpoint(method::Method, line, condition::Expr)
154
173
155
- Add a breakpoint upon entry to `method`.
174
+ Add a breakpoint to `method`.
156
175
"""
157
- function breakpoint (method:: Method , condition:: Union{Bool,Expr} = true )
176
+ function breakpoint (method:: Method , line:: Integer , condition:: Condition = nothing )
177
+ framecode, stmtidx = statementnumber (method, line)
178
+ breakpoint! (framecode, stmtidx, condition)
179
+ end
180
+ function breakpoint (method:: Method , condition:: Condition = nothing )
158
181
framecode = get_framecode (method)
159
182
breakpoint! (framecode, 1 , condition)
160
183
end
@@ -165,19 +188,69 @@ end
165
188
166
189
Break-on-entry to all methods of `f`.
167
190
"""
168
- function breakpoint (f, condition:: Union{Bool,Expr} = true )
191
+ function breakpoint (f, condition:: Condition = nothing )
169
192
bps = BreakpointRef[]
170
193
for method in methods (f)
171
194
push! (bps, breakpoint (method, condition))
172
195
end
173
196
return bps
174
197
end
175
198
176
- macro breakpoint (call_expr, condition)
199
+ """
200
+ @breakpoint f(args...) condition=nothing
201
+ @breakpoint f(args...) line condition=nothing
202
+
203
+ Break upon entry, or at the specified line number, in the method called by `f(args...)`.
204
+ Optionally supply a condition expressed in terms of the arguments and internal variables
205
+ of the method.
206
+ If `line` is supplied, it must be a literal integer.
207
+
208
+ # Example
209
+
210
+ Suppose a method `mysum` is defined as follows, where the numbers to the left are the line
211
+ number in the file:
212
+
213
+ ```
214
+ 12 function mysum(A)
215
+ 13 s = zero(eltype(A))
216
+ 14 for a in A
217
+ 15 s += a
218
+ 16 end
219
+ 17 return s
220
+ 18 end
221
+ ```
222
+
223
+ Then
224
+
225
+ ```
226
+ @breakpoint mysum(A) 15 s>10
227
+ ```
228
+
229
+ would cause execution of the loop to break whenever `s>10`.
230
+ """
231
+ macro breakpoint (call_expr, args... )
177
232
whichexpr = InteractiveUtils. gen_call_with_extracted_types (__module__, :which , call_expr)
178
- return quote
179
- local method = $ whichexpr
180
- $ breakpoint (method, $ (Expr (:quote , condition)))
233
+ haveline, line, condition = false , 0 , nothing
234
+ while ! isempty (args)
235
+ arg = first (args)
236
+ if isa (arg, Integer)
237
+ haveline, line = true , arg
238
+ else
239
+ condition = arg
240
+ end
241
+ args = Base. tail (args)
242
+ end
243
+ condexpr = condition === nothing ? nothing : Expr (:quote , condition)
244
+ if haveline
245
+ return quote
246
+ local method = $ whichexpr
247
+ $ breakpoint (method, $ line, $ condexpr)
248
+ end
249
+ else
250
+ return quote
251
+ local method = $ whichexpr
252
+ $ breakpoint (method, $ condexpr)
253
+ end
181
254
end
182
255
end
183
256
0 commit comments