Much improvement; printing works, and bootstrap tests started
There's probably redundant code in this, but I want to commit here just in case what I think is redundant isn't!
This commit is contained in:
parent
12bbd0076a
commit
dfe4333dfa
|
@ -14,13 +14,19 @@
|
||||||
;; next and more must return ISeq:
|
;; next and more must return ISeq:
|
||||||
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
||||||
(more [this] (if
|
(more [this] (if
|
||||||
(= (.CDR this) NIL)
|
(seq? this)
|
||||||
clojure.lang.PersistentList/EMPTY
|
(if
|
||||||
(.CDR this)))
|
(= (.CDR this) NIL)
|
||||||
|
clojure.lang.PersistentList/EMPTY
|
||||||
|
(.CDR this))
|
||||||
|
NIL))
|
||||||
(next [this] (if
|
(next [this] (if
|
||||||
(= (.CDR this) NIL)
|
(seq? this)
|
||||||
nil ;; next returns nil when empty
|
(if
|
||||||
(.CDR this)))
|
(= (.CDR this) NIL)
|
||||||
|
nil ;; next returns nil when empty
|
||||||
|
(.CDR this))
|
||||||
|
NIL))
|
||||||
|
|
||||||
clojure.lang.Seqable
|
clojure.lang.Seqable
|
||||||
(seq [this] this)
|
(seq [this] this)
|
||||||
|
@ -31,12 +37,50 @@
|
||||||
|
|
||||||
clojure.lang.IPersistentCollection
|
clojure.lang.IPersistentCollection
|
||||||
(count [this] (if
|
(count [this] (if
|
||||||
(= (.CDR this) NIL)
|
(seq? this)
|
||||||
0
|
(if
|
||||||
(inc (count (.CDR this)))))
|
(= (.CDR this) NIL)
|
||||||
|
0
|
||||||
|
(inc (count (.CDR this))))
|
||||||
|
0))
|
||||||
(empty [this] false)
|
(empty [this] false)
|
||||||
(equiv [this other] false))
|
(equiv [this other] false))
|
||||||
|
|
||||||
|
(defn- to-string
|
||||||
|
"Printing ConsCells gave me a *lot* of trouble. This is an internal function
|
||||||
|
used by the print-method override (below) in order that the standard Clojure
|
||||||
|
`print` and `str` functions will print ConsCells correctly. The argument
|
||||||
|
`cell` must, obviously, be an instance of `ConsCell`."
|
||||||
|
[cell]
|
||||||
|
(loop [c cell
|
||||||
|
n 0
|
||||||
|
s "("]
|
||||||
|
(if
|
||||||
|
(instance? beowulf.cons_cell.ConsCell c)
|
||||||
|
(let [car (.CAR c)
|
||||||
|
cdr (.CDR c)
|
||||||
|
cons? (instance? beowulf.cons_cell.ConsCell cdr)
|
||||||
|
ss (str
|
||||||
|
s
|
||||||
|
(to-string car)
|
||||||
|
(cond
|
||||||
|
cons?
|
||||||
|
" "
|
||||||
|
(or (nil? cdr) (= cdr 'NIL))
|
||||||
|
")"
|
||||||
|
:else
|
||||||
|
(str " . " (to-string cdr) ")")))]
|
||||||
|
(if
|
||||||
|
cons?
|
||||||
|
(recur cdr (inc n) ss)
|
||||||
|
ss))
|
||||||
|
(str c))))
|
||||||
|
|
||||||
|
(defmethod clojure.core/print-method beowulf.cons_cell.ConsCell
|
||||||
|
[this writer]
|
||||||
|
(.write writer (to-string this)))
|
||||||
|
|
||||||
|
|
||||||
(defn make-cons-cell
|
(defn make-cons-cell
|
||||||
[a d]
|
[a d]
|
||||||
(ConsCell. a d))
|
(ConsCell. a d))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
(ns beowulf.core
|
(ns beowulf.core
|
||||||
(:require [beowulf.eval :refer [primitive-eval oblist]]
|
(:require [beowulf.eval :refer [primitive-eval oblist]]
|
||||||
[beowulf.read :refer [primitive-read]]
|
[beowulf.read :refer [primitive-read]])
|
||||||
[beowulf.print :refer [primitive-print prin]])
|
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
(defn -main
|
(defn -main
|
||||||
|
@ -12,6 +11,6 @@
|
||||||
(print ":: ")
|
(print ":: ")
|
||||||
(flush)
|
(flush)
|
||||||
(let [input (primitive-read)]
|
(let [input (primitive-read)]
|
||||||
(println (str "\tI read: " (prin input)))
|
(println (str "\tI read: " input))
|
||||||
(println (str "> "(prin (primitive-eval input @oblist))))
|
(println (str "> " (primitive-eval input @oblist)))
|
||||||
(recur))))
|
(recur))))
|
||||||
|
|
|
@ -31,14 +31,18 @@
|
||||||
(if
|
(if
|
||||||
(instance? beowulf.cons_cell.ConsCell x)
|
(instance? beowulf.cons_cell.ConsCell x)
|
||||||
(.CAR x)
|
(.CAR x)
|
||||||
NIL))
|
(throw
|
||||||
|
(Exception.
|
||||||
|
(str "Cannot take CAR of `" x "` (" (.getName (.getClass x)) ")")))))
|
||||||
|
|
||||||
(defn cdr
|
(defn cdr
|
||||||
[x]
|
[x]
|
||||||
(if
|
(if
|
||||||
(instance? beowulf.cons_cell.ConsCell x)
|
(instance? beowulf.cons_cell.ConsCell x)
|
||||||
(.CDR x)
|
(.CDR x)
|
||||||
NIL))
|
(throw
|
||||||
|
(Exception.
|
||||||
|
(str "Cannot take CDR of `" x "` (" (.getName (.getClass x)) ")")))))
|
||||||
|
|
||||||
(defn uaf
|
(defn uaf
|
||||||
"Universal access function; `l` is expected to be an arbitrary list, `path`
|
"Universal access function; `l` is expected to be an arbitrary list, `path`
|
||||||
|
@ -47,14 +51,10 @@
|
||||||
[l path]
|
[l path]
|
||||||
(cond
|
(cond
|
||||||
(null l) NIL
|
(null l) NIL
|
||||||
(not (instance? beowulf.cons_cell.ConsCell l))
|
(empty? path) l
|
||||||
(throw (Exception. (str "Unexpected list argument to uaf: `" l "`")))
|
:else (case (last path)
|
||||||
(empty? (rest path))(case (first path)
|
\a (uaf (car l) (butlast path))
|
||||||
\a (car l)
|
\d (uaf (cdr l) (butlast path)))))
|
||||||
\d (cdr l))
|
|
||||||
:else (case (first path)
|
|
||||||
\a (uaf (car l) (rest path))
|
|
||||||
\d (uaf (cdr l) (rest path)))))
|
|
||||||
|
|
||||||
(defn caar [x] (uaf x (seq "aa")))
|
(defn caar [x] (uaf x (seq "aa")))
|
||||||
(defn cadr [x] (uaf x (seq "ad")))
|
(defn cadr [x] (uaf x (seq "ad")))
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
(ns beowulf.print
|
|
||||||
)
|
|
||||||
|
|
||||||
(defprotocol Printable
|
|
||||||
(prin [x]))
|
|
||||||
|
|
||||||
(extend-type
|
|
||||||
clojure.lang.Symbol
|
|
||||||
Printable
|
|
||||||
(prin [x] (str x)))
|
|
||||||
|
|
||||||
(extend-protocol
|
|
||||||
Printable
|
|
||||||
nil
|
|
||||||
(prin [x] "NIL"))
|
|
||||||
|
|
||||||
(extend-protocol
|
|
||||||
Printable
|
|
||||||
|
|
||||||
clojure.lang.Symbol
|
|
||||||
(prin [x] (str x))
|
|
||||||
|
|
||||||
java.lang.Number
|
|
||||||
(prin [x] (str x))
|
|
||||||
|
|
||||||
beowulf.cons_cell.ConsCell
|
|
||||||
(prin [x]
|
|
||||||
(loop [c x
|
|
||||||
n 0
|
|
||||||
s "("]
|
|
||||||
(let [car (.CAR c)
|
|
||||||
cdr (.CDR c)
|
|
||||||
cons? (instance? beowulf.cons_cell.ConsCell cdr)
|
|
||||||
ss (str
|
|
||||||
s
|
|
||||||
(prin car)
|
|
||||||
(cond
|
|
||||||
cons?
|
|
||||||
" "
|
|
||||||
(or (nil? cdr) (= cdr 'NIL))
|
|
||||||
")"
|
|
||||||
:else
|
|
||||||
(str " . " (prin cdr) ")")))]
|
|
||||||
(if
|
|
||||||
cons?
|
|
||||||
(recur cdr (inc n) ss)
|
|
||||||
ss))))
|
|
||||||
|
|
||||||
java.lang.Object
|
|
||||||
(prin
|
|
||||||
[x]
|
|
||||||
(str x)))
|
|
||||||
|
|
||||||
(defn primitive-print
|
|
||||||
[x]
|
|
||||||
(if
|
|
||||||
(satisfies? beowulf.print.Printable x) (prin x)
|
|
||||||
(str x)))
|
|
||||||
|
|
116
test/beowulf/bootstrap_test.clj
Normal file
116
test/beowulf/bootstrap_test.clj
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
(ns beowulf.bootstrap-test
|
||||||
|
(:require [clojure.math.numeric-tower :refer [abs]]
|
||||||
|
[clojure.test :refer :all]
|
||||||
|
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]
|
||||||
|
[beowulf.eval :refer :all]
|
||||||
|
[beowulf.read :refer [parse simplify generate]]))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; This file is primarily tests of the functions in `beowulf.eval` - which
|
||||||
|
;;; are Clojure functions, but aim to provide sufficient functionality that
|
||||||
|
;;; Beowulf can get up to the level of running its own code.
|
||||||
|
;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(deftest atom-tests
|
||||||
|
(testing "primitive-atom"
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom T)]
|
||||||
|
(is (= actual expected) "T is an atom (symbol)"))
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom (generate (simplify (parse "HELLO"))))]
|
||||||
|
(is (= actual expected) "HELLO is an atom (symbol)"))
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom 7)]
|
||||||
|
(is (= actual expected)
|
||||||
|
"I'm not actually certain whether a number should be treated as an
|
||||||
|
atom, but I'm guessing so"))
|
||||||
|
(let [expected F
|
||||||
|
actual (primitive-atom (make-cons-cell 'A 'B))]
|
||||||
|
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
||||||
|
(let [expected F
|
||||||
|
actual (primitive-atom (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected) "A list is explicitly not an atom")))
|
||||||
|
(testing "primitive-atom?"
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom? T)]
|
||||||
|
(is (= actual expected) "T is an atom (symbol)"))
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom? (generate (simplify (parse "HELLO"))))]
|
||||||
|
(is (= actual expected) "HELLO is an atom (symbol)"))
|
||||||
|
(let [expected T
|
||||||
|
actual (primitive-atom? 7)]
|
||||||
|
(is (= actual expected)
|
||||||
|
"I'm not actually certain whether a number should be treated as an
|
||||||
|
atom, but I'm guessing so"))
|
||||||
|
(let [expected NIL
|
||||||
|
actual (primitive-atom? (make-cons-cell 'A 'B))]
|
||||||
|
(is (= actual expected) "A dotted pair is explicitly not an atom."))
|
||||||
|
(let [expected NIL
|
||||||
|
actual (primitive-atom? (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected) "A list is explicitly not an atom"))
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
|
(deftest access-function-tests
|
||||||
|
(testing "car"
|
||||||
|
(let [expected 'A
|
||||||
|
actual (car (make-cons-cell 'A 'B))]
|
||||||
|
(is (= actual expected) "A is car of (A . B)"))
|
||||||
|
(let [expected 'A
|
||||||
|
actual (car (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected) "A is car of (A B C D)"))
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception
|
||||||
|
#"Cannot take CAR of `.*"
|
||||||
|
(car 'T))
|
||||||
|
"Can't take the car of an atom")
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception
|
||||||
|
#"Cannot take CAR of `.*"
|
||||||
|
(car 7))
|
||||||
|
"Can't take the car of a number"))
|
||||||
|
(testing "cdr"
|
||||||
|
(let [expected 'B
|
||||||
|
actual (cdr (make-cons-cell 'A 'B))]
|
||||||
|
(is (= actual expected) "B is cdr of (A . B)"))
|
||||||
|
(let [expected 'B
|
||||||
|
actual (cdr (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (instance? beowulf.cons_cell.ConsCell actual)
|
||||||
|
"cdr of (A B C D) is a cons cell")
|
||||||
|
(is (= (car actual) expected) "the car of that cons-cell is B"))
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception
|
||||||
|
#"Cannot take CDR of `.*"
|
||||||
|
(cdr 'T))
|
||||||
|
"Can't take the cdr of an atom")
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception
|
||||||
|
#"Cannot take CDR of `.*"
|
||||||
|
(cdr 7))
|
||||||
|
"Can't take the cdr of a number"))
|
||||||
|
(let [s (generate
|
||||||
|
(simplify
|
||||||
|
(parse
|
||||||
|
"((((1 . 2) 3)(4 5) 6)(7 (8 9) (10 11 12) 13) 14 (15 16) 17)")))]
|
||||||
|
;; structure for testing access functions
|
||||||
|
(testing "cadr"
|
||||||
|
(let [expected 'B
|
||||||
|
actual (cadr (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected))))
|
||||||
|
(testing "caddr"
|
||||||
|
(let [expected 'C
|
||||||
|
actual (caddr (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected))))
|
||||||
|
(testing "cadddr"
|
||||||
|
(let [expected 'D
|
||||||
|
actual (cadddr (generate (simplify (parse "(A B C D)"))))]
|
||||||
|
(is (= actual expected))))
|
||||||
|
(testing "caaaar"
|
||||||
|
(let [expected "1"
|
||||||
|
actual (print-str (caaaar s))]
|
||||||
|
(is (= actual expected))))
|
||||||
|
))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
(ns beowulf.mexpr-test
|
(ns beowulf.mexpr-test
|
||||||
(:require [clojure.test :refer :all]
|
(:require [clojure.test :refer :all]
|
||||||
[beowulf.read :refer [parse simplify generate]]
|
[beowulf.read :refer [parse simplify generate]]))
|
||||||
[beowulf.print :refer :all]))
|
|
||||||
|
|
||||||
;; These tests are taken generally from the examples on page 10 of
|
;; These tests are taken generally from the examples on page 10 of
|
||||||
;; Lisp 1.5 Programmers Manual:
|
;; Lisp 1.5 Programmers Manual:
|
||||||
|
@ -23,10 +22,10 @@
|
||||||
(deftest variable-tests
|
(deftest variable-tests
|
||||||
(testing "Variable translation"
|
(testing "Variable translation"
|
||||||
(let [expected "X"
|
(let [expected "X"
|
||||||
actual (prin (generate (simplify (parse "x"))))]
|
actual (print-str (generate (simplify (parse "x"))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
(let [expected "CAR"
|
(let [expected "CAR"
|
||||||
actual (prin (generate (simplify (parse "car"))))]
|
actual (print-str (generate (simplify (parse "car"))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@
|
||||||
;; "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 T))"
|
||||||
actual (prin (generate (simplify (parse "atom[T]"))))]
|
actual (print-str (generate (simplify (parse "atom[T]"))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
;; 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)).
|
||||||
|
@ -47,19 +46,19 @@
|
||||||
(deftest fncall-tests
|
(deftest fncall-tests
|
||||||
(testing "Function calls"
|
(testing "Function calls"
|
||||||
(let [expected "(CAR X)"
|
(let [expected "(CAR X)"
|
||||||
actual (prin (generate (simplify (parse "car[x]"))))]
|
actual (print-str (generate (simplify (parse "car[x]"))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
(let [expected "(FF (CAR X))"
|
(let [expected "(FF (CAR X))"
|
||||||
actual (prin (generate (simplify (parse "ff[car[x]]"))))]
|
actual (print-str (generate (simplify (parse "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) ((QUOTE T) (FF (CAR X))))"
|
||||||
actual (prin (generate (simplify (parse "[atom[x]->x; T->ff[car[x]]]"))))]
|
actual (print-str (generate (simplify (parse "[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) ((QUOTE T) (FF (CAR X))))))"
|
||||||
actual (prin
|
actual (print-str
|
||||||
(generate
|
(generate
|
||||||
(simplify
|
(simplify
|
||||||
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
|
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
(ns beowulf.read-test
|
|
||||||
(:require [clojure.test :refer :all]
|
|
||||||
[beowulf.core :refer :all]))
|
|
||||||
|
|
||||||
;; (deftest a-test
|
|
||||||
;; (testing "FIXME, I fail."
|
|
||||||
;; (is (= 0 1))))
|
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
(:require [clojure.math.numeric-tower :refer [abs]]
|
(:require [clojure.math.numeric-tower :refer [abs]]
|
||||||
[clojure.test :refer :all]
|
[clojure.test :refer :all]
|
||||||
[beowulf.cons-cell :refer :all]
|
[beowulf.cons-cell :refer :all]
|
||||||
[beowulf.read :refer [parse simplify generate]]
|
[beowulf.read :refer [parse simplify generate]]))
|
||||||
[beowulf.print :refer :all]))
|
|
||||||
|
|
||||||
;; broadly, sexprs should be homoiconic
|
;; broadly, sexprs should be homoiconic
|
||||||
|
|
||||||
|
@ -78,17 +77,17 @@
|
||||||
(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 (prin (generate (simplify (parse expected))))]
|
actual (print-str (generate (simplify (parse expected))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
(let [expected "(A B C . D)"
|
(let [expected "(A B C . D)"
|
||||||
actual (prin (generate (simplify (parse expected))))]
|
actual (print-str (generate (simplify (parse expected))))]
|
||||||
(is (= actual expected)))
|
(is (= actual expected)))
|
||||||
(let [expected "(A B (C . D) E)"
|
(let [expected "(A B (C . D) E)"
|
||||||
actual (prin (generate (simplify (parse expected))))]
|
actual (print-str (generate (simplify (parse 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 (prin (generate (simplify (parse expected))))]
|
actual (print-str (generate (simplify (parse expected))))]
|
||||||
(is (= actual expected)))))
|
(is (= actual expected)))))
|
||||||
|
|
Loading…
Reference in a new issue