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

+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.

diff --git a/docs/codox/beowulf.cons-cell.html b/docs/codox/beowulf.cons-cell.html index 6aa8914..5db7b53 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

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 +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 a25496a..f5e11fe 100644 --- a/docs/codox/beowulf.core.html +++ b/docs/codox/beowulf.core.html @@ -1,3 +1,3 @@ -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 +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 119b9f4..946857b 100644 --- a/docs/codox/beowulf.host.html +++ b/docs/codox/beowulf.host.html @@ -1,3 +1,3 @@ -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 +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 d405be7..3deec4d 100644 --- a/docs/codox/beowulf.read.html +++ b/docs/codox/beowulf.read.html @@ -1,6 +1,6 @@ -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.

+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. diff --git a/docs/codox/index.html b/docs/codox/index.html index f3d9637..7dfb2d3 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.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 +Beowulf 0.2.0

      Beowulf 0.2.0

      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"]

      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/docs/codox/intro.html b/docs/codox/intro.html index 441a126..17bdf0c 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,4 +1,4 @@ -Introduction to beowulf

        Introduction to beowulf

        +Introduction to beowulf

        Introduction to beowulf

        TODO: write great documentation

        \ No newline at end of file diff --git a/project.clj b/project.clj index 1aeafa8..1e3cecb 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject beowulf "0.2.0" +(defproject beowulf "0.2.1-SNAPSHOT" :cloverage {:output "docs/cloverage"} :codox {:metadata {:doc "**TODO**: write docs" :doc/format :markdown}