Mainly documentation; preparing for release.

This commit is contained in:
Simon Brooke 2023-03-30 18:01:25 +01:00
parent 197ff0a08f
commit d83fe7849b
21 changed files with 646 additions and 51 deletions

View file

@ -34,11 +34,73 @@ Command line arguments as follows:
```
-h, --help Print this message
-p PROMPT, --prompt PROMPT Sprecan:: Set the REPL prompt to PROMPT
-p PROMPT, --prompt PROMPT Set the REPL prompt to PROMPT
-r INITFILE, --read INITFILE Read Lisp functions from the file INITFILE
-s, --strict Strictly interpret the Lisp 1.5 language, without extensions.
```
To end a session, type `STOP` at the command prompt.
### Functions and symbols implemented
The following functions and symbols are implemented:
| Symbol | Type | Signature | Documentation |
|--------|------|-----------|---------------|
| NIL | ? | null | ? |
| T | ? | null | ? |
| F | ? | null | ? |
| ADD1 | Host function | ([x]) | ? |
| AND | Host function | ([& args]) | `T` if and only if none of my `args` evaluate to either `F` or `NIL`, else `F`. In `beowulf.host` principally because I don't yet feel confident to define varargs functions in Lisp. |
| APPEND | Host function | ([x y]) | Append the the elements of `y` to the elements of `x`. All args are assumed to be `beowulf.cons-cell/ConsCell` objects. See page 11 of the Lisp 1.5 Programmers Manual. |
| APPLY | Host function | ([function args environment depth]) | Apply this `function` to these `arguments` in this `environment` and return the result. For bootstrapping, at least, a version of APPLY written in Clojure. All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects. See page 13 of the Lisp 1.5 Programmers Manual. |
| ATOM | Host function | ([x]) | Returns `T` if and only if the argument `x` is bound to an 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`. |
| CAR | ? | null | ? |
| CDR | ? | null | ? |
| CONS | ? | null | ? |
| COPY | Lisp function | (X) | ? |
| DEFINE | Host function | ([args]) | Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten in LISP. The single argument to `DEFINE` should be an assoc list which should be nconc'ed onto the front of the oblist. Broadly, (SETQ OBLIST (NCONC ARG1 OBLIST)) |
| DIFFERENCE | Host function | ([x y]) | ? |
| DIVIDE | Lisp function | (X Y) | ? |
| ERROR | Host function | ([& args]) | Throw an error |
| EQ | Host function | ([x y]) | Returns `T` if and only if both `x` and `y` are bound to the same atom, else `NIL`. |
| EQUAL | Host function | ([x y]) | This is a predicate that is true if its two arguments are identical S-expressions, and false if they are different. (The elementary predicate `EQ` is defined only for atomic arguments.) The definition of `EQUAL` is an example of a conditional expression inside a conditional expression. NOTE: returns `F` on failure, not `NIL` |
| EVAL | Host function | ([expr] [expr env depth]) | Evaluate this `expr` and return the result. If `environment` is not passed, it defaults to the current value of the global object list. The `depth` argument is part of the tracing system and should not be set by user code. All args are assumed to be numbers, symbols or `beowulf.cons-cell/ConsCell` objects. |
| FIXP | Host function | ([x]) | ? |
| GENSYM | Host function | ([]) | Generate a unique symbol. |
| GET | Lisp function | (X Y) | ? |
| GREATERP | Host function | ([x y]) | ? |
| INTEROP | Host function | ([fn-symbol args]) | Clojure (or other host environment) interoperation API. `fn-symbol` is expected to be either 1. a symbol bound in the host environment to a function; or 2. a sequence (list) of symbols forming a qualified path name bound to a function. Lower case characters cannot normally be represented in Lisp 1.5, so both the upper case and lower case variants of `fn-symbol` will be tried. If the function you're looking for has a mixed case name, that is not currently accessible. `args` is expected to be a Lisp 1.5 list of arguments to be passed to that function. Return value must be something acceptable to Lisp 1.5, so either a symbol, a number, or a Lisp 1.5 list. If `fn-symbol` is not found (even when cast to lower case), or is not a function, or the value returned cannot be represented in Lisp 1.5, an exception is thrown with `:cause` bound to `:interop` and `:detail` set to a value representing the actual problem. |
| INTERSECTION | Lisp function | (X Y) | ? |
| LENGTH | Lisp function | (L) | ? |
| LESSP | Host function | ([x y]) | ? |
| MEMBER | Lisp function | (A X) | ? |
| MINUSP | Lisp function | (X) | ? |
| NULL | Lisp function | (X) | ? |
| NUMBERP | Host function | ([x]) | ? |
| OBLIST | Host function | ([]) | Return a list of the symbols currently bound on the object list. **NOTE THAT** in the Lisp 1.5 manual, footnote at the bottom of page 69, it implies that an argument can be passed but I'm not sure of the semantics of this. |
| ONEP | Lisp function | (X) | ? |
| PAIR | Lisp function | (X Y) | ? |
| PLUS | Host function | ([& args]) | ? |
| PRETTY | ? | null | ? |
| PRINT | ? | null | ? |
| PROP | Lisp function | (X Y U) | ? |
| QUOTIENT | Host function | ([x y]) | I'm not certain from the documentation whether Lisp 1.5 `QUOTIENT` returned the integer part of the quotient, or a realnum representing the whole quotient. I am for now implementing the latter. |
| READ | Host function | ([] [input]) | An implementation of a Lisp reader sufficient for bootstrapping; not necessarily the final Lisp reader. `input` should be either a string representation of a LISP expression, or else an input stream. A single form will be read. |
| REMAINDER | Host function | ([x y]) | ? |
| REPEAT | Lisp function | (N X) | ? |
| RPLACA | Host function | ([cell value]) | Replace the CAR pointer of this `cell` with this `value`. Dangerous, should really not exist, but does in Lisp 1.5 (and was important for some performance hacks in early Lisps) |
| RPLACD | Host function | ([cell value]) | Replace the CDR pointer of this `cell` with this `value`. Dangerous, should really not exist, but does in Lisp 1.5 (and was important for some performance hacks in early Lisps) |
| SET | Host function | ([symbol val]) | Implementation of SET in Clojure. Add to the `oblist` a binding of the value of `var` to the value of `val`. NOTE WELL: this is not SETQ! |
| SUB1 | Lisp function | (N) | ? |
| SYSIN | Host function | ([filename]) | Read the contents of the file at this `filename` into the object list. If the file is not a valid Beowulf sysout file, this will probably corrupt the system, you have been warned. File paths will be considered relative to the filepath set when starting Lisp. It is intended that sysout files can be read both from resources within the jar file, and from the file system. If a named file exists in both the file system and the resources, the file system will be preferred. **NOTE THAT** if the provided `filename` does not end with `.lsp` (which, if you're writing it from the Lisp REPL, it won't), the extension `.lsp` will be appended. |
| SYSOUT | Host function | ([] [filepath]) | Dump the current content of the object list to file. If no `filepath` is specified, a file name will be constructed of the symbol `Sysout` and the current date. File paths will be considered relative to the filepath set when starting Lisp. |
| TERPRI | ? | null | ? |
| TIMES | Host function | ([& args]) | ? |
| TRACE | ? | null | ? |
| UNTRACE | ? | null | ? |
| ZEROP | Lisp function | (N) | ? |
### Architectural plan
Not everything documented in this section is yet built. It indicates the
@ -110,8 +172,13 @@ 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,
implementations.
What's even more surprising is how faithful a reimplementation of Lisp 1.5
the first Lisp dialect I learned, [Acornsoft Lisp](https://en.wikipedia.org/wiki/Acornsoft_LISP), turns out to have been.
I'm convinced you could still use Lisp 1.5 for interesting
and useful software (which isn't to say that modern Lisps aren't better,
but this is software which is almost sixty years old).
## Installation
@ -122,25 +189,6 @@ At present, clone the source and build it using
You will require to have [Leiningen](https://leiningen.org/) installed.
## Usage
`java -jar beowulf-0.1.0-standalone.jar`
This will start a Lisp 1.5 read/eval/print loop (REPL).
Command line arguments are as follows:
```
-f FILEPATH, --file-path FILEPATH Set the path to the directory for reading and writing Lisp files.
-h, --help
-p PROMPT, --prompt PROMPT Sprecan:: Set the REPL prompt to PROMPT
-r INITFILE, --read INITFILE resources/lisp1.5.lsp Read Lisp system from file INITFILE
-s, --strict Strictly interpret the Lisp 1.5 language, without extensions.
-t, --trace Trace Lisp evaluation.
```
To end a session, type `STOP` at the command prompt.
### Input/output
Lisp 1.5 greatly predates modern computers. It had a facility to print to a line printer, or to punch cards on a punch-card machine, and it had a facility to read system images in from tape; but there's no file I/O as we would currently understand it, and, because there are no character strings and the valid characters within an atom are limited, it isn't easy to compose a sensible filename.

View file

@ -1,3 +0,0 @@
# Introduction to beowulf
TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)

1
doc/intro.md Symbolic link
View file

@ -0,0 +1 @@
../README.md

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>beowulf.io 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.1-SNAPSHOT</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 branch current"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</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.io.html#var-SYSIN"><div class="inner"><span>SYSIN</span></div></a></li><li class="depth-1"><a href="beowulf.io.html#var-SYSOUT"><div class="inner"><span>SYSOUT</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.io</h1><div class="doc"><div class="markdown"><p>Non-standard extensions to Lisp 1.5 to read and write to the filesystem.</p>
<html><head><meta charset="UTF-8" /><title>beowulf.io 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.1-SNAPSHOT</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>beowulf</span></div></a></li><li class="depth-1 "><a href="mexpr.html"><div class="inner"><span>M-Expressions</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.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</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 branch current"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li><li class="depth-2"><a href="beowulf.trace.html"><div class="inner"><span class="tree" style="top: -176px;"><span class="top" style="height: 185px;"></span><span class="bottom"></span></span><span>trace</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.io.html#var-SYSIN"><div class="inner"><span>SYSIN</span></div></a></li><li class="depth-1"><a href="beowulf.io.html#var-SYSOUT"><div class="inner"><span>SYSOUT</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.io</h1><div class="doc"><div class="markdown"><p>Non-standard extensions to Lisp 1.5 to read and write to the filesystem.</p>
<p>Lisp 1.5 had only <code>READ</code>, which read one S-Expression at a time, and various forms of <code>PRIN*</code> functions, which printed to the line printer. There was also <code>PUNCH</code>, which wrote to a card punch. It does not seem that there was any concept of an interactive terminal.</p>
<p>See Appendix E, <code>OVERLORD - THE MONITOR</code>, and Appendix F, <code>LISP INPUT
AND OUTPUT</code>.</p>

View file

@ -1,4 +1,4 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>beowulf.oblist 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.1-SNAPSHOT</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch current"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</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.oblist.html#var-*options*"><div class="inner"><span>*options*</span></div></a></li><li class="depth-1"><a href="beowulf.oblist.html#var-NIL"><div class="inner"><span>NIL</span></div></a></li><li class="depth-1"><a href="beowulf.oblist.html#var-oblist"><div class="inner"><span>oblist</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.oblist</h1><div class="doc"><div class="markdown"><p>A namespace mainly devoted to the object list.</p>
<html><head><meta charset="UTF-8" /><title>beowulf.oblist 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.1-SNAPSHOT</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>beowulf</span></div></a></li><li class="depth-1 "><a href="mexpr.html"><div class="inner"><span>M-Expressions</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.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch current"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li><li class="depth-2"><a href="beowulf.trace.html"><div class="inner"><span class="tree" style="top: -176px;"><span class="top" style="height: 185px;"></span><span class="bottom"></span></span><span>trace</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.oblist.html#var-*options*"><div class="inner"><span>*options*</span></div></a></li><li class="depth-1"><a href="beowulf.oblist.html#var-NIL"><div class="inner"><span>NIL</span></div></a></li><li class="depth-1"><a href="beowulf.oblist.html#var-oblist"><div class="inner"><span>oblist</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.oblist</h1><div class="doc"><div class="markdown"><p>A namespace mainly devoted to the object list.</p>
<p>Yes, this makes little sense, but if you put it anywhere else you end up in cyclic dependency hell.</p></div></div><div class="public anchor" id="var-*options*"><h3>*options*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><div class="markdown"><p>Command line options from invocation.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/oblist.clj#L16">view source</a></div></div><div class="public anchor" id="var-NIL"><h3>NIL</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>The canonical empty list symbol.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/oblist.clj#L8">view source</a></div></div><div class="public anchor" id="var-oblist"><h3>oblist</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>The default environment.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/oblist.clj#L12">view source</a></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>beowulf.reader.char-reader 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.1-SNAPSHOT</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>beowulf</span></div></a></li><li class="depth-1 "><a href="mexpr.html"><div class="inner"><span>M-Expressions</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.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch current"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li><li class="depth-2"><a href="beowulf.trace.html"><div class="inner"><span class="tree" style="top: -176px;"><span class="top" style="height: 185px;"></span><span class="bottom"></span></span><span>trace</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.reader.char-reader.html#var-get-reader"><div class="inner"><span>get-reader</span></div></a></li><li class="depth-1"><a href="beowulf.reader.char-reader.html#var-read-chars"><div class="inner"><span>read-chars</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">beowulf.reader.char-reader</h1><div class="doc"><div class="markdown"><p>Provide sensible line editing, auto completion, and history recall.</p>
<p>None of whats needed here is really working yet, and a pull request with a working implementation would be greatly welcomed.</p>
<h2><a href="#whats-needed-rough-specification-" name="whats-needed-rough-specification-"></a>Whats needed (rough specification)</h2>
<ol>
<li>Carriage return <strong>does not</strong> cause input to be returned, <strong>unless</strong> a. the number of open brackets <code>(</code> and closing brackets <code>)</code> match; and b. the number of open square brackets <code>[</code> and closing square brackets <code>]</code> also match;</li>
<li><ctrl-d> aborts editing and returns the string <code>STOP</code>;</ctrl-d></li>
<li><up-arrow> and <down-arrow> scroll back and forward through history, but ideally Id like this to be the Lisp history (i.e. the history of S-Expressions actually read by <code>READ</code>, rather than the strings which were supplied to <code>READ</code>);</down-arrow></up-arrow></li>
<li><tab> offers potential auto-completions taken from the value of <code>(OBLIST)</code>, ideally the current value, not the value at the time the session started;</tab></li>
<li><back-arrow> and <forward-arrow> offer movement and editing within the line.</forward-arrow></back-arrow></li>
</ol></div></div><div class="public anchor" id="var-get-reader"><h3>get-reader</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>Return a reader, first constructing it if necessary.</p>
<p><strong>NOTE THAT</strong> this is not settled API. The existence and call signature of this function is not guaranteed in future versions.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/reader/char_reader.clj#L27">view source</a></div></div><div class="public anchor" id="var-read-chars"><h3>read-chars</h3><div class="usage"><code>(read-chars)</code></div><div class="doc"><div class="markdown"><p>A drop-in replacement for <code>clojure.core/read-line</code>, except that line editing and history should be enabled.</p>
<p><strong>NOTE THAT</strong> this does not work yet, but it is in the API because I hope that it will work later!</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/reader/char_reader.clj#L36">view source</a></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,411 @@
<!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.1-SNAPSHOT</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</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>
<html><head><meta charset="UTF-8" /><title>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.1-SNAPSHOT</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>beowulf</span></div></a></li><li class="depth-1 "><a href="mexpr.html"><div class="inner"><span>M-Expressions</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.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li><li class="depth-2"><a href="beowulf.trace.html"><div class="inner"><span class="tree" style="top: -176px;"><span class="top" style="height: 185px;"></span><span class="bottom"></span></span><span>trace</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#beowulf" name="beowulf"></a>beowulf</h1>
<p>LISP 1.5 is to all Lisp dialects as Beowulf is to Emglish literature.</p>
<h2><a href="#what-this-is" name="what-this-is"></a>What this is</h2>
<p>A work-in-progress towards an implementation of Lisp 1.5 in Clojure. The objective is to build a complete and accurate implementation of Lisp 1.5 as described in the manual, with, in so far as is possible, exactly the same bahaviour - except as documented below.</p>
<h3><a href="#status" name="status"></a>Status</h3>
<p>Boots to REPL, but few functions yet available.</p>
<ul>
<li><a href="https://simon-brooke.github.io/beowulf/">Project website</a>.</li>
<li><a href="https://simon-brooke.github.io/beowulf/docs/codox/index.html">Source code documentation</a>.</li>
<li><a href="https://simon-brooke.github.io/beowulf/docs/cloverage/index.html">Test Coverage Report</a></li>
</ul>
<h3><a href="#building-and-invoking" name="building-and-invoking"></a>Building and Invoking</h3>
<p>Build with</p>
<pre><code>lein uberjar
</code></pre>
<p>Invoke with</p>
<pre><code>java -jar target/uberjar/beowulf-0.2.1-SNAPSHOT-standalone.jar --help
</code></pre>
<p>(Obviously, check your version number)</p>
<p>Command line arguments as follows:</p>
<pre><code> -h, --help Print this message
-p PROMPT, --prompt PROMPT Set the REPL prompt to PROMPT
-r INITFILE, --read INITFILE Read Lisp functions from the file INITFILE
-s, --strict Strictly interpret the Lisp 1.5 language, without extensions.
</code></pre>
<p>To end a session, type <code>STOP</code> at the command prompt.</p>
<h3><a href="#functions-and-symbols-implemented" name="functions-and-symbols-implemented"></a>Functions and symbols implemented</h3>
<p>The following functions and symbols are implemented:</p>
<table>
<thead>
<tr>
<th>Symbol </th>
<th>Type </th>
<th>Signature </th>
<th>Documentation </th>
</tr>
</thead>
<tbody>
<tr>
<td>NIL </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>T </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>F </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>ADD1 </td>
<td>Host function </td>
<td>([x]) </td>
<td>? </td>
</tr>
<tr>
<td>AND </td>
<td>Host function </td>
<td>([&amp; args]) </td>
<td><code>T</code> if and only if none of my <code>args</code> evaluate to either <code>F</code> or <code>NIL</code>, else <code>F</code>. In <code>beowulf.host</code> principally because I dont yet feel confident to define varargs functions in Lisp. </td>
</tr>
<tr>
<td>APPEND </td>
<td>Host function </td>
<td>([x y]) </td>
<td>Append the the elements of <code>y</code> to the elements of <code>x</code>. All args are assumed to be <code>beowulf.cons-cell/ConsCell</code> objects. See page 11 of the Lisp 1.5 Programmers Manual. </td>
</tr>
<tr>
<td>APPLY </td>
<td>Host function </td>
<td>([function args environment depth]) </td>
<td>Apply this <code>function</code> to these <code>arguments</code> in this <code>environment</code> and return the result. For bootstrapping, at least, a version of APPLY written in Clojure. All args are assumed to be symbols or <code>beowulf.cons-cell/ConsCell</code> objects. See page 13 of the Lisp 1.5 Programmers Manual. </td>
</tr>
<tr>
<td>ATOM </td>
<td>Host function </td>
<td>([x]) </td>
<td>Returns <code>T</code> if and only if the argument <code>x</code> is bound to an atom; else <code>F</code>. It is not clear to me from the documentation whether <code>(ATOM 7)</code> should return <code>T</code> or <code>F</code>. Im going to assume <code>T</code>. </td>
</tr>
<tr>
<td>CAR </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>CDR </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>CONS </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>COPY </td>
<td>Lisp function </td>
<td>(X) </td>
<td>? </td>
</tr>
<tr>
<td>DEFINE </td>
<td>Host function </td>
<td>([args]) </td>
<td>Bootstrap-only version of <code>DEFINE</code> which, post boostrap, can be overwritten in LISP. The single argument to <code>DEFINE</code> should be an assoc list which should be nconced onto the front of the oblist. Broadly, (SETQ OBLIST (NCONC ARG1 OBLIST)) </td>
</tr>
<tr>
<td>DIFFERENCE </td>
<td>Host function </td>
<td>([x y]) </td>
<td>? </td>
</tr>
<tr>
<td>DIVIDE </td>
<td>Lisp function </td>
<td>(X Y) </td>
<td>? </td>
</tr>
<tr>
<td>ERROR </td>
<td>Host function </td>
<td>([&amp; args]) </td>
<td>Throw an error </td>
</tr>
<tr>
<td>EQ </td>
<td>Host function </td>
<td>([x y]) </td>
<td>Returns <code>T</code> if and only if both <code>x</code> and <code>y</code> are bound to the same atom, else <code>NIL</code>. </td>
</tr>
<tr>
<td>EQUAL </td>
<td>Host function </td>
<td>([x y]) </td>
<td>This is a predicate that is true if its two arguments are identical S-expressions, and false if they are different. (The elementary predicate <code>EQ</code> is defined only for atomic arguments.) The definition of <code>EQUAL</code> is an example of a conditional expression inside a conditional expression. NOTE: returns <code>F</code> on failure, not <code>NIL</code> </td>
</tr>
<tr>
<td>EVAL </td>
<td>Host function </td>
<td>([expr] [expr env depth]) </td>
<td>Evaluate this <code>expr</code> and return the result. If <code>environment</code> is not passed, it defaults to the current value of the global object list. The <code>depth</code> argument is part of the tracing system and should not be set by user code. All args are assumed to be numbers, symbols or <code>beowulf.cons-cell/ConsCell</code> objects. </td>
</tr>
<tr>
<td>FIXP </td>
<td>Host function </td>
<td>([x]) </td>
<td>? </td>
</tr>
<tr>
<td>GENSYM </td>
<td>Host function </td>
<td>([]) </td>
<td>Generate a unique symbol. </td>
</tr>
<tr>
<td>GET </td>
<td>Lisp function </td>
<td>(X Y) </td>
<td>? </td>
</tr>
<tr>
<td>GREATERP </td>
<td>Host function </td>
<td>([x y]) </td>
<td>? </td>
</tr>
<tr>
<td>INTEROP </td>
<td>Host function </td>
<td>([fn-symbol args]) </td>
<td>Clojure (or other host environment) interoperation API. <code>fn-symbol</code> is expected to be either 1. a symbol bound in the host environment to a function; or 2. a sequence (list) of symbols forming a qualified path name bound to a function. Lower case characters cannot normally be represented in Lisp 1.5, so both the upper case and lower case variants of <code>fn-symbol</code> will be tried. If the function youre looking for has a mixed case name, that is not currently accessible. <code>args</code> is expected to be a Lisp 1.5 list of arguments to be passed to that function. Return value must be something acceptable to Lisp 1.5, so either a symbol, a number, or a Lisp 1.5 list. If <code>fn-symbol</code> is not found (even when cast to lower case), or is not a function, or the value returned cannot be represented in Lisp 1.5, an exception is thrown with <code>:cause</code> bound to <code>:interop</code> and <code>:detail</code> set to a value representing the actual problem. </td>
</tr>
<tr>
<td>INTERSECTION </td>
<td>Lisp function </td>
<td>(X Y) </td>
<td>? </td>
</tr>
<tr>
<td>LENGTH </td>
<td>Lisp function </td>
<td>(L) </td>
<td>? </td>
</tr>
<tr>
<td>LESSP </td>
<td>Host function </td>
<td>([x y]) </td>
<td>? </td>
</tr>
<tr>
<td>MEMBER </td>
<td>Lisp function </td>
<td>(A X) </td>
<td>? </td>
</tr>
<tr>
<td>MINUSP </td>
<td>Lisp function </td>
<td>(X) </td>
<td>? </td>
</tr>
<tr>
<td>NULL </td>
<td>Lisp function </td>
<td>(X) </td>
<td>? </td>
</tr>
<tr>
<td>NUMBERP </td>
<td>Host function </td>
<td>([x]) </td>
<td>? </td>
</tr>
<tr>
<td>OBLIST </td>
<td>Host function </td>
<td>([]) </td>
<td>Return a list of the symbols currently bound on the object list. <strong>NOTE THAT</strong> in the Lisp 1.5 manual, footnote at the bottom of page 69, it implies that an argument can be passed but Im not sure of the semantics of this. </td>
</tr>
<tr>
<td>ONEP </td>
<td>Lisp function </td>
<td>(X) </td>
<td>? </td>
</tr>
<tr>
<td>PAIR </td>
<td>Lisp function </td>
<td>(X Y) </td>
<td>? </td>
</tr>
<tr>
<td>PLUS </td>
<td>Host function </td>
<td>([&amp; args]) </td>
<td>? </td>
</tr>
<tr>
<td>PRETTY </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>PRINT </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>PROP </td>
<td>Lisp function </td>
<td>(X Y U) </td>
<td>? </td>
</tr>
<tr>
<td>QUOTIENT </td>
<td>Host function </td>
<td>([x y]) </td>
<td>Im not certain from the documentation whether Lisp 1.5 <code>QUOTIENT</code> returned the integer part of the quotient, or a realnum representing the whole quotient. I am for now implementing the latter. </td>
</tr>
<tr>
<td>READ </td>
<td>Host function </td>
<td>([] [input]) </td>
<td>An implementation of a Lisp reader sufficient for bootstrapping; not necessarily the final Lisp reader. <code>input</code> should be either a string representation of a LISP expression, or else an input stream. A single form will be read. </td>
</tr>
<tr>
<td>REMAINDER </td>
<td>Host function </td>
<td>([x y]) </td>
<td>? </td>
</tr>
<tr>
<td>REPEAT </td>
<td>Lisp function </td>
<td>(N X) </td>
<td>? </td>
</tr>
<tr>
<td>RPLACA </td>
<td>Host function </td>
<td>([cell value]) </td>
<td>Replace the CAR pointer of this <code>cell</code> with this <code>value</code>. Dangerous, should really not exist, but does in Lisp 1.5 (and was important for some performance hacks in early Lisps) </td>
</tr>
<tr>
<td>RPLACD </td>
<td>Host function </td>
<td>([cell value]) </td>
<td>Replace the CDR pointer of this <code>cell</code> with this <code>value</code>. Dangerous, should really not exist, but does in Lisp 1.5 (and was important for some performance hacks in early Lisps) </td>
</tr>
<tr>
<td>SET </td>
<td>Host function </td>
<td>([symbol val]) </td>
<td>Implementation of SET in Clojure. Add to the <code>oblist</code> a binding of the value of <code>var</code> to the value of <code>val</code>. NOTE WELL: this is not SETQ! </td>
</tr>
<tr>
<td>SUB1 </td>
<td>Lisp function </td>
<td>(N) </td>
<td>? </td>
</tr>
<tr>
<td>SYSIN </td>
<td>Host function </td>
<td>([filename]) </td>
<td>Read the contents of the file at this <code>filename</code> into the object list. If the file is not a valid Beowulf sysout file, this will probably corrupt the system, you have been warned. File paths will be considered relative to the filepath set when starting Lisp. It is intended that sysout files can be read both from resources within the jar file, and from the file system. If a named file exists in both the file system and the resources, the file system will be preferred. <strong>NOTE THAT</strong> if the provided <code>filename</code> does not end with <code>.lsp</code> (which, if youre writing it from the Lisp REPL, it wont), the extension <code>.lsp</code> will be appended. </td>
</tr>
<tr>
<td>SYSOUT </td>
<td>Host function </td>
<td>([] [filepath]) </td>
<td>Dump the current content of the object list to file. If no <code>filepath</code> is specified, a file name will be constructed of the symbol <code>Sysout</code> and the current date. File paths will be considered relative to the filepath set when starting Lisp. </td>
</tr>
<tr>
<td>TERPRI </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>TIMES </td>
<td>Host function </td>
<td>([&amp; args]) </td>
<td>? </td>
</tr>
<tr>
<td>TRACE </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>UNTRACE </td>
<td>? </td>
<td>null </td>
<td>? </td>
</tr>
<tr>
<td>ZEROP </td>
<td>Lisp function </td>
<td>(N) </td>
<td>? </td>
</tr>
</tbody>
</table>
<h3><a href="#architectural-plan" name="architectural-plan"></a>Architectural plan</h3>
<p>Not everything documented in this section is yet built. It indicates the direction of travel and intended destination, not the current state.</p>
<h4><a href="#resources-lisp1-5-lsp" name="resources-lisp1-5-lsp"></a>resources/lisp1.5.lsp</h4>
<p>The objective is to have within <code>resources/lisp1.5.lsp</code>, all those functions defined in the Lisp 1.5 Programmers Manual which can be implemented in Lisp.</p>
<p>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</p>
<ul>
<li>bootstrap.clj</li>
<li>host.clj</li>
<li>read.clj</li>
</ul>
<p>The objective this is to make it fairly easy to implement Lisp 1.5 on top of any of the many <a href="https://github.com/kanaka/mal">Make A Lisp</a> implementations.</p>
<h4><a href="#beowulf-boostrap-clj" name="beowulf-boostrap-clj"></a>beowulf/boostrap.clj</h4>
<p>This file is essentially Lisp as defined in Chapter 1 (pages 1-14) of the Lisp 1.5 Programmers Manual; that is to say, a very simple Lisp language, which should, I believe, be sufficient in conjunction with the functions provided by <code>beowulf.host</code>, to bootstrap the full Lisp 1.5 interpreter.</p>
<p>In addition it contains the function <code>INTEROP</code>, which allows host language functions to be called from Lisp.</p>
<h4><a href="#beowulf-host-clj" name="beowulf-host-clj"></a>beowulf/host.clj</h4>
<p>This file provides Lisp 1.5 functions which cant be (or cant efficiently be) implemented in Lisp 1.5, which therefore need to be implemented in the host language, in this case Clojure.</p>
<h4><a href="#beowulf-read-clj" name="beowulf-read-clj"></a>beowulf/read.clj</h4>
<p>This file provides the reader required for boostrapping. Its not a bad reader - it provides feedback on errors found in the input - but it isnt 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 double 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>
<h3><a href="#but-why-" name="but-why-"></a>BUT WHY?!!?!</h3>
<p>Because.</p>
<p>Because Lisp is the only computer language worth learning, and if a thing is worth learning, its worth learning properly; which means going back to the beginning and trying to understand that.</p>
<p>Because there is, so far as I know, no working implementation of Lisp 1.5 for modern machines.</p>
<p>Because Im barking mad, and this is therapy.</p>
<h3><a href="#commentary" name="commentary"></a>Commentary</h3>
<p>Whats 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 <a href="http://www.softwarepreservation.org/projects/LISP/standard_lisp_family/#Portable_Standard_LISP_">Portable Standard Lisp</a> which is in my opinion one of the best and most usable early Lisp implementations. </p>
<p>Whats even more surprising is how faithful a reimplementation of Lisp 1.5 the first Lisp dialect I learned, <a href="https://en.wikipedia.org/wiki/Acornsoft_LISP">Acornsoft Lisp</a>, turns out to have been.</p>
<p>Im convinced you could still use Lisp 1.5 for interesting and useful software (which isnt to say that modern Lisps arent better, but this is software which is almost sixty years old).</p>
<h2><a href="#installation" name="installation"></a>Installation</h2>
<p>At present, clone the source and build it using</p>
<p><code>lein uberjar</code>.</p>
<p>You will require to have <a href="https://leiningen.org/">Leiningen</a> installed.</p>
<h3><a href="#input-output" name="input-output"></a>Input/output</h3>
<p>Lisp 1.5 greatly predates modern computers. It had a facility to print to a line printer, or to punch cards on a punch-card machine, and it had a facility to read system images in from tape; but theres no file I/O as we would currently understand it, and, because there are no character strings and the valid characters within an atom are limited, it isnt easy to compose a sensible filename.</p>
<p>Ive provided two functions to work around this problem.</p>
<h4><a href="#sysout" name="sysout"></a>SYSOUT</h4>
<p><code>SYSOUT</code> dumps the global object list to disk as a single S Expression (specifically: an association list). This allows you to persist your session, with all your current work, to disk. The function takes one argument, expected to be a symbol, and, if that argument is provided, writes a file whose name is that symbol with <code>.lsp</code> appended. If no argument is provided, it will construct a filename comprising the token <code>Sysout</code>, followed by the current date, followed by <code>.lsp</code>. In either case the file will be written to the directory given in the FILEPATH argument at startup time, or by default the current directory.</p>
<p>Obviously, <code>SYSOUT</code> may be called interactively (and this is the expected practice).</p>
<h4><a href="#sysin" name="sysin"></a>SYSIN</h4>
<p><code>SYSIN</code> reads a file from disk and overwrites the global object list with its contents. The expected practice is that this will be a file created by <code>SYSOUT</code>. A command line flag <code>--read</code> is provided so that you can specify </p>
<h2><a href="#learning-lisp-1-5" name="learning-lisp-1-5"></a>Learning Lisp 1.5</h2>
<p>The <code>Lisp 1.5 Programmer's Manual</code> is still <a href="https://mitpress.mit.edu/books/lisp-15-programmers-manual">in print, ISBN 13 978-0-262-13011-0</a>; but its also <a href="http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf">available online</a>.</p>
<h2><a href="#other-lisp-1-5-resources" name="other-lisp-1-5-resources"></a>Other Lisp 1.5 resources</h2>
<p>The main resource Im aware of is the Software Preservation Societys site, <a href="http://www.softwarepreservation.org/projects/LISP/lisp1.5">here</a>. 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 <code>resources/lisp1.5.lsp</code> is largely copytyped and reconstructed from the manual.</p>
<p>Im not at this time aware of any other working Lisp 1.5 implementations.</p>
<h2><a href="#license" name="license"></a>License</h2>
<p>Copyright © 2019 Simon Brooke. Licensed under the GNU General Public License, version 2.0 or (at your option) any later version.</p></div></div></div></body></html>

41
docs/codox/mexpr.html Normal file
View file

@ -0,0 +1,41 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>M-Expressions</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.1-SNAPSHOT</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>beowulf</span></div></a></li><li class="depth-1 current"><a href="mexpr.html"><div class="inner"><span>M-Expressions</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.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</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 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><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><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li><li class="depth-2"><a href="beowulf.trace.html"><div class="inner"><span class="tree" style="top: -176px;"><span class="top" style="height: 185px;"></span><span class="bottom"></span></span><span>trace</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#m-expressions" name="m-expressions"></a>M-Expressions</h1>
<p>M-Expressions (mexprs) are the grammar which John McCarthy origininally used to write Lisp, and the grammar in which many of the function definitions in the <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf">Lisp 1.5 Programmers Manual</a> are stated. However, I have not seen anywhere a claim that Lisp 1.5 could <em>read</em> M-Expressions, and it is not clear to me whether it was even planned that it should do so.</p>
<p>Rather, it seems to me probably that M-Expressions were only ever a grammar intended to be written on paper, like <a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form">Backus Naur Form</a>, to describe and to reason about algorithms.</p>
<p>I set out to make Beowulf read M-Expressions essentially out of curiousity, to see whether it could be done. I had this idea that if it could be done, I could implement most of Lisp 1.5 simply by copying in the M-Expression definitions out of the manual.</p>
<p>Consequently, the Beowulf parser can parse the M-Expression grammar as stated in the manual, and generate S-Expressions from it according to the table specified on page 10 of the manual.</p>
<p>There are two problems with this.</p>
<h2><a href="#problems-with-interpreting-m-expressions" name="problems-with-interpreting-m-expressions"></a>Problems with interpreting M-Expressions</h2>
<h3><a href="#generating-idiomatic-lisp" name="generating-idiomatic-lisp"></a>Generating idiomatic Lisp</h3>
<p>In the M-Expression notation, a lower case character or sequence of characters represents a variable; an upper case character represents a constant. As the manual says,</p>
<blockquote>
<p>2 . The obvious translation of letting a constant translate into itself will not work. Since the translation of <code>x</code> is <code>X</code>, the translation of <code>X</code> must be something else to avoid ambiguity. The solution is to quote it. Thus <code>X</code> is translated into <code>(QUOTE X)</code>.</p>
</blockquote>
<p>Thus, necessarily, the translation of a constant must always be quoted. In practice, key constants in Lisp such as <code>T</code> are bound to themselves, so it is idiomatic in Lisp, certainly in the way we have learned to use it, to write, for example,</p>
<pre><code>(SET (QUOTE NULL)
(QUOTE (LAMBDA (X)
(COND
((EQUAL X NIL) T) (T F)))))
</code></pre>
<p>However, the literal translation of</p>
<pre><code>null[x] = [x = NIL -&gt; T; T -&gt; F]
</code></pre>
<p>is</p>
<pre><code>(SET (QUOTE NULL)
(QUOTE (LAMBDA (X)
(COND
((EQUAL X (QUOTE NIL)) (QUOTE T))
((QUOTE T) (QUOTE F))))))
</code></pre>
<p>This is certainly more prolix and more awkward, but it also risks being flat wrong.</p>
<p>Is the value of <code>NIL</code> the atom <code>NIL</code>, or is it the empty list <code>()</code>? If the former, then the translation from the M-Expression above is correct. However, that means that recursive functions which recurse down a list seeking the end will fail. So the latter must be the case.</p>
<p><code>NULL</code> is described thus (Ibid, p11):</p>
<blockquote>
<p>This is a predicate useful for deciding when a list is exhausted. It is true if and only if its argument is <code>NIL</code>.</p>
</blockquote>
<p><code>NIL</code> is used explicitly in an M-Expression for example in the definition of <code>intersection</code> (Ibid, p15).</p>
<p>I think there is an ambiguity in referencing constants which are not bound to themselves in the M-Expression notation as given in the manual. This is particularly problematic with regards to <code>NIL</code> and <code>F</code>, but there may be others instances.</p>
<h3><a href="#curly-braces" name="curly-braces"></a>Curly braces</h3>
<p>The use of curly braces is not defined in the grammar as stated on page 10. They are not used in the initial definition of <code>APPLY</code> on page 13, but they are used in the more developed restatement on page 70. I believe they are to be read as indicating a <code>DO</code> statement a list of function calls to be made sequentially but without strict functional dependence on one another but I dont find the exposition here particularly clear and Im not sure of this.</p>
<p>Consequently, the M-Expression interpreter in Beowulf does not interpret curly braces.</p></div></div></div></body></html>

View file

@ -1,5 +1,6 @@
(defproject beowulf "0.2.1-SNAPSHOT"
:cloverage {:output "docs/cloverage"}
:cloverage {:output "docs/cloverage"
:ns-exclude-regex [#"beowulf\.gendoc"]}
:codox {:metadata {:doc "**TODO**: write docs"
:doc/format :markdown}
:output-path "docs/codox"
@ -18,7 +19,7 @@
[rhizome "0.2.9"] ;; not needed in production builds
]
:main ^:skip-aot beowulf.core
:plugins [[lein-cloverage "1.1.1"]
:plugins [[lein-cloverage "1.2.2"]
[lein-codox "0.10.7"]
[lein-environ "1.1.0"]]
:profiles {:uberjar {:aot :all}}

77
src/beowulf/gendoc.clj Normal file
View file

@ -0,0 +1,77 @@
(ns beowulf.gendoc
(:require [beowulf.oblist :refer [oblist]]
[clojure.string :refer [join replace]]))
(def host-functions
"Functions which we can infer are written in Clojure."
(reduce
merge
{}
(map
ns-publics
['beowulf.bootstrap
'beowulf.host
'beowulf.io
'beowulf.read])))
;; OK, this, improbably, works. There's probably a better way...
;; (:doc (meta (eval (read-string (str "#'" "beowulf.read" "/" "READ")))))
(defn- get-metadata-for-function
"Return the metadata associated with this compiled Clojure `function`.
If `key` is passed, return only the value of `key` in that metadata.
The value of `key` should be a keyword; of `function`, a function."
([function]
(try
(meta (eval (read-string (str function))))
(catch Throwable _ "?")))
([function key]
(when (keyword? key)
(key (get-metadata-for-function function)))))
(defn- get-metadata-for-entry [entry key]
(let [fn (host-functions (symbol (first entry)))]
(get-metadata-for-function fn key)))
(defn infer-type
[entry]
(cond
(= (second entry) 'LAMBDA) "Lisp function"
(host-functions (first entry)) "Host function"
:else "?"))
(defn infer-signature
[entry]
(cond
(= (count entry) 1) (get-metadata-for-entry entry :arglists)
(= (second entry) 'LAMBDA) (nth entry 2)
:else "?"))
(defn find-documentation
[entry]
(cond
(= (count entry) 1) (if-let [doc (get-metadata-for-entry entry :doc)]
(replace doc "\n" " ")
"?")
:else "?"))
(defn gen-doc-table
[]
(join
"\n"
(doall
(concat
'("| Symbol | Type | Signature | Documentation |"
"|--------|------|-----------|---------------|")
(map
#(format "| %s | %s | %s | %s |"
(first %)
(infer-type %)
(infer-signature %)
(find-documentation %))
@oblist)))))
;; (println (gen-doc-table))