Compare commits
5 Commits
f4759c5685
...
ecf12d390d
Author | SHA1 | Date |
---|---|---|
|
ecf12d390d | |
|
063c5c52d1 | |
|
cdeeb2fead | |
|
586f06fbf2 | |
|
b4fe711abb |
|
@ -1 +1,2 @@
|
||||||
/.direnv/
|
/.direnv/
|
||||||
|
/music/
|
||||||
|
|
|
@ -19,23 +19,26 @@
|
||||||
(let ((x '(123))
|
(let ((x '(123))
|
||||||
(z '(7 8 9)))
|
(z '(7 8 9)))
|
||||||
;; ' quotes an expression normally.
|
;; ' quotes an expression normally.
|
||||||
(assert-equal ____ '(x 45 6 z))
|
(assert-equal (list 'x 45 6 'z) '(x 45 6 z))
|
||||||
;; ` backquotes an expression; without any unquotes, it is equivalent to
|
;; ` backquotes an expression; without any unquotes, it is equivalent to
|
||||||
;; using the normal quote.
|
;; using the normal quote.
|
||||||
(assert-equal ____ `(x 45 6 z))
|
(assert-equal '(x 45 6 z) `(x 45 6 z))
|
||||||
;; , unquotes a part of the expression.
|
;; , unquotes a part of the expression.
|
||||||
(assert-equal ____ `(,x 45 6 z))
|
(assert-equal '((123) 45 6 z) `(,x 45 6 z))
|
||||||
(assert-equal ____ `(,x 45 6 ,z))
|
(assert-equal '((123) 45 6 (7 8 9)) `(,x 45 6 ,z))
|
||||||
;; ,@ splices an expression into the into the list surrounding it.
|
;; ,@ splices an expression into the into the list surrounding it.
|
||||||
(assert-equal ____ `(,x 45 6 ,@z))
|
(assert-equal '((123) 45 6 7 8 9) `(,x 45 6 ,@z))
|
||||||
(assert-equal ____ `(,@x 45 6 ,@z))))
|
(assert-equal '(123 45 6 7 8 9) `(,@x 45 6 ,@z))))
|
||||||
|
|
||||||
(define-test backquote-forms
|
(define-test backquote-forms
|
||||||
;; Because of its properties, backquote is useful for constructing Lisp forms
|
;; Because of its properties, backquote is useful for constructing Lisp forms
|
||||||
;; that are macroexpansions or parts of macroexpansions.
|
;; that are macroexpansions or parts of macroexpansions.
|
||||||
(let ((variable 'x))
|
(let ((variable 'x))
|
||||||
;; Fill in the blank without without using backquote/unquote notation.
|
;; Fill in the blank without without using backquote/unquote notation.
|
||||||
(assert-equal ____
|
(assert-equal '(if (typep x 'string)
|
||||||
|
(format nil "The value of ~A is ~A" 'x x)
|
||||||
|
(error 'type-error :datum x
|
||||||
|
:expected-type 'string))
|
||||||
`(if (typep ,variable 'string)
|
`(if (typep ,variable 'string)
|
||||||
(format nil "The value of ~A is ~A" ',variable ,variable)
|
(format nil "The value of ~A is ~A" ',variable ,variable)
|
||||||
(error 'type-error :datum ,variable
|
(error 'type-error :datum ,variable
|
||||||
|
@ -43,7 +46,9 @@
|
||||||
(let ((error-type 'type-error)
|
(let ((error-type 'type-error)
|
||||||
(error-arguments '(:datum x :expected-type 'string)))
|
(error-arguments '(:datum x :expected-type 'string)))
|
||||||
;; Fill in the blank without without using backquote/unquote notation.
|
;; Fill in the blank without without using backquote/unquote notation.
|
||||||
(assert-equal ____
|
(assert-equal '(if (typep x 'string)
|
||||||
|
(format nil "The value of ~A is ~A" 'x x)
|
||||||
|
(error 'type-error :datum x :expected-type 'string))
|
||||||
`(if (typep x 'string)
|
`(if (typep x 'string)
|
||||||
(format nil "The value of ~A is ~A" 'x x)
|
(format nil "The value of ~A is ~A" 'x x)
|
||||||
(error ',error-type ,@error-arguments)))))
|
(error ',error-type ,@error-arguments)))))
|
||||||
|
@ -51,15 +56,15 @@
|
||||||
(define-test numbers-and-words
|
(define-test numbers-and-words
|
||||||
(let ((number 5)
|
(let ((number 5)
|
||||||
(word 'dolphin))
|
(word 'dolphin))
|
||||||
(true-or-false? ____ (equal '(1 3 5) `(1 3 5)))
|
(true-or-false? t (equal '(1 3 5) `(1 3 5)))
|
||||||
(true-or-false? ____ (equal '(1 3 5) `(1 3 number)))
|
(true-or-false? nil (equal '(1 3 5) `(1 3 number)))
|
||||||
(assert-equal ____ `(1 3 ,number))
|
(assert-equal '(1 3 5) `(1 3 ,number))
|
||||||
(assert-equal _____ `(word ,word ,word word))))
|
(assert-equal '(word dolphin dolphin word) `(word ,word ,word word))))
|
||||||
|
|
||||||
(define-test splicing
|
(define-test splicing
|
||||||
(let ((axis '(x y z)))
|
(let ((axis '(x y z)))
|
||||||
(assert-equal '(the axis are ____) `(the axis are ,axis))
|
(assert-equal '(the axis are (x y z)) `(the axis are ,axis))
|
||||||
(assert-equal '(the axis are ____) `(the axis are ,@axis)))
|
(assert-equal '(the axis are x y z) `(the axis are ,@axis)))
|
||||||
(let ((coordinates '((43.15 77.6) (42.36 71.06))))
|
(let ((coordinates '((43.15 77.6) (42.36 71.06))))
|
||||||
(assert-equal ____ `(the coordinates are ,coordinates))
|
(assert-equal '(the coordinates are ((43.15 77.6) (42.36 71.06))) `(the coordinates are ,coordinates))
|
||||||
(assert-equal ____ `(the coordinates are ,@coordinates))))
|
(assert-equal '(the coordinates are (43.15 77.6) (42.36 71.06)) `(the coordinates are ,@coordinates))))
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
(very-silly-condition #'handle-very-silly-condition)
|
(very-silly-condition #'handle-very-silly-condition)
|
||||||
(most-silly-condition #'handle-most-silly-condition))
|
(most-silly-condition #'handle-most-silly-condition))
|
||||||
(signal (make-condition 'most-silly-condition)))
|
(signal (make-condition 'most-silly-condition)))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:most-silly-condition :very-silly-condition :silly-condition) *list*)))
|
||||||
|
|
||||||
(define-test multiple-handler-binds
|
(define-test multiple-handler-binds
|
||||||
;; It is possible to bind handlers in steps.
|
;; It is possible to bind handlers in steps.
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
(most-silly-condition #'handle-most-silly-condition))
|
(most-silly-condition #'handle-most-silly-condition))
|
||||||
(handler-bind ((very-silly-condition #'handle-very-silly-condition))
|
(handler-bind ((very-silly-condition #'handle-very-silly-condition))
|
||||||
(signal (make-condition 'most-silly-condition))))
|
(signal (make-condition 'most-silly-condition))))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:most-silly-condition :silly-condition :very-silly-condition) *list*)))
|
||||||
|
|
||||||
(define-test same-handler
|
(define-test same-handler
|
||||||
;; The same handler may be bound multiple times.
|
;; The same handler may be bound multiple times.
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
(silly-condition #'handle-silly-condition)
|
(silly-condition #'handle-silly-condition)
|
||||||
(very-silly-condition #'handle-very-silly-condition))
|
(very-silly-condition #'handle-very-silly-condition))
|
||||||
(signal (make-condition 'most-silly-condition))))
|
(signal (make-condition 'most-silly-condition))))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:silly-condition :silly-condition :very-silly-condition :silly-condition :very-silly-condition ) *list*)))
|
||||||
|
|
||||||
(define-test handler-types
|
(define-test handler-types
|
||||||
;; A handler is not executed if it does not match the condition type.
|
;; A handler is not executed if it does not match the condition type.
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
(very-silly-condition #'handle-very-silly-condition)
|
(very-silly-condition #'handle-very-silly-condition)
|
||||||
(most-silly-condition #'handle-most-silly-condition))
|
(most-silly-condition #'handle-most-silly-condition))
|
||||||
(signal (make-condition 'very-silly-condition)))
|
(signal (make-condition 'very-silly-condition)))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:very-silly-condition :silly-condition) *list*)))
|
||||||
|
|
||||||
(define-test handler-transfer-of-control
|
(define-test handler-transfer-of-control
|
||||||
;; A handler may decline to handle the condition if it returns normally,
|
;; A handler may decline to handle the condition if it returns normally,
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
(return-from my-block)))
|
(return-from my-block)))
|
||||||
(silly-condition #'handle-silly-condition))
|
(silly-condition #'handle-silly-condition))
|
||||||
(signal (make-condition 'silly-condition))))
|
(signal (make-condition 'silly-condition))))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:silly-condition) *list*)))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
(handler-case (signal (make-condition 'my-error))
|
(handler-case (signal (make-condition 'my-error))
|
||||||
(error (condition) (handle-error condition))
|
(error (condition) (handle-error condition))
|
||||||
(my-error (condition) (handle-my-error condition)))
|
(my-error (condition) (handle-my-error condition)))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:error) *list*))) ; well, I don't really understand that
|
||||||
|
|
||||||
(define-test handler-case-order
|
(define-test handler-case-order
|
||||||
;; The order of handler cases matters.
|
;; The order of handler cases matters.
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
(handler-case (signal (make-condition 'my-error))
|
(handler-case (signal (make-condition 'my-error))
|
||||||
(my-error (condition) (handle-my-error condition))
|
(my-error (condition) (handle-my-error condition))
|
||||||
(error (condition) (handle-error condition)))
|
(error (condition) (handle-error condition)))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:my-error) *list*)))
|
||||||
|
|
||||||
(define-test handler-case-type
|
(define-test handler-case-type
|
||||||
;; A handler cases is not executed if it does not match the condition type.
|
;; A handler cases is not executed if it does not match the condition type.
|
||||||
|
@ -179,7 +179,16 @@
|
||||||
(handler-case (signal (make-condition 'error))
|
(handler-case (signal (make-condition 'error))
|
||||||
(my-error (condition) (handle-my-error condition))
|
(my-error (condition) (handle-my-error condition))
|
||||||
(error (condition) (handle-error condition)))
|
(error (condition) (handle-error condition)))
|
||||||
(assert-equal ____ *list*)))
|
(assert-equal '(:error) *list*)))
|
||||||
|
|
||||||
|
;;; it seems that difference between #'handler-case and #'handler-bind
|
||||||
|
;; is that first is like try-catch, where single, first condition for signal is executed
|
||||||
|
;; (and expressions are not handlers, but things to evaluate)
|
||||||
|
;; and handler-bind executes all handlers applicable?
|
||||||
|
;; here handlers are functions
|
||||||
|
;; http://www.lispworks.com/documentation/HyperSpec/Body/09_ada.htm
|
||||||
|
;; here it seems that handler can either transfer control - by return-from of return
|
||||||
|
;; and that "handles" the signal, or "decline" by returning, that that means that following handlers get called
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -199,36 +208,37 @@
|
||||||
(handler-case (divide numerator denominator)
|
(handler-case (divide numerator denominator)
|
||||||
(division-by-zero () :division-by-zero)
|
(division-by-zero () :division-by-zero)
|
||||||
(type-error () :type-error))))
|
(type-error () :type-error))))
|
||||||
(assert-equal ____ (try-to-divide 6 2))
|
(assert-equal 3 (try-to-divide 6 2))
|
||||||
(assert-equal ____ (try-to-divide 6 0))
|
(assert-equal :division-by-zero (try-to-divide 6 0))
|
||||||
(assert-equal ____ (try-to-divide 6 :zero))))
|
(assert-equal :type-error (try-to-divide 6 :zero))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;;; Condition objects can contain metadata about the specific situation that
|
;;; Condition objects can contain metadata about the specific situation that
|
||||||
;;; occurred in the code.
|
;;; occurred in the code.
|
||||||
|
|
||||||
(define-test accessors-division-by-zero
|
(define-test accessors-division-by-zero
|
||||||
(let ((condition (handler-case (divide 6 0) (division-by-zero (c) c))))
|
(setq my-cond (handler-case (divide 6 0) (division-by-zero (c) c)))
|
||||||
|
(let ((my-cond (handler-case (divide 6 0) (division-by-zero (c) c))))
|
||||||
;; Disabled on CLISP and ABCL due to conformance bugs.
|
;; Disabled on CLISP and ABCL due to conformance bugs.
|
||||||
;; See https://gitlab.com/gnu-clisp/clisp/-/issues/22
|
;; See https://gitlab.com/gnu-clisp/clisp/-/issues/22
|
||||||
;; See https://github.com/armedbear/abcl/issues/177
|
;; See https://github.com/armedbear/abcl/issues/177
|
||||||
#-(or clisp abcl)
|
#-(or clisp abcl)
|
||||||
(assert-equal ____ (arithmetic-error-operands condition))
|
(assert-equal '(6 0) (arithmetic-error-operands my-cond)) ; returns '(6 0)
|
||||||
(let ((operation (arithmetic-error-operation condition)))
|
(let ((operation (arithmetic-error-operation my-cond))) ; returns #'/ holy cow
|
||||||
;; Disabled on ABCL due to a conformance bug.
|
;; Disabled on ABCL due to a conformance bug.
|
||||||
;; See https://github.com/armedbear/abcl/issues/177
|
;; See https://github.com/armedbear/abcl/issues/177
|
||||||
#-abcl
|
#-abcl
|
||||||
(assert-equal ____ (funcall operation 12 4)))))
|
(assert-equal 3 (funcall operation 12 4)))))
|
||||||
|
|
||||||
|
(setq my-condition (handler-case (divide 6 :zero) (type-error (c) c)))
|
||||||
(define-test accessors-type-error
|
(define-test accessors-type-error
|
||||||
(let ((condition (handler-case (divide 6 :zero) (type-error (c) c))))
|
(let ((condition (handler-case (divide 6 :zero) (type-error (c) c))))
|
||||||
(assert-equal ____ (type-error-datum condition))
|
(assert-equal :zero (type-error-datum my-condition))
|
||||||
(let ((expected-type (type-error-expected-type condition)))
|
(let ((expected-type (type-error-expected-type my-condition)))
|
||||||
(true-or-false? ____ (typep :zero expected-type))
|
(true-or-false? nil (typep :zero expected-type))
|
||||||
(true-or-false? ____ (typep 0 expected-type))
|
(true-or-false? t (typep 0 expected-type))
|
||||||
(true-or-false? ____ (typep "zero" expected-type))
|
(true-or-false? nil (typep "zero" expected-type))
|
||||||
(true-or-false? ____ (typep 0.0 expected-type)))))
|
(true-or-false? t (typep 0.0 expected-type)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -256,12 +266,12 @@
|
||||||
(flet ((try-log-line-type (line)
|
(flet ((try-log-line-type (line)
|
||||||
(handler-case (log-line-type line)
|
(handler-case (log-line-type line)
|
||||||
(error (condition) condition))))
|
(error (condition) condition))))
|
||||||
(assert-equal ____ (try-log-line-type "TIMESTAMP 2020-05-08 16:59:39"))
|
(assert-equal :timestamp (try-log-line-type "TIMESTAMP 2020-05-08 16:59:39"))
|
||||||
(assert-equal ____ (try-log-line-type "HTTP GET / from 127.0.0.1"))
|
(assert-equal :http (try-log-line-type "HTTP GET / from 127.0.0.1"))
|
||||||
(assert-equal ____ (try-log-line-type "LOGIN administrator:hunter2"))
|
(assert-equal :login (try-log-line-type "LOGIN administrator:hunter2"))
|
||||||
(let ((condition (try-log-line-type "WARNING: 95% of disk space used")))
|
(let ((condition (try-log-line-type "WARNING: 95% of disk space used")))
|
||||||
(assert-equal ____ (line condition))
|
(assert-equal "WARNING: 95% of disk space used" (line condition))
|
||||||
(assert-equal ____ (reason condition)))
|
(assert-equal :unknown-log-line-type (reason condition)))
|
||||||
(let ((condition (try-log-line-type 5555)))
|
(let ((condition (try-log-line-type 5555)))
|
||||||
(assert-equal 'string (____ condition))
|
(assert-equal 'string (type-error-expected-type condition))
|
||||||
(assert-equal 5555 (____ condition)))))
|
(assert-equal 5555 (type-error-datum condition)))))
|
||||||
|
|
|
@ -18,20 +18,29 @@
|
||||||
|
|
||||||
(defclass dice-set ()
|
(defclass dice-set ()
|
||||||
;; Fill in the blank with a proper slot definition.
|
;; Fill in the blank with a proper slot definition.
|
||||||
(____))
|
((dice-values :initarg :dice-values)))
|
||||||
|
|
||||||
|
(setq *my-dice* (make-instance 'dice-set :dice-values '(1 2 3 5)))
|
||||||
|
(slot-value *my-dice* 'dice-values)
|
||||||
|
|
||||||
;;; This method might be unnecessary, depending on how you define the slots of
|
;;; This method might be unnecessary, depending on how you define the slots of
|
||||||
;;; DICE-SET.
|
;;; DICE-SET.
|
||||||
|
|
||||||
(defmethod dice-values ((object dice-set))
|
(defmethod dice-values ((object dice-set))
|
||||||
____)
|
(slot-value object 'dice-values))
|
||||||
|
|
||||||
(defmethod roll (count (object dice-set))
|
(defmethod roll (count (object dice-set))
|
||||||
____)
|
(unless (and (integerp count) (< 0 count)) (signal (make-condition 'type-error
|
||||||
|
:datum count
|
||||||
|
:expected-type 'integer)))
|
||||||
|
(let ((rolls (mapcar (lambda (x) (declare (ignore x)) (+ 1 (random 6))) (make-list count))))
|
||||||
|
(setf (slot-value object 'dice-values) rolls)))
|
||||||
|
|
||||||
|
(roll 5 *my-dice*)
|
||||||
|
|
||||||
(define-test make-dice-set
|
(define-test make-dice-set
|
||||||
(let ((dice (make-instance 'dice-set)))
|
(let ((dice (make-instance 'dice-set)))
|
||||||
(assert-true (typep dice 'dice-set))))
|
(assert-true (typep dice 'dice-set))))
|
||||||
|
|
||||||
(define-test dice-are-six-sided
|
(define-test dice-are-six-sided
|
||||||
(let ((dice (make-instance 'dice-set)))
|
(let ((dice (make-instance 'dice-set)))
|
||||||
|
@ -73,21 +82,34 @@
|
||||||
(assert-equal 100 (length (roll 100 dice)))
|
(assert-equal 100 (length (roll 100 dice)))
|
||||||
(assert-equal 1 (length (roll 1 dice)))))
|
(assert-equal 1 (length (roll 1 dice)))))
|
||||||
|
|
||||||
|
;; this is about signaling error, rhg
|
||||||
|
;; but wtf about expected-type being subtype of '(integer 1 6) ???
|
||||||
|
;; shouldn't it be any integer?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define-test junk-as-dice-count
|
(define-test junk-as-dice-count
|
||||||
(let ((dice (make-instance 'dice-set)))
|
(let ((dice (make-instance 'dice-set)))
|
||||||
(labels ((dice-failure (count)
|
(labels ((dice-failure (count)
|
||||||
(handler-case (progn (roll count dice)
|
(handler-case (progn (roll count dice)
|
||||||
(error "Test failure"))
|
(error "Test failure"))
|
||||||
(error (condition) condition)))
|
(error (condition) condition)))
|
||||||
(test-dice-failure (value)
|
(test-dice-failure (value)
|
||||||
(let* ((condition (dice-failure value))
|
(let* ((condition (dice-failure value))
|
||||||
(expected-type (type-error-expected-type condition)))
|
(expected-type (type-error-expected-type condition)))
|
||||||
(assert-true (typep condition 'type-error))
|
(assert-true (typep condition 'type-error))
|
||||||
(assert-equal value (type-error-datum condition))
|
(assert-equal value (type-error-datum condition))
|
||||||
(assert-true (subtypep '(integer 1 6) expected-type)))))
|
(assert-true (subtypep '(integer 1 6) expected-type)) ; wtf is this?
|
||||||
(test-dice-failure 0)
|
; surely it's got to be just integer?
|
||||||
(test-dice-failure "0")
|
)))
|
||||||
(test-dice-failure :zero)
|
(test-dice-failure 0)
|
||||||
(test-dice-failure 18.0)
|
(test-dice-failure "0")
|
||||||
(test-dice-failure -7)
|
(test-dice-failure :zero)
|
||||||
(test-dice-failure '(6 6 6)))))
|
(test-dice-failure 18.0)
|
||||||
|
(test-dice-failure -7)
|
||||||
|
(test-dice-failure '(6 6 6)))))
|
||||||
|
|
||||||
|
;; (setq dice *my-dice*)
|
||||||
|
;; (dice-failure "0")
|
||||||
|
|
||||||
|
;;; welp. signaling errors is the most unfamiliar thing for me
|
||||||
|
|
|
@ -23,4 +23,4 @@
|
||||||
;;; This is a free form assignment, so approach it however you desire.
|
;;; This is a free form assignment, so approach it however you desire.
|
||||||
|
|
||||||
(define-test play-greed
|
(define-test play-greed
|
||||||
(assert-true ____))
|
(assert-true t))
|
||||||
|
|
|
@ -23,19 +23,22 @@
|
||||||
(cond ((null forms) 'nil)
|
(cond ((null forms) 'nil)
|
||||||
((null (rest forms)) (first forms))
|
((null (rest forms)) (first forms))
|
||||||
(t `(when ,(first forms)
|
(t `(when ,(first forms)
|
||||||
,(generate (rest forms)))))))
|
,(generate (rest forms))))))) ; wowy
|
||||||
(generate forms)))
|
(generate forms)))
|
||||||
|
|
||||||
|
(when (= 2 3) "hello")
|
||||||
|
|
||||||
(define-test my-and
|
(define-test my-and
|
||||||
;; ASSERT-EXPANDS macroexpands the first form once and checks if it is equal
|
;; ASSERT-EXPANDS macroexpands the first form once and checks if it is equal
|
||||||
;; to the second form.
|
;; to the second form.
|
||||||
(assert-expands (my-and (= 0 (random 6)) (error "Bang!"))
|
(assert-expands (my-and (= 0 (random 6)) (error "Bang!"))
|
||||||
'(when (= 0 (random 6)) (error "Bang!")))
|
'(when (= 0 (random 6)) (error "Bang!")))
|
||||||
(assert-expands (my-and (= 0 (random 6))
|
(assert-expands (my-and (= 0 (random 6))
|
||||||
(= 0 (random 6))
|
(= 0 (random 6))
|
||||||
(= 0 (random 6))
|
(= 0 (random 6))
|
||||||
(error "Bang!"))
|
(error "Bang!"))
|
||||||
____))
|
'(when (= 0 (random 6))
|
||||||
|
(when (= 0 (random 6)) (when (= 0 (random 6)) (error "Bang!"))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -43,16 +46,19 @@
|
||||||
|
|
||||||
(define-test variable-capture
|
(define-test variable-capture
|
||||||
(macrolet ((for ((var start stop) &body body)
|
(macrolet ((for ((var start stop) &body body)
|
||||||
`(do ((,var ,start (1+ ,var))
|
`(do ((,var ,start (1+ ,var))
|
||||||
(limit ,stop))
|
(limit ,stop))
|
||||||
((> ,var limit))
|
((> ,var limit))
|
||||||
,@body)))
|
,@body)))
|
||||||
(let ((limit 10)
|
(let ((limit 10)
|
||||||
(result '()))
|
(result '()))
|
||||||
(for (i 0 3)
|
(for (i 0 3)
|
||||||
(push i result)
|
(push i result)
|
||||||
(assert-equal ____ limit))
|
(assert-equal 3 limit))
|
||||||
(assert-equal ____ (nreverse result)))))
|
(assert-equal '(0 1 2 3) (nreverse result))))) ; didn't get it on first tries, ugh
|
||||||
|
;; oh, ok - then try to use names that wouldn't happen in outside condext
|
||||||
|
;; so that explicitly defined things in outside context get overshadowed
|
||||||
|
;; ok
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -60,20 +66,23 @@
|
||||||
;;; meant to be evaluated once.
|
;;; meant to be evaluated once.
|
||||||
|
|
||||||
(define-test multiple-evaluation
|
(define-test multiple-evaluation
|
||||||
;; We use MACROLET for defining a local macro.
|
;; We use MACROLET for defining a local macro.
|
||||||
(macrolet ((for ((var start stop) &body body)
|
(macrolet ((for ((var start stop) &body body)
|
||||||
`(do ((,var ,start (1+ ,var)))
|
`(do ((,var ,start (1+ ,var)))
|
||||||
((> ,var ,stop))
|
((> ,var ,stop))
|
||||||
,@body)))
|
,@body)))
|
||||||
(let ((side-effects '())
|
(let ((side-effects '())
|
||||||
(result '()))
|
(result '()))
|
||||||
;; Our functions RETURN-0 and RETURN-3 have side effects.
|
;; Our functions RETURN-0 and RETURN-3 have side effects.
|
||||||
(flet ((return-0 () (push 0 side-effects) 0)
|
(flet ((return-0 () (push 0 side-effects) 0)
|
||||||
(return-3 () (push 3 side-effects) 3))
|
(return-3 () (push 3 side-effects) 3))
|
||||||
(for (i (return-0) (return-3))
|
(for (i (return-0) (return-3))
|
||||||
(push i result)))
|
(push i result)))
|
||||||
(assert-equal ____ (nreverse result))
|
(assert-equal '(0 1 2 3) (nreverse result))
|
||||||
(assert-equal ____ (nreverse side-effects)))))
|
(assert-equal '(0 3 3 3 3 3) (nreverse side-effects)))))
|
||||||
|
; omg, fuck this guessing
|
||||||
|
; ok, the ,stop was evaluated on each iteraction
|
||||||
|
; to check "whether to stop"
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -81,36 +90,53 @@
|
||||||
;;; subforms.
|
;;; subforms.
|
||||||
|
|
||||||
(define-test wrong-evaluation-order
|
(define-test wrong-evaluation-order
|
||||||
(macrolet ((for ((var start stop) &body body)
|
(macrolet ((for ((var start stop) &body body)
|
||||||
;; The function GENSYM creates GENerated SYMbols, guaranteed to
|
;; The function GENSYM creates GENerated SYMbols, guaranteed to
|
||||||
;; be unique in the whole Lisp system. Because of that, they
|
;; be unique in the whole Lisp system. Because of that, they
|
||||||
;; cannot capture other symbols, preventing variable capture.
|
;; cannot capture other symbols, preventing variable capture.
|
||||||
(let ((limit (gensym "LIMIT")))
|
(let ((limit (gensym "LIMIT")))
|
||||||
`(do ((,limit ,stop)
|
`(do ((,limit ,stop)
|
||||||
(,var ,start (1+ ,var)))
|
(,var ,start (1+ ,var)))
|
||||||
((> ,var ,limit))
|
((> ,var ,limit))
|
||||||
,@body))))
|
,@body))))
|
||||||
(let ((side-effects '())
|
(let ((side-effects '())
|
||||||
(result '()))
|
(result '()))
|
||||||
(flet ((return-0 () (push 0 side-effects) 0)
|
(flet ((return-0 () (push 0 side-effects) 0)
|
||||||
(return-3 () (push 3 side-effects) 3))
|
(return-3 () (push 3 side-effects) 3))
|
||||||
(for (i (return-0) (return-3))
|
(for (i (return-0) (return-3))
|
||||||
(push i result)))
|
(push i result)))
|
||||||
(assert-equal ____ (nreverse result))
|
(assert-equal '(0 1 2 3) (nreverse result))
|
||||||
(assert-equal ____ (nreverse side-effects)))))
|
(assert-equal '(3 0) (nreverse side-effects)))))
|
||||||
|
;; didn't got on first try,
|
||||||
|
;; but yes, for gensym limit ,stop is evaluated first
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(define-test for
|
(define-test for
|
||||||
(macrolet ((for ((var start stop) &body body)
|
(macrolet ((for ((var start stop) &body body)
|
||||||
;; Fill in the blank with a correct FOR macroexpansion that is
|
;; Fill in the blank with a correct FOR macroexpansion that is
|
||||||
;; not affected by the three macro pitfalls mentioned above.
|
;; not affected by the three macro pitfalls mentioned above.
|
||||||
____))
|
(let ((initial (gensym "INITIAL"))
|
||||||
(let ((side-effects '())
|
(limit (gensym "LIMIT")))
|
||||||
(result '()))
|
`(do* ((,initial ,start)
|
||||||
(flet ((return-0 () (push 0 side-effects) 0)
|
(,limit ,stop)
|
||||||
(return-3 () (push 3 side-effects) 3))
|
(,var ,initial (1+ ,var)))
|
||||||
(for (i (return-0) (return-3))
|
((> ,var ,limit))
|
||||||
(push i result)))
|
,@body))))
|
||||||
(assert-equal '(0 1 2 3) (nreverse result))
|
(let ((side-effects '())
|
||||||
(assert-equal '(0 3) (nreverse side-effects)))))
|
(result '()))
|
||||||
|
(flet ((return-0 () (push 0 side-effects) 0)
|
||||||
|
(return-3 () (push 3 side-effects) 3))
|
||||||
|
(for (i (return-0) (return-3))
|
||||||
|
(push i result)))
|
||||||
|
(assert-equal '(0 1 2 3) (nreverse result))
|
||||||
|
(assert-equal '(0 3) (nreverse side-effects)))))
|
||||||
|
|
||||||
|
;; (do* ((a (return-0))
|
||||||
|
;; (b (return-3))
|
||||||
|
;; (i a (1+ i)))
|
||||||
|
;; ((> i b))
|
||||||
|
;; (push i result))
|
||||||
|
;;
|
||||||
|
;; so, my mistake was: using DO and trying to cross reference temp vars
|
||||||
|
;; and mistyping 1+ as 1_
|
||||||
|
|
|
@ -14,15 +14,28 @@
|
||||||
|
|
||||||
(define-condition triangle-error (error)
|
(define-condition triangle-error (error)
|
||||||
;; Fill in the blank with a suitable slot definition.
|
;; Fill in the blank with a suitable slot definition.
|
||||||
(____))
|
((triangle-error-sides :initarg :sides :reader triangle-error-sides)))
|
||||||
|
|
||||||
(defun triangle (a b c)
|
(defun triangle (a b c)
|
||||||
;; Fill in the blank with a function that satisfies the below tests.
|
;; Fill in the blank with a function that satisfies the below tests.
|
||||||
____)
|
(cond
|
||||||
|
((or (<= a 0) (<= b 0) (<= c 0)) (signal (make-condition 'type-error
|
||||||
|
:datum (car (remove-if-not (lambda (n) (>= 0 n)) (list a b c)))
|
||||||
|
:expected-type '(real (0)))))
|
||||||
|
((or (<= (+ a b) c) (<= (+ b c) a) (<= (+ a c) b)) (signal (make-condition 'triangle-error
|
||||||
|
:sides (list a b c))))
|
||||||
|
((= a b c) :equilateral)
|
||||||
|
((or (= a b) (= b c) (= a c)) :isosceles)
|
||||||
|
(t :scalene)))
|
||||||
|
|
||||||
|
(car (remove-if (lambda (n) (>= 0 n)) (list 1 2 -2)))
|
||||||
|
|
||||||
|
(triangle 1 1 1)
|
||||||
|
(triangle 0 0 0)
|
||||||
|
|
||||||
(define-test equilateral-triangles
|
(define-test equilateral-triangles
|
||||||
;; Equilateral triangles have three sides of equal length,
|
;; Equilateral triangles have three sides of equal length,
|
||||||
(assert-equal :equilateral (triangle 2 2 2))
|
(assert-equal :equilateral (triangle 2 2 2))
|
||||||
(assert-equal :equilateral (triangle 10 10 10)))
|
(assert-equal :equilateral (triangle 10 10 10)))
|
||||||
|
|
||||||
(define-test isosceles-triangles
|
(define-test isosceles-triangles
|
||||||
|
@ -39,27 +52,39 @@
|
||||||
(assert-equal :scalene (triangle 10 11 12))
|
(assert-equal :scalene (triangle 10 11 12))
|
||||||
(assert-equal :scalene (triangle 5 4 2)))
|
(assert-equal :scalene (triangle 5 4 2)))
|
||||||
|
|
||||||
(define-test illegal-triangles
|
(defun triangle-failure (a b c)
|
||||||
;; Not all triplets make valid triangles.
|
|
||||||
(flet ((triangle-failure (a b c)
|
|
||||||
(handler-case (progn (triangle a b c) (error "Test failure"))
|
(handler-case (progn (triangle a b c) (error "Test failure"))
|
||||||
(error (condition) condition))))
|
(error (condition) condition)))
|
||||||
(let ((condition (triangle-failure 0 0 0)))
|
(triangle 0 0 0)
|
||||||
(assert-true (typep condition 'type-error))
|
(setq condi (triangle-failure 2 -1 1))
|
||||||
(assert-equal 0 (type-error-datum condition))
|
(type-error-datum condi)
|
||||||
;; The type (REAL (0)) represents all positive numbers.
|
(type-error-expected-type condi)
|
||||||
(assert-true (subtypep (type-error-expected-type condition) '(real (0))))
|
|
||||||
;; If two type specifiers are SUBTYPEP of one another, then they represent
|
(setq condi (triangle-failure 2 4 2))
|
||||||
;; the same Lisp type.
|
(triangle-error-sides condi)
|
||||||
(assert-true (subtypep '(real (0)) (type-error-expected-type condition))))
|
|
||||||
(let ((condition (triangle-failure 3 4 -5)))
|
|
||||||
(assert-true (typep condition 'type-error))
|
(define-test illegal-triangles
|
||||||
(assert-equal -5 (type-error-datum condition))
|
;; Not all triplets make valid triangles.
|
||||||
(assert-true (subtypep (type-error-expected-type condition) '(real (0))))
|
(flet ((triangle-failure (a b c)
|
||||||
(assert-true (subtypep '(real (0)) (type-error-expected-type condition))))
|
(handler-case (progn (triangle a b c) (error "Test failure"))
|
||||||
(let ((condition (triangle-failure 1 1 3)))
|
(error (condition) condition))))
|
||||||
(assert-true (typep condition 'triangle-error))
|
(let ((condition (triangle-failure 0 0 0)))
|
||||||
(assert-equal '(1 1 3) (triangle-error-sides condition)))
|
(assert-true (typep condition 'type-error))
|
||||||
(let ((condition (triangle-failure 2 4 2)))
|
(assert-equal 0 (type-error-datum condition))
|
||||||
(assert-true (typep condition 'triangle-error))
|
;; The type (REAL (0)) represents all positive numbers.
|
||||||
(assert-equal '(2 4 2) (triangle-error-sides condition)))))
|
(assert-true (subtypep (type-error-expected-type condition) '(real (0))))
|
||||||
|
;; If two type specifiers are SUBTYPEP of one another, then they represent
|
||||||
|
;; the same Lisp type.
|
||||||
|
(assert-true (subtypep '(real (0)) (type-error-expected-type condition))))
|
||||||
|
(let ((condition (triangle-failure 3 4 -5)))
|
||||||
|
(assert-true (typep condition 'type-error))
|
||||||
|
(assert-equal -5 (type-error-datum condition))
|
||||||
|
(assert-true (subtypep (type-error-expected-type condition) '(real (0))))
|
||||||
|
(assert-true (subtypep '(real (0)) (type-error-expected-type condition))))
|
||||||
|
(let ((condition (triangle-failure 1 1 3)))
|
||||||
|
(assert-true (typep condition 'triangle-error))
|
||||||
|
(assert-equal '(1 1 3) (triangle-error-sides condition)))
|
||||||
|
(let ((condition (triangle-failure 2 4 2)))
|
||||||
|
(assert-true (typep condition 'triangle-error))
|
||||||
|
(assert-equal '(2 4 2) (triangle-error-sides condition)))))
|
||||||
|
|
Loading…
Reference in New Issue