diff --git a/docs/cloverage/beowulf/bootstrap.clj.html b/docs/cloverage/beowulf/bootstrap.clj.html index 288a122..b8944e7 100644 --- a/docs/cloverage/beowulf/bootstrap.clj.html +++ b/docs/cloverage/beowulf/bootstrap.clj.html @@ -11,985 +11,1012 @@ 002    "Lisp as defined in Chapter 1 (pages 1-14) of the
- 003     `Lisp 1.5 Programmer's Manual`; that is to say, a very simple Lisp language," + 003    `Lisp 1.5 Programmer's Manual`; that is to say, a very simple Lisp language,
- 004    (:require [clojure.tools.trace :refer :all] + 004    which should, I believe, be sufficient in conjunction with the functions
- 005              [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]])) + 005    provided by `beowulf.host`, be sufficient to bootstrap the full Lisp 1.5 +
+ + 006    interpreter..
- 006   + 007  
- 007  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + 008    The convention is adopted that functions in this file with names in
- 008  ;;; + 009    ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that
- 009  ;;; This file is essentially Lisp as defined in Chapter 1 (pages 1-14) of the + 010    therefore all arguments must be numbers, symbols or `beowulf.cons_cell.ConsCell`
- 010  ;;; Lisp 1.5 Programmer's Manual; that is to say, a very simple Lisp language, + 011    objects."
- 011  ;;; which should, I believe, be sufficient in conjunction with the functions + 012    (:require [clojure.tools.trace :refer :all]
- 012  ;;; provided by `beowulf.host`, be sufficient to bootstrap the full Lisp 1.5 + 013              [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]))
- - 013  ;;; interpreter. -
- - 014  ;;; + + 014  
015  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ + 016  ;;; +
+ + 017  ;;; This file is essentially Lisp as defined in Chapter 1 (pages 1-14) of the +
+ + 018  ;;; Lisp 1.5 Programmer's Manual; that is to say, a very simple Lisp language, +
+ + 019  ;;; which should, I believe, be sufficient in conjunction with the functions +
+ + 020  ;;; provided by `beowulf.host`, be sufficient to bootstrap the full Lisp 1.5 +
+ + 021  ;;; interpreter. +
+ + 022  ;;; +
+ + 023  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
- 016   + 024  
- 017  (declare EVAL) + 025  (declare EVAL)
- 018   + 026  
- 019  (def oblist + 027  (def oblist
- 020    "The default environment; modified certainly be `LABEL` (which seems to -
- - 021    be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things." + 028    "The default environment."
- 022    (atom NIL)) + 029    (atom NIL))
- 023   + 030  
- 024  (def ^:dynamic *options* + 031  (def ^:dynamic *options*
- 025    "Command line options from invocation." + 032    "Command line options from invocation."
- 026    {}) + 033    {})
- 027   + 034  
- 028  (defmacro NULL + 035  (defmacro NULL
- 029    [x] + 036    "Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`." +
+ + 037    [x]
- 030    `(if (= ~x NIL) T F)) + 038    `(if (= ~x NIL) T F))
- 031   + 039  
- 032  (defmacro ATOM + 040  (defmacro ATOM
- 033    "It is not clear to me from the documentation whether `(ATOM 7)` should return + 041    "Returns `T` if and only is the argument `x` is bound to and atom; else `F`.
- 034    `T` or `F`. I'm going to assume `T`." + 042    It is not clear to me from the documentation whether `(ATOM 7)` should return
- 035    [x] + 043    `T` or `F`. I'm going to assume `T`." +
+ + 044    [x]
- 036    `(if (or (symbol? ~x) (number? ~x)) T F)) + 045    `(if (or (symbol? ~x) (number? ~x)) T F))
- 037   + 046  
- 038  (defmacro ATOM? + 047  (defmacro ATOM?
- 039    "The convention of returning `F` from predicates, rather than `NIL`, is going + 048    "The convention of returning `F` from predicates, rather than `NIL`, is going
- 040    to tie me in knots. This is a variant of `ATOM` which returns `NIL` + 049    to tie me in knots. This is a variant of `ATOM` which returns `NIL`
- 041    on failure." + 050    on failure."
- 042    [x] + 051    [x]
- 043    `(if (or (symbol? ~x) (number? ~x)) T NIL)) + 052    `(if (or (symbol? ~x) (number? ~x)) T NIL))
- 044   + 053  
- 045  (defn CAR + 054  (defn CAR
- 046    "Return the item indicated by the first pointer of a pair. NIL is treated + 055    "Return the item indicated by the first pointer of a pair. NIL is treated
- 047    specially: the CAR of NIL is NIL." + 056    specially: the CAR of NIL is NIL."
- 048    [x] + 057    [x]
- 049    (cond + 058    (cond
- 050      (= x NIL) NIL + 059      (= x NIL) NIL
- 051      (instance? beowulf.cons_cell.ConsCell x) (.CAR x) + 060      (instance? beowulf.cons_cell.ConsCell x) (.CAR x)
- 052      :else + 061      :else
- 053      (throw + 062      (throw
- 054        (Exception. + 063        (Exception.
- 055          (str "Cannot take CAR of `" x "` (" (.getName (.getClass x)) ")"))))) + 064          (str "Cannot take CAR of `" x "` (" (.getName (.getClass x)) ")")))))
- 056   + 065  
- 057  (defn CDR + 066  (defn CDR
- 058    "Return the item indicated by the second pointer of a pair. NIL is treated + 067    "Return the item indicated by the second pointer of a pair. NIL is treated
- 059    specially: the CDR of NIL is NIL." + 068    specially: the CDR of NIL is NIL."
- 060    [x] + 069    [x]
- 061    (cond + 070    (cond
- 062      (= x NIL) NIL + 071      (= x NIL) NIL
- 063      (instance? beowulf.cons_cell.ConsCell x) (.CDR x) + 072      (instance? beowulf.cons_cell.ConsCell x) (.CDR x)
- 064      :else + 073      :else
- 065      (throw + 074      (throw
- 066        (Exception. + 075        (Exception.
- 067          (str "Cannot take CDR of `" x "` (" (.getName (.getClass x)) ")"))))) + 076          (str "Cannot take CDR of `" x "` (" (.getName (.getClass x)) ")")))))
- 068   + 077  
- 069  (defn uaf + 078  (defn uaf
- 070    "Universal access function; `l` is expected to be an arbitrary list, `path` + 079    "Universal access function; `l` is expected to be an arbitrary list, `path`
- 071    a (clojure) list of the characters `a` and `d`. Intended to make declaring + 080    a (clojure) list of the characters `a` and `d`. Intended to make declaring
- 072    all those fiddly `#'c[ad]+r'` functions a bit easier" + 081    all those fiddly `#'c[ad]+r'` functions a bit easier"
- 073    [l path] + 082    [l path]
- 074    (cond + 083    (cond
- 075      (= l NIL) NIL + 084      (= l NIL) NIL
- 076      (empty? path) l + 085      (empty? path) l
- 077      :else (case (last path) + 086      :else (case (last path)
- 078              \a (uaf (CAR l) (butlast path)) + 087              \a (uaf (CAR l) (butlast path))
- 079              \d (uaf (CDR l) (butlast path))))) + 088              \d (uaf (CDR l) (butlast path)))))
- 080   + 089  
- 081  (defn CAAR [x] (uaf x (seq "aa"))) + 090  (defn CAAR [x] (uaf x (seq "aa")))
- 082  (defn CADR [x] (uaf x (seq "ad"))) + 091  (defn CADR [x] (uaf x (seq "ad")))
- 083  (defn CDDR [x] (uaf x (seq "dd"))) + 092  (defn CDDR [x] (uaf x (seq "dd")))
- 084  (defn CDAR [x] (uaf x (seq "da"))) -
- - 085   -
- - 086  (defn CAAAR [x] (uaf x (seq "aaa"))) -
- - 087  (defn CAADR [x] (uaf x (seq "aad"))) -
- - 088  (defn CADAR [x] (uaf x (seq "ada"))) -
- - 089  (defn CADDR [x] (uaf x (seq "add"))) -
- - 090  (defn CDDAR [x] (uaf x (seq "dda"))) -
- - 091  (defn CDDDR [x] (uaf x (seq "ddd"))) -
- - 092  (defn CDAAR [x] (uaf x (seq "daa"))) -
- - 093  (defn CDADR [x] (uaf x (seq "dad"))) + 093  (defn CDAR [x] (uaf x (seq "da")))
094  
- - 095  (defn CAAAAR [x] (uaf x (seq "aaaa"))) + + 095  (defn CAAAR [x] (uaf x (seq "aaa")))
- 096  (defn CAADAR [x] (uaf x (seq "aada"))) + 096  (defn CAADR [x] (uaf x (seq "aad")))
- 097  (defn CADAAR [x] (uaf x (seq "adaa"))) -
- - 098  (defn CADDAR [x] (uaf x (seq "adda"))) -
- - 099  (defn CDDAAR [x] (uaf x (seq "ddaa"))) -
- - 100  (defn CDDDAR [x] (uaf x (seq "ddda"))) -
- - 101  (defn CDAAAR [x] (uaf x (seq "daaa"))) -
- - 102  (defn CDADAR [x] (uaf x (seq "dada"))) -
- - 103  (defn CAAADR [x] (uaf x (seq "aaad"))) -
- - 104  (defn CAADDR [x] (uaf x (seq "aadd"))) -
- - 105  (defn CADADR [x] (uaf x (seq "adad"))) + 097  (defn CADAR [x] (uaf x (seq "ada")))
- 106  (defn CADDDR [x] (uaf x (seq "addd"))) + 098  (defn CADDR [x] (uaf x (seq "add")))
- 107  (defn CDDADR [x] (uaf x (seq "ddad"))) + 099  (defn CDDAR [x] (uaf x (seq "dda")))
- 108  (defn CDDDDR [x] (uaf x (seq "dddd"))) + 100  (defn CDDDR [x] (uaf x (seq "ddd")))
- 109  (defn CDAADR [x] (uaf x (seq "daad"))) + 101  (defn CDAAR [x] (uaf x (seq "daa")))
- 110  (defn CDADDR [x] (uaf x (seq "dadd"))) + 102  (defn CDADR [x] (uaf x (seq "dad")))
- 111   + 103   +
+ + 104  (defn CAAAAR [x] (uaf x (seq "aaaa"))) +
+ + 105  (defn CAADAR [x] (uaf x (seq "aada"))) +
+ + 106  (defn CADAAR [x] (uaf x (seq "adaa"))) +
+ + 107  (defn CADDAR [x] (uaf x (seq "adda"))) +
+ + 108  (defn CDDAAR [x] (uaf x (seq "ddaa"))) +
+ + 109  (defn CDDDAR [x] (uaf x (seq "ddda"))) +
+ + 110  (defn CDAAAR [x] (uaf x (seq "daaa"))) +
+ + 111  (defn CDADAR [x] (uaf x (seq "dada"))) +
+ + 112  (defn CAAADR [x] (uaf x (seq "aaad"))) +
+ + 113  (defn CAADDR [x] (uaf x (seq "aadd"))) +
+ + 114  (defn CADADR [x] (uaf x (seq "adad"))) +
+ + 115  (defn CADDDR [x] (uaf x (seq "addd"))) +
+ + 116  (defn CDDADR [x] (uaf x (seq "ddad"))) +
+ + 117  (defn CDDDDR [x] (uaf x (seq "dddd"))) +
+ + 118  (defn CDAADR [x] (uaf x (seq "daad"))) +
+ + 119  (defn CDADDR [x] (uaf x (seq "dadd"))) +
+ + 120  
- 112  (defn EQ + 121  (defn EQ
- 113    ;; For some reason providing a doc string for this function breaks the + 122    "Returns `T` if and only if both `x` and `y` are bound to the same atom,
- 114    ;; Clojure parser! + 123    else `F`."
- 115    [x y] + 124    [x y]
- 116    (if (and (= (ATOM x) T) (= x y)) T F)) + 125    (if (and (= (ATOM x) T) (= x y)) T F))
- 117   + 126  
- 118  (defn EQUAL + 127  (defn EQUAL
- 119    "This is a predicate that is true if its two arguments are identical + 128    "This is a predicate that is true if its two arguments are identical
- 120    S-expressions, and false if they are different. (The elementary predicate + 129    S-expressions, and false if they are different. (The elementary predicate
- 121    `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is + 130    `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is
- 122    an example of a conditional expression inside a conditional expression. + 131    an example of a conditional expression inside a conditional expression.
- 123   + 132  
- 124    NOTE: returns F on failure, not NIL" + 133    NOTE: returns `F` on failure, not `NIL`"
- 125    [x y] -
- - 126    (cond -
- - 127      (= (ATOM x) T) (EQ x y) -
- - 128      (= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y)) -
- - 129      :else F)) -
- - 130   -
- - 131  (defn SUBST -
- - 132    "This function gives the result of substituting the S-expression `x` for -
- - 133    all occurrences of the atomic symbol `y` in the S-expression `z`." -
- - 134    [x y z] + 134    [x y]
135    (cond
- - 136      (= (EQUAL y z) T) x + + 136      (= (ATOM x) T) (EQ x y)
- - 137      (= (ATOM? z) T) z ;; NIL is a symbol -
- - 138      :else -
- - 139      (make-cons-cell (SUBST x y (CAR z)) (SUBST x y (CDR z))))) -
- - 140   + + 137      (= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y))
- 141  (defn APPEND -
- - 142    "Append the the elements of `y` to the elements of `x`. + 138      :else F))
- 143   + 139   +
+ + 140  (defn SUBST
- 144    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. + 141    "This function gives the result of substituting the S-expression `x` for
- 145    See page 11 of the Lisp 1.5 Programmers Manual." + 142    all occurrences of the atomic symbol `y` in the S-expression `z`."
- 146    [x y] + 143    [x y z]
- - 147    (cond + + 144    (cond
- - 148      (= x NIL) y + + 145      (= (EQUAL y z) T) x +
+ + 146      (= (ATOM? z) T) z ;; NIL is a symbol
- 149      :else + 147      :else
- - 150      (make-cons-cell (CAR x) (APPEND (CDR x) y)))) + + 148      (make-cons-cell (SUBST x y (CAR z)) (SUBST x y (CDR z)))))
- 151   + 149   +
+ + 150  (defn APPEND +
+ + 151    "Append the the elements of `y` to the elements of `x`.
152  
- - 153  (defn MEMBER + + 153    All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
- 154    "This predicate is true if the S-expression `x` occurs among the elements + 154    See page 11 of the Lisp 1.5 Programmers Manual."
- 155    of the list `y`. + 155    [x y]
- - 156   -
- - 157    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects. -
- - 158    See page 11 of the Lisp 1.5 Programmers Manual." -
- - 159    [x y] -
- - 160    (cond + + 156    (cond
- 161      (= y NIL) F ;; NOTE: returns F on falsity, not NIL + 157      (= x NIL) y +
+ + 158      :else
- 162      (= (EQUAL x (CAR y)) T) T -
- - 163      :else (MEMBER x (CDR y)))) + 159      (make-cons-cell (CAR x) (APPEND (CDR x) y))))
- 164   + 160   +
+ + 161  
- 165  (defn PAIRLIS + 162  (defn MEMBER
- 166    "This function gives the list of pairs of corresponding elements of the + 163    "This predicate is true if the S-expression `x` occurs among the elements
- 167    lists `x` and `y`, and APPENDs this to the list `a`. The resultant list -
- - 168    of pairs, which is like a table with two columns, is called an -
- - 169    association list. + 164    of the list `y`.
- 170   + 165  
- 171    Eessentially, it builds the environment on the stack, implementing shallow + 166    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
- 172    binding. + 167    See page 11 of the Lisp 1.5 Programmers Manual." +
+ + 168    [x y] +
+ + 169    (cond +
+ + 170      (= y NIL) F ;; NOTE: returns F on falsity, not NIL +
+ + 171      (= (EQUAL x (CAR y)) T) T +
+ + 172      :else (MEMBER x (CDR y))))
173  
- - 174    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. + + 174  (defn PAIRLIS
- 175    See page 12 of the Lisp 1.5 Programmers Manual." + 175    "This function gives the list of pairs of corresponding elements of the
- 176    [x y a] + 176    lists `x` and `y`, and APPENDs this to the list `a`. The resultant list +
+ + 177    of pairs, which is like a table with two columns, is called an +
+ + 178    association list. +
+ + 179   +
+ + 180    Eessentially, it builds the environment on the stack, implementing shallow +
+ + 181    binding. +
+ + 182   +
+ + 183    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. +
+ + 184    See page 12 of the Lisp 1.5 Programmers Manual." +
+ + 185    [x y a]
- 177    (cond + 186    (cond
- 178      ;; the original tests only x; testing y as well will be a little more + 187      ;; the original tests only x; testing y as well will be a little more
- 179      ;; robust if `x` and `y` are not the same length. + 188      ;; robust if `x` and `y` are not the same length.
- 180      (or (= NIL x) (= NIL y)) a + 189      (or (= NIL x) (= NIL y)) a
- 181      :else (make-cons-cell + 190      :else (make-cons-cell
- 182              (make-cons-cell (CAR x) (CAR y)) + 191              (make-cons-cell (CAR x) (CAR y))
- 183              (PAIRLIS (CDR x) (CDR y) a)))) + 192              (PAIRLIS (CDR x) (CDR y) a))))
- 184   + 193  
- 185  (defn ASSOC + 194  (defn ASSOC
- 186    "If a is an association list such as the one formed by PAIRLIS in the above + 195    "If a is an association list such as the one formed by PAIRLIS in the above
- 187    example, then assoc will produce the first pair whose first term is x. Thus + 196    example, then assoc will produce the first pair whose first term is x. Thus
- 188    it is a table searching function. + 197    it is a table searching function.
- 189   + 198  
- 190    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. + 199    All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
- 191    See page 12 of the Lisp 1.5 Programmers Manual." + 200    See page 12 of the Lisp 1.5 Programmers Manual."
- 192    [x a] + 201    [x a]
- 193    (cond + 202    (cond
- 194      (= NIL a) NIL ;; this clause is not present in the original but is added for + 203      (= NIL a) NIL ;; this clause is not present in the original but is added for
- 195      ;; robustness. + 204      ;; robustness.
- 196      (= (EQUAL (CAAR a) x) T) (CAR a) + 205      (= (EQUAL (CAAR a) x) T) (CAR a)
- 197      :else + 206      :else
- 198      (ASSOC x (CDR a)))) + 207      (ASSOC x (CDR a))))
- 199   + 208  
- 200  (defn- SUB2 + 209  (defn- SUB2
- 201    "Internal to `SUBLIS`, q.v., which SUBSTitutes into a list from a store. + 210    "Internal to `SUBLIS`, q.v., which SUBSTitutes into a list from a store.
- 202    ? I think this is doing variable binding in the stack frame?" + 211    ? I think this is doing variable binding in the stack frame?"
- 203    [a z] + 212    [a z]
- 204    (cond + 213    (cond
- 205      (= NIL a) z + 214      (= NIL a) z
- 206      (= (CAAR a) z) (CDAR a) ;; TODO: this looks definitely wrong + 215      (= (CAAR a) z) (CDAR a) ;; TODO: this looks definitely wrong
- 207      :else + 216      :else
- 208      (SUB2 (CDR a) z))) -
- - 209   -
- - 210  (defn SUBLIS -
- - 211    "Here `a` is assumed to be an association list of the form -
- - 212    `((ul . vl)...(un . vn))`, where the `u`s are atomic, and `y` is any -
- - 213    S-expression. What `SUBLIS` does, is to treat the `u`s as variables when -
- - 214    they occur in `y`, and to SUBSTitute the corresponding `v`s from the pair -
- - 215    list. -
- - 216   -
- - 217    My interpretation is that this is variable binding in the stack frame. + 217      (SUB2 (CDR a) z)))
218  
- - 219    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. + + 219  (defn SUBLIS
- 220    See page 12 of the Lisp 1.5 Programmers Manual." + 220    "Here `a` is assumed to be an association list of the form
- 221    [a y] + 221    `((ul . vl)...(un . vn))`, where the `u`s are atomic, and `y` is any +
+ + 222    S-expression. What `SUBLIS` does, is to treat the `u`s as variables when +
+ + 223    they occur in `y`, and to SUBSTitute the corresponding `v`s from the pair +
+ + 224    list. +
+ + 225   +
+ + 226    My interpretation is that this is variable binding in the stack frame. +
+ + 227   +
+ + 228    All args are assumed to be `beowulf.cons-cell/ConsCell` objects. +
+ + 229    See page 12 of the Lisp 1.5 Programmers Manual." +
+ + 230    [a y]
- 222    (cond + 231    (cond
- 223      (= (ATOM? y) T) (SUB2 a y) + 232      (= (ATOM? y) T) (SUB2 a y)
- 224      :else + 233      :else
- 225      (make-cons-cell (SUBLIS a (CAR y)) (SUBLIS a (CDR y))))) + 234      (make-cons-cell (SUBLIS a (CAR y)) (SUBLIS a (CDR y)))))
- 226   + 235  
- 227  (defn APPLY + 236  (defn APPLY
- 228    "For bootstrapping, at least, a version of APPLY written in Clojure. + 237    "For bootstrapping, at least, a version of APPLY written in Clojure.
- 229    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects. + 238    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
- 230    See page 13 of the Lisp 1.5 Programmers Manual." + 239    See page 13 of the Lisp 1.5 Programmers Manual."
- 231    [function args environment] + 240    [function args environment]
- 232    (cond + 241    (cond
- 233      (= + 242      (=
- 234        (ATOM? function) + 243        (ATOM? function)
- 235        T)(cond + 244        T)(cond
- 236             ;; TODO: doesn't check whether `function` is bound in the environment; + 245             ;; TODO: doesn't check whether `function` is bound in the environment;
- 237             ;; we'll need that before we can bootstrap. + 246             ;; we'll need that before we can bootstrap.
- 238             (= function 'CAR) (CAAR args) + 247             (= function 'CAR) (CAAR args)
- 239             (= function 'CDR) (CDAR args) + 248             (= function 'CDR) (CDAR args)
- 240             (= function 'CONS) (make-cons-cell (CAR args) (CADR args)) + 249             (= function 'CONS) (make-cons-cell (CAR args) (CADR args))
- 241             (= function 'ATOM) (if (ATOM? (CAR args)) T NIL) + 250             (= function 'ATOM) (if (ATOM? (CAR args)) T NIL)
- 242             (= function 'EQ) (if (= (CAR args) (CADR args)) T NIL) + 251             (= function 'EQ) (if (= (CAR args) (CADR args)) T NIL)
- 243             :else + 252             :else
- 244             (APPLY + 253             (APPLY
- 245               (EVAL function environment) + 254               (EVAL function environment)
- 246               args + 255               args
- 247               environment)) + 256               environment))
- 248      (= (first function) 'LAMBDA) (EVAL + 257      (= (first function) 'LAMBDA) (EVAL
- 249                                     (CADDR function) + 258                                     (CADDR function)
- 250                                     (PAIRLIS (CADR function) args environment)) + 259                                     (PAIRLIS (CADR function) args environment))
- 251      (= (first function) 'LABEL) (APPLY + 260      (= (first function) 'LABEL) (APPLY
- 252                                    (CADDR function) + 261                                    (CADDR function)
- 253                                    args + 262                                    args
- 254                                    (make-cons-cell + 263                                    (make-cons-cell
- 255                                      (make-cons-cell + 264                                      (make-cons-cell
- 256                                        (CADR function) + 265                                        (CADR function)
- 257                                        (CADDR function)) + 266                                        (CADDR function))
- 258                                      environment)))) + 267                                      environment))))
- 259   + 268  
- 260  (defn- EVCON + 269  (defn- EVCON
- 261    "Inner guts of primitive COND. All args are assumed to be + 270    "Inner guts of primitive COND. All args are assumed to be
- 262    `beowulf.cons-cell/ConsCell` objects. + 271    `beowulf.cons-cell/ConsCell` objects.
- 263    See page 13 of the Lisp 1.5 Programmers Manual." + 272    See page 13 of the Lisp 1.5 Programmers Manual."
- 264    [clauses env] + 273    [clauses env]
- 265    (if + 274    (if
- 266      (not= (EVAL (CAAR clauses) env) NIL) + 275      (not= (EVAL (CAAR clauses) env) NIL)
- 267      (EVAL (CADAR clauses) env) + 276      (EVAL (CADAR clauses) env)
- 268      (EVCON (CDR clauses) env))) + 277      (EVCON (CDR clauses) env)))
- 269   + 278  
- 270  (defn- EVLIS + 279  (defn- EVLIS
- 271    "Map `EVAL` across this list of `args` in the context of this + 280    "Map `EVAL` across this list of `args` in the context of this
- 272    `env`ironment.All args are assumed to be `beowulf.cons-cell/ConsCell` objects. + 281    `env`ironment.All args are assumed to be `beowulf.cons-cell/ConsCell` objects.
- 273    See page 13 of the Lisp 1.5 Programmers Manual." + 282    See page 13 of the Lisp 1.5 Programmers Manual."
- 274    [args env] + 283    [args env]
- 275    (cond + 284    (cond
- 276      (= NIL args) NIL + 285      (= NIL args) NIL
- 277      :else + 286      :else
- 278      (make-cons-cell + 287      (make-cons-cell
- 279        (EVAL (CAR args) env) + 288        (EVAL (CAR args) env)
- 280        (EVLIS (CDR args) env)))) + 289        (EVLIS (CDR args) env))))
- 281   + 290  
- 282  (deftrace traced-eval + 291  (deftrace traced-eval
- 283    "Essentially, identical to EVAL except traced." + 292    "Essentially, identical to EVAL except traced."
- 284    [expr env] + 293    [expr env]
- 285    (cond + 294    (cond
- 286      (= + 295      (=
- 287        (ATOM? expr) T) + 296        (ATOM? expr) T)
- 288      (CDR (ASSOC expr env)) + 297      (CDR (ASSOC expr env))
- 289      (= + 298      (=
- 290        (ATOM? (CAR expr)) + 299        (ATOM? (CAR expr))
- 291        T)(cond + 300        T)(cond
- 292             (= (CAR expr) 'QUOTE) (CADR expr) + 301             (= (CAR expr) 'QUOTE) (CADR expr)
- 293             (= (CAR expr) 'COND) (EVCON (CDR expr) env) + 302             (= (CAR expr) 'COND) (EVCON (CDR expr) env)
- 294             :else (APPLY + 303             :else (APPLY
- 295                     (CAR expr) + 304                     (CAR expr)
- 296                     (EVLIS (CDR expr) env) + 305                     (EVLIS (CDR expr) env)
- 297                     env)) + 306                     env))
- 298      :else (APPLY + 307      :else (APPLY
- 299              (CAR expr) + 308              (CAR expr)
- 300              (EVLIS (CDR expr) env) + 309              (EVLIS (CDR expr) env)
- 301              env))) + 310              env)))
- 302   + 311  
- 303  (defn EVAL + 312  (defn EVAL
- 304    "For bootstrapping, at least, a version of EVAL written in Clojure. + 313    "For bootstrapping, at least, a version of EVAL written in Clojure.
- 305    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects. + 314    All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
- 306    See page 13 of the Lisp 1.5 Programmers Manual." + 315    See page 13 of the Lisp 1.5 Programmers Manual."
- 307    [expr env] + 316    [expr env]
- 308    (cond + 317    (cond
- 309      (true? (:trace *options*)) + 318      (true? (:trace *options*))
- 310      (traced-eval expr env) + 319      (traced-eval expr env)
- 311      (= + 320      (=
- 312        (ATOM? expr) T) + 321        (ATOM? expr) T)
- 313      (CDR (ASSOC expr env)) + 322      (CDR (ASSOC expr env))
- 314      (= + 323      (=
- 315        (ATOM? (CAR expr)) + 324        (ATOM? (CAR expr))
- 316        T)(cond + 325        T)(cond
- 317             (= (CAR expr) 'QUOTE) (CADR expr) + 326             (= (CAR expr) 'QUOTE) (CADR expr)
- 318             (= (CAR expr) 'COND) (EVCON (CDR expr) env) + 327             (= (CAR expr) 'COND) (EVCON (CDR expr) env)
- 319             :else (APPLY + 328             :else (APPLY
- 320                     (CAR expr) + 329                     (CAR expr)
- 321                     (EVLIS (CDR expr) env) + 330                     (EVLIS (CDR expr) env)
- 322                     env)) + 331                     env))
- 323      :else (APPLY + 332      :else (APPLY
- 324              (CAR expr) + 333              (CAR expr)
- 325              (EVLIS (CDR expr) env) + 334              (EVLIS (CDR expr) env)
- 326              env))) + 335              env)))
- 327   + 336  
- 328   + 337  
- 329   + 338  
diff --git a/docs/cloverage/beowulf/cons_cell.clj.html b/docs/cloverage/beowulf/cons_cell.clj.html index c820206..e6bba22 100644 --- a/docs/cloverage/beowulf/cons_cell.clj.html +++ b/docs/cloverage/beowulf/cons_cell.clj.html @@ -19,374 +19,374 @@ 005  
- - 006  (def NIL (symbol "NIL")) + + 006  (def NIL
- - 007   + + 007    "The canonical empty list symbol."
- - 008  (def T (symbol "T")) ;; true. + + 008    (symbol "NIL"))
009  
- - 010  (def F (symbol "F")) ;; false as distinct from nil + + 010  (def T +
+ + 011    "The canonical true value." +
+ + 012    (symbol "T")) ;; true.
- 011   + 013   +
+ + 014  (def F +
+ + 015    "The canonical false value - different from `NIL`, which is not caninically +
+ + 016    false in Lisp 1.5." +
+ + 017    (symbol "F")) ;; false as distinct from nil +
+ + 018  
- 012  (deftype ConsCell [CAR CDR] + 019  (deftype ConsCell [CAR CDR]
- 013    clojure.lang.ISeq + 020    clojure.lang.ISeq
- 014    (cons [this x] (ConsCell. x this)) + 021    (cons [this x] (ConsCell. x this))
- 015    (first [this] (.CAR this)) + 022    (first [this] (.CAR this))
- 016    ;; next and more must return ISeq: + 023    ;; next and more must return ISeq:
- 017    ;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java + 024    ;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
- 018    (more [this] (if + 025    (more [this] (if
- 019                   (seq? (.CDR this)) + 026                   (seq? (.CDR this))
- 020                   (.CDR this) + 027                   (.CDR this)
- 021                   clojure.lang.PersistentList/EMPTY)) + 028                   clojure.lang.PersistentList/EMPTY))
- 022    (next [this] (if + 029    (next [this] (if
- 023                   (seq? (.CDR this)) + 030                   (seq? (.CDR this))
- 024                   (.CDR this) + 031                   (.CDR this)
- 025                   nil ;; next returns nil when empty + 032                   nil ;; next returns nil when empty
- 026                   )) -
- - 027   -
- - 028    clojure.lang.Seqable -
- - 029    (seq [this] this) -
- - 030   -
- - 031    ;; for some reason this marker protocol is needed otherwise compiler complains -
- - 032    ;; that `nth not supported on ConsCell` -
- - 033    clojure.lang.Sequential + 033                   ))
034  
- 035    clojure.lang.IPersistentCollection + 035    clojure.lang.Seqable
- 036    (count [this] (if -
- - 037                    (coll? (.CDR this)) -
- - 038                    (inc (.count (.CDR this))) -
- - 039                    1)) -
- - 040    (empty [this] false) ;; a cons cell is by definition not empty. -
- - 041    (equiv [this other] (if -
- - 042                          (seq? other) -
- - 043                          (and -
- - 044                            (if -
- - 045                              (and -
- - 046                                (seq? (first this)) -
- - 047                                (seq? (first other))) -
- - 048                              (.equiv (first this) (first other)) -
- - 049                              (= (first this) (first other))) -
- - 050                            (if -
- - 051                              (and -
- - 052                                (seq? (rest this)) -
- - 053                                (seq? (rest other))) -
- - 054                              (.equiv (rest this) (rest other)) -
- - 055                              (= (rest this) (rest other)))) -
- - 056                          false))) + 036    (seq [this] this)
- 057   + 037   +
+ + 038    ;; for some reason this marker protocol is needed otherwise compiler complains +
+ + 039    ;; that `nth not supported on ConsCell` +
+ + 040    clojure.lang.Sequential +
+ + 041   +
+ + 042    clojure.lang.IPersistentCollection +
+ + 043    (count [this] (if +
+ + 044                    (coll? (.CDR this)) +
+ + 045                    (inc (.count (.CDR this))) +
+ + 046                    1)) +
+ + 047    (empty [this] false) ;; a cons cell is by definition not empty. +
+ + 048    (equiv [this other] (if +
+ + 049                          (seq? other) +
+ + 050                          (and +
+ + 051                            (if +
+ + 052                              (and +
+ + 053                                (seq? (first this)) +
+ + 054                                (seq? (first other))) +
+ + 055                              (.equiv (first this) (first other)) +
+ + 056                              (= (first this) (first other))) +
+ + 057                            (if +
+ + 058                              (and +
+ + 059                                (seq? (rest this)) +
+ + 060                                (seq? (rest other))) +
+ + 061                              (.equiv (rest this) (rest other)) +
+ + 062                              (= (rest this) (rest other)))) +
+ + 063                          false))) +
+ + 064  
- 058  (defn- to-string + 065  (defn- to-string
- 059    "Printing ConsCells gave me a *lot* of trouble. This is an internal function + 066    "Printing ConsCells gave me a *lot* of trouble. This is an internal function
- 060    used by the print-method override (below) in order that the standard Clojure + 067    used by the print-method override (below) in order that the standard Clojure
- 061    `print` and `str` functions will print ConsCells correctly. The argument + 068    `print` and `str` functions will print ConsCells correctly. The argument
- 062    `cell` must, obviously, be an instance of `ConsCell`." + 069    `cell` must, obviously, be an instance of `ConsCell`."
- 063    [cell] + 070    [cell]
- 064    (loop [c cell + 071    (loop [c cell
- 065           n 0 + 072           n 0
- 066           s "("] + 073           s "("]
- 067      (if + 074      (if
- 068        (instance? beowulf.cons_cell.ConsCell c) + 075        (instance? beowulf.cons_cell.ConsCell c)
- 069        (let [car (.CAR c) + 076        (let [car (.CAR c)
- 070              cdr (.CDR c) + 077              cdr (.CDR c)
- 071              cons? (instance? beowulf.cons_cell.ConsCell cdr) + 078              cons? (instance? beowulf.cons_cell.ConsCell cdr)
- 072              ss (str + 079              ss (str
- 073                   s + 080                   s
- 074                   (to-string car) + 081                   (to-string car)
- 075                   (cond + 082                   (cond
- 076                     cons? + 083                     cons?
- 077                     " " + 084                     " "
- 078                     (or (nil? cdr) (= cdr 'NIL)) + 085                     (or (nil? cdr) (= cdr 'NIL))
- 079                     ")" + 086                     ")"
- 080                     :else + 087                     :else
- 081                     (str " . " (to-string cdr) ")")))] + 088                     (str " . " (to-string cdr) ")")))]
- 082          (if + 089          (if
- 083            cons? + 090            cons?
- 084            (recur cdr (inc n) ss) + 091            (recur cdr (inc n) ss)
- 085            ss)) + 092            ss))
- 086        (str c)))) + 093        (str c))))
- 087   + 094  
- 088  (defn pretty-print + 095  (defn pretty-print
- 089    "This isn't the world's best pretty printer but it sort of works." + 096    "This isn't the world's best pretty printer but it sort of works."
- 090    ([^beowulf.cons_cell.ConsCell cell] + 097    ([^beowulf.cons_cell.ConsCell cell]
- 091     (println (pretty-print cell 80 0))) + 098     (println (pretty-print cell 80 0)))
- 092    ([^beowulf.cons_cell.ConsCell cell width level] + 099    ([^beowulf.cons_cell.ConsCell cell width level]
- 093     (loop [c cell + 100     (loop [c cell
- 094            n (inc level) + 101            n (inc level)
- 095            s "("] + 102            s "("]
- 096       (if + 103       (if
- 097         (instance? beowulf.cons_cell.ConsCell c) + 104         (instance? beowulf.cons_cell.ConsCell c)
- 098         (let [car (.CAR c) + 105         (let [car (.CAR c)
- 099               cdr (.CDR c) + 106               cdr (.CDR c)
- 100               cons? (instance? beowulf.cons_cell.ConsCell cdr) + 107               cons? (instance? beowulf.cons_cell.ConsCell cdr)
- 101               print-width (count (print-str c)) + 108               print-width (count (print-str c))
- 102               indent (apply str (repeat n "  ")) + 109               indent (apply str (repeat n "  "))
- 103               ss (str + 110               ss (str
- 104                    s + 111                    s
- 105                    (pretty-print car width n) + 112                    (pretty-print car width n)
- 106                    (cond + 113                    (cond
- 107                      cons? + 114                      cons?
- 108                      (if + 115                      (if
- 109                        (< (+ (count indent) print-width) width) + 116                        (< (+ (count indent) print-width) width)
- 110                        " " + 117                        " "
- 111                        (str "\n" indent)) + 118                        (str "\n" indent))
- 112                      (or (nil? cdr) (= cdr 'NIL)) + 119                      (or (nil? cdr) (= cdr 'NIL))
- 113                      ")" + 120                      ")"
- 114                      :else + 121                      :else
- 115                      (str " . " (pretty-print cdr width n) ")")))] + 122                      (str " . " (pretty-print cdr width n) ")")))]
- 116           (if + 123           (if
- 117             cons? + 124             cons?
- 118             (recur cdr n ss) + 125             (recur cdr n ss)
- 119             ss)) + 126             ss))
- 120         (str c))))) + 127         (str c)))))
- 121   -
- - 122   -
- - 123   -
- - 124  (defmethod clojure.core/print-method -
- - 125    ;;; I have not worked out how to document defmethod without blowing up the world. -
- - 126    beowulf.cons_cell.ConsCell -
- - 127    [this writer] -
- - 128    (.write writer (to-string this))) + 128  
129   @@ -394,62 +394,83 @@ 130  
- - 131  (defmacro make-cons-cell -
- - 132    "Construct a new instance of cons cell with this `car` and `cdr`." -
- - 133    [car cdr] -
- 134    `(ConsCell. ~car ~cdr)) + 131  (defmethod clojure.core/print-method +
+ + 132    ;;; I have not worked out how to document defmethod without blowing up the world. +
+ + 133    beowulf.cons_cell.ConsCell +
+ + 134    [this writer] +
+ + 135    (.write writer (to-string this)))
- 135   + 136   +
+ + 137   +
+ + 138  (defmacro make-cons-cell +
+ + 139    "Construct a new instance of cons cell with this `car` and `cdr`." +
+ + 140    [car cdr] +
+ + 141    `(ConsCell. ~car ~cdr)) +
+ + 142  
- 136  (defn make-beowulf-list + 143  (defn make-beowulf-list
- 137    "Construct a linked list of cons cells with the same content as the + 144    "Construct a linked list of cons cells with the same content as the
- 138    sequence `x`." + 145    sequence `x`."
- 139    [x] + 146    [x]
- 140    (cond + 147    (cond
- 141      (empty? x) NIL + 148      (empty? x) NIL
- 142      (coll? x) (ConsCell. + 149      (coll? x) (ConsCell.
- 143                  (if + 150                  (if
- 144                    (seq? (first x)) + 151                    (seq? (first x))
- 145                    (make-beowulf-list (first x)) + 152                    (make-beowulf-list (first x))
- 146                    (first x)) + 153                    (first x))
- 147                  (make-beowulf-list (rest x))) + 154                  (make-beowulf-list (rest x)))
- 148      :else + 155      :else
- 149      NIL)) + 156      NIL))
diff --git a/docs/cloverage/beowulf/core.clj.html b/docs/cloverage/beowulf/core.clj.html index ab4e3d0..13189d9 100644 --- a/docs/cloverage/beowulf/core.clj.html +++ b/docs/cloverage/beowulf/core.clj.html @@ -8,232 +8,241 @@ 001  (ns beowulf.core

- 002    (:require [beowulf.bootstrap :refer [EVAL oblist *options*]] + 002    "Essentially, the `-main` function and the bootstrap read-eval-print loop."
- 003              [beowulf.read :refer [READ]] + 003    (:require [beowulf.bootstrap :refer [EVAL oblist *options*]]
- 004              [clojure.java.io :as io] + 004              [beowulf.read :refer [READ]]
- 005              [clojure.pprint :refer [pprint]] + 005              [clojure.java.io :as io]
- 006              [clojure.tools.cli :refer [parse-opts]] + 006              [clojure.pprint :refer [pprint]]
- 007              [environ.core :refer [env]]) + 007              [clojure.tools.cli :refer [parse-opts]]
- 008    (:gen-class)) + 008              [environ.core :refer [env]]) +
+ + 009    (:gen-class))
- 009   + 010  
- 010  (def cli-options + 011  (def cli-options
- 011    [["-h" "--help"] + 012    [["-h" "--help"]
- 012     ["-p PROMPT" "--prompt PROMPT" "Set the REPL prompt to PROMPT" + 013     ["-p PROMPT" "--prompt PROMPT" "Set the REPL prompt to PROMPT"
- 013      :default "Sprecan::"] + 014      :default "Sprecan::"]
- 014     ["-r INITFILE" "--read INITFILE" "Read Lisp functions from the file INITFILE" + 015     ["-r INITFILE" "--read INITFILE" "Read Lisp functions from the file INITFILE"
- 015      :validate [#(and + 016      :validate [#(and
- 016                    (.exists (io/file %)) + 017                    (.exists (io/file %))
- 017                    (.canRead (io/file %))) + 018                    (.canRead (io/file %)))
- 018                 "Could not find initfile"]] + 019                 "Could not find initfile"]]
- 019     ["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."] + 020     ["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."]
- 020     ["-t" "--trace" "Trace Lisp evaluation."]]) + 021     ["-t" "--trace" "Trace Lisp evaluation."]])
- 021   + 022  
- 022  (defn repl + 023  (defn repl
- 023    "Read/eval/print loop." + 024    "Read/eval/print loop."
- 024    [prompt] + 025    [prompt]
- 025    (loop [] + 026    (loop []
- 026      (print prompt) + 027      (print prompt)
- 027      (flush) + 028      (flush)
- 028      (try + 029      (try
- 029        (let [input (read-line)] + 030        (let [input (read-line)]
- 030          (cond + 031          (cond
- 031            (= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit})) + 032            (= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit}))
- 032            input (println (str ">  " (print-str (EVAL (READ input) @oblist)))) + 033            input (println (str ">  " (print-str (EVAL (READ input) @oblist))))
- 033            :else (println))) + 034            :else (println)))
- 034        (catch + 035        (catch
- 035          Exception + 036          Exception
- 036          e + 037          e
- 037          (let [data (ex-data e)] + 038          (let [data (ex-data e)]
- 038            (println (.getMessage e)) + 039            (println (.getMessage e))
- 039            (if + 040            (if
- 040              data + 041              data
- 041              (case (:cause data) + 042              (case (:cause data)
- 042                :parse-failure (println (:failure data)) + 043                :parse-failure (println (:failure data))
- 043                :strict nil ;; the message, which has already been printed, is enough. + 044                :strict nil ;; the message, which has already been printed, is enough.
- 044                :quit (throw e) + 045                :quit (throw e)
- 045                ;; default + 046                ;; default
- 046                (pprint data)))))) + 047                (pprint data))))))
- 047      (recur))) + 048      (recur)))
- 048   + 049  
- 049  (defn -main + 050  (defn -main
- 050    [& opts] + 051    "Parse options, print the banner, read the init file if any, and enter the +
+ + 052    read/eval/print loop." +
+ + 053    [& opts]
- 051    (let [args (parse-opts opts cli-options)] + 054    (let [args (parse-opts opts cli-options)]
- 052      (println + 055      (println
- 053        (str + 056        (str
- 054          "\nHider wilcuman. Béowulf is mín nama.\n" -
- - 055          (if -
- - 056            (System/getProperty "beowulf.version") -
- - 057            (str "Síðe " (System/getProperty "beowulf.version") "\n")) + 057          "\nHider wilcuman. Béowulf is mín nama.\n"
058          (if
- - 059            (:help (:options args)) -
- - 060            (:summary args)) -
- - 061          (if (:errors args) -
- - 062            (apply str (interpose "; " (:errors args)))) -
- - 063          "\nSprecan 'quit' tó laéfan\n")) -
- - 064      (binding [*options* (:options args)] -
- - 065        (try -
- - 066          (repl (str (:prompt (:options args)) " ")) -
- - 067          (catch -
- - 068            Exception -
- - 069            e -
- - 070            (let [data (ex-data e)] -
- - 071              (if -
- - 072                data + + 059            (System/getProperty "beowulf.version")
- 073                (case (:cause data) + 060            (str "Síðe " (System/getProperty "beowulf.version") "\n")) +
+ + 061          (if +
+ + 062            (:help (:options args)) +
+ + 063            (:summary args)) +
+ + 064          (if (:errors args) +
+ + 065            (apply str (interpose "; " (:errors args))))
- 074                  :quit nil + 066          "\nSprecan 'quit' tó laéfan\n")) +
+ + 067      (binding [*options* (:options args)] +
+ + 068        (try +
+ + 069          (repl (str (:prompt (:options args)) " "))
- 075                  ;; default + 070          (catch +
+ + 071            Exception +
+ + 072            e +
+ + 073            (let [data (ex-data e)] +
+ + 074              (if +
+ + 075                data +
+ + 076                (case (:cause data) +
+ + 077                  :quit nil +
+ + 078                  ;; default
- 076                  (pprint data)) + 079                  (pprint data))
- 077                (println e)))))))) + 080                (println e))))))))
diff --git a/docs/cloverage/beowulf/host.clj.html b/docs/cloverage/beowulf/host.clj.html index 5671aa2..3acdcf2 100644 --- a/docs/cloverage/beowulf/host.clj.html +++ b/docs/cloverage/beowulf/host.clj.html @@ -5,31 +5,19 @@ - 001  (ns beowulf.host) + 001  (ns beowulf.host +
+ + 002    "provides Lisp 1.5 functions which can't be (or can't efficiently +
+ + 003     be) implemented in Lisp 1.5, which therefore need to be implemented in the +
+ + 004     host language, in this case Clojure.")
- 002   -
- - 003  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -
- - 004  ;;; -
- - 005  ;;; This file provides Lisp 1.5 functions which can't be (or can't efficiently -
- - 006  ;;; be) implemented in Lisp 1.5, which therefore need to be implemented in the -
- - 007  ;;; host language, in this case Clojure. -
- - 008  ;;; -
- - 009  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + 005  
diff --git a/docs/cloverage/beowulf/read.clj.html b/docs/cloverage/beowulf/read.clj.html index 673b400..c8852dc 100644 --- a/docs/cloverage/beowulf/read.clj.html +++ b/docs/cloverage/beowulf/read.clj.html @@ -8,904 +8,937 @@ 001  (ns beowulf.read

- 002    (:require [beowulf.bootstrap :refer [*options*]] + 002    "This provides the reader required for boostrapping. It's not a bad
- 003              [clojure.math.numeric-tower :refer [expt]] + 003    reader - it provides feedback on errors found in the input - but it isn't
- 004              [clojure.string :refer [starts-with? upper-case]] + 004    the real Lisp reader. +
+ + 005  
- 005              [instaparse.core :as i] -
- - 006              [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]])) + 006    Intended deviations from the behaviour of the real Lisp reader are as follows:
007  
- 008  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + 008    1. It reads the meta-expression language `MEXPR` in addition to the
- 009  ;;; + 009        symbolic expression language `SEXPR`, which I do not believe the Lisp 1.5
- 010  ;;; This file provides the reader required for boostrapping. It's not a bad + 010        reader ever did;
- 011  ;;; reader - it provides feedback on errors found in the input - but it isn't + 011    2. It treats everything between a semi-colon and an end of line as a comment,
- 012  ;;; the real Lisp reader. + 012        as most modern Lisps do; but I do not believe Lisp 1.5 had this feature."
- 013  ;;; + 013    (:require [beowulf.bootstrap :refer [*options*]]
- 014  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + 014              [clojure.math.numeric-tower :refer [expt]] +
+ + 015              [clojure.string :refer [starts-with? upper-case]] +
+ + 016              [instaparse.core :as i] +
+ + 017              [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
- 015   + 018   +
+ + 019  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 020  ;;; +
+ + 021  ;;; This file provides the reader required for boostrapping. It's not a bad +
+ + 022  ;;; reader - it provides feedback on errors found in the input - but it isn't +
+ + 023  ;;; the real Lisp reader. +
+ + 024  ;;; +
+ + 025  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +
+ + 026  
- 016  (declare generate) + 027  (declare generate)
- 017   + 028  
- 018  (def parse + 029  (def parse
- 019    "Parse a string presented as argument into a parse tree which can then + 030    "Parse a string presented as argument into a parse tree which can then
- 020    be operated upon further." + 031    be operated upon further."
- 021    (i/parser + 032    (i/parser
- 022      (str + 033      (str
- 023        ;; top level: we accept mexprs as well as sexprs. + 034        ;; top level: we accept mexprs as well as sexprs.
- 024        "expr := mexpr | sexpr;" + 035        "expr := mexpr | sexpr;"
- 025   + 036  
- 026        ;; mexprs. I'm pretty clear that Lisp 1.5 could never read these, + 037        ;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
- 027        ;; but it's a convenience. + 038        ;; but it's a convenience.
- 028        "mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment; + 039        "mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
- 029        λexpr := λ lsqb bindings semi-colon body rsqb; + 040        λexpr := λ lsqb bindings semi-colon body rsqb;
- 030        λ := 'λ'; + 041        λ := 'λ';
- 031        bindings := lsqb args rsqb; + 042        bindings := lsqb args rsqb;
- 032        body := (expr semi-colon opt-space)* expr; + 043        body := (expr semi-colon opt-space)* expr;
- 033        fncall := fn-name lsqb args rsqb; + 044        fncall := fn-name lsqb args rsqb;
- 034        lsqb := '['; + 045        lsqb := '[';
- 035        rsqb := ']'; + 046        rsqb := ']';
- 036        defn := mexpr opt-space '=' opt-space mexpr; + 047        defn := mexpr opt-space '=' opt-space mexpr;
- 037        cond := lsqb (cond-clause semi-colon opt-space)* cond-clause rsqb; + 048        cond := lsqb (cond-clause semi-colon opt-space)* cond-clause rsqb;
- 038        cond-clause := expr opt-space arrow opt-space expr; + 049        cond-clause := expr opt-space arrow opt-space expr;
- 039        arrow := '->'; + 050        arrow := '->';
- 040        args := (expr semi-colon opt-space)* expr; + 051        args := (expr semi-colon opt-space)* expr;
- 041        fn-name := mvar; + 052        fn-name := mvar;
- 042        mvar := #'[a-z]+'; + 053        mvar := #'[a-z]+';
- 043        semi-colon := ';';" + 054        semi-colon := ';';"
- 044   + 055  
- 045        ;; comments. I'm pretty confident Lisp 1.5 did NOT have these. + 056        ;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
- 046        "comment := opt-space <';;'> #'[^\\n\\r]*';" + 057        "comment := opt-space <';;'> #'[^\\n\\r]*';"
- 047   + 058  
- 048        ;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro, + 059        ;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
- 049        ;; but I've included it on the basis that it can do little harm. + 060        ;; but I've included it on the basis that it can do little harm.
- 050        "sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment; + 061        "sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
- 051        list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal; + 062        list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
- 052        dotted-pair := lpar dot-terminal ; + 063        dotted-pair := lpar dot-terminal ;
- 053        dot := '.'; + 064        dot := '.';
- 054        lpar := '('; + 065        lpar := '(';
- 055        rpar := ')'; + 066        rpar := ')';
- 056        quoted-expr := quote sexpr; + 067        quoted-expr := quote sexpr;
- 057        quote := '\\''; + 068        quote := '\\'';
- 058        dot-terminal := sexpr space dot space sexpr rpar; + 069        dot-terminal := sexpr space dot space sexpr rpar;
- 059        space := #'\\p{javaWhitespace}+'; + 070        space := #'\\p{javaWhitespace}+';
- 060        opt-space := #'\\p{javaWhitespace}*'; + 071        opt-space := #'\\p{javaWhitespace}*';
- 061        sep := ',' | opt-space; + 072        sep := ',' | opt-space;
- 062        atom := #'[A-Z][A-Z0-9]*';" + 073        atom := #'[A-Z][A-Z0-9]*';"
- 063   + 074  
- 064        ;; Lisp 1.5 supported octal as well as decimal and scientific notation + 075        ;; Lisp 1.5 supported octal as well as decimal and scientific notation
- 065        "number := integer | decimal | scientific | octal; + 076        "number := integer | decimal | scientific | octal;
- 066        integer := #'-?[1-9][0-9]*'; + 077        integer := #'-?[1-9][0-9]*';
- 067        decimal := #'-?[1-9][0-9]*\\.?[0-9]*' | #'0.[0-9]*'; + 078        decimal := #'-?[1-9][0-9]*\\.?[0-9]*' | #'0.[0-9]*';
- 068        scientific := coefficient e exponent; + 079        scientific := coefficient e exponent;
- 069        coefficient := decimal; + 080        coefficient := decimal;
- 070        exponent := integer; + 081        exponent := integer;
- 071        e := 'E'; + 082        e := 'E';
- 072        octal := #'[+-]?[0-7]+{1,12}' q scale-factor; + 083        octal := #'[+-]?[0-7]+{1,12}' q scale-factor;
- 073        q := 'Q'; + 084        q := 'Q';
- 074        scale-factor := #'[0-9]*'"))) + 085        scale-factor := #'[0-9]*'")))
- 075   + 086  
- 076  (defn simplify + 087  (defn simplify
- 077    "Simplify this parse tree `p`. If `p` is an instaparse failure object, throw + 088    "Simplify this parse tree `p`. If `p` is an instaparse failure object, throw
- 078    an `ex-info`, with `p` as the value of its `:failure` key." + 089    an `ex-info`, with `p` as the value of its `:failure` key."
- 079    ([p] + 090    ([p]
- 080     (if + 091     (if
- 081       (instance? instaparse.gll.Failure p) + 092       (instance? instaparse.gll.Failure p)
- 082       (throw (ex-info "Ic ne behæfd" {:cause :parse-failure :failure p})) + 093       (throw (ex-info "Ic ne behæfd" {:cause :parse-failure :failure p}))
- 083       (simplify p :sexpr))) + 094       (simplify p :sexpr)))
- 084    ([p context] + 095    ([p context]
- 085    (if + 096    (if
- 086      (coll? p) + 097      (coll? p)
- 087      (apply + 098      (apply
- 088        vector + 099        vector
- 089        (remove + 100        (remove
- 090          #(if (coll? %) (empty? %)) + 101          #(if (coll? %) (empty? %))
- 091          (case (first p) + 102          (case (first p)
- 092            (:arg :expr :coefficient :fn-name :number :sexpr) (simplify (second p) context) + 103            (:arg :expr :coefficient :fn-name :number :sexpr) (simplify (second p) context)
- 093            (:λexpr + 104            (:λexpr
- 094              :args :bindings :body :cond :cond-clause :dot-terminal + 105              :args :bindings :body :cond :cond-clause :dot-terminal
- 095              :fncall :octal :quoted-expr :scientific) (map #(simplify % context) p) + 106              :fncall :octal :quoted-expr :scientific) (map #(simplify % context) p)
- 096            (:arrow :dot :e :lpar :lsqb :opt-space :q :quote :rpar :rsqb + 107            (:arrow :dot :e :lpar :lsqb :opt-space :q :quote :rpar :rsqb
- 097              :semi-colon :sep :space) nil + 108              :semi-colon :sep :space) nil
- 098            :atom (if + 109            :atom (if
- 099                    (= context :mexpr) + 110                    (= context :mexpr)
- 100                    [:quoted-expr p] + 111                    [:quoted-expr p]
- 101                    p) + 112                    p)
- 102            :comment (if + 113            :comment (if
- 103                       (:strict *options*) + 114                       (:strict *options*)
- 104                       (throw + 115                       (throw
- 105                         (ex-info "Cannot parse comments in strict mode" + 116                         (ex-info "Cannot parse comments in strict mode"
- 106                                  {:cause :strict}))) + 117                                  {:cause :strict})))
- 107            :dotted-pair (if + 118            :dotted-pair (if
- 108                           (= context :mexpr) + 119                           (= context :mexpr)
- 109                           [:fncall + 120                           [:fncall
- 110                            [:mvar "cons"] + 121                            [:mvar "cons"]
- 111                            [:args + 122                            [:args
- 112                             (simplify (nth p 1) context) + 123                             (simplify (nth p 1) context)
- 113                             (simplify (nth p 2) context)]] + 124                             (simplify (nth p 2) context)]]
- 114                           (map simplify p)) + 125                           (map simplify p))
- 115            :mexpr (if + 126            :mexpr (if
- 116                     (:strict *options*) + 127                     (:strict *options*)
- 117                     (throw + 128                     (throw
- 118                       (ex-info "Cannot parse meta expressions in strict mode" + 129                       (ex-info "Cannot parse meta expressions in strict mode"
- 119                                {:cause :strict})) + 130                                {:cause :strict}))
- 120                     (simplify (second p) :mexpr)) + 131                     (simplify (second p) :mexpr))
- 121            :list (if + 132            :list (if
- 122                    (= context :mexpr) + 133                    (= context :mexpr)
- 123                    [:fncall + 134                    [:fncall
- 124                     [:mvar "list"] + 135                     [:mvar "list"]
- 125                     [:args (apply vector (map simplify (rest p)))]] + 136                     [:args (apply vector (map simplify (rest p)))]]
- 126                    (map #(simplify % context) p)) + 137                    (map #(simplify % context) p))
- 127            ;;default + 138            ;;default
- 128            p))) + 139            p)))
- 129      p))) + 140      p)))
- 130   + 141  
- 131   + 142  
- 132  ;; # From Lisp 1.5 Programmers Manual, page 10 + 143  ;; # From Lisp 1.5 Programmers Manual, page 10
- 133  ;; Note that I've retyped much of this, since copy/pasting out of PDF is less + 144  ;; Note that I've retyped much of this, since copy/pasting out of PDF is less
- 134  ;; than reliable. Any typos are mine. Quote starts [[ + 145  ;; than reliable. Any typos are mine. Quote starts [[
- 135   + 146  
- 136  ;; We are now in a position to define the universal LISP function + 147  ;; We are now in a position to define the universal LISP function
- 137  ;; evalquote[fn;args], When evalquote is given a function and a list of arguments + 148  ;; evalquote[fn;args], When evalquote is given a function and a list of arguments
- 138  ;; for that function, it computes the value of the function applied to the arguments. + 149  ;; for that function, it computes the value of the function applied to the arguments.
- 139  ;; LISP functions have S-expressions as arguments. In particular, the argument "fn" + 150  ;; LISP functions have S-expressions as arguments. In particular, the argument "fn"
- 140  ;; of the function evalquote must be an S-expression. Since we have been + 151  ;; of the function evalquote must be an S-expression. Since we have been
- 141  ;; writing functions as M-expressions, it is necessary to translate them into + 152  ;; writing functions as M-expressions, it is necessary to translate them into
- 142  ;; S-expressions. -
- - 143   -
- - 144  ;; The following rules define a method of translating functions written in the -
- - 145  ;; meta-language into S-expressions. -
- - 146  ;; 1. If the function is represented by its name, it is translated by changing -
- - 147  ;;    all of the letters to upper case, making it an atomic symbol. Thus is -
- - 148  ;;    translated to CAR. -
- - 149  ;; 2. If the function uses the lambda notation, then the expression -
- - 150  ;;    λ[[x ..;xn]; ε] is translated into (LAMBDA (X1 ...XN) ε*), where ε* is the translation -
- - 151  ;;    of ε. -
- - 152  ;; 3. If the function begins with label, then the translation of -
- - 153  ;;    label[α;ε] is (LABEL α* ε*). + 153  ;; S-expressions.
154  
- 155  ;; Forms are translated as follows: + 155  ;; The following rules define a method of translating functions written in the
- 156  ;; 1. A variable, like a function name, is translated by using uppercase letters. + 156  ;; meta-language into S-expressions.
- 157  ;;    Thus the translation of varl is VAR1. + 157  ;; 1. If the function is represented by its name, it is translated by changing
- 158  ;; 2. The obvious translation of letting a constant translate into itself will not + 158  ;;    all of the letters to upper case, making it an atomic symbol. Thus is
- 159  ;;    work. Since the translation of x is X, the translation of X must be something + 159  ;;    translated to CAR.
- 160  ;;    else to avoid ambiguity. The solution is to quote it. Thus X is translated + 160  ;; 2. If the function uses the lambda notation, then the expression
- 161  ;;    into (QUOTE X). + 161  ;;    λ[[x ..;xn]; ε] is translated into (LAMBDA (X1 ...XN) ε*), where ε* is the translation
- 162  ;; 3. The form fn[argl;. ..;argn] is translated into (fn* argl* ...argn*) + 162  ;;    of ε.
- 163  ;; 4. The conditional expression [pl-el;...;pn-en] is translated into + 163  ;; 3. If the function begins with label, then the translation of
- 164  ;;    (COND (p1* e1*)...(pn* en*)) + 164  ;;    label[α;ε] is (LABEL α* ε*).
165  
- 166  ;; ## Examples + 166  ;; Forms are translated as follows: +
+ + 167  ;; 1. A variable, like a function name, is translated by using uppercase letters. +
+ + 168  ;;    Thus the translation of varl is VAR1. +
+ + 169  ;; 2. The obvious translation of letting a constant translate into itself will not +
+ + 170  ;;    work. Since the translation of x is X, the translation of X must be something +
+ + 171  ;;    else to avoid ambiguity. The solution is to quote it. Thus X is translated +
+ + 172  ;;    into (QUOTE X). +
+ + 173  ;; 3. The form fn[argl;. ..;argn] is translated into (fn* argl* ...argn*) +
+ + 174  ;; 4. The conditional expression [pl-el;...;pn-en] is translated into +
+ + 175  ;;    (COND (p1* e1*)...(pn* en*))
- 167   + 176  
- 168  ;; M-expressions                                S-expressions -
- - 169  ;; x                                            X -
- - 170  ;; car                                          CAR -
- - 171  ;; car[x]                                       (CAR X) -
- - 172  ;; T                                            (QUOTE T) -
- - 173  ;; ff[car [x]]                                  (FF (CAR X)) -
- - 174  ;; [atom[x]->x; T->ff[car[x]]]                  (COND ((ATOM X) X) -
- - 175  ;;                                                ((QUOTE T)(FF (CAR X)))) -
- - 176  ;; label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]] (LABEL FF (LAMBDA (X) (COND -
- - 177  ;;                                                ((ATOM X) X) -
- - 178  ;;                                                ((QUOTE T)(FF (CAR X)))))) + 177  ;; ## Examples
- 179   + 178  
- 180  ;; ]] quote ends + 179  ;; M-expressions                                S-expressions +
+ + 180  ;; x                                            X +
+ + 181  ;; car                                          CAR +
+ + 182  ;; car[x]                                       (CAR X) +
+ + 183  ;; T                                            (QUOTE T) +
+ + 184  ;; ff[car [x]]                                  (FF (CAR X)) +
+ + 185  ;; [atom[x]->x; T->ff[car[x]]]                  (COND ((ATOM X) X) +
+ + 186  ;;                                                ((QUOTE T)(FF (CAR X)))) +
+ + 187  ;; label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]] (LABEL FF (LAMBDA (X) (COND +
+ + 188  ;;                                                ((ATOM X) X) +
+ + 189  ;;                                                ((QUOTE T)(FF (CAR X))))))
- 181   + 190   +
+ + 191  ;; ]] quote ends +
+ + 192  
- 182  (defn gen-cond-clause + 193  (defn gen-cond-clause
- 183    "Generate a cond clause from this simplified parse tree fragment `p`; + 194    "Generate a cond clause from this simplified parse tree fragment `p`;
- 184    returns `nil` if `p` does not represent a cond clause." + 195    returns `nil` if `p` does not represent a cond clause."
- 185    [p] + 196    [p]
- 186    (if + 197    (if
- 187      (and (coll? p)(= :cond-clause (first p))) + 198      (and (coll? p)(= :cond-clause (first p)))
- 188      (make-beowulf-list + 199      (make-beowulf-list
- 189        (list (generate (nth p 1)) + 200        (list (generate (nth p 1))
- 190                       (generate (nth p 2)))))) + 201                       (generate (nth p 2))))))
- 191   + 202  
- 192  (defn gen-cond + 203  (defn gen-cond
- 193    "Generate a cond statement from this simplified parse tree fragment `p`; + 204    "Generate a cond statement from this simplified parse tree fragment `p`;
- 194    returns `nil` if `p` does not represent a (MEXPR) cond statement." + 205    returns `nil` if `p` does not represent a (MEXPR) cond statement."
- 195    [p] + 206    [p]
- 196    (if + 207    (if
- 197      (and (coll? p)(= :cond (first p))) + 208      (and (coll? p)(= :cond (first p)))
- 198      (make-beowulf-list + 209      (make-beowulf-list
- 199        (cons + 210        (cons
- 200          'COND + 211          'COND
- 201          (map + 212          (map
- 202            gen-cond-clause + 213            gen-cond-clause
- 203            (rest p)))))) + 214            (rest p))))))
- 204   + 215  
- 205  (defn gen-fn-call + 216  (defn gen-fn-call
- 206    "Generate a function call from this simplified parse tree fragment `p`; + 217    "Generate a function call from this simplified parse tree fragment `p`;
- 207    returns `nil` if `p` does not represent a (MEXPR) function call. + 218    returns `nil` if `p` does not represent a (MEXPR) function call.
- 208    TODO: I'm not yet certain but it appears that args in mexprs are + 219    TODO: I'm not yet certain but it appears that args in mexprs are
- 209    implicitly quoted; this function does not (yet) do that." + 220    implicitly quoted; this function does not (yet) do that."
- 210    [p] + 221    [p]
- 211    (if + 222    (if
- 212      (and (coll? p)(= :fncall (first p))(= :mvar (first (second p)))) + 223      (and (coll? p)(= :fncall (first p))(= :mvar (first (second p))))
- 213      (make-cons-cell + 224      (make-cons-cell
- 214        (generate (second p)) + 225        (generate (second p))
- 215        (generate (nth p 2))))) + 226        (generate (nth p 2)))))
- 216   + 227  
- 217   + 228  
- 218  (defn gen-dot-terminated-list + 229  (defn gen-dot-terminated-list
- 219    "Generate a list, which may be dot-terminated, from this partial parse tree + 230    "Generate a list, which may be dot-terminated, from this partial parse tree
- 220    'p'. Note that the function acts recursively and progressively decapitates + 231    'p'. Note that the function acts recursively and progressively decapitates
- 221    its argument, so that the argument will not always be a valid parse tree." + 232    its argument, so that the argument will not always be a valid parse tree."
- 222    [p] + 233    [p]
- 223    (cond + 234    (cond
- 224      (empty? p) + 235      (empty? p)
- 225      NIL + 236      NIL
- 226      (and (coll? (first p)) (= :dot-terminal (first (first p)))) + 237      (and (coll? (first p)) (= :dot-terminal (first (first p))))
- 227      (let [dt (first p)] + 238      (let [dt (first p)]
- 228        (make-cons-cell + 239        (make-cons-cell
- 229          (generate (nth dt 1)) + 240          (generate (nth dt 1))
- 230          (generate (nth dt 2)))) + 241          (generate (nth dt 2))))
- 231      :else + 242      :else
- 232      (make-cons-cell + 243      (make-cons-cell
- 233        (generate (first p)) + 244        (generate (first p))
- 234        (gen-dot-terminated-list (rest p))))) + 245        (gen-dot-terminated-list (rest p)))))
- 235   + 246  
- 236   + 247  
- 237  (defn strip-leading-zeros + 248  (defn strip-leading-zeros
- 238    "`read-string` interprets strings with leading zeros as octal; strip + 249    "`read-string` interprets strings with leading zeros as octal; strip
- 239    any from this string `s`. If what's left is empty (i.e. there were + 250    any from this string `s`. If what's left is empty (i.e. there were
- 240    only zeros, return `\"0\"`." + 251    only zeros, return `\"0\"`."
- 241    ([s] + 252    ([s]
- 242     (strip-leading-zeros s "")) + 253     (strip-leading-zeros s ""))
- 243    ([s prefix] + 254    ([s prefix]
- 244     (if + 255     (if
- 245       (empty? s) "0" + 256       (empty? s) "0"
- 246       (case (first s) + 257       (case (first s)
- 247         (\+ \-)(strip-leading-zeros (subs s 1) (str (first s) prefix)) + 258         (\+ \-)(strip-leading-zeros (subs s 1) (str (first s) prefix))
- 248         "0" (strip-leading-zeros (subs s 1) prefix) + 259         "0" (strip-leading-zeros (subs s 1) prefix)
- 249         (str prefix s))))) + 260         (str prefix s)))))
- 250   + 261  
- 251  (defn generate + 262  (defn generate
- 252    "Generate lisp structure from this parse tree `p`. It is assumed that + 263    "Generate lisp structure from this parse tree `p`. It is assumed that
- 253    `p` has been simplified." + 264    `p` has been simplified."
- 254    [p] + 265    [p]
- 255    (if + 266    (if
- 256      (coll? p) + 267      (coll? p)
- 257      (case (first p) + 268      (case (first p)
- 258        :λ "LAMBDA" + 269        :λ "LAMBDA"
- 259        :λexpr (make-cons-cell + 270        :λexpr (make-cons-cell
- 260                 (generate (nth p 1)) + 271                 (generate (nth p 1))
- 261                 (make-cons-cell (generate (nth p 2)) + 272                 (make-cons-cell (generate (nth p 2))
- 262                                 (generate (nth p 3)))) + 273                                 (generate (nth p 3))))
- 263        (:args :list) (gen-dot-terminated-list (rest p)) + 274        (:args :list) (gen-dot-terminated-list (rest p))
- 264        :atom (symbol (second p)) + 275        :atom (symbol (second p))
- 265        :bindings (generate (second p)) + 276        :bindings (generate (second p))
- 266        :body (make-beowulf-list (map generate (rest p))) + 277        :body (make-beowulf-list (map generate (rest p)))
- 267        :cond (gen-cond p) + 278        :cond (gen-cond p)
- 268        (:decimal :integer) (read-string (strip-leading-zeros (second p))) + 279        (:decimal :integer) (read-string (strip-leading-zeros (second p)))
- 269        :dotted-pair (make-cons-cell + 280        :dotted-pair (make-cons-cell
- 270                       (generate (nth p 1)) + 281                       (generate (nth p 1))
- 271                       (generate (nth p 2))) + 282                       (generate (nth p 2)))
- 272        :exponent (generate (second p)) + 283        :exponent (generate (second p))
- 273        :fncall (gen-fn-call p) + 284        :fncall (gen-fn-call p)
- 274        :mvar (symbol (upper-case (second p))) + 285        :mvar (symbol (upper-case (second p)))
- 275        :octal (let [n (read-string (strip-leading-zeros (second p) "0")) + 286        :octal (let [n (read-string (strip-leading-zeros (second p) "0"))
- 276                     scale (generate (nth p 2))] + 287                     scale (generate (nth p 2))]
- 277                 (* n (expt 8 scale))) + 288                 (* n (expt 8 scale)))
- 278   + 289  
- 279        ;; the quote read macro (which probably didn't exist in Lisp 1.5, but...) + 290        ;; the quote read macro (which probably didn't exist in Lisp 1.5, but...)
- 280        :quoted-expr (make-beowulf-list (list 'QUOTE (generate (second p)))) + 291        :quoted-expr (make-beowulf-list (list 'QUOTE (generate (second p))))
- 281        :scale-factor (if + 292        :scale-factor (if
- 282                        (empty? (second p)) 0 + 293                        (empty? (second p)) 0
- 283                        (read-string (strip-leading-zeros (second p)))) + 294                        (read-string (strip-leading-zeros (second p))))
- 284        :scientific (let [n (generate (second p)) + 295        :scientific (let [n (generate (second p))
- 285                          exponent (generate (nth p 2))] + 296                          exponent (generate (nth p 2))]
- 286                      (* n (expt 10 exponent))) -
- - 287   -
- - 288        ;; default -
- - 289        (throw (Exception. (str "Cannot yet generate " (first p))))) -
- - 290      p)) -
- - 291   -
- - 292  (defmacro gsp -
- - 293    "Shortcut macro - the internals of read; or, if you like, read-string. -
- - 294    Argument `s` should be a string representation of a valid Lisp -
- - 295    expression." -
- - 296    [s] -
- - 297    `(generate (simplify (parse ~s)))) + 297                      (* n (expt 10 exponent)))
298  
- - 299  (defn READ + + 299        ;; default +
+ + 300        (throw (Exception. (str "Cannot yet generate " (first p))))) +
+ + 301      p)) +
+ + 302   +
+ + 303  (defmacro gsp
- 300    [input] + 304    "Shortcut macro - the internals of read; or, if you like, read-string. +
+ + 305    Argument `s` should be a string representation of a valid Lisp +
+ + 306    expression." +
+ + 307    [s] +
+ + 308    `(generate (simplify (parse ~s)))) +
+ + 309   +
+ + 310  (defn READ +
+ + 311    [input]
- 301    (gsp (or input (read-line)))) + 312    (gsp (or input (read-line))))
diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html index 2afcfff..5610f2b 100644 --- a/docs/cloverage/index.html +++ b/docs/cloverage/index.html @@ -29,7 +29,7 @@ style="width:18.181818181818183%; float:left;"> 32 81.82 % -32939176 +33840176 beowulf.cons-cell
98
56.83 %
36
39
3
26
-60.00 % -1491565 +61.76 % +1561568 beowulf.core
5
89.80 % -77349 +80349 beowulf.host
1
100.00 % -911 +511 beowulf.read
23
81.75 % -30128126 +31230126 Totals: 72.95 % -79.38 % +79.52 % diff --git a/docs/codox/beowulf.bootstrap.html b/docs/codox/beowulf.bootstrap.html index 1ae62c3..cebac49 100644 --- a/docs/codox/beowulf.bootstrap.html +++ b/docs/codox/beowulf.bootstrap.html @@ -1,11 +1,12 @@ -beowulf.bootstrap documentation

beowulf.bootstrap

TODO: write docs

*options*

dynamic

Command line options from invocation.

APPEND

(APPEND x y)

Append the the elements of y to the elements of x.

-

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 11 of the Lisp 1.5 Programmers Manual.

APPLY

(APPLY function args environment)

For bootstrapping, at least, a version of APPLY written in Clojure. All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 13 of the Lisp 1.5 Programmers Manual.

ASSOC

(ASSOC x a)

If a is an association list such as the one formed by PAIRLIS in the above example, then assoc will produce the first pair whose first term is x. Thus it is a table searching function.

-

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

ATOM

(ATOM x)

It is not clear to me from the documentation whether (ATOM 7) should return 'T or 'F. I’m going to assume 'T.

ATOM?

(ATOM? x)

The convention of returning 'F from predicates, rather than NIL, is going to tie me in knots. This is a variant of ATOM which returns NIL on failure.

CAAAAR

(CAAAAR x)

TODO: write docs

CAAADR

(CAAADR x)

TODO: write docs

CAAAR

(CAAAR x)

TODO: write docs

CAADAR

(CAADAR x)

TODO: write docs

CAADDR

(CAADDR x)

TODO: write docs

CAADR

(CAADR x)

TODO: write docs

CAAR

(CAAR x)

TODO: write docs

CADAAR

(CADAAR x)

TODO: write docs

CADADR

(CADADR x)

TODO: write docs

CADAR

(CADAR x)

TODO: write docs

CADDAR

(CADDAR x)

TODO: write docs

CADDDR

(CADDDR x)

TODO: write docs

CADDR

(CADDR x)

TODO: write docs

CADR

(CADR x)

TODO: write docs

CAR

(CAR x)

Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL.

CDAAAR

(CDAAAR x)

TODO: write docs

CDAADR

(CDAADR x)

TODO: write docs

CDAAR

(CDAAR x)

TODO: write docs

CDADAR

(CDADAR x)

TODO: write docs

CDADDR

(CDADDR x)

TODO: write docs

CDADR

(CDADR x)

TODO: write docs

CDAR

(CDAR x)

TODO: write docs

CDDAAR

(CDDAAR x)

TODO: write docs

CDDADR

(CDDADR x)

TODO: write docs

CDDAR

(CDDAR x)

TODO: write docs

CDDDAR

(CDDDAR x)

TODO: write docs

CDDDDR

(CDDDDR x)

TODO: write docs

CDDDR

(CDDDR x)

TODO: write docs

CDDR

(CDDR x)

TODO: write docs

CDR

(CDR x)

Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL.

EQ

(EQ x y)

TODO: write docs

EQUAL

(EQUAL x y)

This is a predicate that is true if its two arguments are identical S-expressions, and false if they are different. (The elementary predicate EQ is defined only for atomic arguments.) The definition of EQUAL is an example of a conditional expression inside a conditional expression.

-

NOTE: returns F on failure, not NIL

EVAL

(EVAL expr env)

For bootstrapping, at least, a version of EVAL written in Clojure. All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 13 of the Lisp 1.5 Programmers Manual.

MEMBER

(MEMBER x y)

This predicate is true if the S-expression x occurs among the elements of the list y.

-

All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 11 of the Lisp 1.5 Programmers Manual.

NULL

(NULL x)

TODO: write docs

oblist

The default environment; modified certainly be LABEL (which seems to be Lisp 1.5’s EQuivalent of SETQ), possibly by other things.

PAIRLIS

(PAIRLIS x y a)

This function gives the list of pairs of corresponding elements of the lists x and y, and APPENDs this to the list a. The resultant list of pairs, which is like a table with two columns, is called an association list.

+beowulf.bootstrap documentation

beowulf.bootstrap

Lisp as defined in Chapter 1 (pages 1-14) of the Lisp 1.5 Programmer's Manual; that is to say, a very simple Lisp language, which should, I believe, be sufficient in conjunction with the functions provided by beowulf.host, be sufficient to bootstrap the full Lisp 1.5 interpreter..

+

The convention is adopted that functions in this file with names in ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that therefore all arguments must be numbers, symbols or beowulf.cons_cell.ConsCell objects.

*options*

dynamic

Command line options from invocation.

APPEND

(APPEND x y)

Append the the elements of y to the elements of x.

+

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 11 of the Lisp 1.5 Programmers Manual.

APPLY

(APPLY function args environment)

For bootstrapping, at least, a version of APPLY written in Clojure. All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 13 of the Lisp 1.5 Programmers Manual.

ASSOC

(ASSOC x a)

If a is an association list such as the one formed by PAIRLIS in the above example, then assoc will produce the first pair whose first term is x. Thus it is a table searching function.

+

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

ATOM

macro

(ATOM x)

Returns T if and only is the argument x is bound to and atom; else F. It is not clear to me from the documentation whether (ATOM 7) should return T or F. I’m going to assume T.

ATOM?

macro

(ATOM? x)

The convention of returning F from predicates, rather than NIL, is going to tie me in knots. This is a variant of ATOM which returns NIL on failure.

CAAAAR

(CAAAAR x)

TODO: write docs

CAAADR

(CAAADR x)

TODO: write docs

CAAAR

(CAAAR x)

TODO: write docs

CAADAR

(CAADAR x)

TODO: write docs

CAADDR

(CAADDR x)

TODO: write docs

CAADR

(CAADR x)

TODO: write docs

CAAR

(CAAR x)

TODO: write docs

CADAAR

(CADAAR x)

TODO: write docs

CADADR

(CADADR x)

TODO: write docs

CADAR

(CADAR x)

TODO: write docs

CADDAR

(CADDAR x)

TODO: write docs

CADDDR

(CADDDR x)

TODO: write docs

CADDR

(CADDR x)

TODO: write docs

CADR

(CADR x)

TODO: write docs

CAR

(CAR x)

Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL.

CDAAAR

(CDAAAR x)

TODO: write docs

CDAADR

(CDAADR x)

TODO: write docs

CDAAR

(CDAAR x)

TODO: write docs

CDADAR

(CDADAR x)

TODO: write docs

CDADDR

(CDADDR x)

TODO: write docs

CDADR

(CDADR x)

TODO: write docs

CDAR

(CDAR x)

TODO: write docs

CDDAAR

(CDDAAR x)

TODO: write docs

CDDADR

(CDDADR x)

TODO: write docs

CDDAR

(CDDAR x)

TODO: write docs

CDDDAR

(CDDDAR x)

TODO: write docs

CDDDDR

(CDDDDR x)

TODO: write docs

CDDDR

(CDDDR x)

TODO: write docs

CDDR

(CDDR x)

TODO: write docs

CDR

(CDR x)

Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL.

EQ

(EQ x y)

Returns T if and only if both x and y are bound to the same atom, else F.

EQUAL

(EQUAL x y)

This is a predicate that is true if its two arguments are identical S-expressions, and false if they are different. (The elementary predicate EQ is defined only for atomic arguments.) The definition of EQUAL is an example of a conditional expression inside a conditional expression.

+

NOTE: returns F on failure, not NIL

EVAL

(EVAL expr env)

For bootstrapping, at least, a version of EVAL written in Clojure. All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 13 of the Lisp 1.5 Programmers Manual.

MEMBER

(MEMBER x y)

This predicate is true if the S-expression x occurs among the elements of the list y.

+

All args are assumed to be symbols or beowulf.cons-cell/ConsCell objects. See page 11 of the Lisp 1.5 Programmers Manual.

NULL

macro

(NULL x)

Returns T if and only if the argument x is bound to NIL; else F.

oblist

The default environment.

PAIRLIS

(PAIRLIS x y a)

This function gives the list of pairs of corresponding elements of the lists x and y, and APPENDs this to the list a. The resultant list of pairs, which is like a table with two columns, is called an association list.

Eessentially, it builds the environment on the stack, implementing shallow binding.

-

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

SUBLIS

(SUBLIS a y)

Here a is assumed to be an association list of the form ((ul . vl)...(un . vn)), where the us are atomic, and y is any S-expression. What SUBLIS does, is to treat the us as variables when they occur in y, and to SUBSTitute the corresponding vs from the pair list.

+

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

SUBLIS

(SUBLIS a y)

Here a is assumed to be an association list of the form ((ul . vl)...(un . vn)), where the us are atomic, and y is any S-expression. What SUBLIS does, is to treat the us as variables when they occur in y, and to SUBSTitute the corresponding vs from the pair list.

My interpretation is that this is variable binding in the stack frame.

-

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

SUBST

(SUBST x y z)

This function gives the result of substituting the S-expression x for all occurrences of the atomic symbol y in the S-expression z.

traced-eval

(traced-eval & args__2883__auto__)

Essentially, identical to EVAL except traced.

uaf

(uaf l path)

Universal access function; l is expected to be an arbitrary list, path a (clojure) list of the characters a and d. Intended to make declaring all those fiddly #'c[ad]+r' functions a bit easier

\ No newline at end of file +

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

SUBST

(SUBST x y z)

This function gives the result of substituting the S-expression x for all occurrences of the atomic symbol y in the S-expression z.

traced-eval

(traced-eval & args__2885__auto__)

Essentially, identical to EVAL except traced.

uaf

(uaf l path)

Universal access function; l is expected to be an arbitrary list, path a (clojure) list of the characters a and d. Intended to make declaring all those fiddly #'c[ad]+r' functions a bit easier

\ No newline at end of file diff --git a/docs/codox/beowulf.cons-cell.html b/docs/codox/beowulf.cons-cell.html index a87a569..6aa8914 100644 --- a/docs/codox/beowulf.cons-cell.html +++ b/docs/codox/beowulf.cons-cell.html @@ -1,3 +1,3 @@ -beowulf.cons-cell documentation

beowulf.cons-cell

TODO: write docs

F

TODO: write docs

make-beowulf-list

(make-beowulf-list x)

TODO: write docs

make-cons-cell

(make-cons-cell a d)

TODO: write docs

NIL

TODO: write docs

pretty-print

(pretty-print cell)(pretty-print cell width level)

This isn’t the world’s best pretty printer but it sort of works.

T

TODO: write docs

\ No newline at end of file +beowulf.cons-cell documentation

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.

F

The canonical false value - different from NIL, which is not canonically false in Lisp 1.5.

make-beowulf-list

(make-beowulf-list x)

Construct a linked list of cons cells with the same content as the sequence x.

make-cons-cell

macro

(make-cons-cell car cdr)

Construct a new instance of cons cell with this car and cdr.

NIL

The canonical empty list symbol.

pretty-print

(pretty-print cell)(pretty-print cell width level)

This isn’t the world’s best pretty printer but it sort of works.

T

The canonical true value.

\ No newline at end of file diff --git a/docs/codox/beowulf.core.html b/docs/codox/beowulf.core.html index 1f30171..a25496a 100644 --- a/docs/codox/beowulf.core.html +++ b/docs/codox/beowulf.core.html @@ -1,3 +1,3 @@ -beowulf.core documentation

beowulf.core

TODO: write docs

-main

(-main & opts)

TODO: write docs

cli-options

TODO: write docs

repl

(repl prompt)

Read/eval/print loop.

\ No newline at end of file +beowulf.core documentation

beowulf.core

Essentially, the -main function and the bootstrap read-eval-print loop.

-main

(-main & opts)

Parse options, print the banner, read the init file if any, and enter the read/eval/print loop.

cli-options

TODO: write docs

repl

(repl prompt)

Read/eval/print loop.

\ No newline at end of file diff --git a/docs/codox/beowulf.host.html b/docs/codox/beowulf.host.html index a8c02cc..119b9f4 100644 --- a/docs/codox/beowulf.host.html +++ b/docs/codox/beowulf.host.html @@ -1,3 +1,3 @@ -beowulf.host documentation

beowulf.host

TODO: write docs

\ No newline at end of file +beowulf.host documentation

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.

\ No newline at end of file diff --git a/docs/codox/beowulf.read.html b/docs/codox/beowulf.read.html index 6d6d131..d405be7 100644 --- a/docs/codox/beowulf.read.html +++ b/docs/codox/beowulf.read.html @@ -1,3 +1,9 @@ -beowulf.read documentation

beowulf.read

TODO: write docs

gen-cond

(gen-cond p)

Generate a cond statement from this simplified parse tree fragment p; returns nil if p does not represent a (MEXPR) cond statement.

gen-cond-clause

(gen-cond-clause p)

Generate a cond clause from this simplified parse tree fragment p; returns nil if p does not represent a cond clause.

gen-dot-terminated-list

(gen-dot-terminated-list p)

Generate a list, which may be dot-terminated, from this partial parse tree ‘p’. Note that the function acts recursively and progressively decapitates its argument, so that the argument will not always be a valid parse tree.

gen-fn-call

(gen-fn-call p)

Generate a function call from this simplified parse tree fragment p; returns nil if p does not represent a (MEXPR) function call. TODO: I’m not yet certain but it appears that args in mexprs are implicitly quoted; this function does not (yet) do that.

generate

(generate p)

Generate lisp structure from this parse tree p. It is assumed that p has been simplified.

gsp

macro

(gsp s)

Shortcut macro - the internals of read; or, if you like, read-string. Argument s should be a string representation of a valid Lisp expression.

parse

Parse a string presented as argument into a parse tree which can then be operated upon further.

READ

(READ input)

TODO: write docs

simplify

(simplify p)(simplify p context)

Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key.

strip-leading-zeros

(strip-leading-zeros s)(strip-leading-zeros s prefix)

read-string interprets strings with leading zeros as octal; strip any from this string s. If what’s left is empty (i.e. there were only zeros, return "0".

\ No newline at end of file +beowulf.read documentation

beowulf.read

This provides the reader required for boostrapping. It’s not a bad reader - it provides feedback on errors found in the input - but it isn’t the real Lisp reader.

+

Intended deviations from the behaviour of the real Lisp reader are as follows:

+
    +
  1. It reads the meta-expression language MEXPR in addition to the symbolic expression language SEXPR, which I do not believe the Lisp 1.5 reader ever did;
  2. +
  3. It treats everything between a semi-colon and an end of line as a comment, as most modern Lisps do; but I do not believe Lisp 1.5 had this feature.
  4. +
+

Both these extensions can be disabled by using the --strict command line switch.

gen-cond

(gen-cond p)

Generate a cond statement from this simplified parse tree fragment p; returns nil if p does not represent a (MEXPR) cond statement.

gen-cond-clause

(gen-cond-clause p)

Generate a cond clause from this simplified parse tree fragment p; returns nil if p does not represent a cond clause.

gen-dot-terminated-list

(gen-dot-terminated-list p)

Generate a list, which may be dot-terminated, from this partial parse tree ‘p’. Note that the function acts recursively and progressively decapitates its argument, so that the argument will not always be a valid parse tree.

gen-fn-call

(gen-fn-call p)

Generate a function call from this simplified parse tree fragment p; returns nil if p does not represent a (MEXPR) function call.

generate

(generate p)

Generate lisp structure from this parse tree p. It is assumed that p has been simplified.

gsp

macro

(gsp s)

Shortcut macro - the internals of read; or, if you like, read-string. Argument s should be a string representation of a valid Lisp expression.

parse

Parse a string presented as argument into a parse tree which can then be operated upon further.

READ

(READ input)

An implementation of a Lisp reader sufficient for bootstrapping; not necessarily the final Lisp reader.

simplify

(simplify p)(simplify p context)

Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key.

strip-leading-zeros

(strip-leading-zeros s)(strip-leading-zeros s prefix)

read-string interprets strings with leading zeros as octal; strip any from this string s. If what’s left is empty (i.e. there were only zeros, return "0".

\ No newline at end of file diff --git a/docs/codox/index.html b/docs/codox/index.html index c25387a..f3d9637 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -Beowulf 0.2.0-SNAPSHOT

Beowulf 0.2.0-SNAPSHOT

Released under the GPL-2.0-or-later

An implementation of LISP 1.5 in Clojure.

Installation

To install, add the following dependency to your project or build file:

[beowulf "0.2.0-SNAPSHOT"]

Topics

Namespaces

beowulf.cons-cell

TODO: write docs

Public variables and functions:

beowulf.core

TODO: write docs

Public variables and functions:

beowulf.host

TODO: write docs

Public variables and functions:

    \ No newline at end of file +Beowulf 0.2.0-SNAPSHOT

    Beowulf 0.2.0-SNAPSHOT

    Released under the GPL-2.0-or-later

    An implementation of LISP 1.5 in Clojure.

    Installation

    To install, add the following dependency to your project or build file:

    [beowulf "0.2.0-SNAPSHOT"]

    Topics

    Namespaces

    beowulf.bootstrap

    Lisp as defined in Chapter 1 (pages 1-14) of the Lisp 1.5 Programmer's Manual; that is to say, a very simple Lisp language, which should, I believe, be sufficient in conjunction with the functions provided by beowulf.host, be sufficient to bootstrap the full Lisp 1.5 interpreter..

    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.

    Public variables and functions:

    beowulf.core

    Essentially, the -main function and the bootstrap read-eval-print loop.

    Public variables and functions:

    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.

    Public variables and functions:

      beowulf.read

      This provides the reader required for boostrapping. It’s not a bad reader - it provides feedback on errors found in the input - but it isn’t the real Lisp reader.

      \ No newline at end of file diff --git a/src/beowulf/bootstrap.clj b/src/beowulf/bootstrap.clj index 50de2c4..4e72869 100644 --- a/src/beowulf/bootstrap.clj +++ b/src/beowulf/bootstrap.clj @@ -1,6 +1,14 @@ (ns beowulf.bootstrap "Lisp as defined in Chapter 1 (pages 1-14) of the - `Lisp 1.5 Programmer's Manual`; that is to say, a very simple Lisp language," + `Lisp 1.5 Programmer's Manual`; that is to say, a very simple Lisp language, + which should, I believe, be sufficient in conjunction with the functions + provided by `beowulf.host`, be sufficient to bootstrap the full Lisp 1.5 + interpreter.. + + The convention is adopted that functions in this file with names in + ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that + therefore all arguments must be numbers, symbols or `beowulf.cons_cell.ConsCell` + objects." (:require [clojure.tools.trace :refer :all] [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]])) @@ -17,8 +25,7 @@ (declare EVAL) (def oblist - "The default environment; modified certainly be `LABEL` (which seems to - be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things." + "The default environment." (atom NIL)) (def ^:dynamic *options* @@ -26,11 +33,13 @@ {}) (defmacro NULL + "Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`." [x] `(if (= ~x NIL) T F)) (defmacro ATOM - "It is not clear to me from the documentation whether `(ATOM 7)` should return + "Returns `T` if and only is the argument `x` is bound to and atom; else `F`. + It is not clear to me from the documentation whether `(ATOM 7)` should return `T` or `F`. I'm going to assume `T`." [x] `(if (or (symbol? ~x) (number? ~x)) T F)) @@ -110,8 +119,8 @@ (defn CDADDR [x] (uaf x (seq "dadd"))) (defn EQ - ;; For some reason providing a doc string for this function breaks the - ;; Clojure parser! + "Returns `T` if and only if both `x` and `y` are bound to the same atom, + else `F`." [x y] (if (and (= (ATOM x) T) (= x y)) T F)) @@ -121,7 +130,7 @@ `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is an example of a conditional expression inside a conditional expression. - NOTE: returns F on failure, not NIL" + NOTE: returns `F` on failure, not `NIL`" [x y] (cond (= (ATOM x) T) (EQ x y) diff --git a/src/beowulf/cons_cell.clj b/src/beowulf/cons_cell.clj index 7800186..3fd104b 100644 --- a/src/beowulf/cons_cell.clj +++ b/src/beowulf/cons_cell.clj @@ -3,11 +3,18 @@ Lisp 1.5 lists do not necessarily have a sequence as their CDR, so cannot be implemented on top of Clojure lists.") -(def NIL (symbol "NIL")) +(def NIL + "The canonical empty list symbol." + (symbol "NIL")) -(def T (symbol "T")) ;; true. +(def T + "The canonical true value." + (symbol "T")) ;; true. -(def F (symbol "F")) ;; false as distinct from nil +(def F + "The canonical false value - different from `NIL`, which is not canonically + false in Lisp 1.5." + (symbol "F")) ;; false as distinct from nil (deftype ConsCell [CAR CDR] clojure.lang.ISeq diff --git a/src/beowulf/core.clj b/src/beowulf/core.clj index 6835742..6ea2757 100644 --- a/src/beowulf/core.clj +++ b/src/beowulf/core.clj @@ -1,4 +1,5 @@ (ns beowulf.core + "Essentially, the `-main` function and the bootstrap read-eval-print loop." (:require [beowulf.bootstrap :refer [EVAL oblist *options*]] [beowulf.read :refer [READ]] [clojure.java.io :as io] @@ -47,6 +48,8 @@ (recur))) (defn -main + "Parse options, print the banner, read the init file if any, and enter the + read/eval/print loop." [& opts] (let [args (parse-opts opts cli-options)] (println diff --git a/src/beowulf/host.clj b/src/beowulf/host.clj index 57d797d..fcd71fd 100644 --- a/src/beowulf/host.clj +++ b/src/beowulf/host.clj @@ -1,9 +1,5 @@ -(ns beowulf.host) +(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.") -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; This file 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. -;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/beowulf/read.clj b/src/beowulf/read.clj index 66d22da..6ede7e8 100644 --- a/src/beowulf/read.clj +++ b/src/beowulf/read.clj @@ -1,4 +1,18 @@ (ns beowulf.read + "This provides the reader required for boostrapping. It's not a bad + reader - it provides feedback on errors found in the input - but it isn't + the real Lisp reader. + + Intended deviations from the behaviour of the real Lisp reader are as follows: + + 1. It reads the meta-expression language `MEXPR` in addition to the + symbolic expression language `SEXPR`, which I do not believe the Lisp 1.5 + reader ever did; + 2. It treats everything between a semi-colon and an end of line as a comment, + as most modern Lisps do; but I do not believe Lisp 1.5 had this feature. + + Both these extensions can be disabled by using the `--strict` command line + switch." (:require [beowulf.bootstrap :refer [*options*]] [clojure.math.numeric-tower :refer [expt]] [clojure.string :refer [starts-with? upper-case]] @@ -204,9 +218,7 @@ (defn gen-fn-call "Generate a function call from this simplified parse tree fragment `p`; - returns `nil` if `p` does not represent a (MEXPR) function call. - TODO: I'm not yet certain but it appears that args in mexprs are - implicitly quoted; this function does not (yet) do that." + returns `nil` if `p` does not represent a (MEXPR) function call." [p] (if (and (coll? p)(= :fncall (first p))(= :mvar (first (second p)))) @@ -297,5 +309,7 @@ `(generate (simplify (parse ~s)))) (defn READ + "An implementation of a Lisp reader sufficient for bootstrapping; not necessarily + the final Lisp reader." [input] (gsp (or input (read-line))))