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))))