| 1 | ;;; -*- Mode:Lisp -*- |
|---|
| 2 | |
|---|
| 3 | (in-package :named-readtables-test) |
|---|
| 4 | |
|---|
| 5 | (defun map-alist (car-fn cdr-fn alist) |
|---|
| 6 | (mapcar #'(lambda (entry) |
|---|
| 7 | (cons (funcall car-fn (car entry)) |
|---|
| 8 | (funcall cdr-fn (cdr entry)))) |
|---|
| 9 | alist)) |
|---|
| 10 | |
|---|
| 11 | (defun length=1 (list) |
|---|
| 12 | (and list (null (cdr list)))) |
|---|
| 13 | |
|---|
| 14 | (defmacro signals-condition-p (name &body body) |
|---|
| 15 | `(handler-case (prog1 nil ,@body) |
|---|
| 16 | (,(second name) () t))) |
|---|
| 17 | |
|---|
| 18 | (defmacro continue-condition (name &body body) |
|---|
| 19 | `(handler-bind ((,(second name) #'continue)) |
|---|
| 20 | ,@body)) |
|---|
| 21 | |
|---|
| 22 | (defun read-with-readtable (name string) |
|---|
| 23 | (let ((*package* '#.*package*) |
|---|
| 24 | (*readtable* (find-readtable name))) |
|---|
| 25 | (values (read-from-string string)))) |
|---|
| 26 | |
|---|
| 27 | (defun random-named-readtable () |
|---|
| 28 | (let ((readtables (list-all-named-readtables))) |
|---|
| 29 | (nth (random (length readtables)) readtables))) |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | (defun readtable-content (named-readtable-designator) |
|---|
| 33 | (let ((readtable (ensure-readtable named-readtable-designator)) |
|---|
| 34 | (result '())) |
|---|
| 35 | ;; Make sure to canonicalize the order and function designators so |
|---|
| 36 | ;; we can compare easily. |
|---|
| 37 | (do-readtable ((char reader-fn ntp disp? table) readtable) |
|---|
| 38 | (setq table (sort (copy-list table) #'char< :key #'car)) |
|---|
| 39 | (push (list* char |
|---|
| 40 | (ensure-function reader-fn) |
|---|
| 41 | ntp |
|---|
| 42 | (and disp? (list (map-alist #'identity |
|---|
| 43 | #'ensure-function |
|---|
| 44 | table)))) |
|---|
| 45 | result)) |
|---|
| 46 | (sort result #'char< :key #'car))) |
|---|
| 47 | |
|---|
| 48 | (defun readtable= (rt1 rt2) |
|---|
| 49 | (tree-equal (readtable-content rt1) (readtable-content rt2) |
|---|
| 50 | :test #'(lambda (x y) |
|---|
| 51 | (if (and (functionp x) (functionp y)) |
|---|
| 52 | (function= x y) |
|---|
| 53 | (eql x y))))) |
|---|
| 54 | |
|---|
| 55 | |
|---|
| 56 | (defun read-A (stream c) |
|---|
| 57 | (declare (ignore stream c)) |
|---|
| 58 | :a) |
|---|
| 59 | |
|---|
| 60 | (defun read-A-as-X (stream c) |
|---|
| 61 | (declare (ignore stream c)) |
|---|
| 62 | :x) |
|---|
| 63 | |
|---|
| 64 | (defun read-B (stream c) |
|---|
| 65 | (declare (ignore stream c)) |
|---|
| 66 | :b) |
|---|
| 67 | |
|---|
| 68 | (defun read-sharp-paren (stream c n) |
|---|
| 69 | (declare (ignore stream c n)) |
|---|
| 70 | 'sharp-paren) |
|---|
| 71 | |
|---|
| 72 | (defun read-C (stream c) |
|---|
| 73 | (declare (ignore stream c)) |
|---|
| 74 | :c) |
|---|
| 75 | |
|---|
| 76 | (defreadtable A |
|---|
| 77 | (:macro-char #\A #'read-A)) |
|---|
| 78 | |
|---|
| 79 | (defreadtable A-as-X |
|---|
| 80 | (:macro-char #\A #'read-A-as-X)) |
|---|
| 81 | |
|---|
| 82 | (defreadtable A-dispatch |
|---|
| 83 | (:macro-char #\A :dispatch) |
|---|
| 84 | (:dispatch-macro-char #\A #\A #'read-A)) |
|---|
| 85 | |
|---|
| 86 | (defreadtable A-dispatch-as-X |
|---|
| 87 | (:macro-char #\A :dispatch) |
|---|
| 88 | (:dispatch-macro-char #\A #\A #'read-A-as-X)) |
|---|
| 89 | |
|---|
| 90 | (defreadtable B |
|---|
| 91 | (:macro-char #\B #'read-B)) |
|---|
| 92 | |
|---|
| 93 | (defreadtable C |
|---|
| 94 | (:macro-char #\C #'read-C)) |
|---|
| 95 | |
|---|
| 96 | (defreadtable A+B+C |
|---|
| 97 | (:merge A B C)) |
|---|
| 98 | |
|---|
| 99 | (defreadtable standard+A+B+C |
|---|
| 100 | (:merge :standard A+B+C)) |
|---|
| 101 | |
|---|
| 102 | (defreadtable sharp-paren |
|---|
| 103 | (:macro-char #\# :dispatch) |
|---|
| 104 | (:dispatch-macro-char #\# #\( #'read-sharp-paren)) |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | (deftest cruft.1 |
|---|
| 108 | (function= (get-macro-character #\" (copy-readtable nil)) |
|---|
| 109 | (get-macro-character #\" (copy-readtable nil))) |
|---|
| 110 | t) |
|---|
| 111 | |
|---|
| 112 | (deftest cruft.2 |
|---|
| 113 | (dispatch-macro-char-p #\# (find-readtable :standard)) |
|---|
| 114 | t) |
|---|
| 115 | |
|---|
| 116 | (deftest cruft.3 |
|---|
| 117 | (dispatch-macro-char-p #\# (make-readtable)) |
|---|
| 118 | nil) |
|---|
| 119 | |
|---|
| 120 | (deftest cruft.4 |
|---|
| 121 | (let ((rt (copy-named-readtable :standard))) |
|---|
| 122 | (ensure-dispatch-macro-character #\# t rt) |
|---|
| 123 | (dispatch-macro-char-p #\# rt)) |
|---|
| 124 | t) |
|---|
| 125 | |
|---|
| 126 | (deftest cruft.5 |
|---|
| 127 | (let ((rt (make-readtable))) |
|---|
| 128 | (values |
|---|
| 129 | (dispatch-macro-char-p #\$ rt) |
|---|
| 130 | (ensure-dispatch-macro-character #\$ t rt) |
|---|
| 131 | (dispatch-macro-char-p #\$ rt))) |
|---|
| 132 | nil t t) |
|---|
| 133 | |
|---|
| 134 | (deftest cruft.6 |
|---|
| 135 | (let ((rt (make-readtable)) |
|---|
| 136 | (fn (constantly nil))) |
|---|
| 137 | (ensure-dispatch-macro-character #\$ t rt) |
|---|
| 138 | (set-dispatch-macro-character #\$ #\# fn rt) |
|---|
| 139 | (values |
|---|
| 140 | (eq fn (get-dispatch-macro-character #\$ #\# rt)) |
|---|
| 141 | (length=1 (readtable-content rt)))) |
|---|
| 142 | t t) |
|---|
| 143 | |
|---|
| 144 | (deftest cruft.7 |
|---|
| 145 | (let ((rt (make-readtable)) |
|---|
| 146 | (fn (constantly nil))) |
|---|
| 147 | (set-macro-character #\$ fn t rt) |
|---|
| 148 | (values |
|---|
| 149 | (eq fn (get-macro-character #\$ rt)) |
|---|
| 150 | (length=1 (readtable-content rt)))) |
|---|
| 151 | t t) |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | (deftest standard.1 |
|---|
| 155 | (read-with-readtable :standard "ABC") |
|---|
| 156 | ABC) |
|---|
| 157 | |
|---|
| 158 | (deftest standard.2 |
|---|
| 159 | (read-with-readtable :standard "(A B C)") |
|---|
| 160 | (A B C)) |
|---|
| 161 | |
|---|
| 162 | (deftest standard.3 |
|---|
| 163 | (let ((x (find-readtable nil)) |
|---|
| 164 | (y (find-readtable :standard)) |
|---|
| 165 | (z (find-readtable :common-lisp))) |
|---|
| 166 | (and (eq x y) (eq y z))) |
|---|
| 167 | t) |
|---|
| 168 | |
|---|
| 169 | |
|---|
| 170 | (deftest modern.1 |
|---|
| 171 | (read-with-readtable :modern "FooF") |
|---|
| 172 | |FooF|) |
|---|
| 173 | |
|---|
| 174 | |
|---|
| 175 | (deftest empty.1 |
|---|
| 176 | (null (readtable-content (make-readtable))) |
|---|
| 177 | t) |
|---|
| 178 | |
|---|
| 179 | (deftest empty.2 |
|---|
| 180 | (readtable= (merge-readtables-into (make-readtable) :standard) |
|---|
| 181 | (find-readtable :standard)) |
|---|
| 182 | t) |
|---|
| 183 | |
|---|
| 184 | (deftest empty.3 |
|---|
| 185 | (let ((rt (copy-named-readtable :standard))) |
|---|
| 186 | (readtable= (merge-readtables-into (make-readtable) rt) |
|---|
| 187 | (merge-readtables-into rt (make-readtable)))) |
|---|
| 188 | t) |
|---|
| 189 | |
|---|
| 190 | |
|---|
| 191 | (deftest basics.1 |
|---|
| 192 | (read-with-readtable 'A "A") |
|---|
| 193 | :a) |
|---|
| 194 | |
|---|
| 195 | (deftest basics.2 |
|---|
| 196 | (read-with-readtable 'A-as-X "A") |
|---|
| 197 | :x) |
|---|
| 198 | |
|---|
| 199 | (deftest basics.3 |
|---|
| 200 | (read-with-readtable 'A "B") |
|---|
| 201 | B) |
|---|
| 202 | |
|---|
| 203 | (deftest basics.4 |
|---|
| 204 | (read-with-readtable 'A "(A B C)") |
|---|
| 205 | |(|) |
|---|
| 206 | |
|---|
| 207 | |
|---|
| 208 | (deftest unregister.1 |
|---|
| 209 | (let ((rt (find-readtable 'A))) |
|---|
| 210 | (register-readtable 'does-not-exist rt) |
|---|
| 211 | (values |
|---|
| 212 | (and (find-readtable 'does-not-exist) t) |
|---|
| 213 | (unregister-readtable 'does-not-exist) |
|---|
| 214 | (and (find-readtable 'does-not-exist) t))) |
|---|
| 215 | t t nil) |
|---|
| 216 | |
|---|
| 217 | |
|---|
| 218 | (deftest name.1 |
|---|
| 219 | (let ((rt (random-named-readtable))) |
|---|
| 220 | (eq rt (find-readtable (readtable-name rt)))) |
|---|
| 221 | t) |
|---|
| 222 | |
|---|
| 223 | (deftest ensure.1 |
|---|
| 224 | (unwind-protect |
|---|
| 225 | (let* ((x (ensure-readtable 'does-not-exist (find-readtable 'A))) |
|---|
| 226 | (y (find-readtable 'A)) |
|---|
| 227 | (z (find-readtable 'does-not-exist))) |
|---|
| 228 | (and (eq x y) (eq y z))) |
|---|
| 229 | (unregister-readtable 'does-not-exist)) |
|---|
| 230 | t) |
|---|
| 231 | |
|---|
| 232 | |
|---|
| 233 | (deftest merge.1 |
|---|
| 234 | (values |
|---|
| 235 | (read-with-readtable 'A+B+C "A") |
|---|
| 236 | (read-with-readtable 'A+B+C "B") |
|---|
| 237 | (read-with-readtable 'A+B+C "C")) |
|---|
| 238 | :a :b :c) |
|---|
| 239 | |
|---|
| 240 | (deftest merge.2 |
|---|
| 241 | (read-with-readtable 'standard+A+B+C "(A B C)") |
|---|
| 242 | (:a :b :c)) |
|---|
| 243 | |
|---|
| 244 | (deftest merge.3 |
|---|
| 245 | (read-with-readtable 'standard+A+B+C "#(A B C)") |
|---|
| 246 | #(:a :b :c)) |
|---|
| 247 | |
|---|
| 248 | (deftest merge.4 |
|---|
| 249 | (let ((A+B+C+standard (merge-readtables-into (copy-named-readtable 'A+B+C) |
|---|
| 250 | :standard))) |
|---|
| 251 | (readtable= 'standard+A+B+C A+B+C+standard)) |
|---|
| 252 | t) |
|---|
| 253 | |
|---|
| 254 | |
|---|
| 255 | (deftest rename.1 |
|---|
| 256 | (unwind-protect |
|---|
| 257 | (progn (make-readtable 'A* :merge '(A)) |
|---|
| 258 | (rename-readtable 'A* 'A**) |
|---|
| 259 | (values (and (find-readtable 'A*) t) |
|---|
| 260 | (and (find-readtable 'A**) t))) |
|---|
| 261 | (unregister-readtable 'A*) |
|---|
| 262 | (unregister-readtable 'A**)) |
|---|
| 263 | nil |
|---|
| 264 | t) |
|---|
| 265 | |
|---|
| 266 | |
|---|
| 267 | (deftest reader-macro-conflict.1 |
|---|
| 268 | (signals-condition-p 'reader-macro-conflict |
|---|
| 269 | (merge-readtables-into (make-readtable) 'A 'A-as-X)) |
|---|
| 270 | t) |
|---|
| 271 | |
|---|
| 272 | (deftest reader-macro-conflict.2 |
|---|
| 273 | (signals-condition-p 'reader-macro-conflict |
|---|
| 274 | (merge-readtables-into (make-readtable) :standard :standard)) |
|---|
| 275 | nil) |
|---|
| 276 | |
|---|
| 277 | (deftest reader-macro-conflict.3 |
|---|
| 278 | (signals-condition-p 'reader-macro-conflict |
|---|
| 279 | (merge-readtables-into (make-readtable) 'A+B+C 'A)) |
|---|
| 280 | nil) |
|---|
| 281 | |
|---|
| 282 | (deftest reader-macro-conflict.4 |
|---|
| 283 | (signals-condition-p 'reader-macro-conflict |
|---|
| 284 | (merge-readtables-into (make-readtable) :standard 'sharp-paren)) |
|---|
| 285 | t) |
|---|
| 286 | |
|---|
| 287 | (deftest reader-macro-conflict.5 |
|---|
| 288 | (signals-condition-p 'reader-macro-conflict |
|---|
| 289 | (merge-readtables-into (make-readtable) 'A 'A-dispatch)) |
|---|
| 290 | t) |
|---|
| 291 | |
|---|
| 292 | (deftest reader-macro-conflict.6 |
|---|
| 293 | (signals-condition-p 'reader-macro-conflict |
|---|
| 294 | (merge-readtables-into (make-readtable) 'A-dispatch 'A)) |
|---|
| 295 | t) |
|---|
| 296 | |
|---|
| 297 | (deftest reader-macro-conflict.7 |
|---|
| 298 | (signals-condition-p 'reader-macro-conflict |
|---|
| 299 | (merge-readtables-into (make-readtable) 'A-dispatch 'A-dispatch-as-X)) |
|---|
| 300 | t) |
|---|
| 301 | |
|---|
| 302 | (deftest reader-macro-conflict.8 |
|---|
| 303 | (signals-condition-p 'reader-macro-conflict |
|---|
| 304 | (merge-readtables-into (make-readtable) 'A 'A)) |
|---|
| 305 | nil) |
|---|
| 306 | |
|---|
| 307 | (deftest reader-macro-conflict.9 |
|---|
| 308 | (signals-condition-p 'reader-macro-conflict |
|---|
| 309 | (merge-readtables-into (make-readtable) 'A-dispatch 'A-dispatch)) |
|---|
| 310 | nil) |
|---|
| 311 | |
|---|
| 312 | |
|---|
| 313 | (deftest readtable-does-not-exist.1 |
|---|
| 314 | (signals-condition-p 'readtable-does-not-exist |
|---|
| 315 | (ensure-readtable 'does-not-exist)) |
|---|
| 316 | t) |
|---|
| 317 | |
|---|
| 318 | |
|---|
| 319 | (deftest readtable-does-already-exist.1 |
|---|
| 320 | (signals-condition-p 'readtable-does-already-exist |
|---|
| 321 | (make-readtable 'A)) |
|---|
| 322 | t) |
|---|
| 323 | |
|---|
| 324 | (deftest readtable-does-already-exist.2 |
|---|
| 325 | (signals-condition-p 'readtable-does-already-exist |
|---|
| 326 | (make-readtable 'A)) |
|---|
| 327 | t) |
|---|
| 328 | |
|---|
| 329 | (deftest readtable-does-already-exist.3 |
|---|
| 330 | (let ((rt (make-readtable 'does-not-exist :merge '(:standard A B)))) |
|---|
| 331 | (declare (ignore rt)) |
|---|
| 332 | (unwind-protect |
|---|
| 333 | (read-with-readtable (continue-condition 'readtable-does-already-exist |
|---|
| 334 | (make-readtable 'does-not-exist |
|---|
| 335 | :merge '(:standard A C))) |
|---|
| 336 | |
|---|
| 337 | "(A B C)") |
|---|
| 338 | (unregister-readtable 'does-not-exist))) |
|---|
| 339 | (:a B :c)) |
|---|
| 340 | |
|---|
| 341 | |
|---|
| 342 | (deftest defreadtable.1 |
|---|
| 343 | (unwind-protect |
|---|
| 344 | (signals-condition-p 'reader-macro-conflict |
|---|
| 345 | (eval `(defreadtable does-not-exist (:merge A A-as-X)))) |
|---|
| 346 | (unregister-readtable 'does-not-exist)) |
|---|
| 347 | t) |
|---|
| 348 | |
|---|
| 349 | (deftest defreadtable.2 |
|---|
| 350 | (unwind-protect |
|---|
| 351 | (signals-condition-p 't |
|---|
| 352 | (eval `(defreadtable does-not-exist (:fuse A A-as-X)))) |
|---|
| 353 | (unregister-readtable 'does-not-exist)) |
|---|
| 354 | nil) |
|---|
| 355 | |
|---|