diff --git a/docs/codox/beowulf.bootstrap.html b/docs/codox/beowulf.bootstrap.html index 8301c99..72c621f 100644 --- a/docs/codox/beowulf.bootstrap.html +++ b/docs/codox/beowulf.bootstrap.html @@ -1,6 +1,6 @@ -beowulf.bootstrap documentation

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..

+beowulf.bootstrap documentation

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.

APPLY

(APPLY 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.

EVAL

(EVAL expr)(EVAL 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. However, if called with just a single arg, expr, I’ll assume it’s being called from the Clojure REPL and will coerce the expr to ConsCell.

find-target

TODO: write docs

PROG

(PROG program env depth)

The accursed PROG feature. See page 71 of the manual.

diff --git a/docs/codox/beowulf.cons-cell.html b/docs/codox/beowulf.cons-cell.html index 6e2b315..cc83668 100644 --- a/docs/codox/beowulf.cons-cell.html +++ b/docs/codox/beowulf.cons-cell.html @@ -1,3 +1,3 @@ -beowulf.cons-cell documentation

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, and must have both CAR and CDR mutable, so cannot be implemented on top of Clojure lists.

cons-cell?

(cons-cell? o)

Is this object o a beowulf cons-cell?

F

The canonical false value - different from NIL, which is not canonically false in Lisp 1.5.

make-beowulf-list

(make-beowulf-list x)

Construct a linked list of cons cells with the same content as the sequence x.

make-cons-cell

(make-cons-cell car cdr)

Construct a new instance of cons cell with this car and cdr.

MutableSequence

protocol

Like a sequence, but mutable.

members

getCar

(getCar this)

Return the first element of this sequence.

getCdr

(getCdr this)

like more, q.v., but returns List NIL not Clojure nil when empty.

getUid

(getUid this)

Returns a unique identifier for this object

rplaca

(rplaca this value)

replace the first element of this sequence with this value

rplacd

(rplacd this value)

replace the rest (but-first; cdr) of this sequence with this value

pretty-print

(pretty-print cell)(pretty-print cell width level)

This isn’t the world’s best pretty printer but it sort of works.

T

The canonical true value.

\ No newline at end of file +beowulf.cons-cell documentation

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, and must have both CAR and CDR mutable, so cannot be implemented on top of Clojure lists.

cons-cell?

(cons-cell? o)

Is this object o a beowulf cons-cell?

F

The canonical false value - different from NIL, which is not canonically false in Lisp 1.5.

make-beowulf-list

(make-beowulf-list x)

Construct a linked list of cons cells with the same content as the sequence x.

make-cons-cell

(make-cons-cell car cdr)

Construct a new instance of cons cell with this car and cdr.

MutableSequence

protocol

Like a sequence, but mutable.

members

getCar

(getCar this)

Return the first element of this sequence.

getCdr

(getCdr this)

like more, q.v., but returns List NIL not Clojure nil when empty.

getUid

(getUid this)

Returns a unique identifier for this object

rplaca

(rplaca this value)

replace the first element of this sequence with this value

rplacd

(rplacd this value)

replace the rest (but-first; cdr) of this sequence with this value

pretty-print

(pretty-print cell)(pretty-print cell width level)

This isn’t the world’s best pretty printer but it sort of works.

T

The canonical true value.

\ No newline at end of file diff --git a/docs/codox/beowulf.core.html b/docs/codox/beowulf.core.html index 8b8b2ef..1d60abf 100644 --- a/docs/codox/beowulf.core.html +++ b/docs/codox/beowulf.core.html @@ -1,3 +1,3 @@ -beowulf.core documentation

beowulf.core

Essentially, the -main function and the bootstrap read-eval-print loop.

-main

(-main & opts)

Parse options, print the banner, read the init file if any, and enter the read/eval/print loop.

cli-options

TODO: write docs

repl

(repl prompt)

Read/eval/print loop.

stop-word

The word which, if submitted an an input line, will cause Beowulf to quit. Question: should this be forlǣte?

\ No newline at end of file +beowulf.core documentation

beowulf.core

Essentially, the -main function and the bootstrap read-eval-print loop.

-main

(-main & opts)

Parse options, print the banner, read the init file if any, and enter the read/eval/print loop.

cli-options

TODO: write docs

repl

(repl prompt)

Read/eval/print loop.

stop-word

The word which, if submitted an an input line, will cause Beowulf to quit. Question: should this be forlǣte?

\ No newline at end of file diff --git a/docs/codox/beowulf.gendoc.html b/docs/codox/beowulf.gendoc.html index 763e8ab..fa4087e 100644 --- a/docs/codox/beowulf.gendoc.html +++ b/docs/codox/beowulf.gendoc.html @@ -1,4 +1,4 @@ -beowulf.gendoc documentation

beowulf.gendoc

Generate table of documentation of Lisp symbols and functions.

+beowulf.gendoc documentation

beowulf.gendoc

Generate table of documentation of Lisp symbols and functions.

NOTE: this is very hacky. You almost certainly do not want to use this!

find-documentation

(find-documentation entry)

Find appropriate documentation for this entry from the oblist.

gen-doc-table

(gen-doc-table)

TODO: write docs

gen-index

(gen-index)(gen-index url destination)

TODO: write docs

host-functions

Functions which we can infer are written in Clojure. We need to collect these at run-time, not compile time, hence memoised function, not variable.

infer-implementation

(infer-implementation entry)

TODO: write docs

infer-signature

(infer-signature entry)

Infer the signature of the function value of this oblist entry, if any.

infer-type

(infer-type entry)

Try to work out what this entry from the oblist actually represents.

open-doc

(open-doc symbol)

Open the documentation page for this symbol, if known, in the default web browser.

\ No newline at end of file diff --git a/docs/codox/beowulf.host.html b/docs/codox/beowulf.host.html index d6c6f6f..efef2cb 100644 --- a/docs/codox/beowulf.host.html +++ b/docs/codox/beowulf.host.html @@ -1,6 +1,6 @@ -beowulf.host documentation

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.

ADD1

(ADD1 x)

TODO: write docs

AND

(AND & args)

T if and only if none of my args evaluate to either F or NIL, else F.

+beowulf.host documentation

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.

ADD1

(ADD1 x)

TODO: write docs

AND

(AND & 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.

ASSOC

(ASSOC x a)

If a is an association list such as the one formed by PAIRLIS in the above example, then assoc will produce the first pair whose first term is x. Thus it is a table searching function.

All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual.

NOTE THAT this function is overridden by an implementation in Lisp, but is currently still present for bootstrapping.

ATOM

(ATOM 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.

ATOM?

macro

(ATOM? x)

The convention of returning F from predicates, rather than NIL, is going to tie me in knots. This is a variant of ATOM which returns NIL on failure.

CAAAAR

macro

(CAAAAR x)

TODO: write docs

CAAADR

macro

(CAAADR x)

TODO: write docs

CAAAR

macro

(CAAAR x)

TODO: write docs

CAADAR

macro

(CAADAR x)

TODO: write docs

CAADDR

macro

(CAADDR x)

TODO: write docs

CAADR

macro

(CAADR x)

TODO: write docs

CAAR

macro

(CAAR x)

TODO: write docs

CADAAR

macro

(CADAAR x)

TODO: write docs

CADADR

macro

(CADADR x)

TODO: write docs

CADAR

macro

(CADAR x)

TODO: write docs

CADDAR

macro

(CADDAR x)

TODO: write docs

CADDDR

macro

(CADDDR x)

TODO: write docs

CADDR

macro

(CADDR x)

TODO: write docs

CADR

macro

(CADR x)

TODO: write docs

CAR

(CAR x)

Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL.

CDAAAR

macro

(CDAAAR x)

TODO: write docs

CDAADR

macro

(CDAADR x)

TODO: write docs

CDAAR

macro

(CDAAR x)

TODO: write docs

CDADAR

macro

(CDADAR x)

TODO: write docs

CDADDR

macro

(CDADDR x)

TODO: write docs

CDADR

macro

(CDADR x)

TODO: write docs

CDAR

macro

(CDAR x)

TODO: write docs

CDDAAR

macro

(CDDAAR x)

TODO: write docs

CDDADR

macro

(CDDADR x)

TODO: write docs

CDDAR

macro

(CDDAR x)

TODO: write docs

CDDDAR

macro

(CDDDAR x)

TODO: write docs

CDDDDR

macro

(CDDDDR x)

TODO: write docs

CDDDR

macro

(CDDDR x)

TODO: write docs

CDDR

macro

(CDDR x)

TODO: write docs

CDR

(CDR x)

Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL.

CONS

(CONS car cdr)

Construct a new instance of cons cell with this car and cdr.

CONSP

(CONSP o)

Return T if object o is a cons cell, else F.

diff --git a/docs/codox/beowulf.interop.html b/docs/codox/beowulf.interop.html index cd46169..59e1c5b 100644 --- a/docs/codox/beowulf.interop.html +++ b/docs/codox/beowulf.interop.html @@ -1,6 +1,6 @@ -beowulf.interop documentation

beowulf.interop

TODO: write docs

INTEROP

(INTEROP fn-symbol args)

Clojure (or other host environment) interoperation API. fn-symbol is expected to be either

+beowulf.interop documentation

beowulf.interop

TODO: write docs

INTEROP

(INTEROP 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.
  3. diff --git a/docs/codox/beowulf.io.html b/docs/codox/beowulf.io.html index d5bae54..648f733 100644 --- a/docs/codox/beowulf.io.html +++ b/docs/codox/beowulf.io.html @@ -1,6 +1,6 @@ -beowulf.io documentation

    beowulf.io

    Non-standard extensions to Lisp 1.5 to read and write to the filesystem.

    +beowulf.io documentation

    beowulf.io

    Non-standard extensions to Lisp 1.5 to read and write to the filesystem.

    Lisp 1.5 had only READ, which read one S-Expression at a time, and various forms of PRIN* functions, which printed to the line printer. There was also PUNCH, which wrote to a card punch. It does not seem that there was any concept of an interactive terminal.

    See Appendix E, OVERLORD - THE MONITOR, and Appendix F, LISP INPUT AND OUTPUT.

    diff --git a/docs/codox/beowulf.manual.html b/docs/codox/beowulf.manual.html index cd01906..3a82449 100644 --- a/docs/codox/beowulf.manual.html +++ b/docs/codox/beowulf.manual.html @@ -1,3 +1,3 @@ -beowulf.manual documentation

    beowulf.manual

    Experimental code for accessing the manual online.

    *manual-url*

    dynamic

    TODO: write docs

    format-page-references

    (format-page-references fn-symbol)

    Format page references from the manual index for the function whose name is fn-symbol.

    index

    This is data extracted from the index pages of Lisp 1.5 Programmer's Manual. It’s here in the hope that we can automatically link to an online PDF link to the manual when the user invokes a function probably called DOC or HELP.

    page-url

    (page-url page-no)

    Format the URL for the page in the manual with this page-no.

    \ No newline at end of file +beowulf.manual documentation

    beowulf.manual

    Experimental code for accessing the manual online.

    *manual-url*

    dynamic

    TODO: write docs

    format-page-references

    (format-page-references fn-symbol)

    Format page references from the manual index for the function whose name is fn-symbol.

    index

    This is data extracted from the index pages of Lisp 1.5 Programmer's Manual. It’s here in the hope that we can automatically link to an online PDF link to the manual when the user invokes a function probably called DOC or HELP.

    page-url

    (page-url page-no)

    Format the URL for the page in the manual with this page-no.

    \ No newline at end of file diff --git a/docs/codox/beowulf.oblist.html b/docs/codox/beowulf.oblist.html index 74f48e7..ea54aa2 100644 --- a/docs/codox/beowulf.oblist.html +++ b/docs/codox/beowulf.oblist.html @@ -1,5 +1,5 @@ -beowulf.oblist documentation

    beowulf.oblist

    A namespace mainly devoted to the object list and other top level global variables.

    +beowulf.oblist documentation

    beowulf.oblist

    A namespace mainly devoted to the object list and other top level global variables.

    Yes, this makes little sense, but if you put them anywhere else you end up in cyclic dependency hell.

    *options*

    dynamic

    Command line options from invocation.

    NIL

    The canonical empty list symbol.

    TODO: this doesn’t really work, because (from Clojure) (empty? NIL) throws an exception. It might be better to subclass beowulf.cons_cell.ConsCell to create a new singleton class Nil which overrides the empty method of IPersistentCollection?

    oblist

    The default environment.

    \ No newline at end of file diff --git a/docs/codox/beowulf.read.html b/docs/codox/beowulf.read.html index cfa7e94..1a7c002 100644 --- a/docs/codox/beowulf.read.html +++ b/docs/codox/beowulf.read.html @@ -1,6 +1,6 @@ -beowulf.read documentation

    beowulf.read

    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.

    +beowulf.read documentation

    beowulf.read

    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. diff --git a/docs/codox/beowulf.reader.char-reader.html b/docs/codox/beowulf.reader.char-reader.html index a014787..e726009 100644 --- a/docs/codox/beowulf.reader.char-reader.html +++ b/docs/codox/beowulf.reader.char-reader.html @@ -1,6 +1,6 @@ -beowulf.reader.char-reader documentation

      beowulf.reader.char-reader

      Provide sensible line editing, auto completion, and history recall.

      +beowulf.reader.char-reader documentation

      beowulf.reader.char-reader

      Provide sensible line editing, auto completion, and history recall.

      None of what’s needed here is really working yet, and a pull request with a working implementation would be greatly welcomed.

      What’s needed (rough specification)

        @@ -10,4 +10,7 @@
      1. offers potential auto-completions taken from the value of (OBLIST), ideally the current value, not the value at the time the session started;
      2. and offer movement and editing within the line.
      -

      TODO: There are multiple problems with JLine; a better solution might be to start from here: https://stackoverflow.com/questions/7931988/how-to-manipulate-control-characters

      \ No newline at end of file +

      TODO: There are multiple problems with JLine; a better solution might be to start from here: https://stackoverflow.com/questions/7931988/how-to-manipulate-control-characters

      build-completer

      (build-completer)

      Build a completer which takes tokens from the oblist.

      +

      This is sort-of working, in as much as hitting on a blank line will show a table of values from the oblist, but hitting after you’ve started input does not show potential completions for tokens you’ve started.

      get-reader

      Return a reader, first constructing it if necessary.

      +

      NOTE THAT this is not settled API. The existence and call signature of this function is not guaranteed in future versions.

      read-chars

      (read-chars)

      A drop-in replacement for clojure.core/read-line, except that line editing and history should be enabled.

      +

      NOTE THAT this does not fully work yet, but it is in the API because I hope that it will work later!

      \ No newline at end of file diff --git a/docs/codox/beowulf.reader.generate.html b/docs/codox/beowulf.reader.generate.html index 58d4e15..f2d763e 100644 --- a/docs/codox/beowulf.reader.generate.html +++ b/docs/codox/beowulf.reader.generate.html @@ -1,6 +1,6 @@ -beowulf.reader.generate documentation

      beowulf.reader.generate

      Generating S-Expressions from parse trees.

      +beowulf.reader.generate documentation

      beowulf.reader.generate

      Generating S-Expressions from parse trees.

      From Lisp 1.5 Programmers Manual, page 10

      Note that I’ve retyped much of this, since copy/pasting out of PDF is less than reliable. Any typos are mine.

      Quote starts:

      diff --git a/docs/codox/beowulf.reader.macros.html b/docs/codox/beowulf.reader.macros.html index 19c4982..55003ec 100644 --- a/docs/codox/beowulf.reader.macros.html +++ b/docs/codox/beowulf.reader.macros.html @@ -1,5 +1,5 @@ -beowulf.reader.macros documentation

      beowulf.reader.macros

      Can I implement reader macros? let’s see!

      +beowulf.reader.macros documentation

      beowulf.reader.macros

      Can I implement reader macros? let’s see!

      We don’t need (at least, in the Clojure reader) to rewrite forms like 'FOO, because that’s handled by the parser. But we do need to rewrite things which don’t evaluate their arguments, like SETQ, because (unless LABEL does it, which I’m not yet sure of) we’re not yet able to implement things which don’t evaluate arguments.

      TODO: at this stage, the following should probably also be read macros: DEFINE

      *readmacros*

      dynamic

      TODO: write docs

      expand-macros

      (expand-macros form)

      TODO: write docs

      \ No newline at end of file diff --git a/docs/codox/beowulf.reader.parser.html b/docs/codox/beowulf.reader.parser.html index 7499c5e..25eb874 100644 --- a/docs/codox/beowulf.reader.parser.html +++ b/docs/codox/beowulf.reader.parser.html @@ -1,3 +1,3 @@ -beowulf.reader.parser documentation

      beowulf.reader.parser

      The actual parser, supporting both S-expression and M-expression syntax.

      parse

      Parse a string presented as argument into a parse tree which can then be operated upon further.

      \ No newline at end of file +beowulf.reader.parser documentation

      beowulf.reader.parser

      The actual parser, supporting both S-expression and M-expression syntax.

      parse

      Parse a string presented as argument into a parse tree which can then be operated upon further.

      \ No newline at end of file diff --git a/docs/codox/beowulf.reader.simplify.html b/docs/codox/beowulf.reader.simplify.html index 52fa75b..013d66f 100644 --- a/docs/codox/beowulf.reader.simplify.html +++ b/docs/codox/beowulf.reader.simplify.html @@ -1,4 +1,4 @@ -beowulf.reader.simplify documentation

      beowulf.reader.simplify

      Simplify parse trees. Be aware that this is very tightly coupled with the parser.

      remove-nesting

      (remove-nesting tree context)

      TODO: write docs

      remove-optional-space

      (remove-optional-space tree)

      TODO: write docs

      simplify

      (simplify p)

      Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key. Calls remove-optional-space before processing.

      simplify-tree

      (simplify-tree p)(simplify-tree p context)

      Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key.

      +beowulf.reader.simplify documentation

      beowulf.reader.simplify

      Simplify parse trees. Be aware that this is very tightly coupled with the parser.

      remove-nesting

      (remove-nesting tree context)

      TODO: write docs

      remove-optional-space

      (remove-optional-space tree)

      TODO: write docs

      simplify

      (simplify p)

      Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key. Calls remove-optional-space before processing.

      simplify-tree

      (simplify-tree p)(simplify-tree p context)

      Simplify this parse tree p. If p is an instaparse failure object, throw an ex-info, with p as the value of its :failure key.

      NOTE THAT it is assumed that remove-optional-space has been run on the parse tree BEFORE it is passed to simplify-tree.

      \ No newline at end of file diff --git a/docs/codox/beowulf.scratch.html b/docs/codox/beowulf.scratch.html index bdd1149..671f5a6 100644 --- a/docs/codox/beowulf.scratch.html +++ b/docs/codox/beowulf.scratch.html @@ -1,3 +1,4 @@ -beowulf.scratch documentation

      beowulf.scratch

      This namespace is for temporary functions and is intentionally excluded from Git.

      accessor-body

      (accessor-body l v)

      TODO: write docs

      accessor-symbol

      (accessor-symbol l)

      Generate a symbol by prepending C and appending A to this list of string fragments l.

      accessors-generator

      (accessors-generator n)

      TODO: write docs

      manual-index

      TODO: write docs

      mogrify-plist

      (mogrify-plist entry fns)

      TODO: write docs

      \ No newline at end of file +beowulf.scratch documentation

      beowulf.scratch

      This namespace is for temporary functions and is intentionally excluded from Git.

      fns

      TODO: write docs

      interop-listify-q-name

      (interop-listify-q-name subr)

      We need to be able to print something we can link to the particular Clojure function subr in a form in which Lisp 1.5 is able to read it back in and relink it.

      +

      This assumes subr is either 1. a string in the format #'beowulf.io/SYSIN or beowulf.io/SYSIN; or 2. something which, when coerced to a string with str, will have such a format.

      mogrify-plist

      (mogrify-plist entry fns)

      TODO: write docs

      \ No newline at end of file diff --git a/resources/codox/themes/journeyman/css/default.css b/docs/codox/default.css similarity index 100% rename from resources/codox/themes/journeyman/css/default.css rename to docs/codox/default.css diff --git a/docs/codox/further_reading.html b/docs/codox/further_reading.html index 4ff9617..2c027dd 100644 --- a/docs/codox/further_reading.html +++ b/docs/codox/further_reading.html @@ -1,6 +1,6 @@ -Further Reading

      Further Reading

      +Further Reading

      Further Reading

      1. CODING for the MIT-IBM 704 COMPUTER, October 1957 This paper is not about Lisp. But it is about the particular individual computer on which Lisp was first implemented, and it is written in part by members of the Lisp team. I have found it useful in understanding the software environment in which, and the constraints under which, Lisp was written.
      2. MIT AI Memo 1, John McCarthy, September 1958 This is, as far as I can find, the earliest specification document of the Lisp project.
      3. diff --git a/resources/codox/themes/journeyman/css/highlight.css b/docs/codox/highlight.css similarity index 100% rename from resources/codox/themes/journeyman/css/highlight.css rename to docs/codox/highlight.css diff --git a/docs/codox/index.html b/docs/codox/index.html index 5d09c60..01c5b4f 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -Beowulf 0.3.0

        Beowulf 0.3.0

        Released under the GPL-2.0-or-later

        LISP 1.5 is to all Lisp dialects as Beowulf is to English literature.

        Installation

        To install, add the following dependency to your project or build file:

        [beowulf "0.3.0"]

        Topics

        Namespaces

        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..

        Public variables and functions:

        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, and must have both CAR and CDR mutable, so cannot be implemented on top of Clojure lists.

        beowulf.core

        Essentially, the -main function and the bootstrap read-eval-print loop.

        Public variables and functions:

        beowulf.gendoc

        Generate table of documentation of Lisp symbols and functions.

        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.

        beowulf.io

        Non-standard extensions to Lisp 1.5 to read and write to the filesystem.

        beowulf.manual

        Experimental code for accessing the manual online.

        Public variables and functions:

        beowulf.oblist

        A namespace mainly devoted to the object list and other top level global variables.

        Public variables and functions:

        beowulf.read

        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.

        Public variables and functions:

        beowulf.reader.char-reader

        Provide sensible line editing, auto completion, and history recall.

        Public variables and functions:

          beowulf.reader.macros

          Can I implement reader macros? let’s see!

          Public variables and functions:

          beowulf.reader.parser

          The actual parser, supporting both S-expression and M-expression syntax.

          Public variables and functions:

          beowulf.reader.simplify

          Simplify parse trees. Be aware that this is very tightly coupled with the parser.

          \ No newline at end of file +Beowulf 0.3.1-SNAPSHOT

          Beowulf 0.3.1-SNAPSHOT

          Released under the GPL-2.0-or-later

          LISP 1.5 is to all Lisp dialects as Beowulf is to English literature.

          Installation

          To install, add the following dependency to your project or build file:

          [beowulf "0.3.1-SNAPSHOT"]

          Topics

          Namespaces

          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..

          Public variables and functions:

          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, and must have both CAR and CDR mutable, so cannot be implemented on top of Clojure lists.

          beowulf.core

          Essentially, the -main function and the bootstrap read-eval-print loop.

          Public variables and functions:

          beowulf.gendoc

          Generate table of documentation of Lisp symbols and functions.

          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.

          beowulf.io

          Non-standard extensions to Lisp 1.5 to read and write to the filesystem.

          beowulf.manual

          Experimental code for accessing the manual online.

          Public variables and functions:

          beowulf.oblist

          A namespace mainly devoted to the object list and other top level global variables.

          Public variables and functions:

          beowulf.read

          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.

          Public variables and functions:

          beowulf.reader.char-reader

          Provide sensible line editing, auto completion, and history recall.

          Public variables and functions:

          beowulf.reader.macros

          Can I implement reader macros? let’s see!

          Public variables and functions:

          beowulf.reader.parser

          The actual parser, supporting both S-expression and M-expression syntax.

          Public variables and functions:

          beowulf.reader.simplify

          Simplify parse trees. Be aware that this is very tightly coupled with the parser.

          beowulf.scratch

          This namespace is for temporary functions and is intentionally excluded from Git.

          Public variables and functions:

          \ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html index e54cf99..03c2696 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,14 +1,835 @@ - - - - Beowulf: Documentation - - - -

          Beowulf: Documentation

          + +beowulf

          beowulf

          +

          Þý liste cræfte spræc

          +

          LISP 1.5 is to all Lisp dialects as Beowulf is to English literature.

          +

          Beowulf logo

          +

          Contents

          + +Table of contents generated with markdown-toc +

          What this is

          +

          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.

          +

          BUT WHY?!!?!

          +

          Because.

          +

          Because Lisp is the only computer language worth learning, and if a thing is worth learning, it’s worth learning properly; which means going back to the beginning and trying to understand that.

          +

          Because there is, so far as I know, no working implementation of Lisp 1.5 for modern machines.

          +

          Because I’m barking mad, and this is therapy.

          +

          Status

          +

          Working Lisp interpreter, but some key features not yet implemented.

          + +

          Project Target

          +

          The project target is to be able to run the Wang algorithm for the propositional calculus given in chapter 8 of the Lisp 1.5 Programmer’s Manual. When that runs, the project is as far as I am concerned feature complete. I may keep tinkering with it after that and I’ll certainly accept pull requests which are in the spirit of the project (i.e. making Beowulf more usable, and/or implementing parts of Lisp 1.5 which I have not implemented), but this isn’t intended to be a new language for doing real work; it’s an educational and archaeological project, not serious engineering.

          +

          Some readline-like functionality would be really useful, but my attempt to integrate JLine has not (yet) been successful.

          +

          An in-core structure editor would be an extremely nice thing, and I may well implement one.

          +

          You are of course welcome to fork the project and do whatever you like with it!

          +

          Invoking

          +

          Invoke with

          +
          java -jar target/uberjar/beowulf-0.3.0-standalone.jar --help
          +
          +

          (Obviously, check your version number)

          +

          Command line arguments as follows:

          +
            -h, --help                               Print this message
          +  -p PROMPT, --prompt PROMPT               Set the REPL prompt to PROMPT
          +  -r INITFILE, --read SYSOUTFILE           Read Lisp sysout from the file SYSOUTFILE 
          +                                           (defaults to `resources/lisp1.5.lsp`)
          +  -s, --strict                             Strictly interpret the Lisp 1.5 language, 
          +                                           without extensions.
          +
          +

          To end a session, type STOP at the command prompt.

          +

          Building and Invoking

          +

          Build with

          +
          lein uberjar
          +
          +

          Reader macros

          +

          Currently SETQ and DEFUN are implemented as reader macros, sort of. It would now be possible to reimplement them as FEXPRs and so the reader macro functionality will probably go away.

          +

          Functions and symbols implemented

          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          Function Type Signature Implementation Documentation
          NIL Lisp variable ? see manual pages 22, 69
          T Lisp variable ? see manual pages 22, 69
          F Lisp variable ? see manual pages 22, 69
          ADD1 Host lambda function ? ?
          AND Host lambda function ? PREDICATE 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 Lisp lambda function ? see manual pages 11, 61
          APPLY Host lambda function ? 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.
          ASSOC Lisp lambda function, Host lambda function ? ? If a is an association list such as the one formed by PAIRLIS in the above example, then assoc will produce the first pair whose first term is x. Thus it is a table searching function. All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual. NOTE THAT this function is overridden by an implementation in Lisp, but is currently still present for bootstrapping.
          ATOM Host lambda function ? PREDICATE 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 Host lambda function ? Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL.
          CAAAAR Lisp lambda function ? ? ?
          CAAADR Lisp lambda function ? ? ?
          CAAAR Lisp lambda function ? ? ?
          CAADAR Lisp lambda function ? ? ?
          CAADDR Lisp lambda function ? ? ?
          CAADR Lisp lambda function ? ? ?
          CAAR Lisp lambda function ? ? ?
          CADAAR Lisp lambda function ? ? ?
          CADADR Lisp lambda function ? ? ?
          CADAR Lisp lambda function ? ? ?
          CADDAR Lisp lambda function ? ? ?
          CADDDR Lisp lambda function ? ? ?
          CADDR Lisp lambda function ? ? ?
          CADR Lisp lambda function ? ? ?
          CDAAAR Lisp lambda function ? ? ?
          CDAADR Lisp lambda function ? ? ?
          CDAAR Lisp lambda function ? ? ?
          CDADAR Lisp lambda function ? ? ?
          CDADDR Lisp lambda function ? ? ?
          CDADR Lisp lambda function ? ? ?
          CDAR Lisp lambda function ? ? ?
          CDDAAR Lisp lambda function ? ? ?
          CDDADR Lisp lambda function ? ? ?
          CDDAR Lisp lambda function ? ? ?
          CDDDAR Lisp lambda function ? ? ?
          CDDDDR Lisp lambda function ? ? ?
          CDDDR Lisp lambda function ? ? ?
          CDDR Lisp lambda function ? ? ?
          CDR Host lambda function ? Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL.
          CONS Host lambda function ? Construct a new instance of cons cell with this car and cdr.
          CONSP Host lambda function ? ? Return T if object o is a cons cell, else F. NOTE THAT this is an extension function, not available in strct mode. I believe that Lisp 1.5 did not have any mechanism for testing whether an argument was, or was not, a cons cell.
          COPY Lisp lambda function ? see manual pages 62
          DEFINE Host lambda function ? PSEUDO-FUNCTION Bootstrap-only version of DEFINE which, post boostrap, can be overwritten in LISP. The single argument to DEFINE should be an association list of symbols to lambda functions. See page 58 of the manual.
          DIFFERENCE Host lambda function ? ?
          DIVIDE Lisp lambda function ? see manual pages 26, 64
          DOC Host lambda function ? ? Open the page for this symbol in the Lisp 1.5 manual, if known, in the default web browser. NOTE THAT this is an extension function, not available in strct mode.
          EFFACE Lisp lambda function ? PSEUDO-FUNCTION see manual pages 63
          ERROR Host lambda function ? PSEUDO-FUNCTION Throw an error
          EQ Host lambda function ? PREDICATE Returns T if and only if both x and y are bound to the same atom, else NIL.
          EQUAL Host lambda function ? PREDICATE 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 lambda function ? 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. However, if called with just a single arg, expr, I’ll assume it’s being called from the Clojure REPL and will coerce the expr to ConsCell.
          FACTORIAL Lisp lambda function ? ? ?
          FIXP Host lambda function ? PREDICATE ?
          GENSYM Host lambda function ? Generate a unique symbol.
          GET Host lambda function ? From the manual: ‘get is somewhat like prop; however its value is car of the rest of the list if the indicator is found, and NIL otherwise.’ It’s clear that GET is expected to be defined in terms of PROP, but we can’t implement PROP here because we lack EVAL; and we can’t have EVAL here because both it and APPLY depends on GET. OK, It’s worse than that: the statement of the definition of GET (and of) PROP on page 59 says that the first argument to each must be a list; But the in the definition of ASSOC on page 70, when GET is called its first argument is always an atom. Since it’s ASSOC and EVAL which I need to make work, I’m going to assume that page 59 is wrong.
          GREATERP Host lambda function ? PREDICATE ?
          INTEROP Host lambda function ? ? ?
          INTERSECTION Lisp lambda function ? ? ?
          LENGTH Lisp lambda function ? see manual pages 62
          LESSP Host lambda function ? PREDICATE ?
          MAPLIST Lisp lambda function ? FUNCTIONAL see manual pages 20, 21, 63
          MEMBER Lisp lambda function ? PREDICATE see manual pages 11, 62
          MINUSP Lisp lambda function ? PREDICATE see manual pages 26, 64
          NOT Lisp lambda function ? PREDICATE see manual pages 21, 23, 58
          NULL Lisp lambda function ? PREDICATE see manual pages 11, 57
          NUMBERP Host lambda function ? PREDICATE ?
          OBLIST Host lambda 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 lambda function ? PREDICATE see manual pages 26, 64
          OR Host lambda function ? PREDICATE T if and only if at least one of my args evaluates to something other than either F or NIL, else F. In beowulf.host principally because I don’t yet feel confident to define varargs functions in Lisp.
          PAIR Lisp lambda function ? see manual pages 60
          PAIRLIS Lisp lambda function, Host lambda function ? ? This function gives the list of pairs of corresponding elements of the lists x and y, and APPENDs this to the list a. The resultant list of pairs, which is like a table with two columns, is called an association list. Eessentially, it builds the environment on the stack, implementing shallow binding. All args are assumed to be beowulf.cons-cell/ConsCell objects. See page 12 of the Lisp 1.5 Programmers Manual. NOTE THAT this function is overridden by an implementation in Lisp, but is currently still present for bootstrapping.
          PLUS Host lambda function ? ?
          PRETTY ? ? ?
          PRINT ? PSEUDO-FUNCTION see manual pages 65, 84
          PROG Host nlambda function ? The accursed PROG feature. See page 71 of the manual. Lisp 1.5 introduced PROG, and most Lisps have been stuck with it ever since. It introduces imperative programming into what should be a pure functional language, and consequently it’s going to be a pig to implement. Broadly, PROG is a variadic pseudo function called as a FEXPR (or possibly an FSUBR, although I’m not presently sure that would even work.) The arguments, which are unevaluated, are a list of forms, the first of which is expected to be a list of symbols which will be treated as names of variables within the program, and the rest of which (the ‘program body’) are either lists or symbols. Lists are treated as Lisp expressions which may be evaulated in turn. Symbols are treated as targets for the GO statement. GO: A GO statement takes the form of (GO target), where target should be one of the symbols which occur at top level among that particular invocation of PROGs arguments. A GO statement may occur at top level in a PROG, or in a clause of a COND statement in a PROG, but not in a function called from the PROG statement. When a GO statement is evaluated, execution should transfer immediately to the expression which is the argument list immediately following the symbol which is its target. If the target is not found, an error with the code A6 should be thrown. RETURN: A RETURN statement takes the form (RETURN value), where value is any value. Following the evaluation of a RETURN statement, the PROG should immediately exit without executing any further expressions, returning the value. SET and SETQ: In addition to the above, if a SET or SETQ expression is encountered in any expression within the PROG body, it should affect not the global object list but instead only the local variables of the program. COND: In strict mode, when in normal execution, a COND statement none of whose clauses match should not return NIL but should throw an error with the code A3except that inside a PROG body, it should not do so. sigh. Flow of control: Apart from the exceptions specified above, expressions in the program body are evaluated sequentially. If execution reaches the end of the program body, NIL is returned. Got all that? Good.
          PROP Lisp lambda function ? FUNCTIONAL see manual pages 59
          QUOTE Lisp lambda function ? see manual pages 10, 22, 71
          QUOTIENT Host lambda function ? 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.
          RANGE Lisp lambda function ? ? ?
          READ Host lambda function ? PSEUDO-FUNCTION 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 lambda function ? ?
          REPEAT Lisp lambda function ? ? ?
          RPLACA Host lambda function ? PSEUDO-FUNCTION 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 lambda function ? PSEUDO-FUNCTION 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)
          SEARCH Lisp lambda function ? FUNCTIONAL see manual pages 63
          SET Host lambda function ? PSEUDO-FUNCTION 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 lambda function, Host lambda function ? ?
          SUB2 Lisp lambda function ? ? ?
          SUBLIS Lisp lambda function ? see manual pages 12, 61
          SUBST Lisp lambda function ? see manual pages 11, 61
          SYSIN Host lambda function ? ? 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. NOTE THAT this is an extension function, not available in strct mode.
          SYSOUT Host lambda function ? ? 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. NOTE THAT this is an extension function, not available in strct mode.
          TERPRI ? PSEUDO-FUNCTION see manual pages 65, 84
          TIMES Host lambda function ? ?
          TRACE Host lambda function ? PSEUDO-FUNCTION Add this s to the set of symbols currently being traced. If s is not a symbol or sequence of symbols, does nothing.
          UNION Lisp lambda function ? ? ?
          UNTRACE Host lambda function ? PSEUDO-FUNCTION Remove this s from the set of symbols currently being traced. If s is not a symbol or sequence of symbols, does nothing.
          ZEROP Lisp lambda function ? PREDICATE see manual pages 26, 64
          +

          Functions described as ‘Lisp function’ above are defined in the default sysout file, resources/lisp1.5.lsp, which will be loaded by default unless you specify another initfile on the command line.

          +

          Functions described as ‘Host function’ are implemented in Clojure, but if you’re brave you can redefine them in Lisp and the Lisp definitions will take precedence over the Clojure implementations.

          +

          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 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, 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. +
          3. 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.
          4. +
          +

          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 which is in my opinion one of the best and most usable early Lisp implementations.

          +

          What’s even more surprising is how faithful a reimplementation of Lisp 1.5 the first Lisp dialect I learned, 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

          +

          Download the latest release ‘uberjar’ and run it using:

          +
              java -jar <path name of uberjar>
          +
          +

          Or clone the source and build it using:

          +
              lein uberjar`
          +
          +

          To build it you will require to have Leiningen installed.

          +

          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.

          +

          I’ve provided two functions to work around this problem.

          +

          SYSOUT

          +

          SYSOUT 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 .lsp appended. If no argument is provided, it will construct a filename comprising the token Sysout, followed by the current date, followed by .lsp. 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.

          +

          Obviously, SYSOUT may be called interactively (and this is the expected practice).

          +

          SYSIN

          +

          SYSIN 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 SYSOUT. A command line flag --read is provided so that you can specify

          +

          Learning Lisp 1.5

          +

          The Lisp 1.5 Programmer's Manual is still in print, ISBN 13 978-0-262-13011-0; but it’s also available online.

          +

          Other Lisp 1.5 resources

          +

          The main resource I’m aware of is the Software Preservation Society’s site, here. 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.

          +

          Other implementations

          +

          There’s an online (browser native) Lisp 1.5 implementation here (source code here). It even has a working compiler!

          +

          History resources

          +

          I’m compiling a list of links to historical documents on Lisp 1.5.

          +

          License

          +

          Copyright © 2019 Simon Brooke. Licensed under the GNU General Public License, version 2.0 or (at your option) any later version.

          \ No newline at end of file diff --git a/docs/codox/mexpr.html b/docs/codox/mexpr.html index 7692fe9..a4cedae 100644 --- a/docs/codox/mexpr.html +++ b/docs/codox/mexpr.html @@ -1,6 +1,6 @@ -Interpreting M-Expressions

          Interpreting M-Expressions

          +Interpreting M-Expressions

          Interpreting M-Expressions

          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 Lisp 1.5 Programmer’s Manual are stated. However, I have not seen anywhere a claim that Lisp 1.5 could read M-Expressions, and it is not clear to me whether it was even planned that it should do so, although the discussion on page 10 suggests that it was.

          Rather, it seems to me possible that M-Expressions were only ever a grammar intended to be written on paper, like Backus Naur Form, to describe and to reason about algorithms. I think at the point at which the M-Expression grammar was written, the idea of the universal Lisp function

          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.

          diff --git a/docs/codox/values.html b/docs/codox/values.html index 1bfdc12..0cfcf99 100644 --- a/docs/codox/values.html +++ b/docs/codox/values.html @@ -1,6 +1,6 @@ -The properties of the system, and their values

          The properties of the system, and their values

          +The properties of the system, and their values

          The properties of the system, and their values

          here be dragons

          Lisp is the list processing language; that is what its name means. It processes data structures built of lists - which may be lists of lists, or lists of numbers, or lists of any other sort of data item provided for by the designers of the system.

          But how is a list, in a computer, actually implemented?

          diff --git a/project.clj b/project.clj index 1fa5892..20483ff 100644 --- a/project.clj +++ b/project.clj @@ -2,16 +2,11 @@ :aot :all :cloverage {:output "docs/cloverage" :ns-exclude-regex [#"beowulf\.gendoc" #"beowulf\.scratch"]} - :codox {:html {:transforms [[:head] [:append - [:link {:rel "icon" - :type "image/x-icon" - :href "../img/beowulf_logo_favicon.png"}]]]} - :metadata {:doc "**TODO**: write docs" + :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}" - ;; :themes [:journeyman] - } + :themes [:journeyman]} :description "LISP 1.5 is to all Lisp dialects as Beowulf is to English literature." :license {:name "GPL-2.0-or-later" :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} @@ -23,7 +18,7 @@ [clojure.java-time "1.2.0"] [environ "1.2.0"] [instaparse "1.4.12"] -;; [org.jline/jline "3.23.0"] + [org.jline/jline "3.23.0"] [rhizome "0.2.9"] ;; not needed in production builds ] :main beowulf.core @@ -31,7 +26,8 @@ [lein-codox "0.10.7"] [lein-environ "1.1.0"]] :profiles {:jar {:aot :all} - :uberjar {:aot :all}} + :uberjar {:aot :all} + :dev {:resource-paths ["resources"]}} :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] @@ -42,4 +38,4 @@ ["change" "version" "leiningen.release/bump-version"] ["vcs" "commit"]] :target-path "target/%s" - :url "https://github.com/simon-brooke/the-great-game") + :url "https://github.com/simon-brooke/beowulf") diff --git a/resources/codox/theme/journeyman/css/default.css b/resources/codox/theme/journeyman/css/default.css new file mode 100644 index 0000000..a445e91 --- /dev/null +++ b/resources/codox/theme/journeyman/css/default.css @@ -0,0 +1,563 @@ +body { + font-family: Helvetica, Arial, sans-serif; + font-size: 15px; + color: limegreen; + background-color: black; +} + +a { + color: lime; +} + +a:active, a:hover { + color: yellowgreen; +} + +a:visited { + color: green; +} + +pre, code { + font-family: Monaco, DejaVu Sans Mono, Consolas, monospace; + font-size: 9pt; + margin: 15px 0; + color: limegreen; + background-color: #111; +} + +h1 { + font-weight: normal; + font-size: 29px; + margin: 10px 0 2px 0; + padding: 0; +} + +h2 { + font-weight: normal; + font-size: 25px; +} + +th, td { + vertical-align: top; +} + +h5.license { + margin: 9px 0 22px 0; + color: lime; + 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: limegreen; + padding: 5px 7px; +} + +#content { + top: 32px; + right: 0; + bottom: 0; + overflow: auto; + background: black; + color: green; + padding: 0 18px; +} + +.sidebar { + position: fixed; + top: 32px; + bottom: 0; + overflow: auto; +} + +.sidebar.primary { + background: #080808; + border-right: solid 1px forestgreen; + left: 0; + width: 250px; +} + +.sidebar.secondary { + background: #111; + border-right: solid 1px darkgreen; + left: 251px; + width: 200px; +} + +#content.namespace-index, #content.document { + left: 251px; +} + +#content.namespace-docs { + left: 452px; +} + +#content.document { + padding-bottom: 10%; +} + +#header { + background: #080808; + box-shadow: 0 0 8px rgba(192, 255, 192, 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 h2 { + float: right; + font-size: 9pt; + font-weight: normal; + margin: 4px 3px; + padding: 0; + color: #5f5; +} + +#header h2 a { + display: inline; +} + +.sidebar h3 { + margin: 0; + padding: 10px 13px 0 13px; + font-size: 19px; + font-weight: lighter; +} + +.sidebar h3 a { + color: #4f4; +} + +.sidebar h3.no-link { + color: green; +} + +.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: #7F7; + 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 yellowgreen; + border-bottom: 1px solid yellowgreen; + height: 19px; +} + +.sidebar li .tree .bottom { + height: 22px; +} + +.sidebar li.branch .tree .bottom { + border-left: 1px solid yellowgreen; +} + +.sidebar.primary li.current a { + border-left: 3px solid goldenrod; + color: goldenrod; +} + +.sidebar.secondary li.current a { + border-left: 3px solid yellow; + color: yellow; +} + +.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 lime; + 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: lime; + 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 #5f5; +} + +#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: #7acc32; +} + +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: goldenrod; +} + +.type-sig pre { + padding-top: 10px; + margin: 0; +} + +.usage code { + display: block; + margin: 2px 0; + color: limegreen; +} + +.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 lime; + border-radius: 2px; +} + +.markdown code:not(.hljs), .src-link a { + background: #111; +} + +pre.deps { + display: inline-block; + margin: 0 10px; + border: 1px solid lime; + border-radius: 2px; + padding: 10px; + background-color: #111; +} + +.markdown hr { + border-style: solid; + border-top: none; + color: goldenrod; +} + +.doc ul, .doc ol { + padding-left: 30px; +} + +.doc table { + border-collapse: collapse; + margin: 0 10px; +} + +.doc table td, .doc table th { + border: 1px solid goldenrod; + padding: 4px 6px; +} + +.doc table th { + background: #111; +} + +.doc dl { + margin: 0 10px 20px 10px; +} + +.doc dl dt { + font-weight: bold; + margin: 0; + padding: 3px 0; + border-bottom: 1px solid goldenrod; +} + +.doc dl dd { + padding: 5px 0; + margin: 0 0 5px 10px; +} + +.doc abbr { + border-bottom: 1px dotted goldenrod; + font-variant: none; + cursor: help; +} + +.src-link { + margin-bottom: 15px; +} + +.src-link a { + font-size: 70%; + padding: 1px 4px; + text-decoration: none; + color: lime5bb; +} diff --git a/resources/codox/theme/journeyman/css/highlight.css b/resources/codox/theme/journeyman/css/highlight.css new file mode 100644 index 0000000..d0cdaa3 --- /dev/null +++ b/resources/codox/theme/journeyman/css/highlight.css @@ -0,0 +1,97 @@ +/* +github.com style (c) Vasily Polovnyov +*/ + +.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; +} diff --git a/resources/codox/theme/journeyman/theme.edn b/resources/codox/theme/journeyman/theme.edn new file mode 100644 index 0000000..0875f7f --- /dev/null +++ b/resources/codox/theme/journeyman/theme.edn @@ -0,0 +1,11 @@ +{:resources ["css/default.css" "css/highlight.css"] + :transforms [[:head] [:append + [:link {:rel "stylesheet" + :type "text/css" + :href "css/default.css"}] + [:link {:rel "stylesheet" + :type "text/css" + :href "css/highlight.css"}] + [:link {:rel "icon" + :type "image/x-icon" + :href "../img/beowulf_logo_favicon.png"}]]]} \ No newline at end of file diff --git a/resources/codox/themes/journeyman/theme.edn b/resources/codox/themes/journeyman/theme.edn deleted file mode 100644 index e1fdd5e..0000000 --- a/resources/codox/themes/journeyman/theme.edn +++ /dev/null @@ -1 +0,0 @@ -{:resources ["css/default.css" "css/highlight.css"]} \ No newline at end of file diff --git a/src/beowulf/core.clj b/src/beowulf/core.clj index d20339d..dacedef 100644 --- a/src/beowulf/core.clj +++ b/src/beowulf/core.clj @@ -63,11 +63,10 @@ (defn repl "Read/eval/print loop." [prompt] - (loop [] - (print prompt) + (loop [] (flush) (try - (if-let [input (trim (read-from-console))] + (if-let [input (trim (read-from-console prompt))] (if (= input stop-word) (throw (ex-info "\nFærwell!" {:cause :quit})) (println @@ -116,7 +115,7 @@ (catch Throwable any (println any)))) (try - (repl (str (:prompt (:options args)) " ")) + (repl (:prompt (:options args))) (catch Exception e diff --git a/src/beowulf/read.clj b/src/beowulf/read.clj index 54fcfe4..38860dc 100644 --- a/src/beowulf/read.clj +++ b/src/beowulf/read.clj @@ -13,13 +13,14 @@ Both these extensions can be disabled by using the `--strict` command line switch." - (:require ;; [beowulf.reader.char-reader :refer [read-chars]] + (:require [beowulf.oblist :refer [*options*]] + [beowulf.reader.char-reader :refer [read-chars]] [beowulf.reader.generate :refer [generate]] [beowulf.reader.parser :refer [parse]] [beowulf.reader.simplify :refer [simplify]] [clojure.string :refer [join split starts-with? trim]]) - (:import [java.io InputStream] - [instaparse.gll Failure])) + (:import [instaparse.gll Failure] + [java.io InputStream])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -83,23 +84,22 @@ (generate (simplify parse-tree))))) (defn read-from-console - "Attempt to read a complete lisp expression from the console. NOTE that this - will only really work for S-Expressions, not M-Expressions." - [] - (loop [r (read-line)] + "Attempt to read a complete lisp expression from the console." + [prompt] + (loop [r (read-chars prompt)] (if (and (= (count (re-seq #"\(" r)) (count (re-seq #"\)" r))) (= (count (re-seq #"\[" r)) (count (re-seq #"\]" r)))) r - (recur (str r "\n" (read-line)))))) + (recur (str r "\n" (read-chars "")))))) (defn READ "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." ([] - (gsp (read-from-console))) + (gsp (read-from-console (:prompt *options*)))) ([input] (cond (empty? input) (READ) diff --git a/src/beowulf/reader/char_reader.clj b/src/beowulf/reader/char_reader.clj index 883f8fa..a38f301 100644 --- a/src/beowulf/reader/char_reader.clj +++ b/src/beowulf/reader/char_reader.clj @@ -20,9 +20,12 @@ TODO: There are multiple problems with JLine; a better solution might be to start from here: https://stackoverflow.com/questions/7931988/how-to-manipulate-control-characters" - ;; (:import [org.jline.reader LineReader LineReaderBuilder] - ;; [org.jline.terminal TerminalBuilder]) - ) + (:require [beowulf.oblist :refer [*options* oblist]]) + (:import [org.jline.reader.impl.completer StringsCompleter] + [org.jline.reader.impl DefaultParser DefaultParser$Bracket] + [org.jline.reader LineReaderBuilder] + [org.jline.terminal TerminalBuilder] + [org.jline.widget AutopairWidgets AutosuggestionWidgets])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -49,27 +52,56 @@ ;; looks as though you'd need a DPhil in JLine to write it, and I don't have ;; the time. -;; (def get-reader -;; "Return a reader, first constructing it if necessary. +(defn build-completer + "Build a completer which takes tokens from the oblist. -;; **NOTE THAT** this is not settled API. The existence and call signature of -;; this function is not guaranteed in future versions." -;; (memoize (fn [] -;; (let [term (.build (.system (TerminalBuilder/builder) true))] -;; (.build (.terminal (LineReaderBuilder/builder) term)))))) + This is sort-of working, in as much as hitting on a blank line will + show a table of values from the oblist, but hitting after you've + started input does not show potential completions for tokens you've started." + [] + (StringsCompleter. (map #(str (first %)) @oblist))) -;; (defn read-chars -;; "A drop-in replacement for `clojure.core/read-line`, except that line editing -;; and history should be enabled. +;; This breaks; it is not correctly resolving the Enum, although I can't work out +;; why not. +;; (defn build-parser +;; [] +;; (println "Building parser") +;; (let [parser (DefaultParser.)] +;; (doall +;; (.setEofOnUnclosedBracket +;; parser DefaultParser$Bracket/ROUND)))) + +(def get-reader + "Return a reader, first constructing it if necessary. -;; **NOTE THAT** this does not work yet, but it is in the API because I hope -;; that it will work later!" -;; [] -;; (let [eddie (get-reader)] -;; (loop [s (.readLine eddie)] -;; (if (and (= (count (re-seq #"\(" s)) -;; (count (re-seq #"\)" s))) -;; (= (count (re-seq #"\[]" s)) -;; (count (re-seq #"\]" s)))) -;; s -;; (recur (str s " " (.readLine eddie))))))) \ No newline at end of file + **NOTE THAT** this is not settled API. The existence and call signature of + this function is not guaranteed in future versions." + (memoize (fn [] + (let [term (.build (.system (TerminalBuilder/builder) true)) + reader (-> (LineReaderBuilder/builder) + (.terminal term) + (.completer (build-completer)) + ;; #(.parser % (build-parser)) + (.build)) + ;; apw (AutopairWidgets. reader false) + ;; asw (AutosuggestionWidgets. reader) + ] + ;; (.enable apw) + ;; (.enable asw) + reader)))) + +(defn read-chars + "A drop-in replacement for `clojure.core/read-line`, except that line editing + and history should be enabled. + + **NOTE THAT** this does not fully work yet, but it is in the API because I + hope that it will work later!" + [prompt] + (let [eddie (get-reader)] + (loop [s (.readLine eddie (str prompt " "))] + (if (and (= (count (re-seq #"\(" s)) + (count (re-seq #"\)" s))) + (= (count (re-seq #"\[]" s)) + (count (re-seq #"\]" s)))) + s + (recur (str s " " (.readLine eddie ":: ")))))))