3 (declaim (optimize (safety 2) (space 3)))
7 #-gcl
(:compile-toplevel
:execute
)
9 (defmacro f
(op &rest args
)
10 `(the fixnum
(,op
,@ (mapcar #'(lambda (x) `(the fixnum
,x
)) args
))))
12 (defmacro fb
(op &rest args
)
13 `(,op
,@ (mapcar #'(lambda (x) `(the fixnum
,x
)) args
))))
15 (defstruct (line-info (:type list
)) line file
)
17 (defstruct (bkpt (:type list
)) form file file-line function
)
19 ;; *mlambda-call-stack*
20 ;; #(NIL ($X) (1) $FF ($BIL $X) ($Y) (36) $JOE ($Y $BIL $X) ($JJX) (36)
21 ;; to get to current values in ff need to unbind bindlist downto ($BIL $X)
22 ;; to get to current values in joe need to unbind bindlist downto ($Y $BIL $X)
24 (defvar *current-frame
* 0)
26 (defvar $mdebug_print_length
100 "Length of forms to print out in debugger")
28 (defvar *lisp-quiet-suppressed-prompt
* "" "The prompt lisp-quiet has suppressed")
32 (let* ((ar *mlambda-call-stack
*)
34 fname vals params backtr lineinfo bdlist
)
36 ;; just in case we do not have an even multiple
37 (setq m
(f - m
(f mod m
5) (* n
5)))
38 (if (<= m
0) (return-from frame-info nil
))
39 (setq fname
(aref ar
(f- m
1)))
40 (setq vals
(aref ar
(f- m
2)))
41 (setq params
(aref ar
(f- m
3)))
42 (setq backtr
(aref ar
(f- m
4)))
43 (setq bdlist
(if (< m
(fill-pointer ar
)) (aref ar m
) bindlist
))
44 ; (setq lineinfo (get-lineinfo backtr))
45 (setq lineinfo
(if ( < m
(fill-pointer ar
))
46 (get-lineinfo (aref ar
(f+ m
1)))
47 (get-lineinfo *last-meval1-form
*)))
48 (values fname vals params backtr lineinfo bdlist
)))
50 (defun print-one-frame (n print-frame-number
&aux val
(st *debug-io
*))
52 (fname vals params backtr lineinfo bdlist
)
55 (princ (if print-frame-number
56 ($sconcat
"#" n
": " fname
"(")
59 (loop for v on params for w in vals
60 do
(setq val
($sconcat w
))
61 (if (> (length val
) 100)
62 (setq val
($sconcat
(subseq val
0 100) "...")))
63 (format st
"~(~a~)=~a~a" ($sconcat
(car v
)) val
67 (format st
(intl:gettext
" (~a line ~a)")
68 (short-name (cadr lineinfo
)) (car lineinfo
)))
70 (values fname vals params backtr lineinfo bdlist
))
73 ;; these are in the system package in gcl...
75 (progn (defun break-call (key args prop
&aux fun
)
76 (setq fun
(complete-prop key
'keyword prop
))
78 (or fun
(return-from break-call nil
))
79 (setq fun
(get fun prop
))
82 (setf (symbol-function gen
) fun
) (setf (get key prop
) gen
)
85 (setq args
(cons fun args
))
87 #+gcl
(evalhook args nil nil
*break-env
*)
91 (intl:gettext
"~&~S is an undefined break command.~%")
94 (defun complete-prop (sym package prop
&optional return-list
)
95 (cond ((and (symbolp sym
)(get sym prop
)(equal (symbol-package sym
)
96 (find-package package
)))
97 (return-from complete-prop sym
)))
98 (loop for vv being the symbols of package
99 when
(and (get vv prop
)
100 (eql #+gcl
(string-match sym vv
)
101 #-gcl
(search (symbol-name sym
)
107 (cond (return-list (return-from complete-prop all
))
110 (intl:gettext
"~&Break command '~(~s~)' is ambiguous.~%")
113 (intl:gettext
"Perhaps you meant one of the following: ~(~{~s~^, ~}~).")
115 (finish-output *debug-io
*))
118 (intl:gettext
"~&Break command '~(~s~)' does not exist.")
120 (finish-output *debug-io
*))
121 (t (return-from complete-prop
124 (defmfun $backtrace
(&optional
(n 0 n-p
))
125 (unless (typep n
'(integer 0))
127 (intl:gettext
"backtrace: number of frames must be a nonnegative integer; got ~M~%")
131 for j from
*current-frame
*
132 when
(and n-p
(= i n
))
134 while
(print-one-frame j t
))))
136 ;; if this is NIL then nothing more is checked in eval
138 (defvar *break-points
* nil
)
139 (defvar *break-point-vector
* (make-array 10 :fill-pointer
0 :adjustable t
))
141 (defun init-break-points ()
142 (setf (fill-pointer *break-point-vector
*) 0)
143 (setf *break-points
* *break-point-vector
*))
145 (defvar *break-step
* nil
)
146 (defvar *step-next
* nil
)
148 (defun step-into (&optional ignored
)
149 (declare (ignore ignored
))
150 (or *break-points
* (init-break-points))
151 (setq *break-step
* 'break-step-into
)
154 (defun step-next (&optional
(n 1))
155 (let ((fun (current-step-fun)))
156 (setq *step-next
* (cons n fun
))
157 (or *break-points
* (init-break-points))
158 (setq *break-step
* 'break-step-next
)
161 (defun maybe-break (form line-info fun env
&aux pos
)
162 (declare (ignore env
))
163 (cond ((setq pos
(position form line-info
))
164 (setq *break-step
* nil
)
165 (or (> (length *break-points
*) 0)
166 (setf *break-points
* nil
))
167 (break-dbm-loop (make-break-point fun line-info pos
))
170 ;; These following functions, when they are the value of *break-step*
171 ;; are invoked by an inner hook in eval. They may choose to stop things.
172 (defun break-step-into (form &optional env
)
173 (let ((fun (current-step-fun)))
174 (let ((line-info (set-full-lineinfo fun
)))
176 (maybe-break form line-info fun env
)))))
178 (defun break-step-next (form &optional env
)
179 (let ((fun (current-step-fun)))
180 (cond ((eql (cdr *step-next
*) fun
)
181 (let ((line-info (set-full-lineinfo fun
)))
182 (maybe-break form line-info fun env
))))))
184 (defvar *lineinfo-array-internal
* nil
)
186 ;; the lineinfo for a function will be a vector of forms
187 ;; such that each one is the first form on a line.
188 ;; we will walk thru the tree taking the first occurrence
190 (defun set-full-lineinfo (fname &aux te
)
191 (let ((body (get fname
'lineinfo
)))
192 (cond ((atom body
) (return-from set-full-lineinfo body
))
193 (t (cond ((null *lineinfo-array-internal
*)
194 (setq *lineinfo-array-internal
*
195 (make-array 20 :fill-pointer
0 :adjustable t
)))
196 (t (setf (fill-pointer *lineinfo-array-internal
*) 0)))
197 (cond ((setq te
(get-lineinfo body
))
198 (vector-push (car te
) *lineinfo-array-internal
*)
199 (walk-get-lineinfo body
*lineinfo-array-internal
*)))
200 (cond ((> (fill-pointer *lineinfo-array-internal
*) 0)
201 (setf (get fname
'lineinfo
)
202 (copy-seq *lineinfo-array-internal
*)))
203 (t (setf (get fname
'lineinfo
) nil
)))))))
205 (defun walk-get-lineinfo (form ar
&aux
(i 0) tem
)
206 (declare (type (vector t
) ar
) (fixnum i
))
207 (cond ((atom form
) nil
)
208 ((setq tem
(get-lineinfo form
))
209 (setq i
(f -
(line-info-line tem
) (aref ar
0) -
1))
210 (cond ((< i
(fill-pointer ar
))
212 (setf (aref ar i
) form
)))
214 (unless (< i
(array-total-size ar
))
215 (setq ar
(adjust-array ar
(+ i
20) :fill-pointer
217 (loop for j from
(fill-pointer ar
) below i
218 do
(setf (aref ar j
) nil
))
219 (setf (fill-pointer ar
) (f + i
1))
220 (setf (aref ar i
) form
)))
221 (loop for v in
(cdr form
)
223 (walk-get-lineinfo v ar
))))))
225 (defun first-form-line (form line
&aux tem
)
226 (cond ((atom form
) nil
)
227 ((and (setq tem
(get-lineinfo form
)) (eql (car tem
) line
))
229 (t (loop for v in
(cdr form
)
230 when
(setq tem
(first-form-line v line
))
231 do
(return-from first-form-line tem
)))))
233 (defvar *last-dbm-command
* nil
)
235 ;; split string into a list of strings, split by any of a list of characters
236 ;; in bag. Returns a list. They will have fill pointers..
237 (defun split-string (string bag
&optional
(start 0) &aux all pos v l
)
238 (declare (fixnum start
) (type string string
))
239 (loop for i from start below
(length string
)
240 do
(setq pos
(position (setq v
(aref string i
)) bag
))
241 (setq start
(+ start
1))
242 (cond ((null pos
) (push v all
))
243 (t (if all
(loop-finish))))
246 (return-from split-string
248 (make-array (setq l
(length all
))
251 :initial-contents
(nreverse all
)
253 ' #.
(array-element-type "ab"))
254 (split-string string bag start
))))))
256 (declaim (special *mread-prompt
*))
258 (defvar *need-prompt
* t
)
260 ;; STREAM, EOF-ERROR-P and EOF-VALUE are analogous to the corresponding
261 ;; arguments to Lisp's READ. REPEAT-IF-NEWLINE, when T, says to repeat
262 ;; the last break command (if available) when only a newline is read.
263 (defun dbm-read (&optional
(stream *standard-input
*) (eof-error-p t
)
264 (eof-value nil
) repeat-if-newline
&aux tem ch
265 (mprompt *mread-prompt
*) (*mread-prompt
* ""))
266 (if (and *need-prompt
* (> (length mprompt
) 0))
268 (fresh-line *standard-output
*)
269 (princ mprompt
*standard-output
*)
270 (finish-output *standard-output
*)
271 (setf *prompt-on-read-hang
* nil
))
273 (setf *prompt-on-read-hang
* t
)
274 (setf *read-hang-prompt
* mprompt
)))
276 ;; Read a character to see what we should do.
279 (setq ch
(read-char stream eof-error-p eof-value
))
280 (cond ((or (eql ch
#\newline
) (eql ch
#\return
))
281 (if (and repeat-if-newline
*last-dbm-command
*)
282 (return-from dbm-read
*last-dbm-command
*))
285 (return-from dbm-read eof-value
)))
286 ;; Put that character back, so we can reread the line correctly.
287 (unread-char ch stream
))
289 ;; Figure out what to do
291 ;; This is a Maxima debugger command (I think)
292 (let* ((line (read-line stream eof-error-p eof-value
))
296 (read-from-string line
)
297 (setq fun
(complete-prop keyword
'keyword
'break-command
))
298 (and (consp fun
) (setq fun
(car fun
)))
299 ;;(print (list 'line line))
300 (setq *last-dbm-command
*
301 (cond ((null fun
) '(:_none
))
302 ((get fun
'maxima-read
)
303 (cons keyword
(mapcar 'macsyma-read-string
304 (split-string line
" " n
))))
306 ($sconcat
"(" (string-right-trim ";" line
)
308 ;;(print (list 'tem tem))
309 (read (make-string-input-stream tem
)
310 eof-error-p eof-value
)))))))
312 ;; Process "?" lines. This is either a call to describe or a
313 ;; quick temporary escape to Lisp to call some Lisp function.
315 ;; First, read and discard the #\? since we don't need it anymore.
317 (let ((next (peek-char nil stream nil
)))
318 (cond ((member next
'(#\space
#\tab
#\
!))
319 ;; Got "? <stuff>" or "?! <stuff>".
320 ;; Invoke exact search on <stuff>.
321 (let* ((line (string-trim
322 '(#\space
#\tab
#\
; #\$)
324 (read-line stream eof-error-p eof-value
) 1))))
325 `((displayinput) nil
(($describe
) ,line $exact
))))
327 ;; Got "?? <stuff>". Invoke inexact search on <stuff>.
328 (let* ((line (string-trim
329 '(#\space
#\tab
#\
; #\$)
331 (read-line stream eof-error-p eof-value
) 1))))
332 `((displayinput) nil
(($describe
) ,line $inexact
))))
334 ;; Got "?<stuff>" This means a call to a Lisp
335 ;; function. Pass this on to mread which can handle
338 ;; Note: There appears to be a bug in Allegro 6.2
339 ;; where concatenated streams don't wait for input
340 ;; on *standard-input*.
341 (mread (make-concatenated-stream
342 (make-string-input-stream "?") stream
)
345 (setq *last-dbm-command
* nil
)
346 (let ((result (mread stream eof-value
))
347 (next-char (read-char-no-hang stream eof-error-p eof-value
)))
349 ((or (eql next-char nil
) (equal next-char
'(nil)))
350 (setf *need-prompt
* t
))
351 ((member next-char
'(#\newline
#\return
))
352 (setf *need-prompt
* t
))
354 (setf *need-prompt
* nil
)
355 (unread-char next-char stream
)))
358 (defvar *break-level
* nil
)
359 (defvar *break-env
* nil
)
360 (defvar *top-eof
* (cons nil nil
))
361 (defvar *quit-tag
* 'macsyma-quit
)
363 (defvar *quit-tags
* nil
)
365 (defun set-env (bkpt)
367 (intl:gettext
"(~a line ~a~@[, in function ~a~])")
368 (short-name (bkpt-file bkpt
))
369 (bkpt-file-line bkpt
)
370 (bkpt-function bkpt
))
371 (format *debug-io
* "~&\x1a\x1a~a:~a::~%" (bkpt-file bkpt
)
372 (bkpt-file-line bkpt
)))
374 (defvar *diff-mspeclist
* nil
)
375 (defvar *diff-bindlist
* nil
)
377 (defun break-dbm-loop (at)
378 (let* ((*quit-tags
* (cons (cons *break-level
* *quit-tag
*) *quit-tags
*))
379 (*break-level
* (if (not at
) *break-level
* (cons t
*break-level
*)))
380 (*quit-tag
* (cons nil nil
))
381 (*break-env
* *break-env
*)
383 (*diff-bindlist
* nil
)
384 (*diff-mspeclist
* nil
)
386 (declare (special *mread-prompt
*))
387 (and (consp at
) (set-env at
))
389 (break-frame 0 nil
)))
390 (catch 'step-continue
394 (format-prompt *debug-io
* "~&~a"
395 (format nil
"~@[(~a:~a) ~]"
396 (unless (stringp at
) "dbm")
397 (length *quit-tags
*)))
398 (finish-output *debug-io
*)
401 (let ((res (dbm-read *debug-io
* nil
*top-eof
* t
)))
402 (declare (special *mread-prompt
*))
403 (cond ((and (consp res
) (keywordp (car res
)))
404 (let ((value (break-call (car res
)
407 (cond ((eq value
:resume
) (return)))))
409 (funcall (get :top
'break-command
)))
411 (setq $__
(nth 2 res
))
412 (setq $%
(meval* $__
))
417 (throw-macsyma-top)))
418 (restore-bindings))))))
420 (defun break-quit (&optional
(level 0)
421 &aux
(current-level (length *break-level
*)))
422 (when (and (>= level
0) (< level current-level
))
423 (let ((x (nth (- current-level level
1) *quit-tags
*)))
424 (if (eq (cdr x
) 'macsyma-quit
)
425 (throw 'macsyma-quit
'top
)
426 (throw (cdr x
) (cdr x
)))))
427 (throw 'macsyma-quit
'top
))
429 (defun break-current ()
432 (intl:gettext
"Back to level ~:@(~S~).")
433 (length *break-level
*))
434 (format *debug-io
* (intl:gettext
"~&Top level.")))
437 (defun def-break (keyword fun doc
)
438 (setf (get keyword
'break-command
) fun
)
439 (and doc
(setf (get keyword
'break-doc
) doc
)))
441 (defun break-help (&optional key
)
444 (dolist (v (complete-prop key
'keyword
'break-doc t
))
445 (format t
"~&~%~(~s~) ~a" v
(get v
'break-doc
)))))
447 ; Skip any undocumented break commands
448 (loop for vv being the symbols of
'keyword
449 when
(and (get vv
'break-command
) (get vv
'break-doc
))
450 collect
(cons vv
(get vv
'break-doc
))
452 finally
(setq all
(sort all
'alphalessp
))
453 (format t
(intl:gettext
"~
454 Break commands start with ':'. Any unique substring may be used,~%~
455 eg :r :re :res all work for :resume.~2%~
456 Command Description~%~
457 ----------- --------------------------------------"))
459 do
(format t
"~% ~(~12s~)" (car vv
))
463 (def-break :help
'break-help
464 "Print help on a break command or with no arguments on
467 ;; This is an undocumented break command which gets placed in
468 ;; *LAST-DBM-COMMAND* when an invalid (nonexistent or ambiguous)
469 ;; break command is read in.
470 (def-break :_none
#'(lambda()) nil
)
472 (def-break :next
'step-next
473 "Like :step, except that subroutine calls are stepped over")
475 (def-break :step
'step-into
476 "Step program until it reaches a new source line")
478 ;;(def-break :location 'loc "" )
480 (def-break :quit
'break-quit
483 (def-break :top
#'(lambda( &rest l
)l
(throw 'macsyma-quit
'top
))
484 "Throw to top level")
486 (defun *break-points
* (form)
487 (let ((pos(position form
*break-points
* :key
'car
)))
488 (format *debug-io
* "Bkpt ~a: " pos
)
489 (break-dbm-loop (aref *break-points
* pos
))))
491 ;; fun = function name eg '$|odeSeriesSolve| and
492 ;; li = offset from beginning of function.
493 ;; Or fun = string (filename) and li = absolute position.
495 (defun break-function (fun &optional
(li 0) absolute
496 &aux i tem info form fun-line
)
498 (format t
"~&Turning on debugging debugmode(true)~%")
501 (let ((file fun
) start
)
502 (loop named joe for vv being the symbols of
'maxima with tem with linfo
503 when
(and (typep (setq tem
(set-full-lineinfo vv
))
505 (setq linfo
(get-lineinfo (aref tem
1)))
506 (equal file
(cadr linfo
))
507 (fb >= li
(setq start
(aref tem
0)))
508 (fb <= li
(+ start
(length (the vector tem
)))))
509 do
(setq fun vv li
(f- li start -
1))
510 ; (print (list 'found fun fun li (aref tem 0)))
511 (return-from joe nil
)
513 (format t
"No line info for ~a " fun
)
514 (return-from break-function nil
)))))
515 (setq fun
($concat fun
))
516 ; (print (list 'fun fun 'hi))
517 (cond ((and (setq tem
(second (mgetl fun
'(mexpr mmacro
))))
518 (setq info
(get-lineinfo (setq form
(third tem
))))
519 (eq (third info
) 'src
))
520 (setq fun-line
(fifth info
))
521 (or (fixnump fun-line
) (setq fun-line
(line-info-line info
)))
522 ; (print (list 'fun-line fun-line))
523 (setq form
(first-form-line
526 (if absolute
0 fun-line
) li
))))
529 (return-from break-function
(break-function fun
1)))
530 (format t
"~& No instructions recorded for this line ~a of ~a" li
532 (return-from break-function nil
))
533 (let ((n (insert-break-point (make-bkpt :form form
535 :file
(line-info-file info
)
537 (format t
"~&Bkpt ~a for ~a (in ~a line ~a) ~%"
538 n
($sconcat fun
) (line-info-file info
) i
)
540 (t (format t
"No line info for ~a " fun
))))
542 ;; note need to make the redefine function, fixup the break point list..
544 (defun make-break-point (fun ar i
)
545 (declare (fixnum i
) (type (vector t
) ar
))
546 (let* ((tem (aref ar i
))
547 (linfo (get-lineinfo tem
)))
548 (and linfo
(list tem
(cadr linfo
) (car linfo
) fun
))))
550 (defun dbm-up (n &aux
(cur *current-frame
*) (m (length *mlambda-call-stack
*)))
551 (declare (fixnum n m cur
))
552 (setq m
(quotient m
5))
560 (defun insert-break-point (bpt &aux at
)
561 (or *break-points
* (init-break-points))
562 (setq at
(or (position nil
*break-points
*)
563 (prog1 (length *break-points
*)
564 (vector-push-extend nil
*break-points
*))))
565 (let ((fun (bkpt-function bpt
)))
566 (push at
(get fun
'break-points
)))
567 (setf (aref *break-points
* at
) bpt
)
570 (defun short-name (name)
571 (let ((pos (position #\
/ name
:from-end t
)))
572 (if pos
(subseq name
(f + 1 pos
)) name
)))
574 (defun show-break-point (n &aux disabled
)
575 (let ((bpt (aref *break-points
* n
)))
577 (when (eq (car bpt
) nil
)
579 (setq bpt
(cdr bpt
)))
580 (format t
"Bkpt ~a: (~a line ~a)~@[ (disabled)~]"
581 n
(short-name (second bpt
))
582 (third bpt
) disabled
)
583 (let ((fun (fourth bpt
)))
584 (format t
" (line ~a of ~a)" (relative-line fun
(nth 2 bpt
))
587 (defun relative-line (fun l
)
588 (let ((info (set-full-lineinfo fun
)))
589 (if info
(f - l
(aref info
0))
592 (defun iterate-over-bkpts (l action
)
593 (dotimes (i (length *break-points
*))
596 (let ((tem (aref *break-points
* i
)))
597 (setf (aref *break-points
* i
)
601 (pop tem
)) ; disabled or already deleted bkpt
603 (setf (get (bkpt-function tem
) 'break-points
)
605 (get (bkpt-function tem
) 'break-points
))))
608 (if (eq (car tem
) nil
) (cdr tem
) tem
))
610 (if (and tem
(not (eq (car tem
) nil
)))
614 (when tem
(show-break-point i
)
619 ;; get the most recent function on the stack with step info.
621 (defun current-step-fun ( &aux fun
)
622 (loop for i below
100000
623 while
(setq fun
(frame-info i
))
624 do
(cond ((and (symbolp fun
) (set-full-lineinfo fun
))
625 (return-from current-step-fun fun
)))))
627 (def-break :bt
'$backtrace
"Print a backtrace of the stack frames")
629 (def-break :info
#'(lambda (&optional type
)
631 (:bkpt
(iterate-over-bkpts nil
:show
)(values))
634 "usage: :info :bkpt -- show breakpoints"))))
635 "Print information about item")
637 (defmacro lisp-quiet
(&rest l
)
638 (if (not (string= *mread-prompt
* ""))
639 (setq *lisp-quiet-suppressed-prompt
* *mread-prompt
*))
640 (setq *mread-prompt
* "")
641 (eval (cons 'progn l
))
644 (def-break :lisp-quiet
'lisp-quiet
645 "Evaluate the lisp form without printing a prompt")
647 (def-break :lisp
'lisp-eval
648 "Evaluate the lisp form following on the line")
650 (defmacro lisp-eval
(&rest l
)
651 (if (string= *mread-prompt
* "")
652 (setq *mread-prompt
* *lisp-quiet-suppressed-prompt
*))
654 (dolist (v (multiple-value-list (eval (cons 'progn l
))))
655 (fresh-line *standard-output
*)
658 (def-break :delete
#'(lambda (&rest l
) (iterate-over-bkpts l
:delete
) (values))
659 "Delete all breakpoints, or if arguments are supplied delete the
660 specified breakpoints")
662 (def-break :frame
'break-frame
663 "With an argument print the selected stack frame.
664 Otherwise the current frame.")
666 (def-break :resume
#'(lambda () :resume
)
667 "Continue the computation.")
669 (def-break :continue
#'(lambda () :resume
)
670 "Continue the computation.")
673 #'(lambda (&rest l
) (iterate-over-bkpts l
:disable
)(values))
674 "Disable the specified breakpoints, or all if none are specified")
676 (def-break :enable
#'(lambda (&rest l
) (iterate-over-bkpts l
:enable
)(values))
677 "Enable the specified breakpoints, or all if none are specified")
679 (def-break :break
'do-break
680 "Set a breakpoint in the specified FUNCTION at the
681 specified LINE offset from the beginning of the function.
682 If FUNCTION is given as a string, then it is presumed to be
683 a FILE and LINE is the offset from the beginning of the file.")
685 ;; force the rest of the line to be broken at spaces,
686 ;; and each item read as a maxima atom.
687 (setf (get :break
'maxima-read
) t
)
689 (defmacro do-break
(&optional name
&rest l
)
690 (declare (special *last-dbl-break
*))
693 (let ((fun (nth 3 *last-dbl-break
*)))
694 (break-function fun
(nth 2 *last-dbl-break
*) t
))))
695 (t (eval `(break-function ',name
,@l
)))))
697 ;; this just sets up a counter for each stream.. we want
698 ;; it to start at one.
700 (defun get-lineinfo (form)
702 (if (consp (cadar form
))
704 (if (consp (caddar form
))
709 ;; restore-bindings from an original binding list.
710 (defun restore-bindings ()
711 (mbind *diff-bindlist
* *diff-mspeclist
* nil
)
712 (setf *diff-bindlist
* nil
*diff-mspeclist
* nil
))
714 (defun remove-bindings (the-bindlist)
715 (loop for v on bindlist with var
717 until
(eq v the-bindlist
)
720 (push var
*diff-bindlist
*)
721 (push (symbol-value var
) *diff-mspeclist
*)
722 (cond ((eq (car mspeclist
) munbound
)
724 (setq $values
(delete var $values
:count
1 :test
#'eq
)))
725 (t (let ((munbindp t
)) (mset var
(car mspeclist
)))))
726 (setq mspeclist
(cdr mspeclist
) bindlist
(cdr bindlist
))))
728 (defun break-frame (&optional
(n 0) (print-frame-number t
))
730 (multiple-value-bind (fname vals params backtr lineinfo bdlist
)
731 (print-one-frame n print-frame-number
)
732 backtr params vals fname
733 (remove-bindings bdlist
)
735 (fresh-line *debug-io
*)
736 (format *debug-io
* "\x1a\x1a~a:~a::~%" (cadr lineinfo
) (+ 0 (car lineinfo
))))