Huge amount of work, not much real progress.

This commit is contained in:
Simon Brooke 2023-03-24 22:18:18 +00:00
parent 75da14790c
commit c0a362f213
No known key found for this signature in database
GPG key ID: A7A4F18D1D4DF987
12 changed files with 266 additions and 182 deletions

3
.gitignore vendored
View file

@ -12,3 +12,6 @@ pom.xml.asc
.hg/ .hg/
.idea/ .idea/
*~ *~
.calva/
.clj-kondo/
.lsp/

25
beowulf.iml Normal file
View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<module cursive.leiningen.project.LeiningenProjectsManager.displayName="beowulf:0.2.1-SNAPSHOT" cursive.leiningen.project.LeiningenProjectsManager.isLeinModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5">
<output url="file://$MODULE_DIR$/target/default/classes" />
<output-test url="file://$MODULE_DIR$/target/default/classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/dev-resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
<excludeFolder url="file://$MODULE_DIR$/target/default" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Leiningen: clojure-complete:0.2.5" level="project" />
<orderEntry type="library" name="Leiningen: environ:1.1.0" level="project" />
<orderEntry type="library" name="Leiningen: instaparse:1.4.10" level="project" />
<orderEntry type="library" name="Leiningen: nrepl:0.6.0" level="project" />
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.8.0" level="project" />
<orderEntry type="library" name="Leiningen: org.clojure/math.numeric-tower:0.0.4" level="project" />
<orderEntry type="library" name="Leiningen: org.clojure/tools.cli:0.4.2" level="project" />
<orderEntry type="library" name="Leiningen: org.clojure/tools.trace:0.7.10" level="project" />
</component>
</module>

View file

@ -0,0 +1,22 @@
;; see page 70 of Lisp 1.5 Programmers Manual; this expands somewhat
;; on the accounts of eval and apply given on page 13. This is M-expr
;; syntax, obviously.
;; apply
;; NOTE THAT I suspect there is a typo in the printed manual in line
;; 7 of this definition, namely a missing closing square bracket before
;; the final semi-colon; that has been corrected here.
apply[fn;args;a] = [
null[fn] -> NIL;
atom[fn] -> [get[fn;EXPR] -> apply[expr; args; a];
get[fn;SUBR] -> {spread[args];
$ALIST := a;
TSX subr4, 4};
T -> apply[cdr[sassoc[fn; a; λ[[]; error[A2]]]]; args a]];
eq[car[fn]; LABEL] -> apply[caddr[fn]; args;
cons[cons[cadr[fn];caddr[fn]]; a]];
eq[car[fn]; FUNARG] -> apply[cadr[fn]; args; caddr[fn]];
eq[car[fn]; LAMBDA] -> eval[caddr[fn]; nconc[pair[cadr[fn]; args]; a]];
T -> apply[eval[fn;a]; args; a]]

View file

@ -0,0 +1,3 @@
;; from page 5
[eq[car[x];A]->cons[B;cdr[x]];T->x]

View file

View file

@ -88,36 +88,36 @@
\a (uaf (.first l) (butlast path)) \a (uaf (.first l) (butlast path))
\d (uaf (.getCdr l) (butlast path))))) \d (uaf (.getCdr l) (butlast path)))))
(defn CAAR [x] (uaf x (seq "aa"))) (defmacro CAAR [x] `(uaf ~x '(\a \a)))
(defn CADR [x] (uaf x (seq "ad"))) (defmacro CADR [x] `(uaf ~x '(\a \d)))
(defn CDDR [x] (uaf x (seq "dd"))) (defmacro CDDR [x] `(uaf ~x '(\d \d)))
(defn CDAR [x] (uaf x (seq "da"))) (defmacro CDAR [x] `(uaf ~x '(\d \a)))
(defn CAAAR [x] (uaf x (seq "aaa"))) (defmacro CAAAR [x] `(uaf ~x '(\a \a \a)))
(defn CAADR [x] (uaf x (seq "aad"))) (defmacro CAADR [x] `(uaf ~x '(\a \a \d)))
(defn CADAR [x] (uaf x (seq "ada"))) (defmacro CADAR [x] `(uaf ~x '(\a \d \a)))
(defn CADDR [x] (uaf x (seq "add"))) (defmacro CADDR [x] `(uaf ~x '(\a \d \d)))
(defn CDDAR [x] (uaf x (seq "dda"))) (defmacro CDDAR [x] `(uaf ~x '(\d \d \a)))
(defn CDDDR [x] (uaf x (seq "ddd"))) (defmacro CDDDR [x] `(uaf ~x '(\d \d \d)))
(defn CDAAR [x] (uaf x (seq "daa"))) (defmacro CDAAR [x] `(uaf ~x '(\d \a \a)))
(defn CDADR [x] (uaf x (seq "dad"))) (defmacro CDADR [x] `(uaf ~x '(\d \a \d)))
(defn CAAAAR [x] (uaf x (seq "aaaa"))) (defmacro CAAAAR [x] `(uaf ~x '(\a \a \a \a)))
(defn CAADAR [x] (uaf x (seq "aada"))) (defmacro CAADAR [x] `(uaf ~x '(\a \a \d \a)))
(defn CADAAR [x] (uaf x (seq "adaa"))) (defmacro CADAAR [x] `(uaf ~x '(\a \d \a \a)))
(defn CADDAR [x] (uaf x (seq "adda"))) (defmacro CADDAR [x] `(uaf ~x '(\a \d \d \a)))
(defn CDDAAR [x] (uaf x (seq "ddaa"))) (defmacro CDDAAR [x] `(uaf ~x '(\d \d \a \a)))
(defn CDDDAR [x] (uaf x (seq "ddda"))) (defmacro CDDDAR [x] `(uaf ~x '(\d \d \d \a)))
(defn CDAAAR [x] (uaf x (seq "daaa"))) (defmacro CDAAAR [x] `(uaf ~x '(\d \a \a \a)))
(defn CDADAR [x] (uaf x (seq "dada"))) (defmacro CDADAR [x] `(uaf ~x '(\d \a \d \a)))
(defn CAAADR [x] (uaf x (seq "aaad"))) (defmacro CAAADR [x] `(uaf ~x '(\a \a \a \d)))
(defn CAADDR [x] (uaf x (seq "aadd"))) (defmacro CAADDR [x] `(uaf ~x '(\a \a \d \d)))
(defn CADADR [x] (uaf x (seq "adad"))) (defmacro CADADR [x] `(uaf ~x '(\a \d \a \d)))
(defn CADDDR [x] (uaf x (seq "addd"))) (defmacro CADDDR [x] `(uaf ~x '(\a \d \d \d)))
(defn CDDADR [x] (uaf x (seq "ddad"))) (defmacro CDDADR [x] `(uaf ~x '(\d \d \a \d)))
(defn CDDDDR [x] (uaf x (seq "dddd"))) (defmacro CDDDDR [x] `(uaf ~x '(\d \d \d \d)))
(defn CDAADR [x] (uaf x (seq "daad"))) (defmacro CDAADR [x] `(uaf ~x '(\d \a \a \d)))
(defn CDADDR [x] (uaf x (seq "dadd"))) (defmacro CDADDR [x] `(uaf ~x '(\d \a \d \d)))
(defn EQ (defn EQ
"Returns `T` if and only if both `x` and `y` are bound to the same atom, "Returns `T` if and only if both `x` and `y` are bound to the same atom,
@ -318,8 +318,6 @@
(= (=
(ATOM? function) (ATOM? function)
T)(cond T)(cond
;; TODO: doesn't check whether `function` is bound in the environment;
;; we'll need that before we can bootstrap.
(= function 'CAR) (CAAR args) (= function 'CAR) (CAAR args)
(= function 'CDR) (CDAR args) (= function 'CDR) (CDAR args)
(= function 'CONS) (make-cons-cell (CAR args) (CADR args)) (= function 'CONS) (make-cons-cell (CAR args) (CADR args))

View file

@ -195,15 +195,20 @@
[this writer] [this writer]
(.write writer (to-string this))) (.write writer (to-string this)))
(defmacro make-cons-cell (defn make-cons-cell
"Construct a new instance of cons cell with this `car` and `cdr`." "Construct a new instance of cons cell with this `car` and `cdr`."
[car cdr] [car cdr]
`(ConsCell. ~car ~cdr)) (try
(ConsCell. car cdr)
(catch Exception any
(throw (ex-info "Cound not construct cons cell" {:car car
:cdr cdr} any)))))
(defn make-beowulf-list (defn make-beowulf-list
"Construct a linked list of cons cells with the same content as the "Construct a linked list of cons cells with the same content as the
sequence `x`." sequence `x`."
[x] [x]
(try
(cond (cond
(empty? x) NIL (empty? x) NIL
(coll? x) (ConsCell. (coll? x) (ConsCell.
@ -213,4 +218,8 @@
(first x)) (first x))
(make-beowulf-list (rest x))) (make-beowulf-list (rest x)))
:else :else
NIL)) NIL)
(catch Exception any
(throw (ex-info "Could not construct Beowulf list"
{:content x}
any)))))

View file

@ -55,13 +55,13 @@
(println (println
(str (str
"\nHider wilcuman. Béowulf is mín nama.\n" "\nHider wilcuman. Béowulf is mín nama.\n"
(if (when
(System/getProperty "beowulf.version") (System/getProperty "beowulf.version")
(str "Síðe " (System/getProperty "beowulf.version") "\n")) (str "Síðe " (System/getProperty "beowulf.version") "\n"))
(if (when
(:help (:options args)) (:help (:options args))
(:summary args)) (:summary args))
(if (:errors args) (when (:errors args)
(apply str (interpose "; " (:errors args)))) (apply str (interpose "; " (:errors args))))
"\nSprecan 'quit' tó laéfan\n")) "\nSprecan 'quit' tó laéfan\n"))
(binding [*options* (:options args)] (binding [*options* (:options args)]

View file

@ -15,7 +15,8 @@
switch." switch."
(:require [beowulf.bootstrap :refer [*options*]] (:require [beowulf.bootstrap :refer [*options*]]
[clojure.math.numeric-tower :refer [expt]] [clojure.math.numeric-tower :refer [expt]]
[clojure.string :refer [starts-with? upper-case]] [clojure.pprint :refer [pprint]]
[clojure.string :refer [join split starts-with? upper-case]]
[instaparse.core :as i] [instaparse.core :as i]
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]])) [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
@ -35,10 +36,20 @@
(i/parser (i/parser
(str (str
;; top level: we accept mexprs as well as sexprs. ;; top level: we accept mexprs as well as sexprs.
"expr := mexpr | sexpr;" "expr := mexpr | sexpr | opt-space expr opt-space;"
;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
"comment := opt-space <';;'> opt-space #'[^\\n\\r]*';"
;; there's a notation comprising a left brace followed by mexprs
;; followed by a right brace which doesn't seem to be documented
;; but I think must represent a prog(?)
;; "prog := lbrace exprs rbrace;"
;; mexprs. I'm pretty clear that Lisp 1.5 could never read these, ;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
;; but it's a convenience. ;; but it's a convenience.
"exprs := expr | exprs;"
"mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment; "mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
λexpr := λ lsqb bindings semi-colon body rsqb; λexpr := λ lsqb bindings semi-colon body rsqb;
λ := '; λ := ';
@ -47,6 +58,8 @@
fncall := fn-name lsqb args rsqb; fncall := fn-name lsqb args rsqb;
lsqb := '['; lsqb := '[';
rsqb := ']'; rsqb := ']';
lbrace := '{';
rbrace := '}';
defn := mexpr opt-space '=' opt-space mexpr; defn := mexpr opt-space '=' opt-space mexpr;
cond := lsqb (cond-clause semi-colon opt-space)* cond-clause rsqb; cond := lsqb (cond-clause semi-colon opt-space)* cond-clause rsqb;
cond-clause := expr opt-space arrow opt-space expr; cond-clause := expr opt-space arrow opt-space expr;
@ -56,13 +69,10 @@
mvar := #'[a-z]+'; mvar := #'[a-z]+';
semi-colon := ';';" semi-colon := ';';"
;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
"comment := opt-space <';;'> #'[^\\n\\r]*';"
;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro, ;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
;; but I've included it on the basis that it can do little harm. ;; but I've included it on the basis that it can do little harm.
"sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment; "sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal; list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal | lbrace exprs rbrace;
dotted-pair := lpar dot-terminal ; dotted-pair := lpar dot-terminal ;
dot := '.'; dot := '.';
lpar := '('; lpar := '(';
@ -101,7 +111,7 @@
(apply (apply
vector vector
(remove (remove
#(if (coll? %) (empty? %)) #(when (coll? %) (empty? %))
(case (first p) (case (first p)
(:arg :expr :coefficient :fn-name :number :sexpr) (simplify (second p) context) (:arg :expr :coefficient :fn-name :number :sexpr) (simplify (second p) context)
(:λexpr (:λexpr
@ -113,7 +123,7 @@
(= context :mexpr) (= context :mexpr)
[:quoted-expr p] [:quoted-expr p]
p) p)
:comment (if :comment (when
(:strict *options*) (:strict *options*)
(throw (throw
(ex-info "Cannot parse comments in strict mode" (ex-info "Cannot parse comments in strict mode"
@ -139,7 +149,9 @@
[:args (apply vector (map simplify (rest p)))]] [:args (apply vector (map simplify (rest p)))]]
(map #(simplify % context) p)) (map #(simplify % context) p))
;;default ;;default
p))) (if (coll? (first p))
(map #(simplify % context) p)
p))))
p))) p)))
@ -197,30 +209,32 @@
"Generate a cond clause from this simplified parse tree fragment `p`; "Generate a cond clause from this simplified parse tree fragment `p`;
returns `nil` if `p` does not represent a cond clause." returns `nil` if `p` does not represent a cond clause."
[p] [p]
(if (when
(and (coll? p) (= :cond-clause (first p))) (and (coll? p) (= :cond-clause (first p)))
(make-beowulf-list (make-beowulf-list
(list (generate (nth p 1)) (list (if (= (nth p 1) [:quoted-expr [:atom "T"]])
'T
(generate (nth p 1)))
(generate (nth p 2)))))) (generate (nth p 2))))))
(defn gen-cond (defn gen-cond
"Generate a cond statement from this simplified parse tree fragment `p`; "Generate a cond statement from this simplified parse tree fragment `p`;
returns `nil` if `p` does not represent a (MEXPR) cond statement." returns `nil` if `p` does not represent a (MEXPR) cond statement."
[p] [p]
(if (when
(and (coll? p) (= :cond (first p))) (and (coll? p) (= :cond (first p)))
(make-beowulf-list (make-beowulf-list
(cons (cons
'COND 'COND
(map (map
gen-cond-clause generate
(rest p)))))) (rest p))))))
(defn gen-fn-call (defn gen-fn-call
"Generate a function call from this simplified parse tree fragment `p`; "Generate a function call from this simplified parse tree fragment `p`;
returns `nil` if `p` does not represent a (MEXPR) function call." returns `nil` if `p` does not represent a (MEXPR) function call."
[p] [p]
(if (when
(and (coll? p) (= :fncall (first p)) (= :mvar (first (second p)))) (and (coll? p) (= :fncall (first p)) (= :mvar (first (second p))))
(make-cons-cell (make-cons-cell
(generate (second p)) (generate (second p))
@ -264,6 +278,7 @@
"Generate lisp structure from this parse tree `p`. It is assumed that "Generate lisp structure from this parse tree `p`. It is assumed that
`p` has been simplified." `p` has been simplified."
[p] [p]
(try
(if (if
(coll? p) (coll? p)
(case (first p) (case (first p)
@ -272,17 +287,19 @@
(generate (nth p 1)) (generate (nth p 1))
(make-cons-cell (generate (nth p 2)) (make-cons-cell (generate (nth p 2))
(generate (nth p 3)))) (generate (nth p 3))))
(:args :list) (gen-dot-terminated-list (rest p)) :args (make-beowulf-list (map generate (rest p)))
:atom (symbol (second p)) :atom (symbol (second p))
:bindings (generate (second p)) :bindings (generate (second p))
:body (make-beowulf-list (map generate (rest p))) :body (make-beowulf-list (map generate (rest p)))
:cond (gen-cond p) :cond (gen-cond p)
:cond-clause (gen-cond-clause p)
(:decimal :integer) (read-string (strip-leading-zeros (second p))) (:decimal :integer) (read-string (strip-leading-zeros (second p)))
:dotted-pair (make-cons-cell :dotted-pair (make-cons-cell
(generate (nth p 1)) (generate (nth p 1))
(generate (nth p 2))) (generate (nth p 2)))
:exponent (generate (second p)) :exponent (generate (second p))
:fncall (gen-fn-call p) :fncall (gen-fn-call p)
:list (gen-dot-terminated-list (rest p))
:mvar (symbol (upper-case (second p))) :mvar (symbol (upper-case (second p)))
:octal (let [n (read-string (strip-leading-zeros (second p) "0")) :octal (let [n (read-string (strip-leading-zeros (second p) "0"))
scale (generate (nth p 2))] scale (generate (nth p 2))]
@ -298,8 +315,13 @@
(* n (expt 10 exponent))) (* n (expt 10 exponent)))
;; default ;; default
(throw (Exception. (str "Cannot yet generate " (first p))))) (throw (ex-info (str "Unrecognised head: " (first p))
p)) {:generating p})))
p)
(catch Throwable any
(throw (ex-info "Could not generate"
{:generating p}
any)))))
(defmacro gsp (defmacro gsp
"Shortcut macro - the internals of read; or, if you like, read-string. "Shortcut macro - the internals of read; or, if you like, read-string.

View file

@ -179,22 +179,22 @@
actual (MEMBER actual (MEMBER
(gsp "ALBERT") (gsp "ALBERT")
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))] (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
(= actual expected)) (is (= actual expected)))
(let [expected 'T (let [expected 'T
actual (MEMBER actual (MEMBER
(gsp "BELINDA") (gsp "BELINDA")
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))] (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
(= actual expected)) (is (= actual expected)))
(let [expected 'T (let [expected 'T
actual (MEMBER actual (MEMBER
(gsp "ELFREDA") (gsp "ELFREDA")
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))] (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
(= actual expected)) (is (= actual expected)))
(let [expected 'F (let [expected 'F
actual (MEMBER actual (MEMBER
(gsp "BERTRAM") (gsp "BERTRAM")
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))] (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
(= actual expected)))) (is (= actual expected)))))
(deftest pairlis-tests (deftest pairlis-tests
(testing "pairlis" (testing "pairlis"

View file

@ -25,10 +25,10 @@
(deftest variable-tests (deftest variable-tests
(testing "Variable translation" (testing "Variable translation"
(let [expected "X" (let [expected "X"
actual (print-str (generate (simplify (parse "x"))))] actual (print-str (gsp "x"))]
(is (= actual expected))) (is (= actual expected)))
(let [expected "CAR" (let [expected "CAR"
actual (print-str (generate (simplify (parse "car"))))] actual (print-str (gsp "car"))]
(is (= actual expected))) (is (= actual expected)))
)) ))
@ -39,28 +39,30 @@
;; Wrapping in a function call puts us into mexpr contest; ;; Wrapping in a function call puts us into mexpr contest;
;; "T" would be interpreted as a sexpr, which would not be ;; "T" would be interpreted as a sexpr, which would not be
;; quoted. ;; quoted.
(let [expected "(ATOM (QUOTE T))" (let [expected "(ATOM (QUOTE A))"
actual (print-str (generate (simplify (parse "atom[T]"))))] actual (print-str (gsp "atom[A]"))]
(is (= actual expected))) (is (= actual expected)
"Atoms should normally be quoted"))
;; I'm not clear how `car[(A B C)]` should be translated, but ;; I'm not clear how `car[(A B C)]` should be translated, but
;; I suspect as (CAR (LIST 'A 'B 'C)). ;; I suspect as (CAR (LIST 'A 'B 'C)).
)) ))
(deftest fncall-tests (deftest fncall-tests
(testing "Function calls" (testing "Function calls"
(let [expected "(CAR X)" (let [expected "(CAR X)"
actual (print-str (generate (simplify (parse "car[x]"))))] actual (print-str (gsp "car[x]"))]
(is (= actual expected))) (is (= actual expected)))
(let [expected "(FF (CAR X))" (let [expected "(FF (CAR X))"
actual (print-str (generate (simplify (parse "ff[car[x]]"))))] actual (print-str (gsp "ff[car[x]]"))]
(is (= actual expected))))) (is (= actual expected)))))
(deftest conditional-tests (deftest conditional-tests
(testing "Conditional expressions" (testing "Conditional expressions"
(let [expected "(COND ((ATOM X) X) ((QUOTE T) (FF (CAR X))))" (let [expected "(COND ((ATOM X) X) (T (FF (CAR X))))"
actual (print-str (generate (simplify (parse "[atom[x]->x; T->ff[car[x]]]"))))] actual (print-str (gsp "[atom[x]->x; T->ff[car[x]]]"))]
(is (= actual expected))) (is (= actual expected)))
(let [expected "(LABEL FF (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X))))))" (let [expected "(LABEL FF (LAMBDA (X) (COND ((ATOM X) X) (T (FF (CAR X))))))"
actual (print-str actual (print-str
(generate (generate
(simplify (simplify

View file

@ -10,19 +10,19 @@
(deftest atom-tests (deftest atom-tests
(testing "Reading atoms" (testing "Reading atoms"
(let [expected 'A (let [expected 'A
actual (generate (simplify (parse (str expected))))] actual (gsp(str expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected 'APPLE (let [expected 'APPLE
actual (generate (simplify (parse (str expected))))] actual (gsp(str expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected 'PART2 (let [expected 'PART2
actual (generate (simplify (parse (str expected))))] actual (gsp(str expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected 'EXTRALONGSTRINGOFLETTERS (let [expected 'EXTRALONGSTRINGOFLETTERS
actual (generate (simplify (parse (str expected))))] actual (gsp(str expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected 'A4B66XYZ2 (let [expected 'A4B66XYZ2
actual (generate (simplify (parse (str expected))))] actual (gsp(str expected))]
(is (= actual expected))))) (is (= actual expected)))))
(deftest comment-tests (deftest comment-tests
@ -54,67 +54,67 @@
(deftest number-tests (deftest number-tests
(testing "Reading octal numbers" (testing "Reading octal numbers"
(let [expected 1 (let [expected 1
actual (generate (simplify (parse "1Q")))] actual (gsp "1Q")]
(is (= actual expected))) (is (= actual expected)))
(let [expected -1 (let [expected -1
actual (generate (simplify (parse "-1Q")))] actual (gsp "-1Q")]
(is (= actual expected))) (is (= actual expected)))
(let [expected 8 (let [expected 8
actual (generate (simplify (parse "1Q1")))] actual (gsp "1Q1")]
(is (= actual expected))) (is (= actual expected)))
(let [expected -8 (let [expected -8
actual (generate (simplify (parse "-1Q1")))] actual (gsp "-1Q1")]
(is (= actual expected))) (is (= actual expected)))
(let [expected 128 (let [expected 128
actual (generate (simplify (parse "2Q2")))] actual (gsp "2Q2")]
(is (= actual expected))) (is (= actual expected)))
(let [expected 2093056 (let [expected 2093056
actual (generate (simplify (parse "777Q4")))] actual (gsp "777Q4")]
(is (= actual expected)))) (is (= actual expected))))
(testing "Reading decimal numbers - broadly should be homiconic" (testing "Reading decimal numbers - broadly should be homiconic"
(let [expected 7 (let [expected 7
actual (generate (simplify (parse "7")))] actual (gsp "7")]
(is (= actual expected))) (is (= actual expected)))
(let [expected -7 (let [expected -7
actual (generate (simplify (parse "-7")))] actual (gsp "-7")]
(is (= actual expected))) (is (= actual expected)))
(let [expected 3.141592 (let [expected 3.141592
actual (generate (simplify (parse "3.141592")))] actual (gsp "3.141592")]
(is (= actual expected))) (is (= actual expected)))
(let [expected 1234567890 (let [expected 1234567890
actual (generate (simplify (parse "1234567890")))] actual (gsp "1234567890")]
(is (= actual expected))) (is (= actual expected)))
(let [expected -45.23 (let [expected -45.23
actual (generate (simplify (parse "-45.23")))] actual (gsp "-45.23")]
(is (= actual expected)))) (is (= actual expected))))
(testing "Reading scientific notation") (testing "Reading scientific notation")
(let [expected 2/5 (let [expected 2/5
actual (generate (simplify (parse "4E-1")))] actual (gsp "4E-1")]
(is (< (abs (- actual expected)) 0.0001))) (is (< (abs (- actual expected)) 0.0001)))
(let [expected 60 (let [expected 60
actual (generate (simplify (parse "6E1")))] actual (gsp "6E1")]
(is (< (abs (- actual expected)) 0.0001))) (is (< (abs (- actual expected)) 0.0001)))
(let [expected 60 (let [expected 60
actual (generate (simplify (parse "600.00E-1")))] actual (gsp "600.00E-1")]
(is (< (abs (- actual expected)) 0.0001))) (is (< (abs (- actual expected)) 0.0001)))
(let [expected 60 (let [expected 60
actual (generate (simplify (parse "0.6E2")))] actual (gsp "0.6E2")]
(is (< (abs (- actual expected)) 0.0001)))) (is (< (abs (- actual expected)) 0.0001))))
(deftest dotted-pair-tests (deftest dotted-pair-tests
(testing "Reading dotted pairs" (testing "Reading dotted pairs"
(let [expected "(A . B)" (let [expected "(A . B)"
actual (print-str (generate (simplify (parse expected))))] actual (print-str (gsp expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected "(A B C . D)" (let [expected "(A B C . D)"
actual (print-str (generate (simplify (parse expected))))] actual (print-str (gsp expected))]
(is (= actual expected))) (is (= actual expected)))
(let [expected "(A B (C . D) E)" (let [expected "(A B (C . D) E)"
actual (print-str (generate (simplify (parse expected))))] actual (print-str (gsp expected))]
(is (= actual expected))))) (is (= actual expected)))))
(deftest list-tests (deftest list-tests
(testing "Reading arbitrarily structured lists" (testing "Reading arbitrarily structured lists"
(let [expected "(DEFUN FACT (X) (COND ((ZEROP X) 1) (T (TIMES X (FACT (SUB1 X))))))" (let [expected "(DEFUN FACT (X) (COND ((ZEROP X) 1) (T (TIMES X (FACT (SUB1 X))))))"
actual (print-str (generate (simplify (parse expected))))] actual (print-str (gsp expected))]
(is (= actual expected))))) (is (= actual expected)))))