Added unit tests for RPLACA and RPLACD

This commit is contained in:
Simon Brooke 2019-08-23 11:34:42 +01:00
parent 3d2c524f3f
commit 877e9ba00a
3 changed files with 94 additions and 11 deletions

View file

@ -1,7 +1,8 @@
(ns beowulf.cons-cell
"The fundamental cons cell on which all Lisp structures are built.
Lisp 1.5 lists do not necessarily have a sequence as their CDR, so
cannot be implemented on top of Clojure lists.")
Lisp 1.5 lists do not necessarily have a sequence as their CDR, and
must have both CAR and CDR mutable, so cannot be implemented on top
of Clojure lists.")
(def NIL
"The canonical empty list symbol."
@ -29,15 +30,19 @@
"like `more`, q.v., but returns List `NIL` not Clojure `nil` when empty." ))
(deftype ConsCell [^:unsynchronized-mutable CAR ^:unsynchronized-mutable CDR]
;; Note that, because the CAR and CDR fields are unsynchronised mutable - i.e.
;; plain old Java instance variables which can be written as well as read -
;; ConsCells are NOT thread safe. This does not matter, since Lisp 1.5 is
;; single threaded.
MutableSequence
(rplaca [this value]
(rplaca [this value]
(if
(or
(satisfies? MutableSequence value) ;; can't reference
;; beowulf.cons_cell.ConsCell,
;; because it is not yet
;; defined
;; beowulf.cons_cell.ConsCell,
;; because it is not yet
;; defined
(number? value)
(symbol? value))
(do
@ -62,7 +67,7 @@
{:cause :bad-value
:detail :rplaca}))))
(getCdr [this]
(. this CDR))
(. this CDR))
clojure.lang.ISeq
(cons [this x] (ConsCell. x this))

View file

@ -1,17 +1,68 @@
(ns beowulf.host
"provides Lisp 1.5 functions which can't be (or can't efficiently
be) implemented in Lisp 1.5, which therefore need to be implemented in the
host language, in this case Clojure.")
host language, in this case Clojure."
(:require [beowulf.cons-cell :refer [T NIL F]]
;; note hyphen - this is Clojure...
)
(:import [beowulf.cons_cell ConsCell]
;; note underscore - same namespace, but Java.
))
;; these are CANDIDATES to be host-implemented. only a subset of them MUST be.
;; those which can be implemented in Lisp should be, since that aids
;; portability.
;; RPLACA
;; RPLACD
(defn RPLACA
"Replace the CAR pointer of this `cell` with this `value`. Dangerous, should
really not exist, but does in Lisp 1.5 (and was important for some
performance hacks in early Lisps)"
[^ConsCell cell value]
(if
(instance? ConsCell cell)
(if
(or
(instance? ConsCell value)
(number? value)
(symbol? value)
(= value NIL))
(do
(.rplaca cell value)
cell)
(throw (ex-info
(str "Invalid value in RPLACA: `" value "` (" (type value) ")")
{:cause :bad-value
:detail :rplaca})))
(throw (ex-info
(str "Invalid cell in RPLACA: `" cell "` (" (type cell) ")")
{:cause :bad-value
:detail :rplaca}))))
;; PLUS
(defn RPLACD
"Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
really not exist, but does in Lisp 1.5 (and was important for some
performance hacks in early Lisps)"
[^ConsCell cell value]
(if
(instance? ConsCell cell)
(if
(or
(instance? ConsCell value)
(number? value)
(symbol? value)
(= value NIL))
(do
(.rplacd cell value)
cell)
(throw (ex-info
(str "Invalid value in RPLACD: `" value "` (" (type value) ")")
{:cause :bad-value
:detail :rplaca})))
(throw (ex-info
(str "Invalid cell in RPLACD: `" cell "` (" (type cell) ")")
{:cause :bad-value
:detail :rplaca}))));; PLUS
;; MINUS

View file

@ -0,0 +1,27 @@
(ns beowulf.host-test
(:require [clojure.math.numeric-tower :refer [abs]]
[clojure.test :refer :all]
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]
[beowulf.bootstrap :refer [CDR]]
[beowulf.host :refer :all]
[beowulf.read :refer [gsp]]))
(deftest destructive-change-test
(testing "RPLACA"
(let
[l (make-beowulf-list '(A B C D E))
target (CDR l)
expected "(A F C D E)"
actual (do (RPLACA target 'F) (print-str l))]
(is (= actual expected)))
)
(testing "RPLACA"
(let
[l (make-beowulf-list '(A B C D E))
target (CDR l)
expected "(A B . F)"
actual (do (RPLACD target 'F) (print-str l))]
(is (= actual expected)))
)
)