diff --git a/docs/cloverage/beowulf/bootstrap.clj.html b/docs/cloverage/beowulf/bootstrap.clj.html
index c45387d..8a1fa87 100644
--- a/docs/cloverage/beowulf/bootstrap.clj.html
+++ b/docs/cloverage/beowulf/bootstrap.clj.html
@@ -331,13 +331,13 @@
109 ;; else
-
+
110 (beowulf.bootstrap/EVAL expr
-
+
111 (merge-vars vars env)
-
+
112 depth))))
@@ -352,13 +352,13 @@
116
-
+
117 Lisp 1.5 introduced `PROG`, and most Lisps have been stuck with it ever
-
+
118 since. It introduces imperative programming into what should be a pure
-
+
119 functional language, and consequently it's going to be a pig to implement.
@@ -757,7 +757,7 @@
251 (let [lisp-fn (value function-symbol '(EXPR FEXPR))
-
+
252 args' (cond (= NIL args) args
diff --git a/docs/cloverage/beowulf/cons_cell.clj.html b/docs/cloverage/beowulf/cons_cell.clj.html
index a229691..aaf1230 100644
--- a/docs/cloverage/beowulf/cons_cell.clj.html
+++ b/docs/cloverage/beowulf/cons_cell.clj.html
@@ -259,7 +259,7 @@
085 (if
-
+
086 (or
@@ -445,22 +445,22 @@
147 clojure.lang.Counted
-
+
148 (count [this] (loop [cell this
149 result 1]
-
+
150 (if
-
+
151 (and (coll? (.getCdr cell)) (not= NIL (.getCdr cell)))
-
+
152 (recur (.getCdr cell) (inc result))
-
+
153 result)))
diff --git a/docs/cloverage/beowulf/core.clj.html b/docs/cloverage/beowulf/core.clj.html
index 209aa59..adf35d5 100644
--- a/docs/cloverage/beowulf/core.clj.html
+++ b/docs/cloverage/beowulf/core.clj.html
@@ -154,10 +154,10 @@
050 :default default-sysout
-
+
051 :validate [#(and
-
+
052 (.exists (io/file %))
@@ -170,40 +170,40 @@
055 ["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."]
- 056 ["-t" "--time" "Time evaluations."]])
+ 056 ["-t" "--time" "Time evaluations."]
+
+
+ 057 ["-x" "--testing" "Disable the jline reader - useful when piping input."]])
- 057
+ 058
- 058 (defn- re
+ 059 (defn- re
- 059 "Like REPL, but it isn't a loop and doesn't print."
+ 060 "Like REPL, but it isn't a loop and doesn't print."
- 060 [input]
+ 061 [input]
- 061 (EVAL (READ input) NIL 0))
+ 062 (EVAL (READ input) NIL 0))
- 062
+ 063
- 063 (defn repl
+ 064 (defn repl
- 064 "Read/eval/print loop."
+ 065 "Read/eval/print loop."
- 065 [prompt]
+ 066 [prompt]
- 066 (loop []
-
-
- 067 (print prompt)
+ 067 (loop []
068 (flush)
@@ -211,8 +211,8 @@
069 (try
-
- 070 (if-let [input (trim (read-from-console))]
+
+ 070 (if-let [input (trim (read-from-console prompt))]
071 (if (= input stop-word)
@@ -259,7 +259,7 @@
085 data
-
+
086 (case (:cause data)
@@ -316,13 +316,13 @@
104 (str "Síðe " (System/getProperty "beowulf.version") "\n"))
-
+
105 (when
106 (:help (:options args))
-
+
107 (:summary args))
@@ -358,8 +358,8 @@
118 (try
-
- 119 (repl (str (:prompt (:options args)) " "))
+
+ 119 (repl (:prompt (:options args)))
120 (catch
diff --git a/docs/cloverage/beowulf/host.clj.html b/docs/cloverage/beowulf/host.clj.html
index 5a4bbed..6437d2b 100644
--- a/docs/cloverage/beowulf/host.clj.html
+++ b/docs/cloverage/beowulf/host.clj.html
@@ -274,7 +274,7 @@
090 [l path]
-
+
091 (cond
@@ -283,1439 +283,1490 @@
093 (empty? path) l
-
- 094 :else
+
+ 094 (not (instance? ConsCell l)) (throw (ex-info (str "Ne liste: "
-
- 095 (try
+
+ 095 l "; " (type l))
+
+
+ 096 {:phase :eval
+
+
+ 097 :function "universal access function"
+
+
+ 098 :args [l path]
+
+
+ 099 :type :beowulf}))
- 096 (case (last path)
+ 100 :else (case (last path)
- 097 \a (uaf (.first l) (butlast path))
+ 101 \a (uaf (.first l) (butlast path))
- 098 \d (uaf (.getCdr l) (butlast path))
-
-
- 099 (throw (ex-info (str "uaf: unexpected letter in path (only `a` and `d` permitted): " (last path))
+ 102 \d (uaf (.getCdr l) (butlast path))
- 100 {:cause :uaf
-
-
- 101 :detail :unexpected-letter
+ 103 (throw (ex-info (str "uaf: unexpected letter in path (only `a` and `d` permitted): "
- 102 :expr (last path)})))
+ 104 (last path))
+
+
+ 105 {:phase :eval
- 103 (catch ClassCastException e
+ 106 :function "universal access function"
- 104 (throw (ex-info
-
-
- 105 (str "uaf: Not a LISP list? " (type l))
-
-
- 106 {:cause :uaf
+ 107 :args [l path]
- 107 :detail :not-a-lisp-list
-
-
- 108 :expr l}
-
-
- 109 e))))))
+ 108 :type :beowulf})))))
- 110
+ 109
- 111 (defmacro CAAR [x] `(uaf ~x '(\a \a)))
+ 110 (defmacro CAAR [x] `(uaf ~x '(\a \a)))
- 112 (defmacro CADR [x] `(uaf ~x '(\a \d)))
+ 111 (defmacro CADR [x] `(uaf ~x '(\a \d)))
-
- 113 (defmacro CDDR [x] `(uaf ~x '(\d \d)))
+
+ 112 (defmacro CDDR [x] `(uaf ~x '(\d \d)))
- 114 (defmacro CDAR [x] `(uaf ~x '(\d \a)))
+ 113 (defmacro CDAR [x] `(uaf ~x '(\d \a)))
- 115
+ 114
- 116 (defmacro CAAAR [x] `(uaf ~x '(\a \a \a)))
+ 115 (defmacro CAAAR [x] `(uaf ~x '(\a \a \a)))
- 117 (defmacro CAADR [x] `(uaf ~x '(\a \a \d)))
+ 116 (defmacro CAADR [x] `(uaf ~x '(\a \a \d)))
- 118 (defmacro CADAR [x] `(uaf ~x '(\a \d \a)))
+ 117 (defmacro CADAR [x] `(uaf ~x '(\a \d \a)))
- 119 (defmacro CADDR [x] `(uaf ~x '(\a \d \d)))
+ 118 (defmacro CADDR [x] `(uaf ~x '(\a \d \d)))
- 120 (defmacro CDDAR [x] `(uaf ~x '(\d \d \a)))
+ 119 (defmacro CDDAR [x] `(uaf ~x '(\d \d \a)))
- 121 (defmacro CDDDR [x] `(uaf ~x '(\d \d \d)))
+ 120 (defmacro CDDDR [x] `(uaf ~x '(\d \d \d)))
- 122 (defmacro CDAAR [x] `(uaf ~x '(\d \a \a)))
+ 121 (defmacro CDAAR [x] `(uaf ~x '(\d \a \a)))
- 123 (defmacro CDADR [x] `(uaf ~x '(\d \a \d)))
+ 122 (defmacro CDADR [x] `(uaf ~x '(\d \a \d)))
- 124
+ 123
- 125 (defmacro CAAAAR [x] `(uaf ~x '(\a \a \a \a)))
+ 124 (defmacro CAAAAR [x] `(uaf ~x '(\a \a \a \a)))
- 126 (defmacro CAADAR [x] `(uaf ~x '(\a \a \d \a)))
+ 125 (defmacro CAADAR [x] `(uaf ~x '(\a \a \d \a)))
- 127 (defmacro CADAAR [x] `(uaf ~x '(\a \d \a \a)))
+ 126 (defmacro CADAAR [x] `(uaf ~x '(\a \d \a \a)))
- 128 (defmacro CADDAR [x] `(uaf ~x '(\a \d \d \a)))
+ 127 (defmacro CADDAR [x] `(uaf ~x '(\a \d \d \a)))
- 129 (defmacro CDDAAR [x] `(uaf ~x '(\d \d \a \a)))
+ 128 (defmacro CDDAAR [x] `(uaf ~x '(\d \d \a \a)))
- 130 (defmacro CDDDAR [x] `(uaf ~x '(\d \d \d \a)))
+ 129 (defmacro CDDDAR [x] `(uaf ~x '(\d \d \d \a)))
- 131 (defmacro CDAAAR [x] `(uaf ~x '(\d \a \a \a)))
+ 130 (defmacro CDAAAR [x] `(uaf ~x '(\d \a \a \a)))
- 132 (defmacro CDADAR [x] `(uaf ~x '(\d \a \d \a)))
+ 131 (defmacro CDADAR [x] `(uaf ~x '(\d \a \d \a)))
- 133 (defmacro CAAADR [x] `(uaf ~x '(\a \a \a \d)))
+ 132 (defmacro CAAADR [x] `(uaf ~x '(\a \a \a \d)))
- 134 (defmacro CAADDR [x] `(uaf ~x '(\a \a \d \d)))
+ 133 (defmacro CAADDR [x] `(uaf ~x '(\a \a \d \d)))
- 135 (defmacro CADADR [x] `(uaf ~x '(\a \d \a \d)))
+ 134 (defmacro CADADR [x] `(uaf ~x '(\a \d \a \d)))
- 136 (defmacro CADDDR [x] `(uaf ~x '(\a \d \d \d)))
+ 135 (defmacro CADDDR [x] `(uaf ~x '(\a \d \d \d)))
- 137 (defmacro CDDADR [x] `(uaf ~x '(\d \d \a \d)))
+ 136 (defmacro CDDADR [x] `(uaf ~x '(\d \d \a \d)))
- 138 (defmacro CDDDDR [x] `(uaf ~x '(\d \d \d \d)))
+ 137 (defmacro CDDDDR [x] `(uaf ~x '(\d \d \d \d)))
- 139 (defmacro CDAADR [x] `(uaf ~x '(\d \a \a \d)))
+ 138 (defmacro CDAADR [x] `(uaf ~x '(\d \a \a \d)))
- 140 (defmacro CDADDR [x] `(uaf ~x '(\d \a \d \d)))
+ 139 (defmacro CDADDR [x] `(uaf ~x '(\d \a \d \d)))
- 141
+ 140
- 142 (defn RPLACA
+ 141 (defn RPLACA
- 143 "Replace the CAR pointer of this `cell` with this `value`. Dangerous, should
+ 142 "Replace the CAR pointer of this `cell` with this `value`. Dangerous, should
- 144 really not exist, but does in Lisp 1.5 (and was important for some
+ 143 really not exist, but does in Lisp 1.5 (and was important for some
- 145 performance hacks in early Lisps)"
+ 144 performance hacks in early Lisps)"
- 146 [^ConsCell cell value]
+ 145 [^ConsCell cell value]
- 147 (if
+ 146 (if
- 148 (instance? ConsCell cell)
+ 147 (instance? ConsCell cell)
- 149 (if
+ 148 (if
- 150 (or
+ 149 (or
- 151 (instance? ConsCell value)
+ 150 (instance? ConsCell value)
- 152 (number? value)
+ 151 (number? value)
- 153 (symbol? value)
+ 152 (symbol? value)
- 154 (= value NIL))
+ 153 (= value NIL))
- 155 (try
+ 154 (try
- 156 (.rplaca cell value)
+ 155 (.rplaca cell value)
- 157 cell
+ 156 cell
- 158 (catch Throwable any
+ 157 (catch Throwable any
- 159 (throw (ex-info
+ 158 (throw (ex-info
- 160 (str (.getMessage any) " in RPLACA: `")
+ 159 (str (.getMessage any) " in RPLACA: `")
- 161 {:cause :upstream-error
+ 160 {:cause :upstream-error
- 162 :phase :host
+ 161 :phase :host
- 163 :function :rplaca
+ 162 :function :rplaca
- 164 :args (list cell value)
+ 163 :args (list cell value)
- 165 :type :beowulf}
+ 164 :type :beowulf}
- 166 any))))
+ 165 any))))
- 167 (throw (ex-info
+ 166 (throw (ex-info
- 168 (str "Un-ġefōg þing in RPLACA: `" value "` (" (type value) ")")
+ 167 (str "Un-ġefōg þing in RPLACA: `" value "` (" (type value) ")")
- 169 {:cause :bad-value
+ 168 {:cause :bad-value
- 170 :phase :host
+ 169 :phase :host
- 171 :function :rplaca
+ 170 :function :rplaca
- 172 :args (list cell value)
+ 171 :args (list cell value)
- 173 :type :beowulf})))
+ 172 :type :beowulf})))
- 174 (throw (ex-info
+ 173 (throw (ex-info
- 175 (str "Uncynlic miercels in RPLACA: `" cell "` (" (type cell) ")")
+ 174 (str "Uncynlic miercels in RPLACA: `" cell "` (" (type cell) ")")
- 176 {:cause :bad-cell
+ 175 {:cause :bad-cell
- 177 :phase :host
+ 176 :phase :host
- 178 :function :rplaca
+ 177 :function :rplaca
- 179 :args (list cell value)
+ 178 :args (list cell value)
- 180 :type :beowulf}))))
+ 179 :type :beowulf}))))
- 181
+ 180
- 182 (defn RPLACD
+ 181 (defn RPLACD
- 183 "Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
+ 182 "Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
- 184 really not exist, but does in Lisp 1.5 (and was important for some
+ 183 really not exist, but does in Lisp 1.5 (and was important for some
- 185 performance hacks in early Lisps)"
+ 184 performance hacks in early Lisps)"
- 186 [^ConsCell cell value]
+ 185 [^ConsCell cell value]
- 187 (if
+ 186 (if
- 188 (instance? ConsCell cell)
+ 187 (instance? ConsCell cell)
- 189 (if
+ 188 (if
-
- 190 (or
+
+ 189 (or
- 191 (instance? ConsCell value)
+ 190 (instance? ConsCell value)
- 192 (number? value)
+ 191 (number? value)
- 193 (symbol? value)
+ 192 (symbol? value)
- 194 (= value NIL))
+ 193 (= value NIL))
- 195 (try
+ 194 (try
- 196 (.rplacd cell value)
+ 195 (.rplacd cell value)
- 197 cell
+ 196 cell
- 198 (catch Throwable any
+ 197 (catch Throwable any
- 199 (throw (ex-info
+ 198 (throw (ex-info
- 200 (str (.getMessage any) " in RPLACD: `")
+ 199 (str (.getMessage any) " in RPLACD: `")
- 201 {:cause :upstream-error
+ 200 {:cause :upstream-error
- 202 :phase :host
+ 201 :phase :host
- 203 :function :rplacd
+ 202 :function :rplacd
- 204 :args (list cell value)
+ 203 :args (list cell value)
- 205 :type :beowulf}
+ 204 :type :beowulf}
- 206 any))))
+ 205 any))))
- 207 (throw (ex-info
+ 206 (throw (ex-info
- 208 (str "Un-ġefōg þing in RPLACD: `" value "` (" (type value) ")")
+ 207 (str "Un-ġefōg þing in RPLACD: `" value "` (" (type value) ")")
- 209 {:cause :bad-value
+ 208 {:cause :bad-value
- 210 :phase :host
+ 209 :phase :host
- 211 :function :rplacd
+ 210 :function :rplacd
- 212 :args (list cell value)
+ 211 :args (list cell value)
- 213 :type :beowulf})))
+ 212 :type :beowulf})))
- 214 (throw (ex-info
+ 213 (throw (ex-info
- 215 (str "Uncynlic miercels in RPLACD: `" cell "` (" (type cell) ")")
+ 214 (str "Uncynlic miercels in RPLACD: `" cell "` (" (type cell) ")")
- 216 {:cause :bad-cell
+ 215 {:cause :bad-cell
- 217 :phase :host
+ 216 :phase :host
- 218 :detail :rplacd
+ 217 :detail :rplacd
- 219 :args (list cell value)
+ 218 :args (list cell value)
- 220 :type :beowulf}))));; PLUS
+ 219 :type :beowulf}))));; PLUS
- 221
+ 220
- 222 (defn LIST
+ 221 (defn LIST
- 223 [& args]
+ 222 [& args]
- 224 (make-beowulf-list args))
+ 223 (make-beowulf-list args))
- 225
+ 224
- 226 ;;;; Basic predicates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 225 ;;;; Basic predicates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 227
+ 226
- 228 (defmacro NULL
+ 227 (defmacro NULL
- 229 "Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`."
+ 228 "Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`."
- 230 [x]
+ 229 [x]
- 231 `(if (= ~x NIL) T F))
+ 230 `(if (= ~x NIL) T F))
- 232
+ 231
- 233 (defmacro NILP
+ 232 (defmacro NILP
- 234 "Not part of LISP 1.5: `T` if `o` is `NIL`, else `NIL`."
+ 233 "Not part of LISP 1.5: `T` if `o` is `NIL`, else `NIL`."
- 235 [x]
+ 234 [x]
- 236 `(if (= ~x NIL) T NIL))
+ 235 `(if (= ~x NIL) T NIL))
- 237
+ 236
- 238 (defn ATOM
+ 237 (defn ATOM
- 239 "Returns `T` if and only if the argument `x` is bound to an atom; else `F`.
+ 238 "Returns `T` if and only if the argument `x` is bound to an atom; else `F`.
- 240 It is not clear to me from the documentation whether `(ATOM 7)` should return
+ 239 It is not clear to me from the documentation whether `(ATOM 7)` should return
- 241 `T` or `F`. I'm going to assume `T`."
+ 240 `T` or `F`. I'm going to assume `T`."
- 242 [x]
+ 241 [x]
- 243 (if (or (symbol? x) (number? x)) T F))
+ 242 (if (or (symbol? x) (number? x)) T F))
- 244
+ 243
- 245 (defmacro ATOM?
+ 244 (defmacro ATOM?
- 246 "The convention of returning `F` from predicates, rather than `NIL`, is going
+ 245 "The convention of returning `F` from predicates, rather than `NIL`, is going
- 247 to tie me in knots. This is a variant of `ATOM` which returns `NIL`
+ 246 to tie me in knots. This is a variant of `ATOM` which returns `NIL`
- 248 on failure."
+ 247 on failure."
- 249 [x]
+ 248 [x]
- 250 `(if (or (symbol? ~x) (number? ~x)) T NIL))
+ 249 `(if (or (symbol? ~x) (number? ~x)) T NIL))
- 251
+ 250
- 252 (defn EQ
+ 251 (defn EQ
- 253 "Returns `T` if and only if both `x` and `y` are bound to the same atom,
+ 252 "Returns `T` if and only if both `x` and `y` are bound to the same atom,
- 254 else `NIL`."
+ 253 else `NIL`."
- 255 [x y]
+ 254 [x y]
- 256 (cond (and (instance? ConsCell x)
+ 255 (cond (and (instance? ConsCell x)
- 257 (.equals x y)) T
+ 256 (.equals x y)) T
- 258 (and (= (ATOM x) T) (= x y)) T
+ 257 (and (= (ATOM x) T) (= x y)) T
- 259 :else NIL))
+ 258 :else NIL))
- 260
+ 259
- 261 (defn EQUAL
+ 260 (defn EQUAL
- 262 "This is a predicate that is true if its two arguments are identical
+ 261 "This is a predicate that is true if its two arguments are identical
- 263 S-expressions, and false if they are different. (The elementary predicate
+ 262 S-expressions, and false if they are different. (The elementary predicate
- 264 `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is
+ 263 `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is
- 265 an example of a conditional expression inside a conditional expression.
+ 264 an example of a conditional expression inside a conditional expression.
- 266
+ 265
- 267 NOTE: returns `F` on failure, not `NIL`"
+ 266 NOTE: returns `F` on failure, not `NIL`"
- 268 [x y]
+ 267 [x y]
- 269 (cond
+ 268 (cond
- 270 (= (ATOM x) T) (if (= x y) T F)
+ 269 (= (ATOM x) T) (if (= x y) T F)
- 271 (= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y))
+ 270 (= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y))
- 272 :else F))
+ 271 :else F))
- 273
+ 272
- 274 (defn AND
+ 273 (defn AND
- 275 "`T` if and only if none of my `args` evaluate to either `F` or `NIL`,
+ 274 "`T` if and only if none of my `args` evaluate to either `F` or `NIL`,
- 276 else `F`.
+ 275 else `F`.
- 277
+ 276
- 278 In `beowulf.host` principally because I don't yet feel confident to define
+ 277 In `beowulf.host` principally because I don't yet feel confident to define
- 279 varargs functions in Lisp."
+ 278 varargs functions in Lisp."
- 280 [& args]
+ 279 [& args]
- 281 ;; (println "AND: " args " type: " (type args) " seq? " (seq? args))
+ 280 ;; (println "AND: " args " type: " (type args) " seq? " (seq? args))
- 282 ;; (println " filtered: " (seq (filter #{F NIL} args)))
+ 281 ;; (println " filtered: " (seq (filter #{F NIL} args)))
- 283 (cond (= NIL args) T
+ 282 (cond (= NIL args) T
- 284 (seq? args) (if (seq (filter #{F NIL} args)) F T)
+ 283 (seq? args) (if (seq (filter #{F NIL} args)) F T)
- 285 :else T))
+ 284 :else T))
+
+
+ 285
286
-
- 287
-
- 288 (defn OR
+ 287 (defn OR
- 289 "`T` if and only if at least one of my `args` evaluates to something other
+ 288 "`T` if and only if at least one of my `args` evaluates to something other
- 290 than either `F` or `NIL`, else `F`.
+ 289 than either `F` or `NIL`, else `F`.
- 291
+ 290
- 292 In `beowulf.host` principally because I don't yet feel confident to define
+ 291 In `beowulf.host` principally because I don't yet feel confident to define
- 293 varargs functions in Lisp."
+ 292 varargs functions in Lisp."
- 294 [& args]
+ 293 [& args]
- 295 ;; (println "OR: " args " type: " (type args) " seq? " (seq? args))
+ 294 ;; (println "OR: " args " type: " (type args) " seq? " (seq? args))
- 296 ;; (println " filtered: " (seq (remove #{F NIL} args)))
+ 295 ;; (println " filtered: " (seq (remove #{F NIL} args)))
- 297 (cond (= NIL args) F
+ 296 (cond (= NIL args) F
- 298 (seq? args) (if (seq (remove #{F NIL} args)) T F)
+ 297 (seq? args) (if (seq (remove #{F NIL} args)) T F)
- 299 :else F))
+ 298 :else F))
+
+
+ 299
300
-
- 301
+
+ 301 ;;;; Operations on lists ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 302 ;;;; Operations on lists ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 302 ;;
- 303 ;;
-
-
- 304 ;; TODO: These are candidates for moving to Lisp urgently!
+ 303 ;; TODO: These are candidates for moving to Lisp urgently!
- 305
+ 304
- 306 (defn ASSOC
+ 305 (defn ASSOC
- 307 "If a is an association list such as the one formed by PAIRLIS in the above
+ 306 "If a is an association list such as the one formed by PAIRLIS in the above
- 308 example, then assoc will produce the first pair whose first term is x. Thus
+ 307 example, then assoc will produce the first pair whose first term is x. Thus
- 309 it is a table searching function.
+ 308 it is a table searching function.
- 310
+ 309
- 311 All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
+ 310 All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
- 312 See page 12 of the Lisp 1.5 Programmers Manual.
+ 311 See page 12 of the Lisp 1.5 Programmers Manual.
- 313
+ 312
- 314 **NOTE THAT** this function is overridden by an implementation in Lisp,
+ 313 **NOTE THAT** this function is overridden by an implementation in Lisp,
- 315 but is currently still present for bootstrapping."
+ 314 but is currently still present for bootstrapping."
- 316 [x a]
+ 315 [x a]
- 317 (cond
+ 316 (cond
- 318 (= NIL a) NIL ;; this clause is not present in the original but is added for
+ 317 (= NIL a) NIL ;; this clause is not present in the original but is added for
- 319 ;; robustness.
+ 318 ;; robustness.
- 320 (= (EQUAL (CAAR a) x) T) (CAR a)
+ 319 (= (EQUAL (CAAR a) x) T) (CAR a)
- 321 :else
+ 320 :else
- 322 (ASSOC x (CDR a))))
+ 321 (ASSOC x (CDR a))))
- 323
+ 322
- 324 (defn PAIRLIS
+ 323 (defn PAIRLIS
- 325 "This function gives the list of pairs of corresponding elements of the
+ 324 "This function gives the list of pairs of corresponding elements of the
- 326 lists `x` and `y`, and APPENDs this to the list `a`. The resultant list
+ 325 lists `x` and `y`, and APPENDs this to the list `a`. The resultant list
- 327 of pairs, which is like a table with two columns, is called an
+ 326 of pairs, which is like a table with two columns, is called an
- 328 association list.
+ 327 association list.
- 329
+ 328
- 330 Eessentially, it builds the environment on the stack, implementing shallow
+ 329 Eessentially, it builds the environment on the stack, implementing shallow
- 331 binding.
+ 330 binding.
- 332
+ 331
- 333 All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
+ 332 All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
- 334 See page 12 of the Lisp 1.5 Programmers Manual.
+ 333 See page 12 of the Lisp 1.5 Programmers Manual.
- 335
+ 334
- 336 **NOTE THAT** this function is overridden by an implementation in Lisp,
+ 335 **NOTE THAT** this function is overridden by an implementation in Lisp,
- 337 but is currently still present for bootstrapping."
+ 336 but is currently still present for bootstrapping."
- 338 [x y a]
+ 337 [x y a]
- 339 (cond
+ 338 (cond
- 340 ;; the original tests only x; testing y as well will be a little more
+ 339 ;; the original tests only x; testing y as well will be a little more
- 341 ;; robust if `x` and `y` are not the same length.
+ 340 ;; robust if `x` and `y` are not the same length.
- 342 (or (= NIL x) (= NIL y)) a
+ 341 (or (= NIL x) (= NIL y)) a
- 343 :else (make-cons-cell
+ 342 :else (make-cons-cell
- 344 (make-cons-cell (CAR x) (CAR y))
+ 343 (make-cons-cell (CAR x) (CAR y))
- 345 (PAIRLIS (CDR x) (CDR y) a))))
+ 344 (PAIRLIS (CDR x) (CDR y) a))))
- 346
+ 345
- 347 ;;;; Arithmetic ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 346 ;;;; Arithmetic ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 348 ;;
+ 347 ;;
- 349 ;; TODO: When in strict mode, should we limit arithmetic precision to that
+ 348 ;; TODO: When in strict mode, should we limit arithmetic precision to that
- 350 ;; supported by Lisp 1.5?
+ 349 ;; supported by Lisp 1.5?
- 351
+ 350
- 352 (defn PLUS
+ 351 (defn PLUS
- 353 [& args]
+ 352 [& args]
- 354 (let [s (apply + args)]
+ 353 (let [s (apply + args)]
- 355 (if (integer? s) s (float s))))
+ 354 (if (integer? s) s (float s))))
- 356
+ 355
- 357 (defn TIMES
+ 356 (defn TIMES
- 358 [& args]
+ 357 [& args]
- 359 (let [p (apply * args)]
+ 358 (let [p (apply * args)]
- 360 (if (integer? p) p (float p))))
+ 359 (if (integer? p) p (float p))))
- 361
+ 360
- 362 (defn DIFFERENCE
+ 361 (defn DIFFERENCE
- 363 [x y]
+ 362 [x y]
- 364 (let [d (- x y)]
+ 363 (let [d (- x y)]
- 365 (if (integer? d) d (float d))))
+ 364 (if (integer? d) d (float d))))
- 366
+ 365
- 367 (defn QUOTIENT
+ 366 (defn QUOTIENT
- 368 "I'm not certain from the documentation whether Lisp 1.5 `QUOTIENT` returned
+ 367 "I'm not certain from the documentation whether Lisp 1.5 `QUOTIENT` returned
- 369 the integer part of the quotient, or a realnum representing the whole
+ 368 the integer part of the quotient, or a realnum representing the whole
- 370 quotient. I am for now implementing the latter."
+ 369 quotient. I am for now implementing the latter."
- 371 [x y]
+ 370 [x y]
- 372 (let [q (/ x y)]
+ 371 (let [q (/ x y)]
- 373 (if (integer? q) q (float q))))
+ 372 (if (integer? q) q (float q))))
- 374
+ 373
- 375 (defn REMAINDER
+ 374 (defn REMAINDER
- 376 [x y]
+ 375 [x y]
- 377 (rem x y))
+ 376 (rem x y))
- 378
+ 377
- 379 (defn ADD1
+ 378 (defn ADD1
- 380 [x]
+ 379 [x]
- 381 (inc x))
+ 380 (inc x))
- 382
+ 381
- 383 (defn SUB1
+ 382 (defn SUB1
- 384 [x]
+ 383 [x]
- 385 (dec x))
+ 384 (dec x))
- 386
+ 385
- 387 (defn FIXP
+ 386 (defn FIXP
- 388 [x]
+ 387 [x]
- 389 (if (integer? x) T F))
+ 388 (if (integer? x) T F))
- 390
+ 389
- 391 (defn NUMBERP
+ 390 (defn NUMBERP
- 392 [x]
+ 391 [x]
- 393 (if (number? x) T F))
+ 392 (if (number? x) T F))
- 394
+ 393
- 395 (defn LESSP
+ 394 (defn LESSP
- 396 [x y]
+ 395 [x y]
- 397 (if (< x y) T F))
+ 396 (if (< x y) T F))
- 398
+ 397
- 399 (defn GREATERP
+ 398 (defn GREATERP
- 400 [x y]
+ 399 [x y]
- 401 (if (> x y) T F))
+ 400 (if (> x y) T F))
- 402
+ 401
- 403 ;;;; Miscellaneous ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 402 ;;;; Miscellaneous ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 404
+ 403
- 405 (defn GENSYM
+ 404 (defn GENSYM
- 406 "Generate a unique symbol."
+ 405 "Generate a unique symbol."
- 407 []
+ 406 []
-
- 408 (symbol (upper-case (str (gensym "SYM")))))
+
+ 407 (symbol (upper-case (str (gensym "SYM")))))
- 409
+ 408
- 410 (defn ERROR
+ 409 (defn ERROR
- 411 "Throw an error"
+ 410 "Throw an error"
- 412 [& args]
+ 411 [& args]
- 413 (throw (ex-info "LISP STÆFLEAHTER" {:args args
+ 412 (throw (ex-info "LISP STÆFLEAHTER" {:args args
- 414 :phase :eval
+ 413 :phase :eval
- 415 :function 'ERROR
+ 414 :function 'ERROR
- 416 :type :lisp
+ 415 :type :lisp
- 417 :code (or (first args) 'A1)})))
+ 416 :code (or (first args) 'A1)})))
- 418
+ 417
- 419 ;;;; Assignment and the object list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 418 ;;;; Assignment and the object list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 420
+ 419
- 421 (defn OBLIST
+ 420 (defn OBLIST
- 422 "Return a list of the symbols currently bound on the object list.
+ 421 "Return a list of the symbols currently bound on the object list.
- 423
+ 422
- 424 **NOTE THAT** in the Lisp 1.5 manual, footnote at the bottom of page 69, it implies
+ 423 **NOTE THAT** in the Lisp 1.5 manual, footnote at the bottom of page 69, it implies
- 425 that an argument can be passed but I'm not sure of the semantics of
+ 424 that an argument can be passed but I'm not sure of the semantics of
- 426 this."
+ 425 this."
- 427 []
+ 426 []
- 428 (if (instance? ConsCell @oblist)
+ 427 (if (instance? ConsCell @oblist)
- 429 (make-beowulf-list (map CAR @oblist))
+ 428 (make-beowulf-list (map CAR @oblist))
- 430 NIL))
+ 429 NIL))
- 431
+ 430
- 432 (def magic-marker
+ 431 (def magic-marker
- 433 "The unexplained magic number which marks the start of a property list."
+ 432 "The unexplained magic number which marks the start of a property list."
- 434 (Integer/parseInt "77777" 8))
+ 433 (Integer/parseInt "77777" 8))
- 435
+ 434
- 436 (defn PUT
+ 435 (defn hit-or-miss-assoc
- 437 "Put this `value` as the value of the property indicated by this `indicator`
+ 436 "Find the position of the binding of this `target` in a Lisp 1.5
- 438 of this `symbol`. Return `value` on success.
+ 437 property list `plist`.
- 439
+ 438
- 440 NOTE THAT there is no `PUT` defined in the manual, but it would have been
+ 439 Lisp 1.5 property lists are not assoc lists, but lists of the form
- 441 easy to have defined it so I don't think this fully counts as an extension."
+ 440 `(name value name value name value...)`. It's therefore necessary to
- 442 [symbol indicator value]
-
-
- 443 (if-let [binding (ASSOC symbol @oblist)]
-
-
- 444 (if-let [prop (ASSOC indicator (CDDR binding))]
-
-
- 445 (RPLACD prop value)
-
-
- 446 (RPLACD binding
-
-
- 447 (make-cons-cell
-
-
- 448 magic-marker
-
-
- 449 (make-cons-cell
-
-
- 450 indicator
-
-
- 451 (make-cons-cell value (CDDR binding))))))
-
-
- 452 (swap!
-
-
- 453 oblist
-
-
- 454 (fn [ob s p v]
-
-
- 455 (make-cons-cell
-
-
- 456 (make-beowulf-list (list s magic-marker p v))
-
-
- 457 ob))
-
-
- 458 symbol indicator value)))
-
-
- 459
-
-
- 460 (defn GET
+ 441 recurse down the list two entries at a time to avoid confusing names
- 461 "From the manual:
+ 442 with values."
- 462
+ 443 [target plist]
-
- 463 '`get` is somewhat like `prop`; however its value is car of the rest of
+
+ 444 (if (and (instance? ConsCell plist)(even? (count plist)))
-
- 464 the list if the `indicator` is found, and NIL otherwise.'
-
-
- 465
-
-
- 466 It's clear that `GET` is expected to be defined in terms of `PROP`, but
-
-
- 467 we can't implement `PROP` here because we lack `EVAL`; and we can't have
-
-
- 468 `EVAL` here because both it and `APPLY` depends on `GET`.
-
-
- 469
-
-
- 470 OK, It's worse than that: the statement of the definition of `GET` (and
-
-
- 471 of) `PROP` on page 59 says that the first argument to each must be a list;
-
-
- 472 But the in the definition of `ASSOC` on page 70, when `GET` is called its
-
-
- 473 first argument is always an atom. Since it's `ASSOC` and `EVAL` which I
-
-
- 474 need to make work, I'm going to assume that page 59 is wrong."
-
-
- 475 [symbol indicator]
-
-
- 476 (let [binding (ASSOC symbol @oblist)
-
-
- 477 val (cond
-
-
- 478 (= binding NIL) NIL
-
-
- 479 (= magic-marker
-
-
- 480 (CADR binding)) (loop [b binding]
-
-
- 481 ;; (println "GET loop, seeking " indicator ":")
-
-
- 482 ;; (pretty-print b)
-
-
- 483 (if (instance? ConsCell b)
+
+ 445 (cond (= plist NIL) NIL
- 484 (if (= (CAR b) indicator)
+ 446 (= (first plist) target) plist
+
+
+ 447 :else (hit-or-miss-assoc target (CDDR plist)))
+
+
+ 448 NIL))
+
+
+ 449
+
+
+ 450 (defn PUT
+
+
+ 451 "Put this `value` as the value of the property indicated by this `indicator`
+
+
+ 452 of this `symbol`. Return `value` on success.
+
+
+ 453
+
+
+ 454 NOTE THAT there is no `PUT` defined in the manual, but it would have been
+
+
+ 455 easy to have defined it so I don't think this fully counts as an extension."
+
+
+ 456 [symbol indicator value]
+
+
+ 457 (let [binding (ASSOC symbol @oblist)]
+
+
+ 458 (if (instance? ConsCell binding)
+
+
+ 459 (let [prop (hit-or-miss-assoc indicator (CDDR binding))]
+
+
+ 460 (if (instance? ConsCell prop)
+
+
+ 461 (RPLACA (CDR prop) value)
- 485 (CADR b) ;; <- this is what we should actually be returning
+ 462 (RPLACD binding
+
+
+ 463 (make-cons-cell
- 486 (recur (CDR b)))
+ 464 magic-marker
+
+
+ 465 (make-cons-cell
- 487 NIL))
+ 466 indicator
+
+
+ 467 (make-cons-cell value (CDDR binding)))))))
+
+
+ 468 (swap!
+
+
+ 469 oblist
+
+
+ 470 (fn [ob s p v]
+
+
+ 471 (make-cons-cell
+
+
+ 472 (make-beowulf-list (list s magic-marker p v))
+
+
+ 473 ob))
+
+
+ 474 symbol indicator value)))
+
+
+ 475 value)
+
+
+ 476
+
+
+ 477 (defn GET
+
+
+ 478 "From the manual:
+
+
+ 479
+
+
+ 480 '`get` is somewhat like `prop`; however its value is car of the rest of
+
+
+ 481 the list if the `indicator` is found, and NIL otherwise.'
+
+
+ 482
+
+
+ 483 It's clear that `GET` is expected to be defined in terms of `PROP`, but
+
+
+ 484 we can't implement `PROP` here because we lack `EVAL`; and we can't have
+
+
+ 485 `EVAL` here because both it and `APPLY` depends on `GET`.
+
+
+ 486
+
+
+ 487 OK, It's worse than that: the statement of the definition of `GET` (and
+
+
+ 488 of) `PROP` on page 59 says that the first argument to each must be a list;
+
+
+ 489 But the in the definition of `ASSOC` on page 70, when `GET` is called its
+
+
+ 490 first argument is always an atom. Since it's `ASSOC` and `EVAL` which I
+
+
+ 491 need to make work, I'm going to assume that page 59 is wrong."
+
+
+ 492 [symbol indicator]
+
+
+ 493 (let [binding (ASSOC symbol @oblist)
+
+
+ 494 val (cond
+
+
+ 495 (= binding NIL) NIL
+
+
+ 496 (= magic-marker
+
+
+ 497 (CADR binding)) (loop [b binding]
+
+
+ 498 ;; (println "GET loop, seeking " indicator ":")
+
+
+ 499 ;; (pretty-print b)
+
+
+ 500 (if (instance? ConsCell b)
+
+
+ 501 (if (= (CAR b) indicator)
+
+
+ 502 (CADR b) ;; <- this is what we should actually be returning
+
+
+ 503 (recur (CDR b)))
+
+
+ 504 NIL))
- 488 :else (throw
+ 505 :else (throw
- 489 (ex-info "Misformatted property list (missing magic marker)"
+ 506 (ex-info "Misformatted property list (missing magic marker)"
- 490 {:phase :host
+ 507 {:phase :host
- 491 :function :get
+ 508 :function :get
- 492 :args (list symbol indicator)
+ 509 :args (list symbol indicator)
- 493 :type :beowulf})))]
+ 510 :type :beowulf})))]
- 494 ;; (println "<< GET returning: " val)
+ 511 ;; (println "<< GET returning: " val)
- 495 val))
+ 512 val))
- 496
+ 513
- 497 (defn DEFLIST
+ 514 (defn DEFLIST
- 498 "For each pair in this association list `a-list`, set the property with this
+ 515 "For each pair in this association list `a-list`, set the property with this
- 499 `indicator` of the symbol which is the first element of the pair to the
+ 516 `indicator` of the symbol which is the first element of the pair to the
- 500 value which is the second element of the pair. See page 58 of the manual."
+ 517 value which is the second element of the pair. See page 58 of the manual."
- 501 [a-list indicator]
+ 518 [a-list indicator]
- 502 (map
+ 519 (map
- 503 #(PUT (CAR %) indicator (CDR %))
+ 520 #(PUT (CAR %) indicator (CDR %))
- 504 a-list))
-
-
- 505
-
-
- 506 (defn DEFINE
-
-
- 507 "Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten
-
-
- 508 in LISP.
-
-
- 509
-
-
- 510 The single argument to `DEFINE` should be an association list of symbols to
-
-
- 511 lambda functions. See page 58 of the manual."
-
-
- 512 [a-list]
-
-
- 513 (DEFLIST a-list 'EXPR))
-
-
- 514
-
-
- 515 (defn SET
-
-
- 516 "Implementation of SET in Clojure. Add to the `oblist` a binding of the
-
-
- 517 value of `var` to the value of `val`. NOTE WELL: this is not SETQ!"
-
-
- 518 [symbol val]
-
-
- 519 (PUT symbol 'APVAL val))
-
-
- 520
-
-
- 521 ;;;; TRACE and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 521 a-list))
522
- 523 (def traced-symbols
+ 523 (defn DEFINE
- 524 "Symbols currently being traced."
+ 524 "Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten
-
- 525 (atom #{}))
+
+ 525 in LISP.
526
-
- 527 (defn traced?
+
+ 527 The single argument to `DEFINE` should be an association list of symbols to
- 528 "Return `true` iff `s` is a symbol currently being traced, else `nil`."
+ 528 lambda functions. See page 58 of the manual."
- 529 [s]
-
-
- 530 (try (contains? @traced-symbols s)
-
-
- 531 (catch Throwable _ nil)))
-
-
- 532
-
-
- 533 (defn TRACE
-
-
- 534 "Add this `s` to the set of symbols currently being traced. If `s`
-
-
- 535 is not a symbol or sequence of symbols, does nothing."
-
-
- 536 [s]
+ 529 [a-list]
- 537 (swap! traced-symbols
-
-
- 538 #(cond
-
-
- 539 (symbol? s) (conj % s)
-
-
- 540 (and (seq? s) (every? symbol? s)) (union % (set s))
-
-
- 541 :else %)))
+ 530 (DEFLIST a-list 'EXPR))
- 542
+ 531
-
- 543 (defn UNTRACE
+
+ 532 (defn SET
- 544 "Remove this `s` from the set of symbols currently being traced. If `s`
+ 533 "Implementation of SET in Clojure. Add to the `oblist` a binding of the
- 545 is not a symbol or sequence of symbols, does nothing."
+ 534 value of `var` to the value of `val`. NOTE WELL: this is not SETQ!"
+
+
+ 535 [symbol val]
+
+
+ 536 (PUT symbol 'APVAL val))
+
+
+ 537
+
+
+ 538 ;;;; TRACE and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+ 539
+
+
+ 540 (def traced-symbols
+
+
+ 541 "Symbols currently being traced."
+
+
+ 542 (atom #{}))
+
+
+ 543
+
+
+ 544 (defn traced?
+
+
+ 545 "Return `true` iff `s` is a symbol currently being traced, else `nil`."
546 [s]
+
+ 547 (try (contains? @traced-symbols s)
+
+
+ 548 (catch Throwable _ nil)))
+
+
+ 549
+
+
+ 550 (defn TRACE
+
+
+ 551 "Add this `s` to the set of symbols currently being traced. If `s`
+
+
+ 552 is not a symbol or sequence of symbols, does nothing."
+
+
+ 553 [s]
+
+
+ 554 (swap! traced-symbols
+
+
+ 555 #(cond
+
+
+ 556 (symbol? s) (conj % s)
+
+
+ 557 (and (seq? s) (every? symbol? s)) (union % (set s))
+
+
+ 558 :else %)))
+
+
+ 559
+
+
+ 560 (defn UNTRACE
+
+
+ 561 "Remove this `s` from the set of symbols currently being traced. If `s`
+
+
+ 562 is not a symbol or sequence of symbols, does nothing."
+
+
+ 563 [s]
+
- 547 (cond
+ 564 (cond
- 548 (symbol? s) (swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))
+ 565 (symbol? s) (swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))
- 549 (and (seq? s) (every? symbol? s)) (map UNTRACE s))
+ 566 (and (seq? s) (every? symbol? s)) (map UNTRACE s))
- 550 @traced-symbols)
+ 567 @traced-symbols)
- 551
+ 568
- 552 ;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 569 ;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- 553
+ 570
- 554 (defn DOC
+ 571 (defn DOC
- 555 "Open the page for this `symbol` in the Lisp 1.5 manual, if known, in the
+ 572 "Open the page for this `symbol` in the Lisp 1.5 manual, if known, in the
- 556 default web browser.
+ 573 default web browser.
- 557
+ 574
- 558 **NOTE THAT** this is an extension function, not available in strct mode."
+ 575 **NOTE THAT** this is an extension function, not available in strct mode."
- 559 [symbol]
+ 576 [symbol]
- 560 (when (lax? 'DOC)
+ 577 (when (lax? 'DOC)
- 561 (open-doc symbol)))
+ 578 (open-doc symbol)))
- 562
+ 579
- 563 (defn CONSP
+ 580 (defn CONSP
- 564 "Return `T` if object `o` is a cons cell, else `F`.
+ 581 "Return `T` if object `o` is a cons cell, else `F`.
- 565
+ 582
- 566 **NOTE THAT** this is an extension function, not available in strct mode.
+ 583 **NOTE THAT** this is an extension function, not available in strct mode.
- 567 I believe that Lisp 1.5 did not have any mechanism for testing whether an
+ 584 I believe that Lisp 1.5 did not have any mechanism for testing whether an
- 568 argument was, or was not, a cons cell."
+ 585 argument was, or was not, a cons cell."
- 569 [o]
+ 586 [o]
- 570 (when (lax? 'CONSP)
+ 587 (when (lax? 'CONSP)
- 571 (if (instance? ConsCell o) 'T 'F)))
+ 588 (if (instance? ConsCell o) 'T 'F)))