1
;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: "CONDITIONS"; Base: 10 -*-
3
(IN-PACKAGE "CONDITIONS")
7
(DEFVAR *UNIQUE-ID-TABLE* (MAKE-HASH-TABLE))
8
(DEFVAR *UNIQUE-ID-COUNT* -1)
10
(DEFUN UNIQUE-ID (OBJ)
11
"Generates a unique integer ID for its argument."
12
(OR (GETHASH OBJ *UNIQUE-ID-TABLE*)
13
(SETF (GETHASH OBJ *UNIQUE-ID-TABLE*) (INCF *UNIQUE-ID-COUNT*))))
15
;;; Miscellaneous Utilities
17
(EVAL-WHEN (EVAL COMPILE LOAD)
19
(DEFUN PARSE-KEYWORD-PAIRS (LIST KEYS)
20
(DO ((L LIST (CDDR L))
21
(K '() (LIST* (CADR L) (CAR L) K)))
22
((OR (NULL L) (NOT (MEMBER (CAR L) KEYS)))
23
(VALUES (NREVERSE K) L))))
25
(DEFMACRO WITH-KEYWORD-PAIRS ((NAMES EXPRESSION &OPTIONAL KEYWORDS-VAR) &BODY FORMS)
26
(LET ((TEMP (MEMBER '&REST NAMES)))
27
(UNLESS (= (LENGTH TEMP) 2) (ERROR "&REST keyword is ~:[missing~;misplaced~]." TEMP))
28
(LET ((KEY-VARS (LDIFF NAMES TEMP))
29
(KEY-VAR (OR KEYWORDS-VAR (GENSYM)))
30
(REST-VAR (CADR TEMP)))
31
(LET ((KEYWORDS (MAPCAR #'(LAMBDA (X) (INTERN (STRING X) (FIND-PACKAGE "KEYWORD")))
33
`(MULTIPLE-VALUE-BIND (,KEY-VAR ,REST-VAR)
34
(PARSE-KEYWORD-PAIRS ,EXPRESSION ',KEYWORDS)
35
(LET ,(MAPCAR #'(LAMBDA (VAR KEYWORD) `(,VAR (GETF ,KEY-VAR ,KEYWORD)))
43
(DEFVAR *RESTART-CLUSTERS* '())
45
(DEFUN COMPUTE-RESTARTS ()
46
#+kcl (nconc (mapcan #'copy-list *RESTART-CLUSTERS*) (kcl-top-restarts))
47
#-kcl (mapcan #'copy-list *RESTART-CLUSTERS*))
49
(DEFUN RESTART-PRINT (RESTART STREAM DEPTH)
50
(DECLARE (IGNORE DEPTH))
52
(FORMAT STREAM "#<~S.~D>" (TYPE-OF RESTART) (UNIQUE-ID RESTART))
53
(RESTART-REPORT RESTART STREAM)))
55
(DEFSTRUCT (RESTART (:PRINT-FUNCTION RESTART-PRINT))
63
(defvar *kcl-top-restarts* nil)
65
(defun make-kcl-top-restart (quit-tag)
66
(make-restart :name 'abort
67
:function #'(lambda () (throw (car (list quit-tag)) quit-tag))
70
(let ((b-l (if (eq quit-tag si::*quit-tag*)
72
(car (or (find quit-tag si::*quit-tags*
75
(cond ((eq b-l :not-found)
76
(format stream "Return to ? level."))
78
(format stream "Return to top level."))
80
(format stream "Return to break level ~D."
82
:interactive-function nil))
84
(defun find-kcl-top-restart (quit-tag)
85
(cdr (or (assoc quit-tag *kcl-top-restarts*)
86
(car (push (cons quit-tag (make-kcl-top-restart quit-tag))
87
*kcl-top-restarts*)))))
89
(defun kcl-top-restarts ()
90
(let* ((old-tags (mapcan #'(lambda (e) (when (cdr e) (list (cdr e))))
92
(tags (if si::*quit-tag* (cons si::*quit-tag* old-tags) old-tags))
93
(restarts (mapcar #'find-kcl-top-restart tags)))
94
(setq *kcl-top-restarts* (mapcar #'cons tags restarts))
98
(DEFUN RESTART-REPORT (RESTART STREAM)
99
(FUNCALL (OR (RESTART-REPORT-FUNCTION RESTART)
100
(LET ((NAME (RESTART-NAME RESTART)))
102
(IF NAME (FORMAT STREAM "~S" NAME)
103
(FORMAT STREAM "~S" RESTART)))))
106
(DEFMACRO RESTART-BIND (BINDINGS &BODY FORMS)
107
`(LET ((*RESTART-CLUSTERS* (CONS (LIST ,@(MAPCAR #'(LAMBDA (BINDING)
109
:NAME ',(CAR BINDING)
110
:FUNCTION ,(CADR BINDING)
113
*RESTART-CLUSTERS*)))
116
(DEFUN FIND-RESTART (NAME)
117
(DOLIST (RESTART-CLUSTER *RESTART-CLUSTERS*)
118
(DOLIST (RESTART RESTART-CLUSTER)
119
(WHEN (OR (EQ RESTART NAME) (EQ (RESTART-NAME RESTART) NAME))
120
(RETURN-FROM FIND-RESTART RESTART))))
122
(let ((RESTART-CLUSTER (kcl-top-restarts)))
123
(DOLIST (RESTART RESTART-CLUSTER)
124
(WHEN (OR (EQ RESTART NAME) (EQ (RESTART-NAME RESTART) NAME))
125
(RETURN-FROM FIND-RESTART RESTART)))))
127
(DEFUN INVOKE-RESTART (RESTART &REST VALUES)
128
(LET ((REAL-RESTART (OR (FIND-RESTART RESTART)
129
(ERROR "Restart ~S is not active." RESTART))))
130
(APPLY (RESTART-FUNCTION REAL-RESTART) VALUES)))
132
(DEFUN INVOKE-RESTART-INTERACTIVELY (RESTART)
133
(LET ((REAL-RESTART (OR (FIND-RESTART RESTART)
134
(ERROR "Restart ~S is not active." RESTART))))
135
(APPLY (RESTART-FUNCTION REAL-RESTART)
136
(LET ((INTERACTIVE-FUNCTION
137
(RESTART-INTERACTIVE-FUNCTION REAL-RESTART)))
138
(IF INTERACTIVE-FUNCTION
139
(FUNCALL INTERACTIVE-FUNCTION)
142
(DEFMACRO RESTART-CASE (EXPRESSION &BODY CLAUSES)
143
(FLET ((TRANSFORM-KEYWORDS (&KEY REPORT INTERACTIVE)
146
(SETQ RESULT (LIST* (IF (STRINGP REPORT)
148
(WRITE-STRING ,REPORT STREAM))
153
(SETQ RESULT (LIST* `#',INTERACTIVE
154
:INTERACTIVE-FUNCTION
157
(LET ((BLOCK-TAG (GENSYM))
160
(MAPCAR #'(LAMBDA (CLAUSE)
161
(WITH-KEYWORD-PAIRS ((REPORT INTERACTIVE &REST FORMS)
163
(LIST (CAR CLAUSE) ;Name=0
165
(TRANSFORM-KEYWORDS :REPORT REPORT ;Keywords=2
166
:INTERACTIVE INTERACTIVE)
171
(LET ((,TEMP-VAR NIL))
174
,(MAPCAR #'(LAMBDA (DATUM)
175
(LET ((NAME (NTH 0 DATUM))
177
(KEYS (NTH 2 DATUM)))
178
`(,NAME #'(LAMBDA (&REST TEMP)
179
#+LISPM (SETQ TEMP (COPY-LIST TEMP))
180
(SETQ ,TEMP-VAR TEMP)
184
(RETURN-FROM ,BLOCK-TAG ,EXPRESSION))
185
,@(MAPCAN #'(LAMBDA (DATUM)
186
(LET ((TAG (NTH 1 DATUM))
188
(BODY (NTH 4 DATUM)))
190
`(RETURN-FROM ,BLOCK-TAG
191
(APPLY #'(LAMBDA ,BVL ,@BODY)
195
(DEFMACRO WITH-SIMPLE-RESTART ((RESTART-NAME FORMAT-STRING
196
&REST FORMAT-ARGUMENTS)
198
`(RESTART-CASE (PROGN ,@FORMS)
200
:REPORT (LAMBDA (STREAM)
201
(FORMAT STREAM ,FORMAT-STRING ,@FORMAT-ARGUMENTS))
204
(DEFUN ABORT () (INVOKE-RESTART 'ABORT)
205
(ERROR 'ABORT-FAILURE))
206
(DEFUN CONTINUE () (INVOKE-RESTART 'CONTINUE))
207
(DEFUN MUFFLE-WARNING () (INVOKE-RESTART 'MUFFLE-WARNING))
208
(DEFUN STORE-VALUE (VALUE) (INVOKE-RESTART 'STORE-VALUE VALUE))
209
(DEFUN USE-VALUE (VALUE) (INVOKE-RESTART 'USE-VALUE VALUE))