1
;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: "CONDITIONS"; Base: 10 -*-
3
(IN-PACKAGE "CONDITIONS")
5
(EVAL-WHEN (EVAL COMPILE LOAD)
7
(DEFUN ACCUMULATE-CASES (MACRO-NAME CASES LIST-IS-ATOM-P)
10
((NULL C) (NREVERSE L))
11
(LET ((KEYS (CAAR C)))
14
((MEMBER KEYS '(OTHERWISE T))
15
(IF (NOT (MEMBER MACRO-NAME '( ECASE CCASE ETYPECASE CTYPECASE)))
16
(ERROR "OTHERWISE is not allowed in ~S expressions." MACRO-NAME))
21
(T (DOLIST (KEY KEYS) (PUSH KEY L)))))))
24
;(DEFUN ESCAPE-SPECIAL-CASES (CASES)
27
; ((NULL C) (NREVERSE L))
28
; (LET ((KEYS (CAAR C)))
31
; ((MEMBER KEYS '(OTHERWISE T))
32
; (PUSH (CONS (LIST KEYS) (CDR (CAR C))) L))
33
; (T (PUSH (CONS KEYS (CDR (CAR C))) L))))
35
; (PUSH (CONS KEYS (CDR (CAR C))) L))))))
37
(DEFUN ESCAPE-SPECIAL-CASES-REPLACE (CASES)
38
(DO ((C CASES (CDR C)))
40
(LET ((KEYS (CAAR C)))
41
(IF (MEMBER KEYS '(OTHERWISE T))
42
(RPLACA (CAR C) (LIST KEYS))))))
44
(DEFMACRO ECASE (KEYFORM &REST CASES)
45
(LET ((KEYS (ACCUMULATE-CASES 'ECASE CASES NIL))
46
(NCASES (ESCAPE-SPECIAL-CASES-REPLACE CASES))
48
`(LET ((,VAR ,KEYFORM))
52
(ERROR 'CASE-FAILURE :NAME 'ECASE
54
:EXPECTED-TYPE '(MEMBER ,@KEYS)
55
:POSSIBILITIES ',KEYS))))))
57
(DEFMACRO CCASE (KEYPLACE &REST CASES)
58
(LET ((KEYS (ACCUMULATE-CASES 'CCASE CASES NIL))
59
(NCASES (ESCAPE-SPECIAL-CASES-REPLACE CASES))
68
(RESTART-CASE (ERROR 'CASE-FAILURE
71
:EXPECTED-TYPE '(MEMBER ,@KEYS)
72
:POSSIBILITIES ',KEYS)
74
:REPORT (LAMBDA (STREAM)
75
(FORMAT STREAM "Supply a new value of ~S."
77
:INTERACTIVE READ-EVALUATED-FORM
78
(SETF ,KEYPLACE VALUE)
81
(DEFMACRO ETYPECASE (KEYFORM &REST CASES)
82
(LET ((TYPES (ACCUMULATE-CASES 'ETYPECASE CASES T))
84
`(LET ((,VAR ,KEYFORM))
88
(ERROR 'CASE-FAILURE :NAME 'ETYPECASE
90
:EXPECTED-TYPE '(OR ,@TYPES)
91
:POSSIBILITIES ',TYPES))))))
93
(DEFMACRO CTYPECASE (KEYPLACE &REST CASES)
94
(LET ((TYPES (ACCUMULATE-CASES 'CTYPECASE CASES T))
103
(RESTART-CASE (ERROR 'CASE-FAILURE
106
:EXPECTED-TYPE '(OR ,@TYPES)
107
:POSSIBILITIES ',TYPES)
109
:REPORT (LAMBDA (STREAM)
110
(FORMAT STREAM "Supply a new value of ~S."
112
:INTERACTIVE READ-EVALUATED-FORM
113
(SETF ,KEYPLACE VALUE)
116
(DEFUN ASSERT-REPORT (NAMES STREAM)
117
(FORMAT STREAM "Retry assertion")
119
(FORMAT STREAM " with new value~P for ~{~S~^, ~}."
120
(LENGTH NAMES) NAMES)
121
(FORMAT STREAM ".")))
123
(DEFUN ASSERT-PROMPT (NAME VALUE)
124
(COND ((Y-OR-N-P "The old value of ~S is ~S.~
125
~%Do you want to supply a new value? "
127
(FORMAT *QUERY-IO* "~&Type a form to be evaluated:~%")
128
(FLET ((READ-IT () (EVAL (READ *QUERY-IO*))))
129
(IF (SYMBOLP NAME) ;Help user debug lexical variables
130
(PROGV (LIST NAME) (LIST VALUE) (READ-IT))
134
(DEFUN SIMPLE-ASSERTION-FAILURE (ASSERTION)
135
(ERROR 'SIMPLE-TYPE-ERROR
137
:EXPECTED-TYPE NIL ; This needs some work in next revision. -kmp
138
:FORMAT-STRING "The assertion ~S failed."
139
:FORMAT-ARGUMENTS (LIST ASSERTION)))
141
(DEFMACRO ASSERT (TEST-FORM &OPTIONAL PLACES DATUM &REST ARGUMENTS)
142
(LET ((TAG (GENSYM)))
145
(RESTART-CASE ,(IF DATUM
146
`(ERROR ,DATUM ,@ARGUMENTS)
147
`(SIMPLE-ASSERTION-FAILURE ',TEST-FORM))
149
:REPORT (LAMBDA (STREAM) (ASSERT-REPORT ',PLACES STREAM))
150
,@(MAPCAR #'(LAMBDA (PLACE)
151
`(SETF ,PLACE (ASSERT-PROMPT ',PLACE ,PLACE)))
155
(DEFUN READ-EVALUATED-FORM ()
156
(FORMAT *QUERY-IO* "~&Type a form to be evaluated:~%")
157
(LIST (EVAL (READ *QUERY-IO*))))
159
(DEFMACRO CHECK-TYPE (PLACE TYPE &OPTIONAL TYPE-STRING)
160
(LET ((TAG1 (GENSYM))
164
(IF (TYPEP ,PLACE ',TYPE) (RETURN-FROM ,TAG1 NIL))
165
(RESTART-CASE ,(IF TYPE-STRING
166
`(ERROR "The value of ~S is ~S, ~
168
',PLACE ,PLACE ,TYPE-STRING)
169
`(ERROR "The value of ~S is ~S, ~
170
which is not of type ~S."
171
',PLACE ,PLACE ',TYPE))
173
:REPORT (LAMBDA (STREAM)
174
(FORMAT STREAM "Supply a new value of ~S."
176
:INTERACTIVE READ-EVALUATED-FORM