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
|
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
|
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
|
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
|
same bahaviour - except as documented below.
|
||||||
'mexprs' (meta language expressions) as well as sexprs.
|
|
||||||
|
|
||||||
## 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.
|
Because.
|
||||||
|
|
||||||
|
@ -23,9 +79,24 @@ for modern machines.
|
||||||
|
|
||||||
Because I'm barking mad, and this is therapy.
|
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
|
## 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
|
## 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
|
[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).
|
[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
|
## License
|
||||||
|
|
||||||
Copyright © 2019 Simon Brooke. Licensed under the GNU General Public 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"
|
:description "An implementation of LISP 1.5 in Clojure"
|
||||||
:url "http://example.com/FIXME"
|
|
||||||
:license {:name "GPL-2.0-or-later"
|
:license {:name "GPL-2.0-or-later"
|
||||||
:url "https://www.eclipse.org/legal/epl-2.0/"}
|
: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/math.numeric-tower "0.0.4"]
|
||||||
|
[org.clojure/tools.cli "0.4.2"]
|
||||||
[org.clojure/tools.trace "0.7.10"]
|
[org.clojure/tools.trace "0.7.10"]
|
||||||
[environ "1.1.0"]
|
[environ "1.1.0"]
|
||||||
[instaparse "1.4.10"]]
|
[instaparse "1.4.10"]]
|
||||||
:main ^:skip-aot beowulf.core
|
: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"
|
: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]
|
(:require [clojure.tools.trace :refer :all]
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]))
|
[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)
|
(declare EVAL)
|
||||||
|
|
||||||
(def oblist
|
(def oblist
|
||||||
"The default environment; modified certainly be `LABEL` (which seems to
|
"The default environment."
|
||||||
be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things."
|
|
||||||
(atom NIL))
|
(atom NIL))
|
||||||
|
|
||||||
(defn NULL
|
(def ^:dynamic *options*
|
||||||
[x]
|
"Command line options from invocation."
|
||||||
(if (= x NIL) 'T 'F))
|
{})
|
||||||
|
|
||||||
(defn ATOM
|
(defmacro NULL
|
||||||
"It is not clear to me from the documentation whether `(ATOM 7)` should return
|
"Returns `T` if and only if the argument `x` is bound to `NIL`; else `F`."
|
||||||
`'T` or `'F`. I'm going to assume `'T`."
|
|
||||||
[x]
|
[x]
|
||||||
(if (or (symbol? x) (number? x)) 'T 'F))
|
`(if (= ~x NIL) T F))
|
||||||
|
|
||||||
(defn ATOM?
|
(defmacro ATOM
|
||||||
"The convention of returning `'F` from predicates, rather than `NIL`, is going
|
"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`
|
to tie me in knots. This is a variant of `ATOM` which returns `NIL`
|
||||||
on failure."
|
on failure."
|
||||||
[x]
|
[x]
|
||||||
(if (or (symbol? x) (number? x)) 'T NIL))
|
`(if (or (symbol? ~x) (number? ~x)) T NIL))
|
||||||
|
|
||||||
(defn CAR
|
(defn CAR
|
||||||
"Return the item indicated by the first pointer of a pair. NIL is treated
|
"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 CDADDR [x] (uaf x (seq "dadd")))
|
||||||
|
|
||||||
(defn EQ
|
(defn EQ
|
||||||
;; For some reason providing a doc string for this function breaks the
|
"Returns `T` if and only if both `x` and `y` are bound to the same atom,
|
||||||
;; Clojure parser!
|
else `F`."
|
||||||
[x y]
|
[x y]
|
||||||
(if (and (= (ATOM x) 'T) (= x y)) 'T 'F))
|
(if (and (= (ATOM x) T) (= x y)) T F))
|
||||||
|
|
||||||
(defn EQUAL
|
(defn EQUAL
|
||||||
"This is a predicate that is true if its two arguments are identical
|
"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
|
`EQ` is defined only for atomic arguments.) The definition of `EQUAL` is
|
||||||
an example of a conditional expression inside a conditional expression.
|
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]
|
[x y]
|
||||||
(cond
|
(cond
|
||||||
(= (ATOM x) 'T) (EQ x y)
|
(= (ATOM x) T) (EQ x y)
|
||||||
(= (EQUAL (CAR x) (CAR y)) 'T) (EQUAL (CDR x) (CDR y))
|
(= (EQUAL (CAR x) (CAR y)) T) (EQUAL (CDR x) (CDR y))
|
||||||
:else 'F))
|
:else F))
|
||||||
|
|
||||||
(defn SUBST
|
(defn SUBST
|
||||||
"This function gives the result of substituting the S-expression `x` for
|
"This function gives the result of substituting the S-expression `x` for
|
||||||
all occurrences of the atomic symbol `y` in the S-expression `z`."
|
all occurrences of the atomic symbol `y` in the S-expression `z`."
|
||||||
[x y z]
|
[x y z]
|
||||||
(cond
|
(cond
|
||||||
(= (EQUAL y z) 'T) x
|
(= (EQUAL y z) T) x
|
||||||
(= (ATOM? z) 'T) z ;; NIL is a symbol
|
(= (ATOM? z) T) z ;; NIL is a symbol
|
||||||
:else
|
:else
|
||||||
(make-cons-cell (SUBST x y (CAR z)) (SUBST x y (CDR z)))))
|
(make-cons-cell (SUBST x y (CAR z)) (SUBST x y (CDR z)))))
|
||||||
|
|
||||||
|
@ -143,7 +168,7 @@
|
||||||
[x y]
|
[x y]
|
||||||
(cond
|
(cond
|
||||||
(= y NIL) F ;; NOTE: returns F on falsity, not NIL
|
(= 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))))
|
:else (MEMBER x (CDR y))))
|
||||||
|
|
||||||
(defn PAIRLIS
|
(defn PAIRLIS
|
||||||
|
@ -177,7 +202,7 @@
|
||||||
(cond
|
(cond
|
||||||
(= NIL a) NIL ;; this clause is not present in the original but is added for
|
(= NIL a) NIL ;; this clause is not present in the original but is added for
|
||||||
;; robustness.
|
;; robustness.
|
||||||
(= (EQUAL (CAAR a) x) 'T) (CAR a)
|
(= (EQUAL (CAAR a) x) T) (CAR a)
|
||||||
:else
|
:else
|
||||||
(ASSOC x (CDR a))))
|
(ASSOC x (CDR a))))
|
||||||
|
|
||||||
|
@ -204,11 +229,11 @@
|
||||||
See page 12 of the Lisp 1.5 Programmers Manual."
|
See page 12 of the Lisp 1.5 Programmers Manual."
|
||||||
[a y]
|
[a y]
|
||||||
(cond
|
(cond
|
||||||
(= (ATOM? y) 'T) (SUB2 a y)
|
(= (ATOM? y) T) (SUB2 a y)
|
||||||
:else
|
:else
|
||||||
(make-cons-cell (SUBLIS a (CAR y)) (SUBLIS a (CDR y)))))
|
(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.
|
"For bootstrapping, at least, a version of APPLY written in Clojure.
|
||||||
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
||||||
See page 13 of the Lisp 1.5 Programmers Manual."
|
See page 13 of the Lisp 1.5 Programmers Manual."
|
||||||
|
@ -216,7 +241,9 @@
|
||||||
(cond
|
(cond
|
||||||
(=
|
(=
|
||||||
(ATOM? function)
|
(ATOM? function)
|
||||||
'T)(cond
|
T)(cond
|
||||||
|
;; TODO: doesn't check whether `function` is bound in the environment;
|
||||||
|
;; we'll need that before we can bootstrap.
|
||||||
(= function 'CAR) (CAAR args)
|
(= function 'CAR) (CAAR args)
|
||||||
(= function 'CDR) (CDAR args)
|
(= function 'CDR) (CDAR args)
|
||||||
(= function 'CONS) (make-cons-cell (CAR args) (CADR args))
|
(= function 'CONS) (make-cons-cell (CAR args) (CADR args))
|
||||||
|
@ -261,19 +288,16 @@
|
||||||
(EVAL (CAR args) env)
|
(EVAL (CAR args) env)
|
||||||
(EVLIS (CDR args) env))))
|
(EVLIS (CDR args) env))))
|
||||||
|
|
||||||
|
(deftrace traced-eval
|
||||||
(deftrace EVAL
|
"Essentially, identical to EVAL except traced."
|
||||||
"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]
|
[expr env]
|
||||||
(cond
|
(cond
|
||||||
(=
|
(=
|
||||||
(ATOM? expr) 'T)
|
(ATOM? expr) T)
|
||||||
(CDR (ASSOC expr env))
|
(CDR (ASSOC expr env))
|
||||||
(=
|
(=
|
||||||
(ATOM? (CAR expr))
|
(ATOM? (CAR expr))
|
||||||
'T)(cond
|
T)(cond
|
||||||
(= (CAR expr) 'QUOTE) (CADR expr)
|
(= (CAR expr) 'QUOTE) (CADR expr)
|
||||||
(= (CAR expr) 'COND) (EVCON (CDR expr) env)
|
(= (CAR expr) 'COND) (EVCON (CDR expr) env)
|
||||||
:else (APPLY
|
:else (APPLY
|
||||||
|
@ -285,3 +309,30 @@
|
||||||
(EVLIS (CDR expr) env)
|
(EVLIS (CDR expr) env)
|
||||||
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
|
(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]
|
(deftype ConsCell [CAR CDR]
|
||||||
clojure.lang.ISeq
|
clojure.lang.ISeq
|
||||||
|
@ -15,12 +24,13 @@
|
||||||
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
;; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
|
||||||
(more [this] (if
|
(more [this] (if
|
||||||
(seq? (.CDR this))
|
(seq? (.CDR this))
|
||||||
clojure.lang.PersistentList/EMPTY
|
(.CDR this)
|
||||||
(.CDR this)))
|
clojure.lang.PersistentList/EMPTY))
|
||||||
(next [this] (if
|
(next [this] (if
|
||||||
(seq? (.CDR this))
|
(seq? (.CDR this))
|
||||||
|
(.CDR this)
|
||||||
nil ;; next returns nil when empty
|
nil ;; next returns nil when empty
|
||||||
(.CDR this)))
|
))
|
||||||
|
|
||||||
clojure.lang.Seqable
|
clojure.lang.Seqable
|
||||||
(seq [this] this)
|
(seq [this] this)
|
||||||
|
@ -31,11 +41,26 @@
|
||||||
|
|
||||||
clojure.lang.IPersistentCollection
|
clojure.lang.IPersistentCollection
|
||||||
(count [this] (if
|
(count [this] (if
|
||||||
(seq? (.CDR this))
|
(coll? (.CDR this))
|
||||||
0
|
(inc (.count (.CDR this)))
|
||||||
(inc (count (.CDR this)))))
|
1))
|
||||||
(empty [this] false)
|
(empty [this] false) ;; a cons cell is by definition not empty.
|
||||||
(equiv [this other] false))
|
(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
|
(defn- to-string
|
||||||
"Printing ConsCells gave me a *lot* of trouble. This is an internal function
|
"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]
|
[this writer]
|
||||||
(.write writer (to-string this)))
|
(.write writer (to-string this)))
|
||||||
|
|
||||||
|
|
||||||
(defn make-cons-cell
|
(defmacro make-cons-cell
|
||||||
[a d]
|
"Construct a new instance of cons cell with this `car` and `cdr`."
|
||||||
(ConsCell. a d))
|
[car cdr]
|
||||||
|
`(ConsCell. ~car ~cdr))
|
||||||
|
|
||||||
(defn make-beowulf-list
|
(defn make-beowulf-list
|
||||||
|
"Construct a linked list of cons cells with the same content as the
|
||||||
|
sequence `x`."
|
||||||
[x]
|
[x]
|
||||||
(cond
|
(cond
|
||||||
(empty? x) NIL
|
(empty? x) NIL
|
||||||
(coll? x) (ConsCell.
|
(coll? x) (ConsCell.
|
||||||
(first x)
|
(if
|
||||||
|
(seq? (first x))
|
||||||
|
(make-beowulf-list (first x))
|
||||||
|
(first x))
|
||||||
(make-beowulf-list (rest x)))
|
(make-beowulf-list (rest x)))
|
||||||
:else
|
:else
|
||||||
NIL))
|
NIL))
|
||||||
|
|
|
@ -1,21 +1,36 @@
|
||||||
(ns beowulf.core
|
(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]]
|
[beowulf.read :refer [READ]]
|
||||||
|
[clojure.java.io :as io]
|
||||||
[clojure.pprint :refer [pprint]]
|
[clojure.pprint :refer [pprint]]
|
||||||
|
[clojure.tools.cli :refer [parse-opts]]
|
||||||
[environ.core :refer [env]])
|
[environ.core :refer [env]])
|
||||||
(:gen-class))
|
(: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
|
(defn repl
|
||||||
"Read/eval/print loop."
|
"Read/eval/print loop."
|
||||||
[]
|
[prompt]
|
||||||
(loop []
|
(loop []
|
||||||
(print "Sprecan:: ")
|
(print prompt)
|
||||||
(flush)
|
(flush)
|
||||||
(try
|
(try
|
||||||
(let [input (read-line)]
|
(let [input (read-line)]
|
||||||
(cond
|
(cond
|
||||||
(= input "quit") (throw (ex-info "Færwell!" {:cause :quit}))
|
(= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit}))
|
||||||
input (println (str "> " (EVAL (READ input) @oblist)))
|
input (println (str "> " (print-str (EVAL (READ input) @oblist))))
|
||||||
:else (println)))
|
:else (println)))
|
||||||
(catch
|
(catch
|
||||||
Exception
|
Exception
|
||||||
|
@ -26,20 +41,32 @@
|
||||||
data
|
data
|
||||||
(case (:cause data)
|
(case (:cause data)
|
||||||
:parse-failure (println (:failure data))
|
:parse-failure (println (:failure data))
|
||||||
|
:strict nil ;; the message, which has already been printed, is enough.
|
||||||
:quit (throw e)
|
:quit (throw e)
|
||||||
;; default
|
;; default
|
||||||
(pprint data))))))
|
(pprint data))))))
|
||||||
(recur)))
|
(recur)))
|
||||||
|
|
||||||
(defn -main
|
(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
|
(println
|
||||||
(str
|
(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")
|
(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
|
(try
|
||||||
(repl)
|
(repl (str (:prompt (:options args)) " "))
|
||||||
(catch
|
(catch
|
||||||
Exception
|
Exception
|
||||||
e
|
e
|
||||||
|
@ -50,4 +77,4 @@
|
||||||
:quit nil
|
:quit nil
|
||||||
;; default
|
;; default
|
||||||
(pprint data))
|
(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
|
(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]]
|
[clojure.string :refer [starts-with? upper-case]]
|
||||||
[instaparse.core :as i]
|
[instaparse.core :as i]
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]])
|
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
|
||||||
;; (:import [beowulf.cons-cell ConsCell])
|
|
||||||
)
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;
|
||||||
|
;;; 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)
|
(declare generate)
|
||||||
|
|
||||||
|
@ -18,7 +39,7 @@
|
||||||
|
|
||||||
;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
|
;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
|
||||||
;; but it's a convenience.
|
;; but it's a convenience.
|
||||||
"mexpr := λexpr | fncall | defn | cond | mvar;
|
"mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
|
||||||
λexpr := λ lsqb bindings semi-colon body rsqb;
|
λexpr := λ lsqb bindings semi-colon body rsqb;
|
||||||
λ := 'λ';
|
λ := 'λ';
|
||||||
bindings := lsqb args rsqb;
|
bindings := lsqb args rsqb;
|
||||||
|
@ -35,9 +56,12 @@
|
||||||
mvar := #'[a-z]+';
|
mvar := #'[a-z]+';
|
||||||
semi-colon := ';';"
|
semi-colon := ';';"
|
||||||
|
|
||||||
|
;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
|
||||||
|
"comment := opt-space <';;'> #'[^\\n\\r]*';"
|
||||||
|
|
||||||
;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
|
;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
|
||||||
;; but I've included it on the basis that it can do little harm.
|
;; but I've included it on the basis that it can do little harm.
|
||||||
"sexpr := quoted-expr | atom | number | dotted-pair | list;
|
"sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
|
||||||
list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
|
list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
|
||||||
dotted-pair := lpar dot-terminal ;
|
dotted-pair := lpar dot-terminal ;
|
||||||
dot := '.';
|
dot := '.';
|
||||||
|
@ -89,6 +113,11 @@
|
||||||
(= context :mexpr)
|
(= context :mexpr)
|
||||||
[:quoted-expr p]
|
[:quoted-expr p]
|
||||||
p)
|
p)
|
||||||
|
:comment (if
|
||||||
|
(:strict *options*)
|
||||||
|
(throw
|
||||||
|
(ex-info "Cannot parse comments in strict mode"
|
||||||
|
{:cause :strict})))
|
||||||
:dotted-pair (if
|
:dotted-pair (if
|
||||||
(= context :mexpr)
|
(= context :mexpr)
|
||||||
[:fncall
|
[:fncall
|
||||||
|
@ -97,7 +126,12 @@
|
||||||
(simplify (nth p 1) context)
|
(simplify (nth p 1) context)
|
||||||
(simplify (nth p 2) context)]]
|
(simplify (nth p 2) context)]]
|
||||||
(map simplify p))
|
(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
|
:list (if
|
||||||
(= context :mexpr)
|
(= context :mexpr)
|
||||||
[:fncall
|
[:fncall
|
||||||
|
@ -109,7 +143,6 @@
|
||||||
p)))
|
p)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; # From Lisp 1.5 Programmers Manual, page 10
|
;; # From Lisp 1.5 Programmers Manual, page 10
|
||||||
;; Note that I've retyped much of this, since copy/pasting out of PDF is less
|
;; Note that I've retyped much of this, since copy/pasting out of PDF is less
|
||||||
;; than reliable. Any typos are mine. Quote starts [[
|
;; than reliable. Any typos are mine. Quote starts [[
|
||||||
|
@ -185,9 +218,7 @@
|
||||||
|
|
||||||
(defn gen-fn-call
|
(defn gen-fn-call
|
||||||
"Generate a function call from this simplified parse tree fragment `p`;
|
"Generate a function call from this simplified parse tree fragment `p`;
|
||||||
returns `nil` if `p` does not represent a (MEXPR) function call.
|
returns `nil` if `p` does not represent a (MEXPR) function call."
|
||||||
TODO: I'm not yet certain but it appears that args in mexprs are
|
|
||||||
implicitly quoted; this function does not (yet) do that."
|
|
||||||
[p]
|
[p]
|
||||||
(if
|
(if
|
||||||
(and (coll? p)(= :fncall (first p))(= :mvar (first (second p))))
|
(and (coll? p)(= :fncall (first p))(= :mvar (first (second p))))
|
||||||
|
@ -278,5 +309,7 @@
|
||||||
`(generate (simplify (parse ~s))))
|
`(generate (simplify (parse ~s))))
|
||||||
|
|
||||||
(defn READ
|
(defn READ
|
||||||
|
"An implementation of a Lisp reader sufficient for bootstrapping; not necessarily
|
||||||
|
the final Lisp reader."
|
||||||
[input]
|
[input]
|
||||||
(gsp (or input (read-line))))
|
(gsp (or input (read-line))))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
(:require [clojure.math.numeric-tower :refer [abs]]
|
(:require [clojure.math.numeric-tower :refer [abs]]
|
||||||
[clojure.test :refer :all]
|
[clojure.test :refer :all]
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL T F]]
|
[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]]))
|
[beowulf.read :refer [gsp]]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -176,16 +176,24 @@
|
||||||
(deftest member-tests
|
(deftest member-tests
|
||||||
(testing "member"
|
(testing "member"
|
||||||
(let [expected 'T
|
(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))
|
(= actual expected))
|
||||||
(let [expected 'T
|
(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))
|
(= actual expected))
|
||||||
(let [expected 'T
|
(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))
|
(= actual expected))
|
||||||
(let [expected 'F
|
(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))))
|
(= actual expected))))
|
||||||
|
|
||||||
(deftest pairlis-tests
|
(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
|
(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]))
|
[beowulf.core :refer :all]))
|
||||||
|
|
||||||
;; (deftest a-test
|
;; (deftest a-test
|
||||||
;; (testing "FIXME, I fail."
|
;; (testing "FIXME, I fail."
|
||||||
;; (is (= 0 1))))
|
;; (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
|
(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]
|
(: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
|
;; These tests are taken generally from the examples on page 10 of
|
||||||
;; Lisp 1.5 Programmers Manual:
|
;; Lisp 1.5 Programmers Manual:
|
||||||
|
@ -64,3 +67,10 @@
|
||||||
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
|
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
|
||||||
(is (= actual expected)))))
|
(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]]
|
(:require [clojure.math.numeric-tower :refer [abs]]
|
||||||
[clojure.test :refer :all]
|
[clojure.test :refer :all]
|
||||||
[beowulf.cons-cell :refer :all]
|
[beowulf.cons-cell :refer :all]
|
||||||
[beowulf.read :refer [parse simplify generate]]))
|
[beowulf.bootstrap :refer [*options*]]
|
||||||
|
[beowulf.read :refer [parse simplify generate gsp]]))
|
||||||
|
|
||||||
;; broadly, sexprs should be homoiconic
|
;; broadly, sexprs should be homoiconic
|
||||||
|
|
||||||
|
@ -24,6 +25,32 @@
|
||||||
actual (generate (simplify (parse (str expected))))]
|
actual (generate (simplify (parse (str expected))))]
|
||||||
(is (= actual 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
|
(deftest number-tests
|
||||||
(testing "Reading octal numbers"
|
(testing "Reading octal numbers"
|
||||||
(let [expected 1
|
(let [expected 1
|
||||||
|
|
Loading…
Reference in a new issue