Mercurial > hg > Members > kokubo > emacs
comparison .emacs.d/haskell-mode/haskell-debug.el @ 0:2764b4f45f9f
1st commit
author | Shohei KOKUBO <e105744@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 21 Apr 2014 04:30:59 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2764b4f45f9f |
---|---|
1 ;;; haskell-debug.el --- Debugging mode via GHCi | |
2 | |
3 ;; Copyright (c) 2014 Chris Done. All rights reserved. | |
4 | |
5 ;; This file is free software; you can redistribute it and/or modify | |
6 ;; it under the terms of the GNU General Public License as published by | |
7 ;; the Free Software Foundation; either version 3, or (at your option) | |
8 ;; any later version. | |
9 | |
10 ;; This file is distributed in the hope that it will be useful, | |
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 ;; GNU General Public License for more details. | |
14 | |
15 ;; You should have received a copy of the GNU General Public License | |
16 ;; along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | |
18 ;;; Code: | |
19 | |
20 (require 'cl) | |
21 | |
22 (defmacro haskell-debug-with-breakpoints (&rest body) | |
23 "Breakpoints need to exist to start stepping." | |
24 `(if (haskell-debug-get-breakpoints) | |
25 ,@body | |
26 (error "No breakpoints to step into!"))) | |
27 | |
28 (defmacro haskell-debug-with-modules (&rest body) | |
29 "Modules need to exist to do debugging stuff." | |
30 `(if (haskell-debug-get-modules) | |
31 ,@body | |
32 (error "No modules loaded!"))) | |
33 | |
34 (define-derived-mode haskell-debug-mode | |
35 text-mode "Debug" | |
36 "Major mode for debugging Haskell via GHCi.") | |
37 | |
38 (define-key haskell-debug-mode-map (kbd "g") 'haskell-debug/refresh) | |
39 (define-key haskell-debug-mode-map (kbd "s") 'haskell-debug/step) | |
40 (define-key haskell-debug-mode-map (kbd "d") 'haskell-debug/delete) | |
41 (define-key haskell-debug-mode-map (kbd "b") 'haskell-debug/break-on-function) | |
42 (define-key haskell-debug-mode-map (kbd "a") 'haskell-debug/abandon) | |
43 (define-key haskell-debug-mode-map (kbd "c") 'haskell-debug/continue) | |
44 (define-key haskell-debug-mode-map (kbd "p") 'haskell-debug/previous) | |
45 (define-key haskell-debug-mode-map (kbd "n") 'haskell-debug/next) | |
46 (define-key haskell-debug-mode-map (kbd "RET") 'haskell-debug/select) | |
47 | |
48 (defvar haskell-debug-history-cache nil | |
49 "Cache of the tracing history.") | |
50 | |
51 (defvar haskell-debug-bindings-cache nil | |
52 "Cache of the current step's bindings.") | |
53 | |
54 (defun haskell-debug-session-debugging-p (session) | |
55 "Does the session have a debugging buffer open?" | |
56 (not (not (get-buffer (haskell-debug-buffer-name session))))) | |
57 | |
58 (defun haskell-debug () | |
59 "Start the debugger for the current Haskell (GHCi) session." | |
60 (interactive) | |
61 (let ((session (haskell-session))) | |
62 (switch-to-buffer-other-window (haskell-debug-buffer-name session)) | |
63 (unless (eq major-mode 'haskell-debug-mode) | |
64 (haskell-debug-mode) | |
65 (haskell-debug-start session)))) | |
66 | |
67 (defun haskell-debug/delete () | |
68 "Delete whatever's at the point." | |
69 (interactive) | |
70 (cond | |
71 ((get-text-property (point) 'break) | |
72 (let ((break (get-text-property (point) 'break))) | |
73 (when (y-or-n-p (format "Delete breakpoint #%d?" | |
74 (plist-get break :number))) | |
75 (haskell-process-queue-sync-request | |
76 (haskell-process) | |
77 (format ":delete %d" | |
78 (plist-get break :number))) | |
79 (haskell-debug/refresh)))))) | |
80 | |
81 (defun haskell-debug/step (&optional expr) | |
82 "Step into the next function." | |
83 (interactive) | |
84 (haskell-debug-with-breakpoints | |
85 (let* ((breakpoints (haskell-debug-get-breakpoints)) | |
86 (context (haskell-debug-get-context)) | |
87 (string | |
88 (haskell-process-queue-sync-request | |
89 (haskell-process) | |
90 (if expr | |
91 (concat ":step " expr) | |
92 ":step")))) | |
93 (cond | |
94 ((string= string "not stopped at a breakpoint") | |
95 (if haskell-debug-bindings-cache | |
96 (progn (setq haskell-debug-bindings-cache nil) | |
97 (haskell-debug/refresh)) | |
98 (call-interactively 'haskell-debug/start-step))) | |
99 (t (let ((maybe-stopped-at (haskell-debug-parse-stopped-at string))) | |
100 (cond | |
101 (maybe-stopped-at | |
102 (set (make-local-variable 'haskell-debug-bindings-cache) | |
103 maybe-stopped-at) | |
104 (message "Computation paused.") | |
105 (haskell-debug/refresh)) | |
106 (t | |
107 (if context | |
108 (message "Computation finished.") | |
109 (when (y-or-n-p "Computation completed without breaking. Reload the module and retry?") | |
110 (message "Reloading and resetting breakpoints...") | |
111 (haskell-interactive-mode-reset-error (haskell-session)) | |
112 (loop for break in breakpoints | |
113 do (haskell-process-file-loadish | |
114 (concat "load " (plist-get break :path)) | |
115 nil | |
116 nil)) | |
117 (loop for break in breakpoints | |
118 do (haskell-debug-break break)) | |
119 (haskell-debug/step expr))))))))) | |
120 (haskell-debug/refresh))) | |
121 | |
122 (defun haskell-debug/start-step (expr) | |
123 "Start stepping EXPR." | |
124 (interactive (list (read-from-minibuffer "Expression to step through: "))) | |
125 (haskell-debug/step expr)) | |
126 | |
127 (defun haskell-debug/refresh () | |
128 "Refresh the debugger buffer." | |
129 (interactive) | |
130 (with-current-buffer (haskell-debug-buffer-name (haskell-session)) | |
131 (let ((inhibit-read-only t) | |
132 (p (point))) | |
133 (erase-buffer) | |
134 (insert (propertize (concat "Debugging " | |
135 (haskell-session-name (haskell-session)) | |
136 "\n\n") | |
137 'face `((:weight bold)))) | |
138 (let ((modules (haskell-debug-get-modules)) | |
139 (breakpoints (haskell-debug-get-breakpoints)) | |
140 (context (haskell-debug-get-context)) | |
141 (history (haskell-debug-get-history))) | |
142 (unless modules | |
143 (insert (propertize "You have to load a module to start debugging.\n\n" | |
144 'face | |
145 `((:foreground ,sunburn-red))))) | |
146 (haskell-debug-insert-bindings modules breakpoints context) | |
147 (when modules | |
148 (haskell-debug-insert-current-context context history) | |
149 (haskell-debug-insert-breakpoints breakpoints)) | |
150 (haskell-debug-insert-modules modules)) | |
151 (insert "\n") | |
152 (goto-char (min (point-max) p))))) | |
153 | |
154 (defun haskell-debug-break (break) | |
155 "Set BREAK breakpoint in module at line/col." | |
156 (haskell-process-queue-without-filters | |
157 (haskell-process) | |
158 (format ":break %s %s %d" | |
159 (plist-get break :module) | |
160 (plist-get (plist-get break :span) :start-line) | |
161 (plist-get (plist-get break :span) :start-col)))) | |
162 | |
163 (defun haskell-debug-insert-current-context (context history) | |
164 "Insert the current context." | |
165 (haskell-debug-insert-header "Context") | |
166 (if context | |
167 (haskell-debug-insert-context context history) | |
168 (haskell-debug-insert-debug-finished)) | |
169 (insert "\n")) | |
170 | |
171 (defun haskell-debug-insert-debug-finished () | |
172 "Insert message that no debugging is happening, but if there is | |
173 some old history, then display that." | |
174 (if haskell-debug-history-cache | |
175 (progn (haskell-debug-insert-muted "Finished debugging.") | |
176 (insert "\n") | |
177 (haskell-debug-insert-history haskell-debug-history-cache)) | |
178 (haskell-debug-insert-muted "Not debugging right now."))) | |
179 | |
180 (defun haskell-debug-insert-context (context history) | |
181 "Insert the context and history." | |
182 (when context | |
183 (insert (propertize (plist-get context :name) 'face `((:weight bold))) | |
184 (haskell-debug-muted " - ") | |
185 (file-name-nondirectory (plist-get context :path)) | |
186 (haskell-debug-muted " (stopped)") | |
187 "\n")) | |
188 (when haskell-debug-bindings-cache | |
189 (insert "\n") | |
190 (let ((bindings haskell-debug-bindings-cache)) | |
191 (insert | |
192 (haskell-debug-get-span-string | |
193 (plist-get bindings :path) | |
194 (plist-get bindings :span))) | |
195 (insert "\n\n") | |
196 (loop for binding in (plist-get bindings :types) | |
197 do (insert (haskell-fontify-as-mode binding 'haskell-mode) | |
198 "\n")))) | |
199 (let ((history (or history | |
200 (list (haskell-debug-make-fake-history context))))) | |
201 (when history | |
202 (insert "\n") | |
203 (haskell-debug-insert-history history)))) | |
204 | |
205 (defun haskell-debug-insert-history (history) | |
206 "Insert tracing HISTORY." | |
207 (let ((i (length history))) | |
208 (loop for span in history | |
209 do (let ((string (haskell-debug-get-span-string | |
210 (plist-get span :path) | |
211 (plist-get span :span))) | |
212 (index (plist-get span :index))) | |
213 (insert (propertize (format "%4d" i) | |
214 'face `((:weight bold :background ,sunburn-bg+1))) | |
215 " " | |
216 (haskell-debug-preview-span | |
217 (plist-get span :span) | |
218 string | |
219 t) | |
220 "\n") | |
221 (setq i (1- i)))))) | |
222 | |
223 (defun haskell-debug-make-fake-history (context) | |
224 "Make a fake history item." | |
225 (list :index -1 | |
226 :path (plist-get context :path) | |
227 :span (plist-get context :span))) | |
228 | |
229 (defun haskell-debug-preview-span (span string &optional collapsed) | |
230 "Make a one-line preview of the given expression." | |
231 (with-temp-buffer | |
232 (haskell-mode) | |
233 (insert string) | |
234 (when (/= 0 (plist-get span :start-col)) | |
235 (indent-rigidly (point-min) | |
236 (point-max) | |
237 1)) | |
238 (font-lock-fontify-buffer) | |
239 (when (/= 0 (plist-get span :start-col)) | |
240 (indent-rigidly (point-min) | |
241 (point-max) | |
242 -1)) | |
243 (goto-char (point-min)) | |
244 (if collapsed | |
245 (replace-regexp-in-string | |
246 "\n[ ]*" | |
247 (propertize " " 'face `((:background ,sunburn-bg+1))) | |
248 (buffer-substring (point-min) | |
249 (point-max))) | |
250 (buffer-string)))) | |
251 | |
252 (defun haskell-debug-get-span-string (path span) | |
253 "Get the string from the PATH and the SPAN." | |
254 (save-window-excursion | |
255 (find-file path) | |
256 (buffer-substring | |
257 (save-excursion | |
258 (goto-char (point-min)) | |
259 (forward-line (1- (plist-get span :start-line))) | |
260 (forward-char (1- (plist-get span :start-col))) | |
261 (point)) | |
262 (save-excursion | |
263 (goto-char (point-min)) | |
264 (forward-line (1- (plist-get span :end-line))) | |
265 (forward-char (plist-get span :end-col)) | |
266 (point))))) | |
267 | |
268 (defun haskell-debug-insert-bindings (modules breakpoints context) | |
269 "Insert a list of bindings." | |
270 (if breakpoints | |
271 (progn (haskell-debug-insert-binding "s" "step into an expression") | |
272 (haskell-debug-insert-binding "b" "breakpoint" t)) | |
273 (progn | |
274 (when modules | |
275 (haskell-debug-insert-binding "b" "breakpoint")) | |
276 (when breakpoints | |
277 (haskell-debug-insert-binding "s" "step into an expression" t)))) | |
278 (when breakpoints | |
279 (haskell-debug-insert-binding "d" "delete breakpoint")) | |
280 (when context | |
281 (haskell-debug-insert-binding "a" "abandon context") | |
282 (haskell-debug-insert-binding "c" "continue" t)) | |
283 (when context | |
284 (haskell-debug-insert-binding "p" "previous step") | |
285 (haskell-debug-insert-binding "n" "next step" t)) | |
286 (haskell-debug-insert-binding "g" "refresh" t) | |
287 (insert "\n")) | |
288 | |
289 (defun haskell-debug-insert-binding (binding desc &optional end) | |
290 "Insert a helpful keybinding." | |
291 (insert (propertize binding 'face `((:foreground ,sunburn-blue :weight bold))) | |
292 (haskell-debug-muted " - ") | |
293 desc | |
294 (if end | |
295 "\n" | |
296 (haskell-debug-muted ", ")))) | |
297 | |
298 (defun haskell-debug/breakpoint-numbers () | |
299 "List breakpoint numbers." | |
300 (interactive) | |
301 (let ((breakpoints (mapcar (lambda (breakpoint) | |
302 (number-to-string (plist-get breakpoint :number))) | |
303 (haskell-debug-get-breakpoints)))) | |
304 (if (null breakpoints) | |
305 (message "No breakpoints.") | |
306 (message "Breakpoint(s): %s" | |
307 (mapconcat #'identity | |
308 breakpoints | |
309 ", "))))) | |
310 | |
311 (defun haskell-debug/abandon () | |
312 "Abandon the current computation." | |
313 (interactive) | |
314 (haskell-debug-with-breakpoints | |
315 (haskell-process-queue-sync-request (haskell-process) ":abandon") | |
316 (message "Computation abandoned.") | |
317 (setq haskell-debug-history-cache nil) | |
318 (setq haskell-debug-bindings-cache nil) | |
319 (haskell-debug/refresh))) | |
320 | |
321 (defun haskell-debug/continue () | |
322 "Continue the current computation." | |
323 (interactive) | |
324 (haskell-debug-with-breakpoints | |
325 (haskell-process-queue-sync-request (haskell-process) ":continue") | |
326 (message "Computation continued.") | |
327 (setq haskell-debug-history-cache nil) | |
328 (setq haskell-debug-bindings-cache nil) | |
329 (haskell-debug/refresh))) | |
330 | |
331 (defun haskell-debug/break-on-function () | |
332 "Break on function IDENT." | |
333 (interactive) | |
334 (haskell-debug-with-modules | |
335 (let ((ident (read-from-minibuffer "Function: " | |
336 (haskell-ident-at-point)))) | |
337 (haskell-process-queue-sync-request | |
338 (haskell-process) | |
339 (concat ":break " | |
340 ident)) | |
341 (message "Breaking on function: %s" ident) | |
342 (haskell-debug/refresh)))) | |
343 | |
344 (defun haskell-debug/select () | |
345 "Select whatever is at point." | |
346 (interactive) | |
347 (cond | |
348 ((get-text-property (point) 'break) | |
349 (let ((break (get-text-property (point) 'break))) | |
350 (haskell-debug-highlight (plist-get break :path) | |
351 (plist-get break :span)))) | |
352 ((get-text-property (point) 'module) | |
353 (let ((break (get-text-property (point) 'module))) | |
354 (haskell-debug-highlight (plist-get break :path)))))) | |
355 | |
356 (defun haskell-debug/next () | |
357 "Go to next step to inspect bindings." | |
358 (interactive) | |
359 (haskell-debug-with-breakpoints | |
360 (haskell-debug-navigate "forward"))) | |
361 | |
362 (defun haskell-debug/previous () | |
363 "Go to previous step to inspect the bindings." | |
364 (interactive) | |
365 (haskell-debug-with-breakpoints | |
366 (haskell-debug-navigate "back"))) | |
367 | |
368 (defun haskell-debug-highlight (path &optional span) | |
369 "Highlight the file at span." | |
370 (let ((p (make-overlay | |
371 (line-beginning-position) | |
372 (line-end-position)))) | |
373 (overlay-put p 'face `((:background ,sunburn-bg+1))) | |
374 (with-current-buffer | |
375 (if span | |
376 (save-window-excursion | |
377 (find-file path) | |
378 (current-buffer)) | |
379 (find-file path) | |
380 (current-buffer)) | |
381 (let ((o (when span | |
382 (make-overlay | |
383 (save-excursion | |
384 (goto-char (point-min)) | |
385 (forward-line (1- (plist-get span :start-line))) | |
386 (forward-char (1- (plist-get span :start-col))) | |
387 (point)) | |
388 (save-excursion | |
389 (goto-char (point-min)) | |
390 (forward-line (1- (plist-get span :end-line))) | |
391 (forward-char (plist-get span :end-col)) | |
392 (point)))))) | |
393 (when o | |
394 (overlay-put o 'face `((:background ,sunburn-bg+1)))) | |
395 (sit-for 0.5) | |
396 (when o | |
397 (delete-overlay o)) | |
398 (delete-overlay p))))) | |
399 | |
400 (defun haskell-debug-insert-modules (modules) | |
401 "Insert the list of modules." | |
402 (haskell-debug-insert-header "Modules") | |
403 (if (null modules) | |
404 (haskell-debug-insert-muted "No loaded modules.") | |
405 (progn (loop for module in modules | |
406 do (insert (propertize (plist-get module :module) | |
407 'module module | |
408 'face `((:weight bold))) | |
409 (haskell-debug-muted " - ") | |
410 (propertize (file-name-nondirectory (plist-get module :path)) | |
411 'module module))) | |
412 (insert "\n")))) | |
413 | |
414 (defun haskell-debug-insert-header (title) | |
415 "Insert a header title." | |
416 (insert (propertize title | |
417 'face `((:foreground ,sunburn-green))) | |
418 "\n\n")) | |
419 | |
420 (defun haskell-debug-insert-breakpoints (breakpoints) | |
421 "Insert the list of breakpoints." | |
422 (haskell-debug-insert-header "Breakpoints") | |
423 (if (null breakpoints) | |
424 (haskell-debug-insert-muted "No active breakpoints.") | |
425 (loop for break in breakpoints | |
426 do (insert (propertize (format "%d" | |
427 (plist-get break :number)) | |
428 'face `((:weight bold)) | |
429 'break break) | |
430 (haskell-debug-muted " - ") | |
431 (propertize (plist-get break :module) | |
432 'break break | |
433 'break break) | |
434 (haskell-debug-muted | |
435 (format " (%d:%d)" | |
436 (plist-get (plist-get break :span) :start-line) | |
437 (plist-get (plist-get break :span) :start-col))) | |
438 "\n"))) | |
439 (insert "\n")) | |
440 | |
441 (defun haskell-debug-insert-muted (text) | |
442 "Insert some muted text." | |
443 (insert (haskell-debug-muted text) | |
444 "\n")) | |
445 | |
446 (defun haskell-debug-muted (text) | |
447 "Make some muted text." | |
448 (propertize text 'face `((:foreground ,sunburn-grey+1)))) | |
449 | |
450 (defun haskell-debug-buffer-name (session) | |
451 "The debug buffer name for the current session." | |
452 (format "*debug:%s*" | |
453 (haskell-session-name session))) | |
454 | |
455 (defun haskell-debug-start (session) | |
456 "Start the debug mode." | |
457 (setq buffer-read-only t) | |
458 (haskell-session-assign session) | |
459 (haskell-debug/refresh)) | |
460 | |
461 (defun haskell-debug-get-modules () | |
462 "Get the list of modules currently set." | |
463 (let ((string (haskell-process-queue-sync-request | |
464 (haskell-process) | |
465 ":show modules"))) | |
466 (if (string= string "") | |
467 (list) | |
468 (mapcar #'haskell-debug-parse-module | |
469 (split-string | |
470 string | |
471 "\n"))))) | |
472 | |
473 (defun haskell-debug-get-context () | |
474 "Get the current context." | |
475 (let ((string (haskell-process-queue-sync-request | |
476 (haskell-process) | |
477 ":show context"))) | |
478 (if (string= string "") | |
479 nil | |
480 (haskell-debug-parse-context string)))) | |
481 | |
482 (defun haskell-debug-navigate (direction) | |
483 "Navigate in DIRECTION \"back\" or \"forward\"." | |
484 (let ((string (haskell-process-queue-sync-request | |
485 (haskell-process) | |
486 (concat ":" direction)))) | |
487 (let ((bindings (haskell-debug-parse-logged string))) | |
488 (set (make-local-variable 'haskell-debug-bindings-cache) | |
489 bindings) | |
490 (when (not bindings) | |
491 (message "No more %s results!" direction))) | |
492 (haskell-debug/refresh))) | |
493 | |
494 (defun haskell-debug-parse-logged (string) | |
495 "Parse the logged breakpoint." | |
496 (cond | |
497 ((string= "no more logged breakpoints" string) | |
498 nil) | |
499 ((string= "already at the beginning of the history" string) | |
500 nil) | |
501 (t | |
502 (with-temp-buffer | |
503 (insert string) | |
504 (goto-char (point-min)) | |
505 (list :path (progn (search-forward " at ") | |
506 (buffer-substring-no-properties | |
507 (point) | |
508 (1- (search-forward ":")))) | |
509 :span (haskell-debug-parse-span | |
510 (buffer-substring-no-properties | |
511 (point) | |
512 (line-end-position))) | |
513 :types (progn (forward-line) | |
514 (split-string (buffer-substring-no-properties | |
515 (point) | |
516 (point-max)) | |
517 "\n"))))))) | |
518 | |
519 (defun haskell-debug-get-history () | |
520 "Get the step history." | |
521 (let ((string (haskell-process-queue-sync-request | |
522 (haskell-process) | |
523 ":history"))) | |
524 (if (or (string= string "") | |
525 (string= string "Not stopped at a breakpoint")) | |
526 nil | |
527 (if (string= string "Empty history. Perhaps you forgot to use :trace?") | |
528 nil | |
529 (let ((entries (mapcar #'haskell-debug-parse-history-entry | |
530 (remove-if (lambda (line) (string= "<end of history>" line)) | |
531 (split-string | |
532 string | |
533 "\n"))))) | |
534 (set (make-local-variable 'haskell-debug-history-cache) | |
535 entries) | |
536 entries))))) | |
537 | |
538 (defun haskell-debug-parse-history-entry (string) | |
539 "Parse a history entry." | |
540 (if (string-match "^\\([-0-9]+\\)[ ]+:[ ]+\\([A-Za-z0-9_':]+\\)[ ]+(\\([^:]+\\):\\(.+?\\))$" | |
541 string) | |
542 (list :index (string-to-number (match-string 1 string)) | |
543 :name (match-string 2 string) | |
544 :path (match-string 3 string) | |
545 :span (haskell-debug-parse-span (match-string 4 string))) | |
546 (error "Unable to parse history entry: %s" string))) | |
547 | |
548 (defun haskell-debug-parse-context (string) | |
549 "Parse the context." | |
550 (cond | |
551 ((string-match "^--> \\(.+\\)\n \\(.+\\)" string) | |
552 (let ((name (match-string 1 string)) | |
553 (stopped (haskell-debug-parse-stopped-at (match-string 2 string)))) | |
554 (list :name name | |
555 :path (plist-get stopped :path) | |
556 :span (plist-get stopped :span)))))) | |
557 | |
558 (defun haskell-debug-get-breakpoints () | |
559 "Get the list of breakpoints currently set." | |
560 (let ((string (haskell-process-queue-sync-request | |
561 (haskell-process) | |
562 ":show breaks"))) | |
563 (if (string= string "No active breakpoints.") | |
564 (list) | |
565 (mapcar #'haskell-debug-parse-break-point | |
566 (split-string | |
567 string | |
568 "\n"))))) | |
569 | |
570 (defun haskell-debug-parse-stopped-at (string) | |
571 "Parse the location stopped at from the given string. | |
572 | |
573 For example: | |
574 | |
575 Stopped at /home/foo/project/src/x.hs:6:25-36 | |
576 | |
577 " | |
578 (let ((index (string-match "Stopped at \\([^:]+\\):\\(.+\\)\n?" | |
579 string))) | |
580 (when index | |
581 (list :path (match-string 1 string) | |
582 :span (haskell-debug-parse-span (match-string 2 string)) | |
583 :types (cdr (split-string (substring string index) | |
584 "\n")))))) | |
585 | |
586 (defun haskell-debug-parse-module (string) | |
587 "Parse a module and path. | |
588 | |
589 For example: | |
590 | |
591 X ( /home/foo/X.hs, interpreted ) | |
592 | |
593 " | |
594 (if (string-match "^\\([^ ]+\\)[ ]+( \\([^ ]+?\\), [a-z]+ )$" | |
595 string) | |
596 (list :module (match-string 1 string) | |
597 :path (match-string 2 string)) | |
598 (error "Unable to parse module from string: %s" | |
599 string))) | |
600 | |
601 (defun haskell-debug-parse-break-point (string) | |
602 "Parse a breakpoint number, module and location from a string. | |
603 | |
604 For example: | |
605 | |
606 [13] Main /home/foo/src/x.hs:(5,1)-(6,37) | |
607 | |
608 " | |
609 (if (string-match "^\\[\\([0-9]+\\)\\] \\([^ ]+\\) \\([^:]+\\):\\(.+\\)$" | |
610 string) | |
611 (list :number (string-to-number (match-string 1 string)) | |
612 :module (match-string 2 string) | |
613 :path (match-string 3 string) | |
614 :span (haskell-debug-parse-span (match-string 4 string))) | |
615 (error "Unable to parse breakpoint from string: %s" | |
616 string))) | |
617 | |
618 (defun haskell-debug-parse-span (string) | |
619 "Parse a source span from a string. | |
620 | |
621 Examples: | |
622 | |
623 (5,1)-(6,37) | |
624 6:25-36 | |
625 5:20 | |
626 | |
627 People like to make other people's lives interesting by making | |
628 variances in source span notation." | |
629 (cond | |
630 ((string-match "\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)" | |
631 string) | |
632 (list :start-line (string-to-number (match-string 1 string)) | |
633 :start-col (string-to-number (match-string 2 string)) | |
634 :end-line (string-to-number (match-string 1 string)) | |
635 :end-col (string-to-number (match-string 3 string)))) | |
636 ((string-match "\\([0-9]+\\):\\([0-9]+\\)" | |
637 string) | |
638 (list :start-line (string-to-number (match-string 1 string)) | |
639 :start-col (string-to-number (match-string 2 string)) | |
640 :end-line (string-to-number (match-string 1 string)) | |
641 :end-col (string-to-number (match-string 2 string)))) | |
642 ((string-match "(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" | |
643 string) | |
644 (list :start-line (string-to-number (match-string 1 string)) | |
645 :start-col (string-to-number (match-string 2 string)) | |
646 :end-line (string-to-number (match-string 3 string)) | |
647 :end-col (string-to-number (match-string 4 string)))) | |
648 (t (error "Unable to parse source span from string: %s" | |
649 string)))) | |
650 | |
651 (provide 'haskell-debug) | |
652 | |
653 ;; Local Variables: | |
654 ;; byte-compile-warnings: (not cl-functions) | |
655 ;; End: |