Merge branch 'release/0.2.0'
This commit is contained in:
commit
cab4ead3b9
90
README.md
90
README.md
|
@ -7,10 +7,66 @@ LISP 1.5 is to all Lisp dialects as Beowulf is to Emglish literature.
|
|||
A work-in-progress towards an implementation of Lisp 1.5 in Clojure. The
|
||||
objective is to build a complete and accurate implementation of Lisp 1.5
|
||||
as described in the manual, with, in so far as is possible, exactly the
|
||||
same bahaviour; the only intended deviation is that the parser reads
|
||||
'mexprs' (meta language expressions) as well as sexprs.
|
||||
same bahaviour - except as documented below.
|
||||
|
||||
## BUT WHY?!!?!
|
||||
### Status
|
||||
|
||||
Boots to REPL, but few functions yet available.
|
||||
|
||||
### Architectural plan
|
||||
|
||||
Not everything documented in this section is yet built. It indicates the
|
||||
direction of travel and intended destination, not the current state.
|
||||
|
||||
#### resources/lisp1.5.lsp
|
||||
|
||||
The objective is to have within `resources/lisp1.5.lsp`, all those functions
|
||||
defined in the Lisp 1.5 Programmer's Manual which can be implemented in Lisp.
|
||||
|
||||
This means that, while Beowulf is hosted on Clojure, all that would be
|
||||
required to rehost Lisp 1.5 on a different platform would be to reimplement
|
||||
|
||||
* bootstrap.clj
|
||||
* host.clj
|
||||
* read.clj
|
||||
|
||||
The objective this is to make it fairly easy to implement Lisp 1.5 on top of
|
||||
any of the many [Make A Lisp](https://github.com/kanaka/mal)
|
||||
implementations.
|
||||
|
||||
#### beowulf/boostrap.clj
|
||||
|
||||
This file is essentially 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.
|
||||
|
||||
In addition it contains the function `INTEROP`, which allows host language
|
||||
functions to be called from Lisp.
|
||||
|
||||
#### beowulf/host.clj
|
||||
|
||||
This file provides Lisp 1.5 functions which can't be (or can't efficiently
|
||||
be) implemented in Lisp 1.5, which therefore need to be implemented in the
|
||||
host language, in this case Clojure.
|
||||
|
||||
#### beowulf/read.clj
|
||||
|
||||
This file provides the reader required for boostrapping. It's not a bad
|
||||
reader - it provides feedback on errors found in the input - but it isn't
|
||||
the real Lisp reader.
|
||||
|
||||
Intended deviations from the behaviour of the real Lisp reader are as follows:
|
||||
|
||||
1. It reads the meta-expression language `MEXPR` in addition to the
|
||||
symbolic expression language `SEXPR`, which I do not believe the Lisp 1.5
|
||||
reader ever did;
|
||||
2. It treats everything between a semi-colon and an end of line as a comment,
|
||||
as most modern Lisps do; but I do not believe Lisp 1.5 had this feature.
|
||||
|
||||
|
||||
### BUT WHY?!!?!
|
||||
|
||||
Because.
|
||||
|
||||
|
@ -23,9 +79,24 @@ for modern machines.
|
|||
|
||||
Because I'm barking mad, and this is therapy.
|
||||
|
||||
### Commentary
|
||||
|
||||
What's surprised me in working on this is how much more polished Lisp 1.5 is
|
||||
than legend had led me to believe. The language is remarkably close to
|
||||
[Portable Standard Lisp](http://www.softwarepreservation.org/projects/LISP/standard_lisp_family/#Portable_Standard_LISP_)
|
||||
which is in my opinion one of the best and most usable early Lisp
|
||||
implementations. I'm convinced you could still use Lisp 1.5 for interesting
|
||||
and useful software (which isn't to say that some modern Lisps aren't better,
|
||||
but this is software which is almost sixty years old).
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Download from http://example.com/FIXME.
|
||||
At present, clone the source and build it using
|
||||
|
||||
`lein uberjar`.
|
||||
|
||||
You will require to have [Leiningen](https://leiningen.org/) installed.
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -41,6 +112,17 @@ The `Lisp 1.5 Programmer's Manual` is still
|
|||
[in print, ISBN 13 978-0-262-13011-0](https://mitpress.mit.edu/books/lisp-15-programmers-manual); but it's also
|
||||
[available online](http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf).
|
||||
|
||||
## Other Lisp 1.5 resources
|
||||
|
||||
The main resource I'm aware of is the Software Preservation Society's site,
|
||||
[here](http://www.softwarepreservation.org/projects/LISP/lisp1.5). It has lots
|
||||
of fascinating stuff including full assembler listings for various obsolete
|
||||
processors, but I failed to find the Lisp source of Lisp functions as a text
|
||||
file, which is why `resources/lisp1.5.lsp` is largely copytyped and
|
||||
reconstructed from the manual.
|
||||
|
||||
I'm not at this time aware of any other working Lisp 1.5 implementations.
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2019 Simon Brooke. Licensed under the GNU General Public License,
|
||||
|
|
1022
docs/cloverage/beowulf/bootstrap.clj.html
Normal file
1022
docs/cloverage/beowulf/bootstrap.clj.html
Normal file
File diff suppressed because it is too large
Load diff
476
docs/cloverage/beowulf/cons_cell.clj.html
Normal file
476
docs/cloverage/beowulf/cons_cell.clj.html
Normal file
|
@ -0,0 +1,476 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../coverage.css"/> <title> beowulf/cons_cell.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns beowulf.cons-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "The fundamental cons cell on which all Lisp structures are built.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 Lisp 1.5 lists do not necessarily have a sequence as their CDR, so
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 cannot be implemented on top of Clojure lists.")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
005
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
006 (def NIL
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 "The canonical empty list symbol."
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
008 (symbol "NIL"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
009
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
010 (def T
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 "The canonical true value."
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
012 (symbol "T")) ;; true.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
013
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
014 (def F
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 "The canonical false value - different from `NIL`, which is not canonically
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 false in Lisp 1.5."
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
017 (symbol "F")) ;; false as distinct from nil
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
018
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 8 forms covered">
|
||||
019 (deftype ConsCell [CAR CDR]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 clojure.lang.ISeq
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 (cons [this x] (ConsCell. x this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 (first [this] (.CAR this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;; next and more must return ISeq:
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 (more [this] (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 (seq? (.CDR this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 (.CDR this)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 clojure.lang.PersistentList/EMPTY))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 (next [this] (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 (seq? (.CDR this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 (.CDR this)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 nil ;; next returns nil when empty
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
034
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 clojure.lang.Seqable
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 (seq [this] this)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
037
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;; for some reason this marker protocol is needed otherwise compiler complains
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ;; that `nth not supported on ConsCell`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 clojure.lang.Sequential
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
041
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 clojure.lang.IPersistentCollection
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 (count [this] (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 (coll? (.CDR this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 (inc (.count (.CDR this)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 1))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 (empty [this] false) ;; a cons cell is by definition not empty.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 (equiv [this other] (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 (seq? other)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 (and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 (and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 (seq? (first this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 (seq? (first other)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 (.equiv (first this) (first other))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
056 (= (first this) (first other)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 (and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 (seq? (rest this))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 (seq? (rest other)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 (.equiv (rest this) (rest other))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 (= (rest this) (rest other))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 false)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
064
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
065 (defn- to-string
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 "Printing ConsCells gave me a *lot* of trouble. This is an internal function
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 used by the print-method override (below) in order that the standard Clojure
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
068 `print` and `str` functions will print ConsCells correctly. The argument
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 `cell` must, obviously, be an instance of `ConsCell`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 [cell]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
071 (loop [c cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 n 0
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
073 s "("]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
074 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
075 (instance? beowulf.cons_cell.ConsCell c)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
076 (let [car (.CAR c)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
077 cdr (.CDR c)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
078 cons? (instance? beowulf.cons_cell.ConsCell cdr)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
079 ss (str
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
080 s
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
081 (to-string car)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
082 (cond
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
083 cons?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 " "
|
||||
</span><br/>
|
||||
<span class="partial" title="10 out of 11 forms covered">
|
||||
085 (or (nil? cdr) (= cdr 'NIL))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
086 ")"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
087 :else
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
088 (str " . " (to-string cdr) ")")))]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
089 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
090 cons?
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
091 (recur cdr (inc n) ss)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
092 ss))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
093 (str c))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
094
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
095 (defn pretty-print
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
096 "This isn't the world's best pretty printer but it sort of works."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 ([^beowulf.cons_cell.ConsCell cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
098 (println (pretty-print cell 80 0)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
099 ([^beowulf.cons_cell.ConsCell cell width level]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
100 (loop [c cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
101 n (inc level)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
102 s "("]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
103 (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
104 (instance? beowulf.cons_cell.ConsCell c)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
105 (let [car (.CAR c)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
106 cdr (.CDR c)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
107 cons? (instance? beowulf.cons_cell.ConsCell cdr)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
108 print-width (count (print-str c))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
109 indent (apply str (repeat n " "))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
110 ss (str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
111 s
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
112 (pretty-print car width n)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
113 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
114 cons?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
115 (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
116 (< (+ (count indent) print-width) width)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 " "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
118 (str "\n" indent))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
119 (or (nil? cdr) (= cdr 'NIL))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
120 ")"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
121 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
122 (str " . " (pretty-print cdr width n) ")")))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
123 (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
124 cons?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
125 (recur cdr n ss)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
126 ss))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
127 (str c)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
128
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
129
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
130
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
131 (defmethod clojure.core/print-method
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
132 ;;; I have not worked out how to document defmethod without blowing up the world.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
133 beowulf.cons_cell.ConsCell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
134 [this writer]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
135 (.write writer (to-string this)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
136
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
137
|
||||
</span><br/>
|
||||
<span class="covered" title="17 out of 17 forms covered">
|
||||
138 (defmacro make-cons-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
139 "Construct a new instance of cons cell with this `car` and `cdr`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
140 [car cdr]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
141 `(ConsCell. ~car ~cdr))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
142
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
143 (defn make-beowulf-list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 "Construct a linked list of cons cells with the same content as the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
145 sequence `x`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
146 [x]
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 3 forms covered">
|
||||
147 (cond
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
148 (empty? x) NIL
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
149 (coll? x) (ConsCell.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
150 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
151 (seq? (first x))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
152 (make-beowulf-list (first x))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
153 (first x))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
154 (make-beowulf-list (rest x)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
155 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
156 NIL))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
248
docs/cloverage/beowulf/core.clj.html
Normal file
248
docs/cloverage/beowulf/core.clj.html
Normal file
|
@ -0,0 +1,248 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../coverage.css"/> <title> beowulf/core.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns beowulf.core
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Essentially, the `-main` function and the bootstrap read-eval-print loop."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 (:require [beowulf.bootstrap :refer [EVAL oblist *options*]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 [beowulf.read :refer [READ]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 [clojure.java.io :as io]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 [clojure.pprint :refer [pprint]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [clojure.tools.cli :refer [parse-opts]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [environ.core :refer [env]])
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 (:gen-class))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
011 (def cli-options
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
012 [["-h" "--help"]
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
013 ["-p PROMPT" "--prompt PROMPT" "Set the REPL prompt to PROMPT"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 :default "Sprecan::"]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
015 ["-r INITFILE" "--read INITFILE" "Read Lisp functions from the file INITFILE"
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
016 :validate [#(and
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
017 (.exists (io/file %))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 (.canRead (io/file %)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 "Could not find initfile"]]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
020 ["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
021 ["-t" "--trace" "Trace Lisp evaluation."]])
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
022
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
023 (defn repl
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 "Read/eval/print loop."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 [prompt]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
026 (loop []
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
027 (print prompt)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
028 (flush)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
029 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
030 (let [input (read-line)]
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 3 forms covered">
|
||||
031 (cond
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
032 (= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit}))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
033 input (println (str "> " (print-str (EVAL (READ input) @oblist))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
034 :else (println)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 (catch
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 Exception
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 e
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
038 (let [data (ex-data e)]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
039 (println (.getMessage e))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
040 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
041 data
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
042 (case (:cause data)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
043 :parse-failure (println (:failure data))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 :strict nil ;; the message, which has already been printed, is enough.
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
045 :quit (throw e)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 ;; default
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
047 (pprint data))))))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
048 (recur)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
049
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
050 (defn -main
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 "Parse options, print the banner, read the init file if any, and enter the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 read/eval/print loop."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 [& opts]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
054 (let [args (parse-opts opts cli-options)]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
055 (println
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
056 (str
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 "\nHider wilcuman. Béowulf is mín nama.\n"
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
058 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
059 (System/getProperty "beowulf.version")
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
060 (str "Síðe " (System/getProperty "beowulf.version") "\n"))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
061 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
062 (:help (:options args))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
063 (:summary args))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
064 (if (:errors args)
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
065 (apply str (interpose "; " (:errors args))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 "\nSprecan 'quit' tó laéfan\n"))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
067 (binding [*options* (:options args)]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
068 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
069 (repl (str (:prompt (:options args)) " "))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 (catch
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
071 Exception
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 e
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
073 (let [data (ex-data e)]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
074 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
075 data
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
076 (case (:cause data)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 :quit nil
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 ;; default
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
079 (pprint data))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
080 (println e))))))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
23
docs/cloverage/beowulf/host.clj.html
Normal file
23
docs/cloverage/beowulf/host.clj.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../coverage.css"/> <title> beowulf/host.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns beowulf.host
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "provides Lisp 1.5 functions which can't be (or can't efficiently
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 be) implemented in Lisp 1.5, which therefore need to be implemented in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 host language, in this case Clojure.")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
005
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
953
docs/cloverage/beowulf/read.clj.html
Normal file
953
docs/cloverage/beowulf/read.clj.html
Normal file
|
@ -0,0 +1,953 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../coverage.css"/> <title> beowulf/read.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns beowulf.read
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "This provides the reader required for boostrapping. It's not a bad
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 reader - it provides feedback on errors found in the input - but it isn't
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 the real Lisp reader.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
005
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 Intended deviations from the behaviour of the real Lisp reader are as follows:
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
007
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 1. It reads the meta-expression language `MEXPR` in addition to the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 symbolic expression language `SEXPR`, which I do not believe the Lisp 1.5
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 reader ever did;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 2. It treats everything between a semi-colon and an end of line as a comment,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 as most modern Lisps do; but I do not believe Lisp 1.5 had this feature.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
013
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 Both these extensions can be disabled by using the `--strict` command line
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 switch."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 (:require [beowulf.bootstrap :refer [*options*]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 [clojure.math.numeric-tower :refer [expt]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 [clojure.string :refer [starts-with? upper-case]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 [instaparse.core :as i]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
021
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;; This file provides the reader required for boostrapping. It's not a bad
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;; reader - it provides feedback on errors found in the input - but it isn't
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;; the real Lisp reader.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
029
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
030 (declare generate)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
031
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
032 (def parse
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 "Parse a string presented as argument into a parse tree which can then
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 be operated upon further."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
035 (i/parser
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
036 (str
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ;; top level: we accept mexprs as well as sexprs.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 "expr := mexpr | sexpr;"
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
039
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 ;; but it's a convenience.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 "mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 λexpr := λ lsqb bindings semi-colon body rsqb;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 λ := 'λ';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 bindings := lsqb args rsqb;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 body := (expr semi-colon opt-space)* expr;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 fncall := fn-name lsqb args rsqb;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 lsqb := '[';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 rsqb := ']';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 defn := mexpr opt-space '=' opt-space mexpr;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 cond := lsqb (cond-clause semi-colon opt-space)* cond-clause rsqb;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 cond-clause := expr opt-space arrow opt-space expr;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 arrow := '->';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 args := (expr semi-colon opt-space)* expr;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 fn-name := mvar;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
056 mvar := #'[a-z]+';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 semi-colon := ';';"
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
058
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 ;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 "comment := opt-space <';;'> #'[^\\n\\r]*';"
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
061
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 ;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 ;; but I've included it on the basis that it can do little harm.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 "sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 dotted-pair := lpar dot-terminal ;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 dot := '.';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
068 lpar := '(';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 rpar := ')';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 quoted-expr := quote sexpr;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
071 quote := '\\'';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 dot-terminal := sexpr space dot space sexpr rpar;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
073 space := #'\\p{javaWhitespace}+';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
074 opt-space := #'\\p{javaWhitespace}*';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
075 sep := ',' | opt-space;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 atom := #'[A-Z][A-Z0-9]*';"
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
077
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 ;; Lisp 1.5 supported octal as well as decimal and scientific notation
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 "number := integer | decimal | scientific | octal;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
080 integer := #'-?[1-9][0-9]*';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
081 decimal := #'-?[1-9][0-9]*\\.?[0-9]*' | #'0.[0-9]*';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
082 scientific := coefficient e exponent;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 coefficient := decimal;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 exponent := integer;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
085 e := 'E';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
086 octal := #'[+-]?[0-7]+{1,12}' q scale-factor;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
087 q := 'Q';
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 scale-factor := #'[0-9]*'")))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
089
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
090 (defn simplify
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 "Simplify this parse tree `p`. If `p` is an instaparse failure object, throw
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 an `ex-info`, with `p` as the value of its `:failure` key."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
093 ([p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
094 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
095 (instance? instaparse.gll.Failure p)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
096 (throw (ex-info "Ic ne behæfd" {:cause :parse-failure :failure p}))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
097 (simplify p :sexpr)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
098 ([p context]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
099 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
100 (coll? p)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
101 (apply
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
102 vector
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
103 (remove
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
104 #(if (coll? %) (empty? %))
|
||||
</span><br/>
|
||||
<span class="partial" title="17 out of 18 forms covered">
|
||||
105 (case (first p)
|
||||
</span><br/>
|
||||
<span class="partial" title="30 out of 36 forms covered">
|
||||
106 (:arg :expr :coefficient :fn-name :number :sexpr) (simplify (second p) context)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
107 (:λexpr
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
108 :args :bindings :body :cond :cond-clause :dot-terminal
|
||||
</span><br/>
|
||||
<span class="partial" title="80 out of 88 forms covered">
|
||||
109 :fncall :octal :quoted-expr :scientific) (map #(simplify % context) p)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
110 (:arrow :dot :e :lpar :lsqb :opt-space :q :quote :rpar :rsqb
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
111 :semi-colon :sep :space) nil
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
112 :atom (if
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
113 (= context :mexpr)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
114 [:quoted-expr p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
115 p)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
116 :comment (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
117 (:strict *options*)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
118 (throw
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
119 (ex-info "Cannot parse comments in strict mode"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
120 {:cause :strict})))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
121 :dotted-pair (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
122 (= context :mexpr)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
123 [:fncall
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
124 [:mvar "cons"]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
125 [:args
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
126 (simplify (nth p 1) context)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
127 (simplify (nth p 2) context)]]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
128 (map simplify p))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
129 :mexpr (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
130 (:strict *options*)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
131 (throw
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
132 (ex-info "Cannot parse meta expressions in strict mode"
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
133 {:cause :strict}))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
134 (simplify (second p) :mexpr))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
135 :list (if
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
136 (= context :mexpr)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
137 [:fncall
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
138 [:mvar "list"]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
139 [:args (apply vector (map simplify (rest p)))]]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
140 (map #(simplify % context) p))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 ;;default
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
142 p)))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
143 p)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
144
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
145
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
146 ;; # From Lisp 1.5 Programmers Manual, page 10
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
147 ;; Note that I've retyped much of this, since copy/pasting out of PDF is less
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
148 ;; than reliable. Any typos are mine. Quote starts [[
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
149
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
150 ;; We are now in a position to define the universal LISP function
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
151 ;; evalquote[fn;args], When evalquote is given a function and a list of arguments
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
152 ;; for that function, it computes the value of the function applied to the arguments.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
153 ;; LISP functions have S-expressions as arguments. In particular, the argument "fn"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
154 ;; of the function evalquote must be an S-expression. Since we have been
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
155 ;; writing functions as M-expressions, it is necessary to translate them into
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
156 ;; S-expressions.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
157
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
158 ;; The following rules define a method of translating functions written in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
159 ;; meta-language into S-expressions.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
160 ;; 1. If the function is represented by its name, it is translated by changing
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
161 ;; all of the letters to upper case, making it an atomic symbol. Thus is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
162 ;; translated to CAR.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
163 ;; 2. If the function uses the lambda notation, then the expression
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
164 ;; λ[[x ..;xn]; ε] is translated into (LAMBDA (X1 ...XN) ε*), where ε* is the translation
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
165 ;; of ε.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
166 ;; 3. If the function begins with label, then the translation of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
167 ;; label[α;ε] is (LABEL α* ε*).
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
168
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
169 ;; Forms are translated as follows:
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
170 ;; 1. A variable, like a function name, is translated by using uppercase letters.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
171 ;; Thus the translation of varl is VAR1.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
172 ;; 2. The obvious translation of letting a constant translate into itself will not
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
173 ;; work. Since the translation of x is X, the translation of X must be something
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
174 ;; else to avoid ambiguity. The solution is to quote it. Thus X is translated
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
175 ;; into (QUOTE X).
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
176 ;; 3. The form fn[argl;. ..;argn] is translated into (fn* argl* ...argn*)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
177 ;; 4. The conditional expression [pl-el;...;pn-en] is translated into
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
178 ;; (COND (p1* e1*)...(pn* en*))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
179
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
180 ;; ## Examples
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
181
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
182 ;; M-expressions S-expressions
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
183 ;; x X
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
184 ;; car CAR
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
185 ;; car[x] (CAR X)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
186 ;; T (QUOTE T)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
187 ;; ff[car [x]] (FF (CAR X))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
188 ;; [atom[x]->x; T->ff[car[x]]] (COND ((ATOM X) X)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
189 ;; ((QUOTE T)(FF (CAR X))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
190 ;; label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]] (LABEL FF (LAMBDA (X) (COND
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
191 ;; ((ATOM X) X)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
192 ;; ((QUOTE T)(FF (CAR X))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
193
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
194 ;; ]] quote ends
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
195
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
196 (defn gen-cond-clause
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
197 "Generate a cond clause from this simplified parse tree fragment `p`;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
198 returns `nil` if `p` does not represent a cond clause."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
199 [p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
200 (if
|
||||
</span><br/>
|
||||
<span class="partial" title="12 out of 13 forms covered">
|
||||
201 (and (coll? p)(= :cond-clause (first p)))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
202 (make-beowulf-list
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
203 (list (generate (nth p 1))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
204 (generate (nth p 2))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
205
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
206 (defn gen-cond
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
207 "Generate a cond statement from this simplified parse tree fragment `p`;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
208 returns `nil` if `p` does not represent a (MEXPR) cond statement."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
209 [p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
210 (if
|
||||
</span><br/>
|
||||
<span class="partial" title="12 out of 13 forms covered">
|
||||
211 (and (coll? p)(= :cond (first p)))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
212 (make-beowulf-list
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
213 (cons
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
214 'COND
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
215 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
216 gen-cond-clause
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
217 (rest p))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
218
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
219 (defn gen-fn-call
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
220 "Generate a function call from this simplified parse tree fragment `p`;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
221 returns `nil` if `p` does not represent a (MEXPR) function call."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
222 [p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
223 (if
|
||||
</span><br/>
|
||||
<span class="partial" title="23 out of 25 forms covered">
|
||||
224 (and (coll? p)(= :fncall (first p))(= :mvar (first (second p))))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
225 (make-cons-cell
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
226 (generate (second p))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
227 (generate (nth p 2)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
228
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
229
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
230 (defn gen-dot-terminated-list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
231 "Generate a list, which may be dot-terminated, from this partial parse tree
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
232 'p'. Note that the function acts recursively and progressively decapitates
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
233 its argument, so that the argument will not always be a valid parse tree."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
234 [p]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
235 (cond
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
236 (empty? p)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
237 NIL
|
||||
</span><br/>
|
||||
<span class="partial" title="16 out of 17 forms covered">
|
||||
238 (and (coll? (first p)) (= :dot-terminal (first (first p))))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
239 (let [dt (first p)]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
240 (make-cons-cell
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
241 (generate (nth dt 1))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
242 (generate (nth dt 2))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
243 :else
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
244 (make-cons-cell
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
245 (generate (first p))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
246 (gen-dot-terminated-list (rest p)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
247
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
248
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
249 (defn strip-leading-zeros
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
250 "`read-string` interprets strings with leading zeros as octal; strip
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
251 any from this string `s`. If what's left is empty (i.e. there were
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
252 only zeros, return `\"0\"`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
253 ([s]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
254 (strip-leading-zeros s ""))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
255 ([s prefix]
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 2 forms covered">
|
||||
256 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
257 (empty? s) "0"
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
258 (case (first s)
|
||||
</span><br/>
|
||||
<span class="partial" title="12 out of 24 forms covered">
|
||||
259 (\+ \-)(strip-leading-zeros (subs s 1) (str (first s) prefix))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
260 "0" (strip-leading-zeros (subs s 1) prefix)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
261 (str prefix s)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
262
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
263 (defn generate
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
264 "Generate lisp structure from this parse tree `p`. It is assumed that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
265 `p` has been simplified."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
266 [p]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
267 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
268 (coll? p)
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
269 (case (first p)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
270 :λ "LAMBDA"
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
271 :λexpr (make-cons-cell
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
272 (generate (nth p 1))
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
273 (make-cons-cell (generate (nth p 2))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
274 (generate (nth p 3))))
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
275 (:args :list) (gen-dot-terminated-list (rest p))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
276 :atom (symbol (second p))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
277 :bindings (generate (second p))
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
278 :body (make-beowulf-list (map generate (rest p)))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
279 :cond (gen-cond p)
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
280 (:decimal :integer) (read-string (strip-leading-zeros (second p)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
281 :dotted-pair (make-cons-cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
282 (generate (nth p 1))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
283 (generate (nth p 2)))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
284 :exponent (generate (second p))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
285 :fncall (gen-fn-call p)
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
286 :mvar (symbol (upper-case (second p)))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
287 :octal (let [n (read-string (strip-leading-zeros (second p) "0"))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
288 scale (generate (nth p 2))]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
289 (* n (expt 8 scale)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
290
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
291 ;; the quote read macro (which probably didn't exist in Lisp 1.5, but...)
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
292 :quoted-expr (make-beowulf-list (list 'QUOTE (generate (second p))))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
293 :scale-factor (if
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
294 (empty? (second p)) 0
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
295 (read-string (strip-leading-zeros (second p))))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
296 :scientific (let [n (generate (second p))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
297 exponent (generate (nth p 2))]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
298 (* n (expt 10 exponent)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
299
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
300 ;; default
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
301 (throw (Exception. (str "Cannot yet generate " (first p)))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
302 p))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
303
|
||||
</span><br/>
|
||||
<span class="covered" title="40 out of 40 forms covered">
|
||||
304 (defmacro gsp
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
305 "Shortcut macro - the internals of read; or, if you like, read-string.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
306 Argument `s` should be a string representation of a valid Lisp
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
307 expression."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
308 [s]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
309 `(generate (simplify (parse ~s))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
310
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
311 (defn READ
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
312 "An implementation of a Lisp reader sufficient for bootstrapping; not necessarily
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
313 the final Lisp reader."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
314 [input]
|
||||
</span><br/>
|
||||
<span class="partial" title="8 out of 10 forms covered">
|
||||
315 (gsp (or input (read-line))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
40
docs/cloverage/coverage.css
Normal file
40
docs/cloverage/coverage.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
.covered {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: #558B55;
|
||||
}
|
||||
|
||||
.not-covered {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.partial {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.not-tracked {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
}
|
||||
|
||||
.blank {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
td.with-bar {
|
||||
width: 250px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.with-number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td.ns-name {
|
||||
min-width: 150px;
|
||||
padding-right: 25px;
|
||||
}
|
104
docs/cloverage/index.html
Normal file
104
docs/cloverage/index.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./coverage.css"/>
|
||||
<title>Coverage Summary</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<td class="ns-name"> Namespace </td>
|
||||
<td class="with-bar"> Forms </td>
|
||||
<td class="with-number">Forms %</td>
|
||||
<td class="with-bar"> Lines </td>
|
||||
<td class="with-number">Lines %</td>
|
||||
<td class="with-number">Total</td><td class="with-number">Blank</td><td class="with-number">Instrumented</td>
|
||||
</tr></thead>
|
||||
<tr>
|
||||
<td><a href="beowulf/bootstrap.clj.html">beowulf.bootstrap</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:67.4439461883408%;
|
||||
float:left;"> 752 </div><div class="not-covered"
|
||||
style="width:32.55605381165919%;
|
||||
float:left;"> 363 </div></td>
|
||||
<td class="with-number">67.44 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:58.52272727272727%;
|
||||
float:left;"> 103 </div><div class="partial"
|
||||
style="width:23.295454545454547%;
|
||||
float:left;"> 41 </div><div class="not-covered"
|
||||
style="width:18.181818181818183%;
|
||||
float:left;"> 32 </div></td>
|
||||
<td class="with-number">81.82 %</td>
|
||||
<td class="with-number">338</td><td class="with-number">40</td><td class="with-number">176</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="beowulf/cons_cell.clj.html">beowulf.cons-cell</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:56.82819383259912%;
|
||||
float:left;"> 129 </div><div class="not-covered"
|
||||
style="width:43.17180616740088%;
|
||||
float:left;"> 98 </div></td>
|
||||
<td class="with-number">56.83 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:57.35294117647059%;
|
||||
float:left;"> 39 </div><div class="partial"
|
||||
style="width:4.411764705882353%;
|
||||
float:left;"> 3 </div><div class="not-covered"
|
||||
style="width:38.23529411764706%;
|
||||
float:left;"> 26 </div></td>
|
||||
<td class="with-number">61.76 %</td>
|
||||
<td class="with-number">156</td><td class="with-number">15</td><td class="with-number">68</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="beowulf/core.clj.html">beowulf.core</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:90.9090909090909%;
|
||||
float:left;"> 170 </div><div class="not-covered"
|
||||
style="width:9.090909090909092%;
|
||||
float:left;"> 17 </div></td>
|
||||
<td class="with-number">90.91 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:87.75510204081633%;
|
||||
float:left;"> 43 </div><div class="partial"
|
||||
style="width:2.0408163265306123%;
|
||||
float:left;"> 1 </div><div class="not-covered"
|
||||
style="width:10.204081632653061%;
|
||||
float:left;"> 5 </div></td>
|
||||
<td class="with-number">89.80 %</td>
|
||||
<td class="with-number">80</td><td class="with-number">3</td><td class="with-number">49</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="beowulf/host.clj.html">beowulf.host</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 1 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 1 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">5</td><td class="with-number">1</td><td class="with-number">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="beowulf/read.clj.html">beowulf.read</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:81.8941504178273%;
|
||||
float:left;"> 588 </div><div class="not-covered"
|
||||
style="width:18.105849582172702%;
|
||||
float:left;"> 130 </div></td>
|
||||
<td class="with-number">81.89 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:73.80952380952381%;
|
||||
float:left;"> 93 </div><div class="partial"
|
||||
style="width:7.936507936507937%;
|
||||
float:left;"> 10 </div><div class="not-covered"
|
||||
style="width:18.253968253968253%;
|
||||
float:left;"> 23 </div></td>
|
||||
<td class="with-number">81.75 %</td>
|
||||
<td class="with-number">315</td><td class="with-number">31</td><td class="with-number">126</td>
|
||||
</tr>
|
||||
<tr><td>Totals:</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">72.95 %</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">79.52 %</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
12
docs/codox/beowulf.bootstrap.html
Normal file
12
docs/codox/beowulf.bootstrap.html
Normal file
File diff suppressed because one or more lines are too long
3
docs/codox/beowulf.cons-cell.html
Normal file
3
docs/codox/beowulf.cons-cell.html
Normal file
File diff suppressed because one or more lines are too long
3
docs/codox/beowulf.core.html
Normal file
3
docs/codox/beowulf.core.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>beowulf.core documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Beowulf</span> <span class="project-version">0.2.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to beowulf</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>beowulf</span></div></div></li><li class="depth-2 branch"><a href="beowulf.bootstrap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>bootstrap</span></div></a></li><li class="depth-2 branch"><a href="beowulf.cons-cell.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>cons-cell</span></div></a></li><li class="depth-2 branch current"><a href="beowulf.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="beowulf.host.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>host</span></div></a></li><li class="depth-2"><a href="beowulf.read.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="beowulf.core.html#var--main"><div class="inner"><span>-main</span></div></a></li><li class="depth-1"><a href="beowulf.core.html#var-cli-options"><div class="inner"><span>cli-options</span></div></a></li><li class="depth-1"><a href="beowulf.core.html#var-repl"><div class="inner"><span>repl</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.core</h1><div class="doc"><div class="markdown"><p>Essentially, the <code>-main</code> function and the bootstrap read-eval-print loop.</p></div></div><div class="public anchor" id="var--main"><h3>-main</h3><div class="usage"><code>(-main & opts)</code></div><div class="doc"><div class="markdown"><p>Parse options, print the banner, read the init file if any, and enter the read/eval/print loop.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/core.clj#L50">view source</a></div></div><div class="public anchor" id="var-cli-options"><h3>cli-options</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/core.clj#L11">view source</a></div></div><div class="public anchor" id="var-repl"><h3>repl</h3><div class="usage"><code>(repl prompt)</code></div><div class="doc"><div class="markdown"><p>Read/eval/print loop.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/core.clj#L23">view source</a></div></div></div></body></html>
|
3
docs/codox/beowulf.host.html
Normal file
3
docs/codox/beowulf.host.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>beowulf.host documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Beowulf</span> <span class="project-version">0.2.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to beowulf</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>beowulf</span></div></div></li><li class="depth-2 branch"><a href="beowulf.bootstrap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>bootstrap</span></div></a></li><li class="depth-2 branch"><a href="beowulf.cons-cell.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>cons-cell</span></div></a></li><li class="depth-2 branch"><a href="beowulf.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch current"><a href="beowulf.host.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>host</span></div></a></li><li class="depth-2"><a href="beowulf.read.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.host</h1><div class="doc"><div class="markdown"><p>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.</p></div></div></div></body></html>
|
9
docs/codox/beowulf.read.html
Normal file
9
docs/codox/beowulf.read.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>beowulf.read documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Beowulf</span> <span class="project-version">0.2.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to beowulf</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>beowulf</span></div></div></li><li class="depth-2 branch"><a href="beowulf.bootstrap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>bootstrap</span></div></a></li><li class="depth-2 branch"><a href="beowulf.cons-cell.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>cons-cell</span></div></a></li><li class="depth-2 branch"><a href="beowulf.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="beowulf.host.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>host</span></div></a></li><li class="depth-2 current"><a href="beowulf.read.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="beowulf.read.html#var-gen-cond"><div class="inner"><span>gen-cond</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-gen-cond-clause"><div class="inner"><span>gen-cond-clause</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-gen-dot-terminated-list"><div class="inner"><span>gen-dot-terminated-list</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-gen-fn-call"><div class="inner"><span>gen-fn-call</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-generate"><div class="inner"><span>generate</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-gsp"><div class="inner"><span>gsp</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-parse"><div class="inner"><span>parse</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-READ"><div class="inner"><span>READ</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-simplify"><div class="inner"><span>simplify</span></div></a></li><li class="depth-1"><a href="beowulf.read.html#var-strip-leading-zeros"><div class="inner"><span>strip-leading-zeros</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.read</h1><div class="doc"><div class="markdown"><p>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.</p>
|
||||
<p>Intended deviations from the behaviour of the real Lisp reader are as follows:</p>
|
||||
<ol>
|
||||
<li>It reads the meta-expression language <code>MEXPR</code> in addition to the symbolic expression language <code>SEXPR</code>, which I do not believe the Lisp 1.5 reader ever did;</li>
|
||||
<li>It treats everything between a semi-colon and an end of line as a comment, as most modern Lisps do; but I do not believe Lisp 1.5 had this feature.</li>
|
||||
</ol>
|
||||
<p>Both these extensions can be disabled by using the <code>--strict</code> command line switch.</p></div></div><div class="public anchor" id="var-gen-cond"><h3>gen-cond</h3><div class="usage"><code>(gen-cond p)</code></div><div class="doc"><div class="markdown"><p>Generate a cond statement from this simplified parse tree fragment <code>p</code>; returns <code>nil</code> if <code>p</code> does not represent a (MEXPR) cond statement.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L206">view source</a></div></div><div class="public anchor" id="var-gen-cond-clause"><h3>gen-cond-clause</h3><div class="usage"><code>(gen-cond-clause p)</code></div><div class="doc"><div class="markdown"><p>Generate a cond clause from this simplified parse tree fragment <code>p</code>; returns <code>nil</code> if <code>p</code> does not represent a cond clause.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L196">view source</a></div></div><div class="public anchor" id="var-gen-dot-terminated-list"><h3>gen-dot-terminated-list</h3><div class="usage"><code>(gen-dot-terminated-list p)</code></div><div class="doc"><div class="markdown"><p>Generate a list, which may be dot-terminated, from this partial parse tree ‘p’. Note that the function acts recursively and progressively decapitates its argument, so that the argument will not always be a valid parse tree.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L230">view source</a></div></div><div class="public anchor" id="var-gen-fn-call"><h3>gen-fn-call</h3><div class="usage"><code>(gen-fn-call p)</code></div><div class="doc"><div class="markdown"><p>Generate a function call from this simplified parse tree fragment <code>p</code>; returns <code>nil</code> if <code>p</code> does not represent a (MEXPR) function call.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L219">view source</a></div></div><div class="public anchor" id="var-generate"><h3>generate</h3><div class="usage"><code>(generate p)</code></div><div class="doc"><div class="markdown"><p>Generate lisp structure from this parse tree <code>p</code>. It is assumed that <code>p</code> has been simplified.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L263">view source</a></div></div><div class="public anchor" id="var-gsp"><h3>gsp</h3><h4 class="type">macro</h4><div class="usage"><code>(gsp s)</code></div><div class="doc"><div class="markdown"><p>Shortcut macro - the internals of read; or, if you like, read-string. Argument <code>s</code> should be a string representation of a valid Lisp expression.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L304">view source</a></div></div><div class="public anchor" id="var-parse"><h3>parse</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>Parse a string presented as argument into a parse tree which can then be operated upon further.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L32">view source</a></div></div><div class="public anchor" id="var-READ"><h3>READ</h3><div class="usage"><code>(READ input)</code></div><div class="doc"><div class="markdown"><p>An implementation of a Lisp reader sufficient for bootstrapping; not necessarily the final Lisp reader.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L311">view source</a></div></div><div class="public anchor" id="var-simplify"><h3>simplify</h3><div class="usage"><code>(simplify p)</code><code>(simplify p context)</code></div><div class="doc"><div class="markdown"><p>Simplify this parse tree <code>p</code>. If <code>p</code> is an instaparse failure object, throw an <code>ex-info</code>, with <code>p</code> as the value of its <code>:failure</code> key.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L90">view source</a></div></div><div class="public anchor" id="var-strip-leading-zeros"><h3>strip-leading-zeros</h3><div class="usage"><code>(strip-leading-zeros s)</code><code>(strip-leading-zeros s prefix)</code></div><div class="doc"><div class="markdown"><p><code>read-string</code> interprets strings with leading zeros as octal; strip any from this string <code>s</code>. If what’s left is empty (i.e. there were only zeros, return <code>"0"</code>.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/read.clj#L249">view source</a></div></div></div></body></html>
|
551
docs/codox/css/default.css
Normal file
551
docs/codox/css/default.css
Normal file
|
@ -0,0 +1,551 @@
|
|||
body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
|
||||
font-size: 9pt;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 29px;
|
||||
margin: 10px 0 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
h5.license {
|
||||
margin: 9px 0 22px 0;
|
||||
color: #555;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.document h1, .namespace-index h1 {
|
||||
font-size: 32px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#header, #content, .sidebar {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#header {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 22px;
|
||||
color: #f5f5f5;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
#content {
|
||||
top: 32px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.sidebar.primary {
|
||||
background: #e2e2e2;
|
||||
border-right: solid 1px #cccccc;
|
||||
left: 0;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.sidebar.secondary {
|
||||
background: #f2f2f2;
|
||||
border-right: solid 1px #d7d7d7;
|
||||
left: 251px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#content.namespace-index, #content.document {
|
||||
left: 251px;
|
||||
}
|
||||
|
||||
#content.namespace-docs {
|
||||
left: 452px;
|
||||
}
|
||||
|
||||
#content.document {
|
||||
padding-bottom: 10%;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #3f3f3f;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 18px;
|
||||
font-weight: lighter;
|
||||
text-shadow: -1px -1px 0px #333;
|
||||
}
|
||||
|
||||
#header h1 .project-version {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.project-version {
|
||||
padding-left: 0.15em;
|
||||
}
|
||||
|
||||
#header a, .sidebar a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#header a {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#header h2 {
|
||||
float: right;
|
||||
font-size: 9pt;
|
||||
font-weight: normal;
|
||||
margin: 4px 3px;
|
||||
padding: 0;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#header h2 a {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.sidebar h3 {
|
||||
margin: 0;
|
||||
padding: 10px 13px 0 13px;
|
||||
font-size: 19px;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
.sidebar h3 a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.sidebar h3.no-link {
|
||||
color: #636363;
|
||||
}
|
||||
|
||||
.sidebar ul {
|
||||
padding: 7px 0 6px 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar ul.index-link {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.sidebar li {
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.sidebar li a, .sidebar li .no-link {
|
||||
border-left: 3px solid transparent;
|
||||
padding: 0 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar li .no-link {
|
||||
display: block;
|
||||
color: #777;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sidebar li .inner {
|
||||
display: inline-block;
|
||||
padding-top: 7px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.sidebar li a, .sidebar li .tree {
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
.depth-1 .inner { padding-left: 2px; }
|
||||
.depth-2 .inner { padding-left: 6px; }
|
||||
.depth-3 .inner { padding-left: 20px; }
|
||||
.depth-4 .inner { padding-left: 34px; }
|
||||
.depth-5 .inner { padding-left: 48px; }
|
||||
.depth-6 .inner { padding-left: 62px; }
|
||||
|
||||
.sidebar li .tree {
|
||||
display: block;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
margin: 0 4px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar li.depth-1 .tree {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar li .tree .top, .sidebar li .tree .bottom {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
.sidebar li .tree .top {
|
||||
border-left: 1px solid #aaa;
|
||||
border-bottom: 1px solid #aaa;
|
||||
height: 19px;
|
||||
}
|
||||
|
||||
.sidebar li .tree .bottom {
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.sidebar li.branch .tree .bottom {
|
||||
border-left: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.sidebar.primary li.current a {
|
||||
border-left: 3px solid #a33;
|
||||
color: #a33;
|
||||
}
|
||||
|
||||
.sidebar.secondary li.current a {
|
||||
border-left: 3px solid #33a;
|
||||
color: #33a;
|
||||
}
|
||||
|
||||
.namespace-index h2 {
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
|
||||
.namespace-index h3 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.namespace-index .topics {
|
||||
padding-left: 30px;
|
||||
margin: 11px 0 0 0;
|
||||
}
|
||||
|
||||
.namespace-index .topics li {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.namespace-docs h3 {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.public h3 {
|
||||
margin: 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.usage {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.public {
|
||||
margin: 0;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
padding-top: 14px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.public:last-child {
|
||||
margin-bottom: 20%;
|
||||
}
|
||||
|
||||
.members .public:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.members {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.members h4 {
|
||||
color: #555;
|
||||
font-weight: normal;
|
||||
font-variant: small-caps;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.members .inner {
|
||||
padding-top: 5px;
|
||||
padding-left: 12px;
|
||||
margin-top: 2px;
|
||||
margin-left: 7px;
|
||||
border-left: 1px solid #bbb;
|
||||
}
|
||||
|
||||
#content .members .inner h3 {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.members .public {
|
||||
border-top: none;
|
||||
margin-top: 0;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.members .public:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
h4.type,
|
||||
h4.dynamic,
|
||||
h4.added,
|
||||
h4.deprecated {
|
||||
float: left;
|
||||
margin: 3px 10px 15px 0;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
.public h4.type,
|
||||
.public h4.dynamic,
|
||||
.public h4.added,
|
||||
.public h4.deprecated {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
margin: 3px 0 0 10px;
|
||||
}
|
||||
|
||||
.members h4.type,
|
||||
.members h4.added,
|
||||
.members h4.deprecated {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
h4.type {
|
||||
color: #717171;
|
||||
}
|
||||
|
||||
h4.dynamic {
|
||||
color: #9933aa;
|
||||
}
|
||||
|
||||
h4.added {
|
||||
color: #508820;
|
||||
}
|
||||
|
||||
h4.deprecated {
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.namespace:last-child {
|
||||
margin-bottom: 10%;
|
||||
}
|
||||
|
||||
.index {
|
||||
padding: 0;
|
||||
font-size: 80%;
|
||||
margin: 15px 0;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.index * {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.index p {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.index li {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.index ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.type-sig {
|
||||
clear: both;
|
||||
color: #088;
|
||||
}
|
||||
|
||||
.type-sig pre {
|
||||
padding-top: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.usage code {
|
||||
display: block;
|
||||
color: #008;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.usage code:first-child {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.public p:first-child, .public pre.plaintext {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.doc {
|
||||
margin: 0 0 26px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.public .doc {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.namespace-index .doc {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.namespace-index .namespace .doc {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.markdown li {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-weight: normal;
|
||||
font-size: 25px;
|
||||
margin: 30px 0 10px 0;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 15px;
|
||||
margin: 22px 0 -4px 0;
|
||||
}
|
||||
|
||||
.doc, .public, .namespace .index {
|
||||
max-width: 680px;
|
||||
overflow-x: visible;
|
||||
}
|
||||
|
||||
.markdown pre > code {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.markdown pre > code, .src-link a {
|
||||
border: 1px solid #e4e4e4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.markdown code:not(.hljs), .src-link a {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
pre.deps {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
border: 1px solid #e4e4e4;
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
border-style: solid;
|
||||
border-top: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.doc ul, .doc ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.doc table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.doc table td, .doc table th {
|
||||
border: 1px solid #dddddd;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
.doc table th {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.doc dl {
|
||||
margin: 0 10px 20px 10px;
|
||||
}
|
||||
|
||||
.doc dl dt {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.doc dl dd {
|
||||
padding: 5px 0;
|
||||
margin: 0 0 5px 10px;
|
||||
}
|
||||
|
||||
.doc abbr {
|
||||
border-bottom: 1px dotted #333;
|
||||
font-variant: none;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.src-link {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.src-link a {
|
||||
font-size: 70%;
|
||||
padding: 1px 4px;
|
||||
text-decoration: none;
|
||||
color: #5555bb;
|
||||
}
|
97
docs/codox/css/highlight.css
Normal file
97
docs/codox/css/highlight.css
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-subst {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-literal,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-tag .hljs-attr {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-doctag {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section,
|
||||
.hljs-selector-id {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-type,
|
||||
.hljs-class .hljs-title {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-name,
|
||||
.hljs-attribute {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-link {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.hljs-bullet {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-builtin-name {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-meta {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
3
docs/codox/index.html
Normal file
3
docs/codox/index.html
Normal file
File diff suppressed because one or more lines are too long
4
docs/codox/intro.html
Normal file
4
docs/codox/intro.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>Introduction to beowulf</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Beowulf</span> <span class="project-version">0.2.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>Introduction to beowulf</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>beowulf</span></div></div></li><li class="depth-2 branch"><a href="beowulf.bootstrap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>bootstrap</span></div></a></li><li class="depth-2 branch"><a href="beowulf.cons-cell.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>cons-cell</span></div></a></li><li class="depth-2 branch"><a href="beowulf.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="beowulf.host.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>host</span></div></a></li><li class="depth-2"><a href="beowulf.read.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#introduction-to-beowulf" name="introduction-to-beowulf"></a>Introduction to beowulf</h1>
|
||||
<p>TODO: write <a href="http://jacobian.org/writing/what-to-write/">great documentation</a></p></div></div></div></body></html>
|
2
docs/codox/js/highlight.min.js
vendored
Normal file
2
docs/codox/js/highlight.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
docs/codox/js/jquery.min.js
vendored
Normal file
4
docs/codox/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
112
docs/codox/js/page_effects.js
Normal file
112
docs/codox/js/page_effects.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
function visibleInParent(element) {
|
||||
var position = $(element).position().top
|
||||
return position > -50 && position < ($(element).offsetParent().height() - 50)
|
||||
}
|
||||
|
||||
function hasFragment(link, fragment) {
|
||||
return $(link).attr("href").indexOf("#" + fragment) != -1
|
||||
}
|
||||
|
||||
function findLinkByFragment(elements, fragment) {
|
||||
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
|
||||
}
|
||||
|
||||
function scrollToCurrentVarLink(elements) {
|
||||
var elements = $(elements);
|
||||
var parent = elements.offsetParent();
|
||||
|
||||
if (elements.length == 0) return;
|
||||
|
||||
var top = elements.first().position().top;
|
||||
var bottom = elements.last().position().top + elements.last().height();
|
||||
|
||||
if (top >= 0 && bottom <= parent.height()) return;
|
||||
|
||||
if (top < 0) {
|
||||
parent.scrollTop(parent.scrollTop() + top);
|
||||
}
|
||||
else if (bottom > parent.height()) {
|
||||
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
|
||||
}
|
||||
}
|
||||
|
||||
function setCurrentVarLink() {
|
||||
$('.secondary a').parent().removeClass('current')
|
||||
$('.anchor').
|
||||
filter(function(index) { return visibleInParent(this) }).
|
||||
each(function(index, element) {
|
||||
findLinkByFragment(".secondary a", element.id).
|
||||
parent().
|
||||
addClass('current')
|
||||
});
|
||||
scrollToCurrentVarLink('.secondary .current');
|
||||
}
|
||||
|
||||
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
|
||||
|
||||
function scrollPositionId(element) {
|
||||
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
|
||||
return 'scroll::' + $(element).attr('id') + '::' + directory
|
||||
}
|
||||
|
||||
function storeScrollPosition(element) {
|
||||
if (!hasStorage) return;
|
||||
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
|
||||
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
|
||||
}
|
||||
|
||||
function recallScrollPosition(element) {
|
||||
if (!hasStorage) return;
|
||||
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
|
||||
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
|
||||
}
|
||||
|
||||
function persistScrollPosition(element) {
|
||||
recallScrollPosition(element)
|
||||
$(element).scroll(function() { storeScrollPosition(element) })
|
||||
}
|
||||
|
||||
function sidebarContentWidth(element) {
|
||||
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
|
||||
return Math.max.apply(Math, widths)
|
||||
}
|
||||
|
||||
function calculateSize(width, snap, margin, minimum) {
|
||||
if (width == 0) {
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
|
||||
}
|
||||
}
|
||||
|
||||
function resizeSidebars() {
|
||||
var primaryWidth = sidebarContentWidth('.primary')
|
||||
var secondaryWidth = 0
|
||||
|
||||
if ($('.secondary').length != 0) {
|
||||
secondaryWidth = sidebarContentWidth('.secondary')
|
||||
}
|
||||
|
||||
// snap to grid
|
||||
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
|
||||
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
|
||||
|
||||
$('.primary').css('width', primaryWidth)
|
||||
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
|
||||
|
||||
if (secondaryWidth > 0) {
|
||||
$('#content').css('left', primaryWidth + secondaryWidth + 2)
|
||||
}
|
||||
else {
|
||||
$('#content').css('left', primaryWidth + 1)
|
||||
}
|
||||
}
|
||||
|
||||
$(window).ready(resizeSidebars)
|
||||
$(window).ready(setCurrentVarLink)
|
||||
$(window).ready(function() { persistScrollPosition('.primary')})
|
||||
$(window).ready(function() {
|
||||
$('#content').scroll(setCurrentVarLink)
|
||||
$(window).resize(setCurrentVarLink)
|
||||
})
|
30
project.clj
30
project.clj
|
@ -1,14 +1,34 @@
|
|||
(defproject beowulf "0.1.0-SNAPSHOT"
|
||||
(defproject beowulf "0.2.1-SNAPSHOT"
|
||||
:cloverage {:output "docs/cloverage"}
|
||||
:codox {:metadata {:doc "**TODO**: write docs"
|
||||
:doc/format :markdown}
|
||||
:output-path "docs/codox"
|
||||
:source-uri "https://github.com/simon-brooke/beowulf/blob/master/{filepath}#L{line}"}
|
||||
:description "An implementation of LISP 1.5 in Clojure"
|
||||
:url "http://example.com/FIXME"
|
||||
:license {:name "GPL-2.0-or-later"
|
||||
:url "https://www.eclipse.org/legal/epl-2.0/"}
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
:dependencies [[org.clojure/clojure "1.8.0"]
|
||||
[org.clojure/math.numeric-tower "0.0.4"]
|
||||
[org.clojure/tools.cli "0.4.2"]
|
||||
[org.clojure/tools.trace "0.7.10"]
|
||||
[environ "1.1.0"]
|
||||
[instaparse "1.4.10"]]
|
||||
:main ^:skip-aot beowulf.core
|
||||
:plugins [[lein-environ "1.1.0"]]
|
||||
:plugins [[lein-cloverage "1.1.1"]
|
||||
[lein-codox "0.10.7"]
|
||||
[lein-environ "1.1.0"]]
|
||||
:profiles {:uberjar {:aot :all}}
|
||||
:release-tasks [["vcs" "assert-committed"]
|
||||
["change" "version" "leiningen.release/bump-version" "release"]
|
||||
["vcs" "commit"]
|
||||
["vcs" "tag" "v." "--no-sign"]
|
||||
["clean"]
|
||||
["codox"]
|
||||
["cloverage"]
|
||||
["uberjar"]
|
||||
["change" "version" "leiningen.release/bump-version"]
|
||||
["vcs" "commit"]]
|
||||
|
||||
:target-path "target/%s"
|
||||
:profiles {:uberjar {:aot :all}})
|
||||
:url "https://github.com/simon-brooke/the-great-game"
|
||||
)
|
||||
|
|
0
resources/lisp1.5.lsp
Normal file
0
resources/lisp1.5.lsp
Normal file
|
@ -1,30 +1,55 @@
|
|||
(ns beowulf.eval
|
||||
(ns beowulf.bootstrap
|
||||
"Lisp as defined in Chapter 1 (pages 1-14) of the
|
||||
`Lisp 1.5 Programmer's Manual`; that is to say, a very simple Lisp language,
|
||||
which should, I believe, be sufficient in conjunction with the functions
|
||||
provided by `beowulf.host`, be sufficient to bootstrap the full Lisp 1.5
|
||||
interpreter..
|
||||
|
||||
The convention is adopted that functions in this file with names in
|
||||
ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that
|
||||
therefore all arguments must be numbers, symbols or `beowulf.cons_cell.ConsCell`
|
||||
objects."
|
||||
(:require [clojure.tools.trace :refer :all]
|
||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;
|
||||
;;; This file is essentially 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.
|
||||
;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(declare EVAL)
|
||||
|
||||
(def oblist
|
||||
"The default environment; modified certainly be `LABEL` (which seems to
|
||||
be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things."
|
||||
"The default environment."
|
||||
(atom NIL))
|
||||
|
||||
(defn NULL
|
||||
[x]
|
||||
(if (= x NIL) 'T 'F))
|
||||
(def ^:dynamic *options*
|
||||
"Command line options from invocation."
|
||||
{})
|
||||
|
||||
(defn ATOM
|
||||
"It is not clear to me from the documentation whether `(ATOM 7)` should return
|
||||
`'T` or `'F`. I'm going to assume `'T`."
|
||||
(defmacro NULL
|
||||
"Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`."
|
||||
[x]
|
||||
(if (or (symbol? x) (number? x)) 'T 'F))
|
||||
`(if (= ~x NIL) T F))
|
||||
|
||||
(defn ATOM?
|
||||
"The convention of returning `'F` from predicates, rather than `NIL`, is going
|
||||
(defmacro ATOM
|
||||
"Returns `T` if and only is the argument `x` is bound to and atom; else `F`.
|
||||
It is not clear to me from the documentation whether `(ATOM 7)` should return
|
||||
`T` or `F`. I'm going to assume `T`."
|
||||
[x]
|
||||
`(if (or (symbol? ~x) (number? ~x)) T F))
|
||||
|
||||
(defmacro ATOM?
|
||||
"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."
|
||||
[x]
|
||||
(if (or (symbol? x) (number? x)) 'T NIL))
|
||||
`(if (or (symbol? ~x) (number? ~x)) T NIL))
|
||||
|
||||
(defn CAR
|
||||
"Return the item indicated by the first pointer of a pair. NIL is treated
|
||||
|
@ -94,10 +119,10 @@
|
|||
(defn CDADDR [x] (uaf x (seq "dadd")))
|
||||
|
||||
(defn EQ
|
||||
;; For some reason providing a doc string for this function breaks the
|
||||
;; Clojure parser!
|
||||
"Returns `T` if and only if both `x` and `y` are bound to the same atom,
|
||||
else `F`."
|
||||
[x y]
|
||||
(if (and (= (ATOM x) 'T) (= x y)) 'T 'F))
|
||||
(if (and (= (ATOM x) T) (= x y)) T F))
|
||||
|
||||
(defn EQUAL
|
||||
"This is a predicate that is true if its two arguments are identical
|
||||
|
@ -105,20 +130,20 @@
|
|||
`EQ` is defined only for atomic arguments.) The definition of `EQUAL` is
|
||||
an example of a conditional expression inside a conditional expression.
|
||||
|
||||
NOTE: returns F on failure, not NIL"
|
||||
NOTE: returns `F` on failure, not `NIL`"
|
||||
[x y]
|
||||
(cond
|
||||
(= (ATOM x) 'T) (EQ x y)
|
||||
(= (EQUAL (CAR x) (CAR y)) 'T) (EQUAL (CDR x) (CDR y))
|
||||
:else 'F))
|
||||
(= (ATOM x) T) (EQ x y)
|
||||
(= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y))
|
||||
:else F))
|
||||
|
||||
(defn SUBST
|
||||
"This function gives the result of substituting the S-expression `x` for
|
||||
all occurrences of the atomic symbol `y` in the S-expression `z`."
|
||||
[x y z]
|
||||
(cond
|
||||
(= (EQUAL y z) 'T) x
|
||||
(= (ATOM? z) 'T) z ;; NIL is a symbol
|
||||
(= (EQUAL y z) T) x
|
||||
(= (ATOM? z) T) z ;; NIL is a symbol
|
||||
:else
|
||||
(make-cons-cell (SUBST x y (CAR z)) (SUBST x y (CDR z)))))
|
||||
|
||||
|
@ -143,7 +168,7 @@
|
|||
[x y]
|
||||
(cond
|
||||
(= y NIL) F ;; NOTE: returns F on falsity, not NIL
|
||||
(= (EQUAL x (CAR y)) 'T) 'T
|
||||
(= (EQUAL x (CAR y)) T) T
|
||||
:else (MEMBER x (CDR y))))
|
||||
|
||||
(defn PAIRLIS
|
||||
|
@ -177,7 +202,7 @@
|
|||
(cond
|
||||
(= NIL a) NIL ;; this clause is not present in the original but is added for
|
||||
;; robustness.
|
||||
(= (EQUAL (CAAR a) x) 'T) (CAR a)
|
||||
(= (EQUAL (CAAR a) x) T) (CAR a)
|
||||
:else
|
||||
(ASSOC x (CDR a))))
|
||||
|
||||
|
@ -204,11 +229,11 @@
|
|||
See page 12 of the Lisp 1.5 Programmers Manual."
|
||||
[a y]
|
||||
(cond
|
||||
(= (ATOM? y) 'T) (SUB2 a y)
|
||||
(= (ATOM? y) T) (SUB2 a y)
|
||||
:else
|
||||
(make-cons-cell (SUBLIS a (CAR y)) (SUBLIS a (CDR y)))))
|
||||
|
||||
(deftrace APPLY
|
||||
(defn APPLY
|
||||
"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."
|
||||
|
@ -216,7 +241,9 @@
|
|||
(cond
|
||||
(=
|
||||
(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 'CDR) (CDAR args)
|
||||
(= function 'CONS) (make-cons-cell (CAR args) (CADR args))
|
||||
|
@ -261,19 +288,16 @@
|
|||
(EVAL (CAR args) env)
|
||||
(EVLIS (CDR args) env))))
|
||||
|
||||
|
||||
(deftrace EVAL
|
||||
"For bootstrapping, at least, a version of EVAL written in Clojure.
|
||||
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
||||
See page 13 of the Lisp 1.5 Programmers Manual."
|
||||
(deftrace traced-eval
|
||||
"Essentially, identical to EVAL except traced."
|
||||
[expr env]
|
||||
(cond
|
||||
(=
|
||||
(ATOM? expr) 'T)
|
||||
(ATOM? expr) T)
|
||||
(CDR (ASSOC expr env))
|
||||
(=
|
||||
(ATOM? (CAR expr))
|
||||
'T)(cond
|
||||
T)(cond
|
||||
(= (CAR expr) 'QUOTE) (CADR expr)
|
||||
(= (CAR expr) 'COND) (EVCON (CDR expr) env)
|
||||
:else (APPLY
|
||||
|
@ -285,3 +309,30 @@
|
|||
(EVLIS (CDR expr) env)
|
||||
env)))
|
||||
|
||||
(defn EVAL
|
||||
"For bootstrapping, at least, a version of EVAL written in Clojure.
|
||||
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
||||
See page 13 of the Lisp 1.5 Programmers Manual."
|
||||
[expr env]
|
||||
(cond
|
||||
(true? (:trace *options*))
|
||||
(traced-eval expr env)
|
||||
(=
|
||||
(ATOM? expr) T)
|
||||
(CDR (ASSOC expr env))
|
||||
(=
|
||||
(ATOM? (CAR expr))
|
||||
T)(cond
|
||||
(= (CAR expr) 'QUOTE) (CADR expr)
|
||||
(= (CAR expr) 'COND) (EVCON (CDR expr) env)
|
||||
:else (APPLY
|
||||
(CAR expr)
|
||||
(EVLIS (CDR expr) env)
|
||||
env))
|
||||
:else (APPLY
|
||||
(CAR expr)
|
||||
(EVLIS (CDR expr) env)
|
||||
env)))
|
||||
|
||||
|
||||
|
|
@ -1,11 +1,20 @@
|
|||
(ns 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.")
|
||||
|
||||
(def NIL (symbol "NIL"))
|
||||
(def NIL
|
||||
"The canonical empty list symbol."
|
||||
(symbol "NIL"))
|
||||
|
||||
(def T (symbol "T")) ;; true.
|
||||
(def T
|
||||
"The canonical true value."
|
||||
(symbol "T")) ;; true.
|
||||
|
||||
(def F (symbol "F")) ;; false as distinct from nil
|
||||
(def F
|
||||
"The canonical false value - different from `NIL`, which is not canonically
|
||||
false in Lisp 1.5."
|
||||
(symbol "F")) ;; false as distinct from nil
|
||||
|
||||
(deftype ConsCell [CAR CDR]
|
||||
clojure.lang.ISeq
|
||||
|
@ -15,12 +24,13 @@
|
|||
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
||||
(more [this] (if
|
||||
(seq? (.CDR this))
|
||||
clojure.lang.PersistentList/EMPTY
|
||||
(.CDR this)))
|
||||
(.CDR this)
|
||||
clojure.lang.PersistentList/EMPTY))
|
||||
(next [this] (if
|
||||
(seq? (.CDR this))
|
||||
(.CDR this)
|
||||
nil ;; next returns nil when empty
|
||||
(.CDR this)))
|
||||
))
|
||||
|
||||
clojure.lang.Seqable
|
||||
(seq [this] this)
|
||||
|
@ -31,11 +41,26 @@
|
|||
|
||||
clojure.lang.IPersistentCollection
|
||||
(count [this] (if
|
||||
(seq? (.CDR this))
|
||||
0
|
||||
(inc (count (.CDR this)))))
|
||||
(empty [this] false)
|
||||
(equiv [this other] false))
|
||||
(coll? (.CDR this))
|
||||
(inc (.count (.CDR this)))
|
||||
1))
|
||||
(empty [this] false) ;; a cons cell is by definition not empty.
|
||||
(equiv [this other] (if
|
||||
(seq? other)
|
||||
(and
|
||||
(if
|
||||
(and
|
||||
(seq? (first this))
|
||||
(seq? (first other)))
|
||||
(.equiv (first this) (first other))
|
||||
(= (first this) (first other)))
|
||||
(if
|
||||
(and
|
||||
(seq? (rest this))
|
||||
(seq? (rest other)))
|
||||
(.equiv (rest this) (rest other))
|
||||
(= (rest this) (rest other))))
|
||||
false)))
|
||||
|
||||
(defn- to-string
|
||||
"Printing ConsCells gave me a *lot* of trouble. This is an internal function
|
||||
|
@ -103,21 +128,29 @@
|
|||
|
||||
|
||||
|
||||
(defmethod clojure.core/print-method beowulf.cons_cell.ConsCell
|
||||
(defmethod clojure.core/print-method
|
||||
;;; I have not worked out how to document defmethod without blowing up the world.
|
||||
beowulf.cons_cell.ConsCell
|
||||
[this writer]
|
||||
(.write writer (to-string this)))
|
||||
|
||||
|
||||
(defn make-cons-cell
|
||||
[a d]
|
||||
(ConsCell. a d))
|
||||
(defmacro make-cons-cell
|
||||
"Construct a new instance of cons cell with this `car` and `cdr`."
|
||||
[car cdr]
|
||||
`(ConsCell. ~car ~cdr))
|
||||
|
||||
(defn make-beowulf-list
|
||||
"Construct a linked list of cons cells with the same content as the
|
||||
sequence `x`."
|
||||
[x]
|
||||
(cond
|
||||
(empty? x) NIL
|
||||
(coll? x) (ConsCell.
|
||||
(first x)
|
||||
(if
|
||||
(seq? (first x))
|
||||
(make-beowulf-list (first x))
|
||||
(first x))
|
||||
(make-beowulf-list (rest x)))
|
||||
:else
|
||||
NIL))
|
||||
|
|
|
@ -1,21 +1,36 @@
|
|||
(ns beowulf.core
|
||||
(:require [beowulf.eval :refer [EVAL oblist]]
|
||||
"Essentially, the `-main` function and the bootstrap read-eval-print loop."
|
||||
(:require [beowulf.bootstrap :refer [EVAL oblist *options*]]
|
||||
[beowulf.read :refer [READ]]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[clojure.tools.cli :refer [parse-opts]]
|
||||
[environ.core :refer [env]])
|
||||
(:gen-class))
|
||||
|
||||
(def cli-options
|
||||
[["-h" "--help"]
|
||||
["-p PROMPT" "--prompt PROMPT" "Set the REPL prompt to PROMPT"
|
||||
:default "Sprecan::"]
|
||||
["-r INITFILE" "--read INITFILE" "Read Lisp functions from the file INITFILE"
|
||||
:validate [#(and
|
||||
(.exists (io/file %))
|
||||
(.canRead (io/file %)))
|
||||
"Could not find initfile"]]
|
||||
["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."]
|
||||
["-t" "--trace" "Trace Lisp evaluation."]])
|
||||
|
||||
(defn repl
|
||||
"Read/eval/print loop."
|
||||
[]
|
||||
[prompt]
|
||||
(loop []
|
||||
(print "Sprecan:: ")
|
||||
(print prompt)
|
||||
(flush)
|
||||
(try
|
||||
(let [input (read-line)]
|
||||
(cond
|
||||
(= input "quit") (throw (ex-info "Færwell!" {:cause :quit}))
|
||||
input (println (str "> " (EVAL (READ input) @oblist)))
|
||||
(= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit}))
|
||||
input (println (str "> " (print-str (EVAL (READ input) @oblist))))
|
||||
:else (println)))
|
||||
(catch
|
||||
Exception
|
||||
|
@ -26,20 +41,32 @@
|
|||
data
|
||||
(case (:cause data)
|
||||
:parse-failure (println (:failure data))
|
||||
:strict nil ;; the message, which has already been printed, is enough.
|
||||
:quit (throw e)
|
||||
;; default
|
||||
(pprint data))))))
|
||||
(recur)))
|
||||
|
||||
(defn -main
|
||||
[& args]
|
||||
"Parse options, print the banner, read the init file if any, and enter the
|
||||
read/eval/print loop."
|
||||
[& opts]
|
||||
(let [args (parse-opts opts cli-options)]
|
||||
(println
|
||||
(str
|
||||
"Hider wilcuman. Béowulf is mín nama\nSíðe "
|
||||
"\nHider wilcuman. Béowulf is mín nama.\n"
|
||||
(if
|
||||
(System/getProperty "beowulf.version")
|
||||
"\n\n"))
|
||||
(str "Síðe " (System/getProperty "beowulf.version") "\n"))
|
||||
(if
|
||||
(:help (:options args))
|
||||
(:summary args))
|
||||
(if (:errors args)
|
||||
(apply str (interpose "; " (:errors args))))
|
||||
"\nSprecan 'quit' tó laéfan\n"))
|
||||
(binding [*options* (:options args)]
|
||||
(try
|
||||
(repl)
|
||||
(repl (str (:prompt (:options args)) " "))
|
||||
(catch
|
||||
Exception
|
||||
e
|
||||
|
@ -50,4 +77,4 @@
|
|||
:quit nil
|
||||
;; default
|
||||
(pprint data))
|
||||
(println e))))))
|
||||
(println e))))))))
|
||||
|
|
5
src/beowulf/host.clj
Normal file
5
src/beowulf/host.clj
Normal file
|
@ -0,0 +1,5 @@
|
|||
(ns beowulf.host
|
||||
"provides Lisp 1.5 functions which can't be (or can't efficiently
|
||||
be) implemented in Lisp 1.5, which therefore need to be implemented in the
|
||||
host language, in this case Clojure.")
|
||||
|
|
@ -1,10 +1,31 @@
|
|||
(ns beowulf.read
|
||||
(:require [clojure.math.numeric-tower :refer [expt]]
|
||||
"This provides the reader required for boostrapping. It's not a bad
|
||||
reader - it provides feedback on errors found in the input - but it isn't
|
||||
the real Lisp reader.
|
||||
|
||||
Intended deviations from the behaviour of the real Lisp reader are as follows:
|
||||
|
||||
1. It reads the meta-expression language `MEXPR` in addition to the
|
||||
symbolic expression language `SEXPR`, which I do not believe the Lisp 1.5
|
||||
reader ever did;
|
||||
2. It treats everything between a semi-colon and an end of line as a comment,
|
||||
as most modern Lisps do; but I do not believe Lisp 1.5 had this feature.
|
||||
|
||||
Both these extensions can be disabled by using the `--strict` command line
|
||||
switch."
|
||||
(:require [beowulf.bootstrap :refer [*options*]]
|
||||
[clojure.math.numeric-tower :refer [expt]]
|
||||
[clojure.string :refer [starts-with? upper-case]]
|
||||
[instaparse.core :as i]
|
||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]])
|
||||
;; (:import [beowulf.cons-cell ConsCell])
|
||||
)
|
||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;
|
||||
;;; This file 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.
|
||||
;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(declare generate)
|
||||
|
||||
|
@ -18,7 +39,7 @@
|
|||
|
||||
;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
|
||||
;; but it's a convenience.
|
||||
"mexpr := λexpr | fncall | defn | cond | mvar;
|
||||
"mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
|
||||
λexpr := λ lsqb bindings semi-colon body rsqb;
|
||||
λ := 'λ';
|
||||
bindings := lsqb args rsqb;
|
||||
|
@ -35,9 +56,12 @@
|
|||
mvar := #'[a-z]+';
|
||||
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,
|
||||
;; but I've included it on the basis that it can do little harm.
|
||||
"sexpr := quoted-expr | atom | number | dotted-pair | list;
|
||||
"sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
|
||||
list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
|
||||
dotted-pair := lpar dot-terminal ;
|
||||
dot := '.';
|
||||
|
@ -89,6 +113,11 @@
|
|||
(= context :mexpr)
|
||||
[:quoted-expr p]
|
||||
p)
|
||||
:comment (if
|
||||
(:strict *options*)
|
||||
(throw
|
||||
(ex-info "Cannot parse comments in strict mode"
|
||||
{:cause :strict})))
|
||||
:dotted-pair (if
|
||||
(= context :mexpr)
|
||||
[:fncall
|
||||
|
@ -97,7 +126,12 @@
|
|||
(simplify (nth p 1) context)
|
||||
(simplify (nth p 2) context)]]
|
||||
(map simplify p))
|
||||
:mexpr (simplify (second p) :mexpr)
|
||||
:mexpr (if
|
||||
(:strict *options*)
|
||||
(throw
|
||||
(ex-info "Cannot parse meta expressions in strict mode"
|
||||
{:cause :strict}))
|
||||
(simplify (second p) :mexpr))
|
||||
:list (if
|
||||
(= context :mexpr)
|
||||
[:fncall
|
||||
|
@ -109,7 +143,6 @@
|
|||
p)))
|
||||
|
||||
|
||||
|
||||
;; # From Lisp 1.5 Programmers Manual, page 10
|
||||
;; Note that I've retyped much of this, since copy/pasting out of PDF is less
|
||||
;; than reliable. Any typos are mine. Quote starts [[
|
||||
|
@ -185,9 +218,7 @@
|
|||
|
||||
(defn gen-fn-call
|
||||
"Generate a function call from this simplified parse tree fragment `p`;
|
||||
returns `nil` if `p` does not represent a (MEXPR) function call.
|
||||
TODO: I'm not yet certain but it appears that args in mexprs are
|
||||
implicitly quoted; this function does not (yet) do that."
|
||||
returns `nil` if `p` does not represent a (MEXPR) function call."
|
||||
[p]
|
||||
(if
|
||||
(and (coll? p)(= :fncall (first p))(= :mvar (first (second p))))
|
||||
|
@ -278,5 +309,7 @@
|
|||
`(generate (simplify (parse ~s))))
|
||||
|
||||
(defn READ
|
||||
"An implementation of a Lisp reader sufficient for bootstrapping; not necessarily
|
||||
the final Lisp reader."
|
||||
[input]
|
||||
(gsp (or input (read-line))))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
(: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.bootstrap :refer :all]
|
||||
[beowulf.read :refer [gsp]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -176,16 +176,24 @@
|
|||
(deftest member-tests
|
||||
(testing "member"
|
||||
(let [expected 'T
|
||||
actual (MEMBER (gsp "ALBERT") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
actual (MEMBER
|
||||
(gsp "ALBERT")
|
||||
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
(= actual expected))
|
||||
(let [expected 'T
|
||||
actual (MEMBER (gsp "BELINDA") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
actual (MEMBER
|
||||
(gsp "BELINDA")
|
||||
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
(= actual expected))
|
||||
(let [expected 'T
|
||||
actual (MEMBER (gsp "ELFREDA") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
actual (MEMBER
|
||||
(gsp "ELFREDA")
|
||||
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
(= actual expected))
|
||||
(let [expected 'F
|
||||
actual (MEMBER (gsp "BERTRAM") (gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
actual (MEMBER
|
||||
(gsp "BERTRAM")
|
||||
(gsp "(ALBERT BELINDA CHARLIE DORIS ELFREDA FRED)"))]
|
||||
(= actual expected))))
|
||||
|
||||
(deftest pairlis-tests
|
||||
|
|
57
test/beowulf/cons_cell_test.clj
Normal file
57
test/beowulf/cons_cell_test.clj
Normal file
|
@ -0,0 +1,57 @@
|
|||
(ns beowulf.core-test
|
||||
(:require [clojure.test :refer :all]
|
||||
[beowulf.cons-cell :refer :all]))
|
||||
|
||||
(deftest cons-cell-tests
|
||||
(testing "make-cons-cell"
|
||||
(let [expected "(A . B)"
|
||||
actual (print-str (beowulf.cons_cell.ConsCell. 'A 'B))]
|
||||
(is (= actual expected) "Cons cells should print as cons cells, natch."))
|
||||
(let [expected "(A . B)"
|
||||
actual (print-str (make-cons-cell 'A 'B))]
|
||||
(is (= actual expected) "Even if build with the macro."))
|
||||
(let [expected beowulf.cons_cell.ConsCell
|
||||
actual (print-str (make-cons-cell 'A 'B))]
|
||||
(is (= actual expected) "And they should be cons cells."))
|
||||
)
|
||||
(testing "make-beowulf-list"
|
||||
(let [expected "(A (B C) (D E (F) G) H)"
|
||||
actual (print-str (make-beowulf-list '(A (B C) (D E (F) G) H)))]
|
||||
(is (= actual expected) "Should work for clojure lists, recursively."))
|
||||
(let [expected "(A (B C) (D E (F) G) H)"
|
||||
actual (print-str (make-beowulf-list [A [B C] [D E [F] G] H]))]
|
||||
(is (= actual expected) "Should work for vectors, too."))
|
||||
(let [expected "NIL"
|
||||
actual (print-str (make-beowulf-list []))]
|
||||
(is (= actual expected) "An empty sequence is NIL."))
|
||||
(let [expected beowulf.cons_cell.ConsCell
|
||||
actual (make-beowulf-list '(A (B C) (D E (F) G) H))]
|
||||
(is (= actual expected) "A beowulf list is made of cons cells.")))
|
||||
(testing "pretty-print"
|
||||
(let [expected "(A\n (B C)\n (D E (F) G) H)"
|
||||
actual (pretty-print (make-beowulf-list '(A (B C) (D E (F) G) H)) 20 0)]
|
||||
(is (= actual expected)))
|
||||
(let [expected "(A (B C) (D E (F) G) H)"
|
||||
actual (pretty-print (make-beowulf-list '(A (B C) (D E (F) G) H)))]
|
||||
(is (= actual expected))))
|
||||
(testing "count"
|
||||
(let [expected 4
|
||||
actual (count (make-beowulf-list '(A (B C) (D E (F) G) H)) 20 0)]
|
||||
(is (= actual expected)))
|
||||
(let [expected 1
|
||||
actual (count (make-beowulf-list '(A)))]
|
||||
(is (= actual expected)))
|
||||
(let [expected 1
|
||||
actual (count (make-cons-cell 'A 'B))]
|
||||
(is (= actual expected))))
|
||||
(testing "sequence functions"
|
||||
(let [expected "A"
|
||||
actual (print-str (first (make-beowulf-list '(A (B C) (D E (F) G) H))))]
|
||||
(is (= actual expected)))
|
||||
(let [expected "((B C) (D E (F) G) H)"
|
||||
actual (print-str (more (make-beowulf-list '(A (B C) (D E (F) G) H))))]
|
||||
(is (= actual expected)))
|
||||
(let [expected "((B C) (D E (F) G) H)"
|
||||
actual (print-str (next (make-beowulf-list '(A (B C) (D E (F) G) H))))]
|
||||
(is (= actual expected)))
|
||||
))
|
|
@ -1,7 +1,175 @@
|
|||
(ns beowulf.core-test
|
||||
(:require [clojure.test :refer :all]
|
||||
(:require [clojure.java.io :refer [reader]]
|
||||
[clojure.string :refer [split]]
|
||||
[clojure.test :refer :all]
|
||||
[beowulf.core :refer :all]))
|
||||
|
||||
;; (deftest a-test
|
||||
;; (testing "FIXME, I fail."
|
||||
;; (is (= 0 1))))
|
||||
|
||||
(defn string->stream
|
||||
"Copied shamelessly from
|
||||
https://stackoverflow.com/questions/38283891/how-to-wrap-a-string-in-an-input-stream"
|
||||
([s] (string->stream s "UTF-8"))
|
||||
([s encoding]
|
||||
(-> s
|
||||
(.getBytes encoding)
|
||||
(java.io.ByteArrayInputStream.))))
|
||||
|
||||
(deftest repl-tests
|
||||
(testing "quit functionality"
|
||||
(with-open [r (reader (string->stream "quit"))]
|
||||
(binding [*in* r]
|
||||
(is (thrown-with-msg? Exception #"\nFærwell!" (repl "")))))
|
||||
|
||||
(let [expected nil
|
||||
actual (with-open [r (reader (string->stream "quit"))]
|
||||
(binding [*in* r]
|
||||
(-main)))]
|
||||
(is (= actual expected)))))
|
||||
|
||||
(deftest flag-tests
|
||||
(testing "No flags"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error ""
|
||||
expected-result #".*\(A \. B\)"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main)) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= error expected-error))
|
||||
(is (re-matches expected-result result))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "unknown flag"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error #"Unknown option:.*"
|
||||
expected-result #".*\(A \. B\)"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--unknown")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (re-matches expected-error error))
|
||||
(is (re-matches expected-result result))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "help"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-h1 " -h, --help"
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-result #".*\(A \. B\)"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version h1 h2 h3 h4 h5 quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--help")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= h1 expected-h1))
|
||||
(is (re-matches expected-result result))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "prompt"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error ""
|
||||
expected-result #".*\(A \. B\).*"
|
||||
expected-prompt "? "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--prompt" "?")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= error expected-error))
|
||||
(is (re-matches expected-result result ))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "read - file not found"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error #"Failed to validate.*"
|
||||
expected-result #".*\(A \. B\)"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--read" "froboz")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (re-matches expected-error error))
|
||||
(is (re-matches expected-result result))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "read - file found"
|
||||
;; TODO: there's no feedback from this because the initfile
|
||||
;; is not yet read. This will change
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error ""
|
||||
expected-result #".*\(A \. B\)"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--read" "README.md")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= error expected-error))
|
||||
(is (re-matches expected-result result))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "strict"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error ""
|
||||
expected-result #".*Cannot parse meta expressions in strict mode.*"
|
||||
expected-prompt "Sprecan:: "
|
||||
expected-signoff "Færwell!"
|
||||
[_ greeting version error quit-message _ result prompt signoff]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--strict")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= error expected-error))
|
||||
(is (re-matches expected-result result ))
|
||||
(is (= quit-message expected-quit-message))
|
||||
(is (= prompt expected-prompt))
|
||||
(is (= signoff expected-signoff))
|
||||
))
|
||||
(testing "trace"
|
||||
(let [expected-greeting "Hider wilcuman. Béowulf is mín nama."
|
||||
expected-quit-message "Sprecan 'quit' tó laéfan"
|
||||
expected-error ""
|
||||
expected-trace #".*traced-eval.*"
|
||||
[_ greeting version error quit-message _ trace & _]
|
||||
(with-open [r (reader (string->stream "cons[A; B]\nquit"))]
|
||||
(binding [*in* r]
|
||||
(split (with-out-str (-main "--trace")) #"\n")))]
|
||||
(is (= greeting expected-greeting))
|
||||
(is (= error expected-error))
|
||||
(is (re-matches expected-trace trace))
|
||||
))
|
||||
|
||||
)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
(ns beowulf.mexpr-test
|
||||
"These tests are taken generally from the examples on page 10 of
|
||||
Lisp 1.5 Programmers Manual"
|
||||
(:require [clojure.test :refer :all]
|
||||
[beowulf.read :refer [parse simplify generate]]))
|
||||
[beowulf.bootstrap :refer [*options*]]
|
||||
[beowulf.read :refer [parse simplify generate gsp]]))
|
||||
|
||||
;; These tests are taken generally from the examples on page 10 of
|
||||
;; Lisp 1.5 Programmers Manual:
|
||||
|
@ -64,3 +67,10 @@
|
|||
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
|
||||
(is (= actual expected)))))
|
||||
|
||||
(deftest strict-tests
|
||||
(testing "Strict feature"
|
||||
(binding [*options* {:strict true}]
|
||||
(is (thrown-with-msg?
|
||||
Exception
|
||||
#"Cannot parse meta expressions in strict mode"
|
||||
(gsp "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))))
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
(:require [clojure.math.numeric-tower :refer [abs]]
|
||||
[clojure.test :refer :all]
|
||||
[beowulf.cons-cell :refer :all]
|
||||
[beowulf.read :refer [parse simplify generate]]))
|
||||
[beowulf.bootstrap :refer [*options*]]
|
||||
[beowulf.read :refer [parse simplify generate gsp]]))
|
||||
|
||||
;; broadly, sexprs should be homoiconic
|
||||
|
||||
|
@ -24,6 +25,32 @@
|
|||
actual (generate (simplify (parse (str expected))))]
|
||||
(is (= actual expected)))))
|
||||
|
||||
(deftest comment-tests
|
||||
(testing "Reading comments"
|
||||
(let [expected 'A
|
||||
actual (gsp "A ;; comment")]
|
||||
(is (= actual expected)))
|
||||
(let [expected 10
|
||||
actual (gsp "10 ;; comment")]
|
||||
(is (= actual expected)))
|
||||
(let [expected 2/5
|
||||
actual (gsp "4E-1 ;; comment")]
|
||||
(is (= actual expected)))
|
||||
(let [expected "(A B C)"
|
||||
actual (print-str (gsp "(A ;; comment
|
||||
B C)"))]
|
||||
(is (= actual expected)
|
||||
"Really important that comments work inside lists"))
|
||||
;; ;; TODO: Currently failing and I'm not sure why
|
||||
;; (binding [*options* {:strict true}]
|
||||
;; (is (thrown-with-msg?
|
||||
;; Exception
|
||||
;; #"Cannot parse comments in strict mode"
|
||||
;; (gsp "(A ;; comment
|
||||
;; B C)"))))
|
||||
))
|
||||
|
||||
|
||||
(deftest number-tests
|
||||
(testing "Reading octal numbers"
|
||||
(let [expected 1
|
||||
|
|
Loading…
Reference in a new issue