Added unit tests for about half the bootstrap functions
This commit is contained in:
parent
3f4e873e74
commit
10b2ad5322
|
@ -67,6 +67,42 @@
|
||||||
ss))
|
ss))
|
||||||
(str c))))
|
(str c))))
|
||||||
|
|
||||||
|
(defn pretty-print
|
||||||
|
"This isn't the world's best pretty printer but it sort of works."
|
||||||
|
([^beowulf.cons_cell.ConsCell cell]
|
||||||
|
(println (pretty-print cell 80 0)))
|
||||||
|
([^beowulf.cons_cell.ConsCell cell width level]
|
||||||
|
(loop [c cell
|
||||||
|
n (inc level)
|
||||||
|
s "("]
|
||||||
|
(if
|
||||||
|
(instance? beowulf.cons_cell.ConsCell c)
|
||||||
|
(let [car (.CAR c)
|
||||||
|
cdr (.CDR c)
|
||||||
|
cons? (instance? beowulf.cons_cell.ConsCell cdr)
|
||||||
|
print-width (count (print-str c))
|
||||||
|
indent (apply str (repeat n " "))
|
||||||
|
ss (str
|
||||||
|
s
|
||||||
|
(pretty-print car width n)
|
||||||
|
(cond
|
||||||
|
cons?
|
||||||
|
(if
|
||||||
|
(< (+ (count indent) print-width) width)
|
||||||
|
" "
|
||||||
|
(str "\n" indent))
|
||||||
|
(or (nil? cdr) (= cdr 'NIL))
|
||||||
|
")"
|
||||||
|
:else
|
||||||
|
(str " . " (pretty-print cdr width n) ")")))]
|
||||||
|
(if
|
||||||
|
cons?
|
||||||
|
(recur cdr n ss)
|
||||||
|
ss))
|
||||||
|
(str c)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defmethod clojure.core/print-method beowulf.cons_cell.ConsCell
|
(defmethod clojure.core/print-method beowulf.cons_cell.ConsCell
|
||||||
[this writer]
|
[this writer]
|
||||||
(.write writer (to-string this)))
|
(.write writer (to-string this)))
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
(defn null
|
(defn null
|
||||||
[x]
|
[x]
|
||||||
(= x NIL))
|
(if (= x NIL) 'T 'F))
|
||||||
|
|
||||||
(defn primitive-atom
|
(defn primitive-atom
|
||||||
"It is not clear to me from the documentation whether `(ATOM 7)` should return
|
"It is not clear to me from the documentation whether `(ATOM 7)` should return
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
all those fiddly `#'c[ad]+r'` functions a bit easier"
|
all those fiddly `#'c[ad]+r'` functions a bit easier"
|
||||||
[l path]
|
[l path]
|
||||||
(cond
|
(cond
|
||||||
(null l) NIL
|
(= l NIL) NIL
|
||||||
(empty? path) l
|
(empty? path) l
|
||||||
:else (case (last path)
|
:else (case (last path)
|
||||||
\a (uaf (car l) (butlast path))
|
\a (uaf (car l) (butlast path))
|
||||||
|
@ -87,30 +87,23 @@
|
||||||
(defn cdaadr [x] (uaf x (seq "daad")))
|
(defn cdaadr [x] (uaf x (seq "daad")))
|
||||||
(defn cdaddr [x] (uaf x (seq "dadd")))
|
(defn cdaddr [x] (uaf x (seq "dadd")))
|
||||||
|
|
||||||
;; (defn eq
|
(defn eq
|
||||||
;; "`eq` is only defined for atoms (symbols); it is NOT pointer identity, as
|
;; For some reason providing a doc string for this function breaks the
|
||||||
;; it is in later Lisps. Returns `'T` on success (identical atoms), `'F`
|
;; Clojure parser!
|
||||||
;; (NOT `NIL`) on failure. The behaviour if either argument is not an atom is
|
[x y]
|
||||||
;; stated to be 'undefined', but I shall return `'F` for consistency."I
|
(if (and (= (primitive-atom x) 'T) (= x y)) 'T 'F))
|
||||||
;; [x y]
|
|
||||||
;; (cond
|
|
||||||
;; (and (primitive-atom? x) (= x y)) 'T
|
|
||||||
;; :else
|
|
||||||
;; 'F))
|
|
||||||
|
|
||||||
(defn eq [x y] (if (and (primitive-atom? x) (= x y)) T F))
|
|
||||||
|
|
||||||
(defn equal
|
(defn equal
|
||||||
"This is a predicate that is true if its two arguments are identical
|
"This is a predicate that is true if its two arguments are identical
|
||||||
S-expressions, and false if they are different. (The elementary predicate
|
S-expressions, and false if they are different. (The elementary predicate
|
||||||
`eq` is defined only for atomic arguments.) The definition of `equal` is
|
`eq` is defined only for atomic arguments.) The definition of `equal` is
|
||||||
an example of a conditional expression inside a conditional expression."
|
an example of a conditional expression inside a conditional expression.
|
||||||
|
|
||||||
|
NOTE: returns F on failure, not NIL"
|
||||||
[x y]
|
[x y]
|
||||||
(cond
|
(cond
|
||||||
(primitive-atom? x) (cond
|
(= (primitive-atom x) 'T) (eq x y)
|
||||||
(primitive-atom? y) (eq x y)
|
(= (equal (car x) (car y)) 'T) (equal (cdr x) (cdr y))
|
||||||
:else 'F) ;; NOTE: returns F on failure, not NIL
|
|
||||||
(equal (car x) (car y)) (equal (cdr x) (cdr y))
|
|
||||||
:else 'F))
|
:else 'F))
|
||||||
|
|
||||||
(defn subst
|
(defn subst
|
||||||
|
@ -118,8 +111,8 @@
|
||||||
all occurrences of the atomic symbol `y` in the S-expression `z`."
|
all occurrences of the atomic symbol `y` in the S-expression `z`."
|
||||||
[x y z]
|
[x y z]
|
||||||
(cond
|
(cond
|
||||||
(equal y z) x
|
(= (equal y z) 'T) x
|
||||||
(primitive-atom? z) z ;; NIL is a symbol
|
(= (primitive-atom? z) 'T) z ;; NIL is a symbol
|
||||||
:else
|
:else
|
||||||
(make-cons-cell (subst x y (car z)) (subst x y (cdr z)))))
|
(make-cons-cell (subst x y (car z)) (subst x y (cdr z)))))
|
||||||
|
|
||||||
|
@ -130,9 +123,9 @@
|
||||||
See page 11 of the Lisp 1.5 Programmers Manual."
|
See page 11 of the Lisp 1.5 Programmers Manual."
|
||||||
[x y]
|
[x y]
|
||||||
(cond
|
(cond
|
||||||
(null x) y
|
(= x NIL) y
|
||||||
:else
|
:else
|
||||||
(cons (car x) (append (cdr x) y))))
|
(make-cons-cell (car x) (append (cdr x) y))))
|
||||||
|
|
||||||
|
|
||||||
(defn member
|
(defn member
|
||||||
|
@ -144,7 +137,7 @@
|
||||||
[x y]
|
[x y]
|
||||||
(cond
|
(cond
|
||||||
(= y NIL) F ;; NOTE: returns F on falsity, not NIL
|
(= y NIL) F ;; NOTE: returns F on falsity, not NIL
|
||||||
(equal x (car y)) T
|
(= (equal x (car y)) 'T) 'T
|
||||||
:else (member x (cdr y))))
|
:else (member x (cdr y))))
|
||||||
|
|
||||||
(defn pairlis
|
(defn pairlis
|
||||||
|
@ -162,7 +155,7 @@
|
||||||
(cond
|
(cond
|
||||||
;; the original tests only x; testing y as well will be a little more
|
;; the original tests only x; testing y as well will be a little more
|
||||||
;; robust if `x` and `y` are not the same length.
|
;; robust if `x` and `y` are not the same length.
|
||||||
(or (null x) (null y)) a
|
(or (= NIL x) (= NIL y)) a
|
||||||
:else (make-cons-cell
|
:else (make-cons-cell
|
||||||
(make-cons-cell (car x) (car y))
|
(make-cons-cell (car x) (car y))
|
||||||
(pairlis (cdr x) (cdr y) a))))
|
(pairlis (cdr x) (cdr y) a))))
|
||||||
|
@ -176,9 +169,9 @@
|
||||||
See page 12 of the Lisp 1.5 Programmers Manual."
|
See page 12 of the Lisp 1.5 Programmers Manual."
|
||||||
[x a]
|
[x a]
|
||||||
(cond
|
(cond
|
||||||
(null a) NIL ;; this clause is not present in the original but is added for
|
(= NIL a) NIL ;; this clause is not present in the original but is added for
|
||||||
;; robustness.
|
;; robustness.
|
||||||
(equal (caar a) x) (car a)
|
(= (equal (caar a) x) 'T) (car a)
|
||||||
:else
|
:else
|
||||||
(primitive-assoc x (cdr a))))
|
(primitive-assoc x (cdr a))))
|
||||||
|
|
||||||
|
@ -187,8 +180,8 @@
|
||||||
? I think this is doing variable binding in the stack frame?"
|
? I think this is doing variable binding in the stack frame?"
|
||||||
[a z]
|
[a z]
|
||||||
(cond
|
(cond
|
||||||
(null a) z
|
(= NIL a) z
|
||||||
(= (caar a) z) (cdar a)
|
(= (caar a) z) (cdar a) ;; TODO: this looks definitely wrong
|
||||||
:else
|
:else
|
||||||
(sub2 (cdr a) z)))
|
(sub2 (cdr a) z)))
|
||||||
|
|
||||||
|
@ -243,10 +236,9 @@
|
||||||
`beowulf.cons-cell/ConsCell` objects.
|
`beowulf.cons-cell/ConsCell` objects.
|
||||||
See page 13 of the Lisp 1.5 Programmers Manual."
|
See page 13 of the Lisp 1.5 Programmers Manual."
|
||||||
[clauses env]
|
[clauses env]
|
||||||
(cond
|
(if
|
||||||
(not= (primitive-eval (caar clauses) env) NIL)
|
(not= (primitive-eval (caar clauses) env) NIL)
|
||||||
(primitive-eval (cadar clauses) env)
|
(primitive-eval (cadar clauses) env)
|
||||||
:else
|
|
||||||
(evcon (cdr clauses) env)))
|
(evcon (cdr clauses) env)))
|
||||||
|
|
||||||
(defn- evlis
|
(defn- evlis
|
||||||
|
|
|
@ -269,3 +269,10 @@
|
||||||
(defn primitive-read
|
(defn primitive-read
|
||||||
[]
|
[]
|
||||||
(generate (simplify (parse (read-line)))))
|
(generate (simplify (parse (read-line)))))
|
||||||
|
|
||||||
|
(defmacro gsp
|
||||||
|
"Shortcut macro - the internals of read; or, if you like, read-string.
|
||||||
|
Argument `s` should be a string representation of a valid Lisp
|
||||||
|
expression."
|
||||||
|
[s]
|
||||||
|
`(generate (simplify (parse ~s))))
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[clojure.test :refer :all]
|
[clojure.test :refer :all]
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]
|
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]
|
||||||
[beowulf.eval :refer :all]
|
[beowulf.eval :refer :all]
|
||||||
[beowulf.read :refer [parse simplify generate]]))
|
[beowulf.read :refer [gsp]]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;
|
;;;
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
actual (primitive-atom T)]
|
actual (primitive-atom T)]
|
||||||
(is (= actual expected) "T is an atom (symbol)"))
|
(is (= actual expected) "T is an atom (symbol)"))
|
||||||
(let [expected T
|
(let [expected T
|
||||||
actual (primitive-atom (generate (simplify (parse "HELLO"))))]
|
actual (primitive-atom (gsp "HELLO"))]
|
||||||
(is (= actual expected) "HELLO is an atom (symbol)"))
|
(is (= actual expected) "HELLO is an atom (symbol)"))
|
||||||
(let [expected T
|
(let [expected T
|
||||||
actual (primitive-atom 7)]
|
actual (primitive-atom 7)]
|
||||||
|
@ -30,14 +30,14 @@
|
||||||
actual (primitive-atom (make-cons-cell 'A 'B))]
|
actual (primitive-atom (make-cons-cell 'A 'B))]
|
||||||
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
||||||
(let [expected F
|
(let [expected F
|
||||||
actual (primitive-atom (generate (simplify (parse "(A B C D)"))))]
|
actual (primitive-atom (gsp "(A B C D)"))]
|
||||||
(is (= actual expected) "A list is explicitly not an atom")))
|
(is (= actual expected) "A list is explicitly not an atom")))
|
||||||
(testing "primitive-atom?"
|
(testing "primitive-atom?"
|
||||||
(let [expected T
|
(let [expected T
|
||||||
actual (primitive-atom? T)]
|
actual (primitive-atom? T)]
|
||||||
(is (= actual expected) "T is an atom (symbol)"))
|
(is (= actual expected) "T is an atom (symbol)"))
|
||||||
(let [expected T
|
(let [expected T
|
||||||
actual (primitive-atom? (generate (simplify (parse "HELLO"))))]
|
actual (primitive-atom? (gsp "HELLO"))]
|
||||||
(is (= actual expected) "HELLO is an atom (symbol)"))
|
(is (= actual expected) "HELLO is an atom (symbol)"))
|
||||||
(let [expected T
|
(let [expected T
|
||||||
actual (primitive-atom? 7)]
|
actual (primitive-atom? 7)]
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
actual (primitive-atom? (make-cons-cell 'A 'B))]
|
actual (primitive-atom? (make-cons-cell 'A 'B))]
|
||||||
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
||||||
(let [expected NIL
|
(let [expected NIL
|
||||||
actual (primitive-atom? (generate (simplify (parse "(A B C D)"))))]
|
actual (primitive-atom? (gsp "(A B C D)"))]
|
||||||
(is (= actual expected) "A list is explicitly not an atom"))
|
(is (= actual expected) "A list is explicitly not an atom"))
|
||||||
|
|
||||||
))
|
))
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
actual (car (make-cons-cell 'A 'B))]
|
actual (car (make-cons-cell 'A 'B))]
|
||||||
(is (= actual expected) "A is car of (A . B)"))
|
(is (= actual expected) "A is car of (A . B)"))
|
||||||
(let [expected 'A
|
(let [expected 'A
|
||||||
actual (car (generate (simplify (parse "(A B C D)"))))]
|
actual (car (gsp "(A B C D)"))]
|
||||||
(is (= actual expected) "A is car of (A B C D)"))
|
(is (= actual expected) "A is car of (A B C D)"))
|
||||||
(is (thrown-with-msg?
|
(is (thrown-with-msg?
|
||||||
Exception
|
Exception
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
actual (cdr (make-cons-cell 'A 'B))]
|
actual (cdr (make-cons-cell 'A 'B))]
|
||||||
(is (= actual expected) "B is cdr of (A . B)"))
|
(is (= actual expected) "B is cdr of (A . B)"))
|
||||||
(let [expected 'B
|
(let [expected 'B
|
||||||
actual (cdr (generate (simplify (parse "(A B C D)"))))]
|
actual (cdr (gsp "(A B C D)"))]
|
||||||
(is (instance? beowulf.cons_cell.ConsCell actual)
|
(is (instance? beowulf.cons_cell.ConsCell actual)
|
||||||
"cdr of (A B C D) is a cons cell")
|
"cdr of (A B C D) is a cons cell")
|
||||||
(is (= (car actual) expected) "the car of that cons-cell is B"))
|
(is (= (car actual) expected) "the car of that cons-cell is B"))
|
||||||
|
@ -90,22 +90,23 @@
|
||||||
#"Cannot take CDR of `.*"
|
#"Cannot take CDR of `.*"
|
||||||
(cdr 7))
|
(cdr 7))
|
||||||
"Can't take the cdr of a number"))
|
"Can't take the cdr of a number"))
|
||||||
(let [s (generate
|
(let [s (gsp "((((1 . 2) 3)(4 5) 6)(7 (8 9) (10 11 12) 13) 14 (15 16) 17)")]
|
||||||
(simplify
|
|
||||||
(parse
|
|
||||||
"((((1 . 2) 3)(4 5) 6)(7 (8 9) (10 11 12) 13) 14 (15 16) 17)")))]
|
|
||||||
;; structure for testing access functions
|
;; structure for testing access functions
|
||||||
(testing "cadr"
|
(testing "cadr"
|
||||||
(let [expected 'B
|
(let [expected 'B
|
||||||
actual (cadr (generate (simplify (parse "(A B C D)"))))]
|
actual (cadr (gsp "(A B C D)"))]
|
||||||
(is (= actual expected))))
|
(is (= actual expected))))
|
||||||
(testing "caddr"
|
(testing "caddr"
|
||||||
(let [expected 'C
|
(let [expected 'C
|
||||||
actual (caddr (generate (simplify (parse "(A B C D)"))))]
|
actual (caddr (gsp "(A B C D)"))]
|
||||||
(is (= actual expected))))
|
(is (= actual expected)))
|
||||||
|
(let [expected 14
|
||||||
|
actual (caddr s)]
|
||||||
|
(is (= actual expected)))
|
||||||
|
)
|
||||||
(testing "cadddr"
|
(testing "cadddr"
|
||||||
(let [expected 'D
|
(let [expected 'D
|
||||||
actual (cadddr (generate (simplify (parse "(A B C D)"))))]
|
actual (cadddr (gsp "(A B C D)"))]
|
||||||
(is (= actual expected))))
|
(is (= actual expected))))
|
||||||
(testing "caaaar"
|
(testing "caaaar"
|
||||||
(let [expected "1"
|
(let [expected "1"
|
||||||
|
@ -114,3 +115,74 @@
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest equality-tests
|
||||||
|
(testing "eq"
|
||||||
|
(let [expected 'T
|
||||||
|
actual (eq 'FRED 'FRED)]
|
||||||
|
(is (= actual expected) "identical symbols"))
|
||||||
|
(let [expected 'F
|
||||||
|
actual (eq 'FRED 'ELFREDA)]
|
||||||
|
(is (= actual expected) "different symbols"))
|
||||||
|
(let [expected 'F
|
||||||
|
l (gsp "(NOT AN ATOM)")
|
||||||
|
actual (eq l l)]
|
||||||
|
(is (= actual expected) "identical lists (eq is not defined for lists)")))
|
||||||
|
(testing "equal"
|
||||||
|
(let [expected 'T
|
||||||
|
actual (equal 'FRED 'FRED)]
|
||||||
|
(is (= actual expected) "identical symbols"))
|
||||||
|
(let [expected 'F
|
||||||
|
actual (equal 'FRED 'ELFREDA)]
|
||||||
|
(is (= actual expected) "different symbols"))
|
||||||
|
(let [expected 'T
|
||||||
|
l (gsp "(NOT AN ATOM)")
|
||||||
|
actual (equal l l)]
|
||||||
|
(is (= actual expected) "same list, same content"))
|
||||||
|
(let [expected 'T
|
||||||
|
l (gsp "(NOT AN ATOM)")
|
||||||
|
m (gsp "(NOT AN ATOM)")
|
||||||
|
actual (equal l m)]
|
||||||
|
(is (= actual expected) "different lists, same content"))
|
||||||
|
(let [expected 'F
|
||||||
|
l (gsp "(NOT AN ATOM)")
|
||||||
|
m (gsp "(NOT REALLY AN ATOM)")
|
||||||
|
actual (equal l m)]
|
||||||
|
(is (= actual expected) "different lists, different content"))))
|
||||||
|
|
||||||
|
(deftest substitution-tests
|
||||||
|
(testing "subst"
|
||||||
|
(let [expected "((A X . A) . C)"
|
||||||
|
;; differs from example in book only because of how the function
|
||||||
|
;; `beowulf.cons-cell/to-string` formats lists.
|
||||||
|
actual (print-str
|
||||||
|
(subst
|
||||||
|
(gsp "(X . A)")
|
||||||
|
(gsp "B")
|
||||||
|
(gsp "((A . B) . C)")))]
|
||||||
|
(is (= actual expected)))))
|
||||||
|
|
||||||
|
(deftest append-tests
|
||||||
|
(testing "append"
|
||||||
|
(let [expected "(A B C D E)"
|
||||||
|
actual (print-str
|
||||||
|
(append
|
||||||
|
(gsp "(A B)")
|
||||||
|
(gsp "(C D E)")))]
|
||||||
|
(is (= actual expected)))))
|
||||||
|
|
||||||
|
(deftest member-tests
|
||||||
|
(testing "member"
|
||||||
|
(let [expected 'T
|
||||||
|
actual (member (gsp "ALBERT") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||||
|
(= actual expected))
|
||||||
|
(let [expected 'T
|
||||||
|
actual (member (gsp "BELINDA") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||||
|
(= actual expected))
|
||||||
|
(let [expected 'T
|
||||||
|
actual (member (gsp "ELFREDA") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||||
|
(= actual expected))
|
||||||
|
(let [expected 'F
|
||||||
|
actual (member (gsp "BERTRAM") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||||
|
(= actual expected))))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue