diff --git a/.gitignore b/.gitignore index 8945cf2..a0db7e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /target /classes /checkouts +resources/scratch/ profiles.clj pom.xml pom.xml.asc @@ -18,3 +19,5 @@ pom.xml.asc resources/scratch.lsp Sysout*.lsp *.pdf + +src/beowulf/scratch.clj diff --git a/README.md b/README.md index 2bccfe0..968bee8 100644 --- a/README.md +++ b/README.md @@ -43,63 +43,93 @@ To end a session, type `STOP` at the command prompt. The following functions and symbols are implemented: -| Symbol | Type | Signature | Documentation | -|--------|------|-----------|---------------| -| NIL | Lisp variable | | ? | -| T | Lisp variable | | ? | -| F | Lisp variable | | ? | -| ADD1 | Host function | (ADD1 X) | ? | -| AND | Host function | (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. | -| APPEND | Lisp function | (APPEND X Y) | ? | -| APPLY | Host function | (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. | -| ATOM | Host function | (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`. | -| CAR | Host function | (CAR X) | Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL. | -| CDR | Host function | (CDR X) | Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL. | -| CONS | Host function | (CONS CAR CDR) | Construct a new instance of cons cell with this `car` and `cdr`. | -| COPY | Lisp function | (COPY X) | ? | -| DEFINE | Host function | (DEFINE 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 | (DIFFERENCE X Y) | ? | -| DIVIDE | Lisp function | (DIVIDE X Y) | ? | -| ERROR | Host function | (ERROR & ARGS) | Throw an error | -| EQ | Host function | (EQ X Y) | Returns `T` if and only if both `x` and `y` are bound to the same atom, else `NIL`. | -| EQUAL | Host function | (EQUAL 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 | (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. | -| FACTORIAL | Lisp function | (FACTORIAL N) | ? | -| FIXP | Host function | (FIXP X) | ? | -| GENSYM | Host function | (GENSYM ) | Generate a unique symbol. | -| GET | Lisp function | (GET X Y) | ? | -| GREATERP | Host function | (GREATERP X Y) | ? | -| INTEROP | Host function | (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. 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 | (INTERSECTION X Y) | ? | -| LENGTH | Lisp function | (LENGTH L) | ? | -| LESSP | Host function | (LESSP X Y) | ? | -| MEMBER | Lisp function | (MEMBER A X) | ? | -| MINUSP | Lisp function | (MINUSP X) | ? | -| NOT | Lisp function | (NOT X) | ? | -| NULL | Lisp function | (NULL X) | ? | -| NUMBERP | Host function | (NUMBERP X) | ? | -| OBLIST | Host function | (OBLIST ) | 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 | (ONEP X) | ? | -| PAIR | Lisp function | (PAIR X Y) | ? | -| PLUS | Host function | (PLUS & ARGS) | ? | -| PRETTY | Lisp variable | | ? | -| PRINT | Lisp variable | | ? | -| PROP | Lisp function | (PROP X Y U) | ? | -| QUOTIENT | Host function | (QUOTIENT 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 | (READ ); (READ 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 | (REMAINDER X Y) | ? | -| REPEAT | Lisp function | (REPEAT N X) | ? | -| RPLACA | Host function | (RPLACA 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 | (RPLACD 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 | (SET 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 | (SUB1 N) | ? | -| SYSIN | Host function | (SYSIN ); (SYSIN 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 | (SYSOUT ); (SYSOUT 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 | Lisp variable | | ? | -| TIMES | Host function | (TIMES & ARGS) | ? | -| TRACE | Host function | (TRACE S) | Add this symbol `s` to the set of symbols currently being traced. If `s` is not a symbol, does nothing. | -| UNTRACE | Host function | (UNTRACE S) | ? | -| ZEROP | Lisp function | (ZEROP N) | ? | +| Function | Type | Signature | Implementation | Documentation | +|--------------|----------------|------------------|----------------|----------------------| +| NIL | Lisp variable | | | ? | +| T | Lisp variable | | | ? | +| F | Lisp variable | | | ? | +| ADD1 | Host function | (ADD1 X) | | ? | +| AND | Host function | (AND & ARGS) | 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 function | (APPEND X Y) | LAMBDA-fn | see manual pages 11, 61 | +| APPLY | Host function | (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. | +| ATOM | Host function | (ATOM X) | 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 function | (CAR X) | | Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL. | +| CAAAAR | Lisp function | (CAAAAR X) | LAMBDA-fn | ? | +| CAAADR | Lisp function | (CAAADR X) | LAMBDA-fn | ? | +| CAAAR | Lisp function | (CAAAR X) | LAMBDA-fn | ? | +| CAADAR | Lisp function | (CAADAR X) | LAMBDA-fn | ? | +| CAADDR | Lisp function | (CAADDR X) | LAMBDA-fn | ? | +| CAADR | Lisp function | (CAADR X) | LAMBDA-fn | ? | +| CAAR | Lisp function | (CAAR X) | LAMBDA-fn | ? | +| CADAAR | Lisp function | (CADAAR X) | LAMBDA-fn | ? | +| CADADR | Lisp function | (CADADR X) | LAMBDA-fn | ? | +| CADAR | Lisp function | (CADAR X) | LAMBDA-fn | ? | +| CADDAR | Lisp function | (CADDAR X) | LAMBDA-fn | ? | +| CADDDR | Lisp function | (CADDDR X) | LAMBDA-fn | ? | +| CADDR | Lisp function | (CADDR X) | LAMBDA-fn | ? | +| CADR | Lisp function | (CADR X) | LAMBDA-fn | ? | +| CDAAAR | Lisp function | (CDAAAR X) | LAMBDA-fn | ? | +| CDAADR | Lisp function | (CDAADR X) | LAMBDA-fn | ? | +| CDAAR | Lisp function | (CDAAR X) | LAMBDA-fn | ? | +| CDADAR | Lisp function | (CDADAR X) | LAMBDA-fn | ? | +| CDADDR | Lisp function | (CDADDR X) | LAMBDA-fn | ? | +| CDADR | Lisp function | (CDADR X) | LAMBDA-fn | ? | +| CDAR | Lisp function | (CDAR X) | LAMBDA-fn | ? | +| CDDAAR | Lisp function | (CDDAAR X) | LAMBDA-fn | ? | +| CDDADR | Lisp function | (CDDADR X) | LAMBDA-fn | ? | +| CDDAR | Lisp function | (CDDAR X) | LAMBDA-fn | ? | +| CDDDAR | Lisp function | (CDDDAR X) | LAMBDA-fn | ? | +| CDDDDR | Lisp function | (CDDDDR X) | LAMBDA-fn | ? | +| CDDDR | Lisp function | (CDDDR X) | LAMBDA-fn | ? | +| CDDR | Lisp function | (CDDR X) | LAMBDA-fn | ? | +| CDR | Host function | (CDR X) | | Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL. | +| CONS | Host function | (CONS CAR CDR) | | Construct a new instance of cons cell with this `car` and `cdr`. | +| COPY | Lisp function | (COPY X) | LAMBDA-fn | see manual pages 62 | +| DEFINE | Host function | (DEFINE ARGS) | PSEUDO-FUNCTION | 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 | (DIFFERENCE X Y) | | ? | +| DIVIDE | Lisp function | (DIVIDE X Y) | LAMBDA-fn | see manual pages 26, 64 | +| ERROR | Host function | (ERROR & ARGS) | PSEUDO-FUNCTION | Throw an error | +| EQ | Host function | (EQ X Y) | PREDICATE | Returns `T` if and only if both `x` and `y` are bound to the same atom, else `NIL`. | +| EQUAL | Host function | (EQUAL X Y) | 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 function | (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. | +| FACTORIAL | Lisp function | (FACTORIAL N) | LAMBDA-fn | ? | +| FIXP | Host function | (FIXP X) | PREDICATE | ? | +| GENSYM | Host function | (GENSYM ) | | Generate a unique symbol. | +| GET | Lisp function | (GET X Y) | LAMBDA-fn | see manual pages 41, 59 | +| GREATERP | Host function | (GREATERP X Y) | PREDICATE | ? | +| INTEROP | Host function | (INTEROP FN-SYMBOL ARGS) | (INTEROP) | 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 | (INTERSECTION X Y) | LAMBDA-fn | ? | +| LENGTH | Lisp function | (LENGTH L) | LAMBDA-fn | see manual pages 62 | +| LESSP | Host function | (LESSP X Y) | PREDICATE | ? | +| MEMBER | Lisp function | (MEMBER A X) | LAMBDA-fn | see manual pages 11, 62 | +| MINUSP | Lisp function | (MINUSP X) | LAMBDA-fn | see manual pages 26, 64 | +| NOT | Lisp function | (NOT X) | LAMBDA-fn | see manual pages 21, 23, 58 | +| NULL | Lisp function | (NULL X) | LAMBDA-fn | see manual pages 11, 57 | +| NUMBERP | Host function | (NUMBERP X) | PREDICATE | ? | +| OBLIST | Host function | (OBLIST ) | | 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 | (ONEP X) | LAMBDA-fn | see manual pages 26, 64 | +| PAIR | Lisp function | (PAIR X Y) | LAMBDA-fn | see manual pages 60 | +| PLUS | Host function | (PLUS & ARGS) | | ? | +| PRETTY | Lisp variable | | (PRETTY) | ? | +| PRINT | Lisp variable | | PSEUDO-FUNCTION | ? | +| PROP | Lisp function | (PROP X Y U) | LAMBDA-fn | see manual pages 59 | +| QUOTIENT | Host function | (QUOTIENT 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. | +| RANGE | Lisp variable | ? | (RANGE (LAMBDA (N M) (COND ((LESSP M N) (QUOTE NIL)) ((QUOTE T) (CONS N (RANGE (ADD1 N) M)))))) | ? | +| READ | Host function | (READ ); (READ INPUT) | 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 function | (REMAINDER X Y) | | ? | +| REPEAT | Lisp function | (REPEAT N X) | LAMBDA-fn | ? | +| RPLACA | Host function | (RPLACA CELL VALUE) | 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 function | (RPLACD CELL VALUE) | 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) | +| SET | Host function | (SET SYMBOL VAL) | 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 function | (SUB1 N) | LAMBDA-fn | see manual pages 26, 64 | +| SYSIN | Host function | (SYSIN ); (SYSIN FILENAME) | (SYSIN) | 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 | (SYSOUT ); (SYSOUT FILEPATH) | (SYSOUT) | 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 | Lisp variable | | PSEUDO-FUNCTION | ? | +| TIMES | Host function | (TIMES & ARGS) | | ? | +| TRACE | Host function | (TRACE S) | PSEUDO-FUNCTION | Add this symbol `s` to the set of symbols currently being traced. If `s` is not a symbol, does nothing. | +| UNTRACE | Host function | (UNTRACE S) | PSEUDO-FUNCTION | ? | +| ZEROP | Lisp function | (ZEROP N) | LAMBDA-fn | 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 diff --git a/doc/lisp1.5.md b/doc/lisp1.5.md index 95237dc..c187ba4 100644 --- a/doc/lisp1.5.md +++ b/doc/lisp1.5.md @@ -331,20 +331,28 @@ It Is important to become familiar with the results of elementary functions on S-expressions written in list notation. These can always be determined by translating into dot notation. -#### Examples - lisp notation 2 -car[(^ B c)]=A -cdr[(~ I3 c)]=(B C) -cons[^; (B c)]=(A B C) -car[((^ B) c)]*(A B) -c~~[(A)]=NIL -car[cdr[(~ B C)]]=B -It is convenient to abbreviate multiple car's and,=s. This is done by forming -function names that begin with c, end with r, qnd have several a's and dl s between +#### Examples - list notation 2 + +``` +car[(A B C)] = A +cdr[(A B C)] = (B C) +cons[A; (B C)] = (A B C) +car[((A B) C)] = (A B) +cdr[(A)] = NIL +car[cdr[(A B C)]] = B +``` + +It is convenient to abbreviate multiple `car`s and `cdr`s. This is done by forming +function names that begin with `c`, end with `r`, and have several `a`s and `d`s between them. -Examples -cadr[(~ B ~)]scar[cdrl(A B C)I=B -caddr[(A B C )I=c -cadadr[(A (B C) D)]=c + +### Examples - composed accessor functions + +``` +cadr[(A B C)] = car[cdr[(A B C)]] = B +caddr[(A B C )] = C +cadadr[(A (B C) D)] = C +``` The last a or d in the name actually signifies the first operation in order to be performed, since it is nearest to the argument. @@ -4842,576 +4850,156 @@ SW6 on to return to overlord after accumulator printout resulting from error *I? 5*. SW6 off for error printout. ``` -``` -INDEX TO FUNCTION DESCRIPTIONS -``` +## Index -Function - -``` -ADD 1 -ADVANCE -AND -APPEND -APPLY -ARRAY -ATOM -ATTRIB -BLANK -CAR -CDR -CHARCOUNT -CLEARBUFF -COMMA -COMMON -COMPILE -CONC -COND -CONS -COPY -COUNT -CP1 -CSET -CSETQ -CURCHAR -DASH -DEFINE -DEFLIST -DIFFERENCE -DIGIT -DIVIDE -DOLLAR -DUMP -EFFACE -ENDREAD -EOF -EOR -EQ -EQSIGN -EQUAL -ERROR -ERROR1 -ERRORSET -EVAL -EVLIS -EXCISE -EXPT -F -FIXP -FLAG -FLOATP -FUNCTION -GENSYM -GET -GO -GREATERP -INTERN -``` - -``` -SUBR -SUBR -FSUBR -SUBR -SUBR -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -APVAL -SUBR -APVAL -SUBR -SUBR -FEXPR -FSUBR -SUBR -SUBR -SUBR -SUBR -EXPR -FEXPR -APVAL -SUBR -EXPR -EXPR -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -SUBR -APVAL -APVAL -SUBR -APVAL -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -APVAL -SUBR -EXPR -SUBR -FSUBR -SUBR -SUBR -FSUBR -SUBR -SUBR -``` - -``` -PSEUDO-FUNCTION -PREDICATE -``` - -``` -PSEUDO-FUNCTION -PREDICATE -PSEUDO-FUNCTION -``` - -``` -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -``` - -``` -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PREDICATE -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PREDICATE -``` - -``` -PSEUDO-FUNCTION -PSEUDO- FUNC TION -PSEUDO-FUNCTION -``` - -``` -PREDICATE -PREDICATE -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -``` - -``` -PSEUDO-FUNCTION -``` - -``` -PREDICATE -PSEUDO-FUNCTION -PREDICATE -``` - -``` -PSEUDO-FUNCTION -PREDICATE -PSEUDO-FUNCTION -``` - -``` -Page - -26,64 -88 -21, 58 -11,61 -70 -27,64 -3, 57 -59 -69,85 -2, 56 -3,56 -69,87 -8 6 -69,85 -64, 78 -64,76 -6 1 -18 -2, 56 -62 -34,66 -66 -17, 59 -59 -69,87 -APVAL 15, 85,87 18, 58 -41, 58 -26, 64 -87 -26, 64 -69,85 -67 -63 -8 8 -69,88 -69,88 -3, 23, 57 -69,85 -11, 26, 57 -32,66 -88 -35,66 -71 -71 -67,77 -26, 64 -22,69 -26, 64 -41, 60 -26,64 -21,71 -66 -41,59 -30,72 -26, 64 -67,87 -``` - -``` -INDEX TO FUNCTION DESCRIPTIONS -``` - -Function -LABEL -LAP -LEFTSHIFT -LENGTH -LESSP -LIST -LITER -LOAD -LOG AND -LOGOR -LOGXOR -LPAR -MAP -MAPCON -MAPLIST -MAX -MEMBER -MIN -MINUS -MINUSP -MKNAM -NCONC -NIL -NOT -NULL -NUMBERP -NUMOB -OBLIST -ONE P -OPCHAR -OPDEFINE -OR -PACK -PAIR -PAUSE -PERIOD -PLB -PLUS -PLUSS -PRIN 1 -PRINT -PRINTPROP -PROG -PROG2 -PROP -PUNCH -PUNCHDEF -PUNCHLAP -QUOTE -QUOTIENT -READ -READLAP -RECIP -RECLAIM -REMAINDER -REMFLAG -REMOB - -``` -FSUBR -SUBR -SUBR -SUBR -SUBR -FSUBR -SUBR -SUBR -FSUBR -FSUBR -FSUBR -APVAL -SUBR -SUBR -SUBR -FSUBR -SUBR -FSUBR -SUBR -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -EXPR -FSUBR -SUBR -SUBR -SUBR -APVAL -SUBR -FSUBR -APVAL -SUBR -SUBR -EXPR -FSUBR -SUBR -SUBR -SUBR -EXPR -EXPR -FSUBR -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -SUBR -``` - -``` -Page - -8, 18,70 -PSEUDO-FUNCTION 65,73 -27, 64 -62 -PREDICATE 26,64 -57 -PREDICATE 87 -PSEUDO-FUNCTION 67 -27,64 -26,64 -27, 64 -69,85 -FUNCTIONAL 63 -FUNCTIONAL PSEUDO- FUNCTION 6 3 -FUNCTIONAL 20, 21, 63 -26,64 -PREDICATE 11,62 -26, 64 -26,63 -PREDICATE 26,64 -86 -PSEUDO-FUNCTION 62 -22,69 -PREDICATE 21, 23,^58 -PREDICATE 11,57 -PREDICATE 26, 64 -PSEUDO-FUNCTION 86 -69 -PREDICATE 26, 64 -PREDICATE 8 7 -PSEUDO-FUNCTION 65,75 -PREDICATE 21, 58 -PSEUDO-FUNCTION 86 -60 -PSEUDO-FUNCTION 67 -69,85 -PSEUDO- FUNCTION 67 -25,63 -69,85 -PSEUDO-FUNCTION 65,84 -PSEUDO-FUNCTION 65,84 -PSEUDO-FUNCTION LIBRARY 68 -29,71 -42,66 -FUNCTIONAL 59 -PSEUDO-FUNCTION 65,84 -PSEUDO-FUNCTION LIBRARY 6 8 -PSEUDO-FUNCTION LIBRARY 68,76 -10, 22, 71 -26,64 -PSEUDO-FUNCTION 65,84 -PSEUDO-FUNCTION 65,76 -26,64 -PSEUDO-FUNCTION 67 -26, 64 -PSEUDO-FUNCTION 41, 60 -PSEUDO-FUNCTION 67 -``` - -``` -INDEX TO FUNCTION DESCRIPTIONS -``` - -Function - -``` -REMPROP -RETURN -REVERSE -RPAR -RPLACA -RPLACD -SASSOC -SEARCH -SELECT -SET -SETQ -SLASH -SPEAK -SPECIAL -STAR -STARTREAD -SUB1 -SUB LIS -SUBST -T -TEMPUS-FUGIT -TERPRI -TIMES -TRACE -TRACESET -UNCOMMON -UNCOUNT -UNPACK -UNSPECIAL -UNTRACE -UNTRACESET -ZEROP -*T* -``` - -``` -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -SUBR -SUBR -FEXPR -SUBR -FSUBR -APVAL -SUBR -SUBR -APVAL -SUBR -SUBR -SUBR -SUBR -APVAL -SUBR -SUBR -FSUBR -EXPR -EXPR -SUBR -SUBR -SUBR -SUBR -EXPR -EXPR -SUBR -APVAL -``` - -``` -PSEUDO-FUNCTION -PSEUDO-FUNCTION -``` - -``` -PSEUDO-FUNCTION -PSEUDO-FUNCTION -FUNCTIONAL -FUNCTIONAL -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -``` - -``` -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSETJDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO-FUNCTION -PSEUDO- FUNC TION -PREDICATE -``` - -``` -Page -41,59 -30,72 -6 2 -69,85 -41,58 -41,58 -60 -63 -66 -30, 71 -30, 71 -69,85 -34,66 64, 78 -69,85 -87 -26, 64 -12,61 -11, 61 -22,69 -67 -65,84 -26,64 -32,66, 79 -LIBRARY 6 8 -64, 78 -34,66 -87 -64,78 -32,66 -68 -26,64 -22,69 -``` +| Function | Call type | Implementation | Pages | +|--------------|------------|------------------|------------------------------| +| ADD1 | SUBR | | [26](#page26), [64](#page64) | +| ADVANCE | SUBR | PSEUDO-FUNCTION | [88](#page88) | +| AND | FSUBR | PREDICATE | [21](#page21), [58](#page58) | +| APPEND | SUBR | | [11](#page11), [61](#page61) | +| APPLY | SUBR | | [70](#page70) | +| ARRAY | SUBR | PSEUDO-FUNCTION | [27](#page27), [64](#page64) | +| ATOM | SUBR | PREDICATE | [3](#page3), [57](#page57) | +| ATTRIB | SUBR | PSEUDO-FUNCTION | [59](#page59) | +| BLANK | APVAL | | [69](#page69), [85](#page85) | +| CAR | SUBR | | [2](#page2), [56](#page56) | +| CDR | SUBR | | [3](#page3), [56](#page56) | +| CHARCOUNT | APVAL | | [69](#page69), [87](#page87) | +| CLEARBUFF | SUBR | PSEUDO-FUNCTION | [86](#page86) | +| COMMA | APVAL | | [69](#page69), [85](#page85) | +| COMMON | SUBR | PSEUDO-FUNCTION | [64](#page64), [78](#page78) | +| COMPILE | SUBR | PSEUDO-FUNCTION | [64](#page64), [76](#page76) | +| CONC | FEXPR | | [61](#page61) | +| COND | FSUBR | | [18](#page18) | +| CONS | SUBR | | [2](#page2), [56](#page56) | +| COPY | SUBR | | [62](#page62) | +| COUNT | SUBR | PSEUDO-FUNCTION | [34](#page34), [66](#page66) | +| CP1 | SUBR | | [66](#page66) | +| CSET | EXPR | PSEUDO-FUNCTION | [17](#page17), [59](#page59) | +| CSETQ | FEXPR | PSEUDO-FUNCTION | [59](#page59) | +| CURCHAR | APVAL | | [69](#page69), [87](#page87) | +| DASH | SUBR | PREDICATE APVAL | [85](#page85), [87](#page87) | +| DEFINE | EXPR | PSEUDO-FUNCTION | [15](#page15), [18](#page18), [58](#page58) | +| DEFLIST | EXPR | PSEUDO-FUNCTION | [41](#page41), [58](#page58) | +| DIFFERENCE | SUBR | | [26](#page26), [64](#page64) | +| DIGIT | SUBR | PREDICATE | [87](#page87) | +| DIVIDE | SUBR | | [26](#page26), [64](#page64) | +| DOLLAR | APVAL | | [69](#page69), [85](#page85) | +| DUMP | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| EFFACE | SUBR | PSEUDO-FUNCTION | [63](#page63) | +| ENDREAD | SUBR | PSEUDO-FUNCTION | [8 8](#page8 8) | +| EOF | APVAL | | [69](#page69), [88](#page88) | +| EOR | APVAL | | [69](#page69), [88](#page88) | +| EQ | SUBR | PREDICATE | [3](#page3), [23](#page23), [57](#page57) | +| EQSIGN | APVAL | | [69](#page69), [85](#page85) | +| EQUAL | SUBR | PREDICATE | [11](#page11), [26](#page26), [57](#page57) | +| ERROR | SUBR | PSEUDO-FUNCTION | [32](#page32), [66](#page66) | +| ERROR1 | SUBR | PSEUDO-FUNCTION | [88](#page88) | +| ERRORSET | SUBR | PSEUDO-FUNCTION | [35](#page35), [66](#page66) | +| EVAL | SUBR | | [71](#page71) | +| EVLIS | SUBR | | [71](#page71) | +| EXCISE | SUBR | PSEUDO-FUNCTION | [67](#page67), [77](#page77) | +| EXPT | SUBR | | [26](#page26), [64](#page64) | +| F | APVAL | | [22](#page22), [69](#page69) | +| FIXP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| FLAG | EXPR | PSEUDO-FUNCTION | [41](#page41), [60](#page60) | +| FLOATP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| FUNCTION | FSUBR | | [21](#page21), [71](#page71) | +| GENSYM | SUBR | | [66](#page66) | +| GET | SUBR | | [41](#page41), [59](#page59) | +| GO | FSUBR | PSEUDO-FUNCTION | [30](#page30), [72](#page72) | +| GREATERP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| INTERN | SUBR | PSEUDO-FUNCTION | [67](#page67), [87](#page87) | +| LABEL | FSUBR | | [8](#page8), [18](#page18), [70](#page70) | +| LAP | SUBR | PSEUDO-FUNCTION | [65](#page65), [73](#page73) | +| LEFTSHIFT | SUBR | | [27](#page27), [64](#page64) | +| LENGTH | SUBR | | [62](#page62) | +| LESSP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| LIST | FSUBR | | [57](#page57) | +| LITER | SUBR | PREDICATE | [87](#page87) | +| LOAD | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| LOGAND | FSUBR | | [27](#page27), [64](#page64) | +| LOGOR | FSUBR | | [26](#page26), [64](#page64) | +| LOGXOR | FSUBR | | [27](#page27), [64](#page64) | +| LPAR | APVAL | | [69](#page69), [85](#page85) | +| MAP | SUBR | FUNCTIONAL | [63](#page63) | +| MAPCON | SUBR | FUNCTIONAL PSEUDO- FUNCTION | [63](#page63) | +| MAPLIST | SUBR | FUNCTIONAL | [20](#page20), [21](#page21), [63](#page63) | +| MAX | FSUBR | | [26](#page26), [64](#page64) | +| MEMBER | SUBR | PREDICATE | [11](#page11), [62](#page62) | +| MIN | FSUBR | | [26](#page26), [64](#page64) | +| MINUS | SUBR | | [26](#page26), [63](#page63) | +| MINUSP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| MKNAM | SUBR | | [86](#page86) | +| NCONC | SUBR | PSEUDO-FUNCTION | [62](#page62) | +| NIL | APVAL | | [22](#page22), [69](#page69) | +| NOT | SUBR | PREDICATE | [21](#page21), [23](#page23), [58](#page58) | +| NULL | SUBR | PREDICATE | [11](#page11), [57](#page57) | +| NUMBERP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| NUMOB | SUBR | PSEUDO-FUNCTION | [86](#page86) | +| OBLIST | APVAL | | [69](#page69) | +| ONEP | SUBR | PREDICATE | [26](#page26), [64](#page64) | +| OPCHAR | SUBR | PREDICATE | [87](#page87) | +| OPDEFINE | EXPR | PSEUDO-FUNCTION | [65](#page65), [75](#page75) | +| OR | FSUBR | PREDICATE | [21](#page21), [58](#page58) | +| PACK | SUBR | PSEUDO-FUNCTION | [86](#page86) | +| PAIR | SUBR | | [60](#page60) | +| PAUSE | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| PERIOD | APVAL | | [69](#page69), [85](#page85) | +| PLB | SUBR | PSEUDO- FUNCTION | [67](#page67) | +| PLUS | FSUBR | | [25](#page25), [63](#page63) | +| PLUSS | APVAL | | [69](#page69), [85](#page85) | +| PRIN1 | SUBR | PSEUDO-FUNCTION | [65](#page65), [84](#page84) | +| PRINT | SUBR | PSEUDO-FUNCTION | [65](#page65), [84](#page84) | +| PRINTPROP | EXPR | PSEUDO-FUNCTION LIBRARY | [68](#page68) | +| PROG | FSUBR | | [29](#page29), [71](#page71) | +| PROG2 | SUBR | | [42](#page42), [66](#page66) | +| PROP | SUBR | FUNCTIONAL | [59](#page59) | +| PUNCH | SUBR | PSEUDO-FUNCTION | [65](#page65), [84](#page84) | +| PUNCHDEF | EXPR | PSEUDO-FUNCTION LIBRARY | [68](#page68) | +| PUNCHLAP | EXPR | PSEUDO-FUNCTION LIBRARY | [68](#page68), [76](#page76) | +| QUOTE | FSUBR | | [10](#page10), [22](#page22), [71](#page71) | +| QUOTIENT | SUBR | | [26](#page26), [64](#page64) | +| READ | SUBR | PSEUDO-FUNCTION | [5](#page5), [84](#page84) | +| READLAP | SUBR | PSEUDO-FUNCTION | [65](#page65), [76](#page76) | +| RECIP | SUBR | | [26](#page26), [64](#page64) | +| RECLAIM | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| REMAINDER | SUBR | | [26](#page26), [64](#page64) | +| REMFLAG | SUBR | PSEUDO-FUNCTION | [41](#page41), [60](#page60) | +| REMOB | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| REMPROP | SUBR | PSEUDO-FUNCTION | [41](#page41), [59](#page59) | +| RETURN | SUBR | PSEUDO-FUNCTION | [30](#page30), [72](#page72) | +| REVERSE | SUBR | | [6 2](#page6 2) | +| RPAR | APVAL | | [69](#page69), [85](#page85) | +| RPLACA | SUBR | PSEUDO-FUNCTION | [41](#page41), [58](#page58) | +| RPLACD | SUBR | PSEUDO-FUNCTION | [41](#page41), [58](#page58) | +| SASSOC | SUBR | FUNCTIONAL | [60](#page60) | +| SEARCH | SUBR | FUNCTIONAL | [63](#page63) | +| SELECT | FEXPR | | [66](#page66) | +| SET | SUBR | PSEUDO-FUNCTION | [30](#page30), [71](#page71) | +| SETQ | FSUBR | PSEUDO-FUNCTION | [30](#page30), [71](#page71) | +| SLASH | APVAL | | [69](#page69), [85](#page85) | +| SPEAK | SUBR | PSEUDO-FUNCTION | [34](#page34), [66](#page66) | +| SPECIAL | SUBR | PSEUDO-FUNCTION | [64](#page64), [78](#page78) | +| STAR | APVAL | | [69](#page69), [85](#page85) | +| STARTREAD | SUBR | PSEUDO-FUNCTION | [87](#page87) | +| SUB1 | SUBR | | [26](#page26), [64](#page64) | +| SUBLIS | SUBR | | [12](#page12), [61](#page61) | +| SUBST | SUBR | | [11](#page11), [61](#page61) | +| T | APVAL | | [22](#page22), [69](#page69) | +| TEMPUS-FUGIT | SUBR | PSEUDO-FUNCTION | [67](#page67) | +| TERPRI | SUBR | PSEUDO-FUNCTION | [65](#page65), [84](#page84) | +| TIMES | FSUBR | | [26](#page26), [64](#page64) | +| TRACE | EXPR | PSEUDO-FUNCTION | [32](#page32), [66](#page66), [79](#page79) | +| TRACESET | EXPR | PSEUDO-FUNCTION LIBRARY | [68](#page68) | +| UNCOMMON | SUBR | PSEUDO-FUNCTION | [64](#page64), [78](#page78) | +| UNCOUNT | SUBR | PSEUDO-FUNCTION | [34](#page34), [66](#page66) | +| UNPACK | SUBR | PSEUDO-FUNCTION | [87](#page87) | +| UNSPECIAL | SUBR | | [64](#page64), [78](#page78) | +| UNTRACE | EXPR | PSEUDO-FUNCTION | [32](#page32), [66](#page66) | +| UNTRACESET | EXPR | PSEUDO-FUNCTION | [68](#page68) | +| ZEROP | SUBR | PREDICATE | [26](#page26), [64](#page64) | ``` Symbol or Term diff --git a/docs/codox/beowulf.bootstrap.html b/docs/codox/beowulf.bootstrap.html index 7e9a986..77f8deb 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.

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

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

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.

INTEROP

(INTEROP fn-symbol args)

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

diff --git a/docs/codox/beowulf.cons-cell.html b/docs/codox/beowulf.cons-cell.html index 4f0c280..1458ba0 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 bd8eda5..a2400c6 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

TODO: write docs

\ 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

TODO: write docs

\ No newline at end of file diff --git a/docs/codox/beowulf.gendoc.html b/docs/codox/beowulf.gendoc.html index e13eff2..b0ab126 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.

-

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)(gen-doc-table sysfile)

TODO: write docs

host-functions

Functions which we can infer are written in Clojure.

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.

\ No newline at end of file +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)(gen-doc-table sysfile)

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.

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.

\ No newline at end of file diff --git a/docs/codox/beowulf.host.html b/docs/codox/beowulf.host.html index b80469d..a2a6253 100644 --- a/docs/codox/beowulf.host.html +++ b/docs/codox/beowulf.host.html @@ -1,12 +1,12 @@ -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.

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.

DEFINE

(DEFINE 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

(DIFFERENCE x y)

TODO: write docs

EQ

(EQ x y)

Returns T if and only if both x and y are bound to the same atom, else NIL.

EQUAL

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

+

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

(DIFFERENCE x y)

TODO: write docs

EQ

(EQ x y)

Returns T if and only if both x and y are bound to the same atom, else NIL.

EQUAL

(EQUAL 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

ERROR

(ERROR & args)

Throw an error

FIXP

(FIXP x)

TODO: write docs

GENSYM

(GENSYM)

Generate a unique symbol.

GREATERP

(GREATERP x y)

TODO: write docs

lax?

(lax? symbol)

Are we in lax mode? If so. return true; is not, throw an exception with this symbol.

LESSP

(LESSP x y)

TODO: write docs

LIST

(LIST & args)

TODO: write docs

NILP

macro

(NILP x)

Not part of LISP 1.5: T if o is NIL, else NIL.

NULL

macro

(NULL x)

Returns T if and only if the argument x is bound to NIL; else F.

NUMBERP

(NUMBERP x)

TODO: write docs

OBLIST

(OBLIST)

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.

PAIRLIS

(PAIRLIS x y a)

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.

+

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.

PAIRLIS

(PAIRLIS x y a)

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.

PLUS

(PLUS & args)

TODO: write docs

QUOTIENT

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

REMAINDER

(REMAINDER x y)

TODO: write docs

RPLACA

(RPLACA 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

(RPLACD 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

(SET 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

(SUB1 x)

TODO: write docs

SUBLIS

(SUBLIS a y)

Here a is assumed to be an association list of the form ((ul . vl)...(un . vn)), where the us are atomic, and y is any S-expression. What SUBLIS does, is to treat the us as variables when they occur in y, and to SUBSTitute the corresponding vs from the pair list.

+

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

PLUS

(PLUS & args)

TODO: write docs

QUOTIENT

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

REMAINDER

(REMAINDER x y)

TODO: write docs

RPLACA

(RPLACA 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

(RPLACD 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

(SET 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

(SUB1 x)

TODO: write docs

SUBLIS

(SUBLIS a y)

Here a is assumed to be an association list of the form ((ul . vl)...(un . vn)), where the us are atomic, and y is any S-expression. What SUBLIS does, is to treat the us as variables when they occur in y, and to SUBSTitute the corresponding vs from the pair list.

My interpretation is that this is variable binding in the stack frame.

-

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

SUBST

(SUBST x y z)

This function gives the result of substituting the S-expression x for all occurrences of the atomic symbol y in the S-expression z.

TIMES

(TIMES & args)

TODO: write docs

TRACE

(TRACE s)

Add this symbol s to the set of symbols currently being traced. If s is not a symbol, does nothing.

traced-symbols

Symbols currently being traced.

traced?

(traced? s)

Return true iff s is a symbol currently being traced, else nil.

uaf

(uaf l path)

Universal access function; l is expected to be an arbitrary LISP list, path a (clojure) list of the characters a and d. Intended to make declaring all those fiddly #'c[ad]+r' functions a bit easier

UNTRACE

(UNTRACE s)

TODO: write docs

\ No newline at end of file +

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

SUBST

(SUBST x y z)

This function gives the result of substituting the S-expression x for all occurrences of the atomic symbol y in the S-expression z.

TIMES

(TIMES & args)

TODO: write docs

TRACE

(TRACE s)

Add this symbol s to the set of symbols currently being traced. If s is not a symbol, does nothing.

traced-symbols

Symbols currently being traced.

traced?

(traced? s)

Return true iff s is a symbol currently being traced, else nil.

uaf

(uaf l path)

Universal access function; l is expected to be an arbitrary LISP list, path a (clojure) list of the characters a and d. Intended to make declaring all those fiddly #'c[ad]+r' functions a bit easier

UNTRACE

(UNTRACE s)

TODO: write docs

\ No newline at end of file diff --git a/docs/codox/beowulf.io.html b/docs/codox/beowulf.io.html index 172158c..432dd61 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 new file mode 100644 index 0000000..f31ee80 --- /dev/null +++ b/docs/codox/beowulf.manual.html @@ -0,0 +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 diff --git a/docs/codox/beowulf.oblist.html b/docs/codox/beowulf.oblist.html index aaa9063..d11a024 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 4d8fa8b..6d41e58 100644 --- a/docs/codox/beowulf.read.html +++ b/docs/codox/beowulf.read.html @@ -1,9 +1,9 @@ -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. 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.
-

Both these extensions can be disabled by using the --strict command line switch.

gsp

(gsp s)

Shortcut macro - the internals of read; or, if you like, read-string. Argument s should be a string representation of a valid Lisp expression.

number-lines

(number-lines s)(number-lines s e)

TODO: write docs

READ

(READ)(READ 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.

read-from-console

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

strip-line-comments

(strip-line-comments s)

Strip blank lines and comment lines from this string s, expected to be Lisp source.

\ No newline at end of file +

Both these extensions can be disabled by using the --strict command line switch.

gsp

(gsp s)

Shortcut macro - the internals of read; or, if you like, read-string. Argument s should be a string representation of a valid Lisp expression.

number-lines

(number-lines s)(number-lines s e)

TODO: write docs

READ

(READ)(READ 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.

read-from-console

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

strip-line-comments

(strip-line-comments s)

Strip blank lines and comment lines from this string s, expected to be Lisp source.

\ No newline at end of file diff --git a/docs/codox/beowulf.reader.char-reader.html b/docs/codox/beowulf.reader.char-reader.html index d4f4a97..3f81a15 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)

    diff --git a/docs/codox/beowulf.reader.generate.html b/docs/codox/beowulf.reader.generate.html index f5a8a7c..8b6f86b 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 8ebe04e..e4dd087 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 022bb21..f31c302 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 73779f6..25d3f90 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 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.

    \ No newline at end of file +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 new file mode 100644 index 0000000..f59675e --- /dev/null +++ b/docs/codox/beowulf.scratch.html @@ -0,0 +1,3 @@ + +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

    \ No newline at end of file diff --git a/docs/codox/index.html b/docs/codox/index.html index 9cace4f..b4c2e6a 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -Beowulf 0.3.0-SNAPSHOT

    Beowulf 0.3.0-SNAPSHOT

    Released under the GPL-2.0-or-later

    An implementation of LISP 1.5 in Clojure.

    Installation

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

    [beowulf "0.3.0-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..

    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.

    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.

    Public variables and functions:

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

    Beowulf 0.3.0-SNAPSHOT

    Released under the GPL-2.0-or-later

    An implementation of LISP 1.5 in Clojure.

    Installation

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

    [beowulf "0.3.0-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..

    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.

    Public variables and functions:

    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.

    \ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html index b55fb54..654591c 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,6 +1,6 @@ -beowulf

    beowulf

    +beowulf

    beowulf

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

    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.

    @@ -30,330 +30,601 @@ - + + - - + + + - - + + + - - + + + - + + - + + - - - + + + + - + + - + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - + + + + - - + + + - + + - + + - - + + + - + + - + + - + + - + + + + + + + + + - + + - + + - - + + + - + + - + + - + + - - + + + - + + - - + + + - - + + + + + + + + + + - - + + + - + + - + + - - + + + - - + + + - + + - - + + + - - + + + - - + + + - + + + + + + + + + - + + - + + - + + - + + - + + - + + - - + + + - + + - + + - - + + + - + + - - - + + + + - - + + + - - + + +
    Symbol Function Type Signature Implementation Documentation
    NIL ? null Lisp variable ?
    T ? null Lisp variable ?
    F ? null Lisp variable ?
    ADD1 Host function ([x]) (ADD1 X) ?
    AND Host function ([& args]) (AND & ARGS) 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 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. Lisp function (APPEND X Y) LAMBDA-fn see manual pages 11, 61
    APPLY Host function ([function args environment depth]) (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.
    ATOM Host function ([x]) (ATOM X) 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 function (CAR X) Return the item indicated by the first pointer of a pair. NIL is treated specially: the CAR of NIL is NIL.
    CAAAAR Lisp function (CAAAAR X) LAMBDA-fn ? null
    CAAADR Lisp function (CAAADR X) LAMBDA-fn ?
    CAAAR Lisp function (CAAAR X) LAMBDA-fn ?
    CAADAR Lisp function (CAADAR X) LAMBDA-fn ?
    CAADDR Lisp function (CAADDR X) LAMBDA-fn ?
    CAADR Lisp function (CAADR X) LAMBDA-fn ?
    CAAR Lisp function (CAAR X) LAMBDA-fn ?
    CADAAR Lisp function (CADAAR X) LAMBDA-fn ?
    CADADR Lisp function (CADADR X) LAMBDA-fn ?
    CADAR Lisp function (CADAR X) LAMBDA-fn ?
    CADDAR Lisp function (CADDAR X) LAMBDA-fn ?
    CADDDR Lisp function (CADDDR X) LAMBDA-fn ?
    CADDR Lisp function (CADDR X) LAMBDA-fn ?
    CADR Lisp function (CADR X) LAMBDA-fn ?
    CDAAAR Lisp function (CDAAAR X) LAMBDA-fn ?
    CDAADR Lisp function (CDAADR X) LAMBDA-fn ?
    CDAAR Lisp function (CDAAR X) LAMBDA-fn ?
    CDADAR Lisp function (CDADAR X) LAMBDA-fn ?
    CDADDR Lisp function (CDADDR X) LAMBDA-fn ?
    CDADR Lisp function (CDADR X) LAMBDA-fn ?
    CDAR Lisp function (CDAR X) LAMBDA-fn ?
    CDDAAR Lisp function (CDDAAR X) LAMBDA-fn ?
    CDDADR Lisp function (CDDADR X) LAMBDA-fn ?
    CDDAR Lisp function (CDDAR X) LAMBDA-fn ?
    CDDDAR Lisp function (CDDDAR X) LAMBDA-fn ?
    CDDDDR Lisp function (CDDDDR X) LAMBDA-fn ?
    CDDDR Lisp function (CDDDR X) LAMBDA-fn ?
    CDDR Lisp function (CDDR X) LAMBDA-fn ?
    CDR ? null ? Host function (CDR X) Return the item indicated by the second pointer of a pair. NIL is treated specially: the CDR of NIL is NIL.
    CONS ? null ? Host function (CONS CAR CDR) Construct a new instance of cons cell with this car and cdr.
    COPY Lisp function (X) ? (COPY X) LAMBDA-fn see manual pages 62
    DEFINE Host function ([args]) (DEFINE ARGS) PSEUDO-FUNCTION 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]) (DIFFERENCE X Y) ?
    DIVIDE Lisp function (X Y) ? (DIVIDE X Y) LAMBDA-fn see manual pages 26, 64
    ERROR Host function ([& args]) (ERROR & ARGS) PSEUDO-FUNCTION Throw an error
    EQ Host function ([x y]) (EQ X Y) PREDICATE Returns T if and only if both x and y are bound to the same atom, else NIL.
    EQUAL Host function ([x y]) (EQUAL X Y) 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 function ([expr] [expr env depth]) (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.
    FACTORIAL Lisp function (FACTORIAL N) LAMBDA-fn ?
    FIXP Host function ([x]) (FIXP X) PREDICATE ?
    GENSYM Host function ([]) (GENSYM ) Generate a unique symbol.
    GET Lisp function (X Y) ? (GET X Y) LAMBDA-fn see manual pages 41, 59
    GREATERP Host function ([x y]) (GREATERP X Y) PREDICATE ?
    INTEROP Host function ([fn-symbol args]) (INTEROP FN-SYMBOL ARGS) (INTEROP) 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) (INTERSECTION X Y) LAMBDA-fn ?
    LENGTH Lisp function (L) ? (LENGTH L) LAMBDA-fn see manual pages 62
    LESSP Host function ([x y]) (LESSP X Y) PREDICATE ?
    MEMBER Lisp function (A X) ? (MEMBER A X) LAMBDA-fn see manual pages 11, 62
    MINUSP Lisp function (X) ? (MINUSP X) LAMBDA-fn see manual pages 26, 64
    NOT Lisp function (NOT X) LAMBDA-fn see manual pages 21, 23, 58
    NULL Lisp function (X) ? (NULL X) LAMBDA-fn see manual pages 11, 57
    NUMBERP Host function ([x]) (NUMBERP X) PREDICATE ?
    OBLIST Host function ([]) (OBLIST ) 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) ? (ONEP X) LAMBDA-fn see manual pages 26, 64
    PAIR Lisp function (X Y) ? (PAIR X Y) LAMBDA-fn see manual pages 60
    PLUS Host function ([& args]) (PLUS & ARGS) ?
    PRETTY ? null Lisp variable (PRETTY) ?
    PRINT ? null Lisp variable PSEUDO-FUNCTION ?
    PROP Lisp function (X Y U) ? (PROP X Y U) LAMBDA-fn see manual pages 59
    QUOTIENT Host function ([x y]) (QUOTIENT 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.
    RANGE Lisp variable ? (RANGE (LAMBDA (N M) (COND ((LESSP M N) (QUOTE NIL)) ((QUOTE T) (CONS N (RANGE (ADD1 N) M)))))) ?
    READ Host function ([] [input]) (READ ); (READ INPUT) 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 function ([x y]) (REMAINDER X Y) ?
    REPEAT Lisp function (N X) (REPEAT N X) LAMBDA-fn ?
    RPLACA Host function ([cell value]) (RPLACA CELL VALUE) 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 function ([cell value]) (RPLACD CELL VALUE) 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)
    SET Host function ([symbol val]) (SET SYMBOL VAL) 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 function (N) ? (SUB1 N) LAMBDA-fn see manual pages 26, 64
    SYSIN Host function ([filename]) (SYSIN ); (SYSIN FILENAME) (SYSIN) 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]) (SYSOUT ); (SYSOUT FILEPATH) (SYSOUT) 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 Lisp variable PSEUDO-FUNCTION ?
    TIMES Host function ([& args]) (TIMES & ARGS) ?
    TRACE ? null ? Host function (TRACE S) PSEUDO-FUNCTION Add this symbol s to the set of symbols currently being traced. If s is not a symbol, does nothing.
    UNTRACE ? null Host function (UNTRACE S) PSEUDO-FUNCTION ?
    ZEROP Lisp function (N) ? (ZEROP N) LAMBDA-fn see manual pages 26, 64
    diff --git a/docs/codox/mexpr.html b/docs/codox/mexpr.html index 76f0721..f58b337 100644 --- a/docs/codox/mexpr.html +++ b/docs/codox/mexpr.html @@ -1,6 +1,6 @@ -M-Expressions

    M-Expressions

    +M-Expressions

    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.

    Rather, it seems to me probably 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 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/project.clj b/project.clj index a626c21..0989300 100644 --- a/project.clj +++ b/project.clj @@ -9,9 +9,9 @@ :license {:name "GPL-2.0-or-later" :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} :dependencies [[org.clojure/clojure "1.11.1"] + [org.clojure/math.combinatorics "0.2.0"] ;; not needed in production builds [org.clojure/math.numeric-tower "0.0.5"] [org.clojure/tools.cli "1.0.214"] - [org.clojure/tools.trace "0.7.11"] [clojure.java-time "1.2.0"] [environ "1.2.0"] [instaparse "1.4.12"] @@ -22,7 +22,9 @@ :plugins [[lein-cloverage "1.2.2"] [lein-codox "0.10.7"] [lein-environ "1.1.0"]] - :profiles {:uberjar {:aot :all}} + :profiles {:uberjar {:aot :all + :omit-source true + :uberjar-exclusions [#"beowulf\.scratch"]}} :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] @@ -34,5 +36,4 @@ ["vcs" "commit"]] :target-path "target/%s" - :url "https://github.com/simon-brooke/the-great-game" - ) + :url "https://github.com/simon-brooke/the-great-game") diff --git a/resources/lisp1.5.lsp b/resources/lisp1.5.lsp index 2d4966e..13b90aa 100644 --- a/resources/lisp1.5.lsp +++ b/resources/lisp1.5.lsp @@ -13,6 +13,34 @@ (APPLY) (ATOM) (CAR) + (CAAAAR LAMBDA (X) (CAR (CAR (CAR (CAR X))))) + (CAAADR LAMBDA (X) (CAR (CAR (CAR (CDR X))))) + (CAAAR LAMBDA (X) (CAR (CAR (CAR X)))) + (CAADAR LAMBDA (X) (CAR (CAR (CDR (CAR X))))) + (CAADDR LAMBDA (X) (CAR (CAR (CDR (CDR X))))) + (CAADR LAMBDA (X) (CAR (CAR (CDR X)))) + (CAAR LAMBDA (X) (CAR (CAR X))) + (CADAAR LAMBDA (X) (CAR (CDR (CAR (CAR X))))) + (CADADR LAMBDA (X) (CAR (CDR (CAR (CDR X))))) + (CADAR LAMBDA (X) (CAR (CDR (CAR X)))) + (CADDAR LAMBDA (X) (CAR (CDR (CDR (CAR X))))) + (CADDDR LAMBDA (X) (CAR (CDR (CDR (CDR X))))) + (CADDR LAMBDA (X) (CAR (CDR (CDR X)))) + (CADR LAMBDA (X) (CAR (CDR X))) + (CDAAAR LAMBDA (X) (CDR (CAR (CAR (CAR X))))) + (CDAADR LAMBDA (X) (CDR (CAR (CAR (CDR X))))) + (CDAAR LAMBDA (X) (CDR (CAR (CAR X)))) + (CDADAR LAMBDA (X) (CDR (CAR (CDR (CAR X))))) + (CDADDR LAMBDA (X) (CDR (CAR (CDR (CDR X))))) + (CDADR LAMBDA (X) (CDR (CAR (CDR X)))) + (CDAR LAMBDA (X) (CDR (CAR X))) + (CDDAAR LAMBDA (X) (CDR (CDR (CAR (CAR X))))) + (CDDADR LAMBDA (X) (CDR (CDR (CAR (CDR X))))) + (CDDAR LAMBDA (X) (CDR (CDR (CAR X)))) + (CDDDAR LAMBDA (X) (CDR (CDR (CDR (CAR X))))) + (CDDDDR LAMBDA (X) (CDR (CDR (CDR (CDR X))))) + (CDDDR LAMBDA (X) (CDR (CDR (CDR X)))) + (CDDR LAMBDA (X) (CDR (CDR X))) (CDR) (CONS) (COPY @@ -79,6 +107,7 @@ (COND ((NULL X) (U)) ((EQ (CAR X) Y) (CDR X)) ((QUOTE T) (PROP (CDR X) Y U)))) (QUOTIENT) + (RANGE LAMBDA (N M) (COND ((LESSP M N) (QUOTE NIL)) ((QUOTE T) (CONS N (RANGE (ADD1 N) M))))) (READ) (REMAINDER) (REPEAT diff --git a/resources/mexpr/range.mexpr.lsp b/resources/mexpr/range.mexpr.lsp new file mode 100644 index 0000000..2e84d4f --- /dev/null +++ b/resources/mexpr/range.mexpr.lsp @@ -0,0 +1,3 @@ +;; this isn't a standard Lisp 1.5 function + +range[n; m] = [lessp[m; n] -> NIL; T -> cons[n; range[add1[n]; m]]] \ No newline at end of file diff --git a/src/beowulf/bootstrap.clj b/src/beowulf/bootstrap.clj index 78729e7..08f4864 100644 --- a/src/beowulf/bootstrap.clj +++ b/src/beowulf/bootstrap.clj @@ -249,7 +249,7 @@ (case function-symbol ;; there must be a better way of doing this! ADD1 (safe-apply ADD1 args) AND (safe-apply AND args) - APPLY (safe-apply APPLY args) ;; TODO: need to pass the environment and depth + APPLY (APPLY (first args) (rest args) environment depth) ;; TODO: need to pass the environment and depth ATOM (ATOM? (CAR args)) CAR (safe-apply CAR args) CDR (safe-apply CDR args) diff --git a/src/beowulf/gendoc.clj b/src/beowulf/gendoc.clj index 2988327..def8b58 100644 --- a/src/beowulf/gendoc.clj +++ b/src/beowulf/gendoc.clj @@ -4,7 +4,10 @@ NOTE: this is *very* hacky. You almost certainly do not want to use this!" (:require [beowulf.io :refer [default-sysout SYSIN]] - [beowulf.oblist :refer [oblist]] + [beowulf.host :refer [ASSOC]] + [beowulf.manual :refer [format-page-references index *manual-url*]] + [beowulf.oblist :refer [NIL oblist]] + [clojure.java.browse :refer [browse-url]] [clojure.string :refer [join replace upper-case]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -95,34 +98,56 @@ (= (second entry) 'LAMBDA) (str (cons (first entry) (nth entry 2))) :else "?")) +(defn infer-implementation + [entry] + (case (second entry) + LAMBDA (format "%s-fn" (second entry)) + LABEL (format "%s-fn" (second entry)) + (or (:implementation (index (keyword (first entry)))) (str entry)))) + (defn find-documentation "Find appropriate documentation for this `entry` from the oblist." [entry] - (cond - (= (count entry) 1) (if-let [doc (get-metadata-for-entry entry :doc)] - (replace doc "\n" " ") - "?") - :else "?")) + (let [k (keyword (first entry))] + (cond + (= (count entry) 1) (if-let [doc (get-metadata-for-entry entry :doc)] + (replace doc "\n" " ") + "?") + (k index) (str "see manual pages " (format-page-references k)) + :else "?"))) (defn gen-doc-table ([] (gen-doc-table default-sysout)) ([sysfile] - (try (SYSIN sysfile) - (catch Throwable any - (println (.getMessage any) " while reading " sysfile))) + (when (= NIL @oblist) + (try (SYSIN sysfile) + (catch Throwable any + (println (.getMessage any) " while reading " sysfile)))) (join "\n" (doall (concat - '("| Symbol | Type | Signature | Documentation |" - "|--------|------|-----------|---------------|") + '("| Function | Type | Signature | Implementation | Documentation |" + "|--------------|----------------|------------------|----------------|----------------------|") (map - #(format "| %s | %s | %s | %s |" + #(format "| %-12s | %-14s | %-16s | %-14s | %-20s |" (first %) (infer-type %) (infer-signature %) + (infer-implementation %) (find-documentation %)) @oblist)))))) -;; (println (gen-doc-table)) \ No newline at end of file +(defn gen-index + ([] (gen-index "" "resources/scratch/manual.md")) + ([url destination] + (binding [*manual-url* url] + (spit destination + (with-out-str + (doall + (map + println + (list "## Index" + "" + (gen-doc-table))))))))) \ No newline at end of file diff --git a/src/beowulf/host.clj b/src/beowulf/host.clj index 46ea8db..8600faa 100644 --- a/src/beowulf/host.clj +++ b/src/beowulf/host.clj @@ -389,11 +389,11 @@ (defn LESSP [x y] - (< x y)) + (if (< x y) T F)) (defn GREATERP [x y] - (> x y)) + (if (> x y) T F)) ;;;; Miscellaneous ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -405,8 +405,11 @@ (defn ERROR "Throw an error" [& args] - (throw (ex-info "LISP ERROR" {:cause (apply vector args) - :phase :eval}))) + (throw (ex-info "LISP ERROR" {:args args + :phase :eval + :function 'ERROR + :type :lisp + :code (or (first args) 'A1)}))) ;;;; Assignment and the object list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/beowulf/manual.clj b/src/beowulf/manual.clj new file mode 100644 index 0000000..8a36fe5 --- /dev/null +++ b/src/beowulf/manual.clj @@ -0,0 +1,769 @@ +(ns beowulf.manual + "Experimental code for accessing the manual online." + (:require [clojure.string :refer [ends-with? join trim]])) + +(def ^:dynamic *manual-url* + "https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf") + +(def ^:constant 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`." + {:RECIP + {:fn-name "RECIP", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :QUOTE + {:fn-name "QUOTE", + :call-type "FSUBR", + :implementation "", + :page-nos ["10" "22" "71"]}, + :RECLAIM + {:fn-name "RECLAIM", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["67"]}, + :NUMOB + {:fn-name "NUMOB", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["86"]}, + :EVLIS + {:fn-name "EVLIS", + :call-type "SUBR", + :implementation "", + :page-nos ["71"]}, + :DASH + {:fn-name "DASH", + :call-type "SUBR", + :implementation "PREDICATE APVAL", + :page-nos ["85" "87 "]}, + :EQUAL + {:fn-name "EQUAL", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["11" "26" "57"]}, + :PRIN1 + {:fn-name "PRIN1", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["65" "84"]}, + :REMFLAG + {:fn-name "REMFLAG", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["41" "60"]}, + :DEFINE + {:fn-name "DEFINE", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["15" "18" "58"]}, + :PUNCHLAP + {:fn-name "PUNCHLAP", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION LIBRARY", + :page-nos ["68" "76"]}, + :STARTREAD + {:fn-name "STARTREAD", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["87"]}, + :PERIOD + {:fn-name "PERIOD", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :CP1 + {:fn-name "CP1", + :call-type "SUBR", + :implementation "", + :page-nos ["66"]}, + :NCONC + {:fn-name "NCONC", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["62"]}, + :EQ + {:fn-name "EQ", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["3" "23" "57"]}, + :RPLACD + {:fn-name "RPLACD", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["41" "58"]}, + :PROG2 + {:fn-name "PROG2", + :call-type "SUBR", + :implementation "", + :page-nos ["42" "66"]}, + :UNCOUNT + {:fn-name "UNCOUNT", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["34" "66"]}, + :ERROR1 + {:fn-name "ERROR1", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["88"]}, + :EXPT + {:fn-name "EXPT", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :NOT + {:fn-name "NOT", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["21" "23" "58"]}, + :SLASH + {:fn-name "SLASH", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :RPLACA + {:fn-name "RPLACA", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["41" "58"]}, + :QUOTIENT + {:fn-name "QUOTIENT", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :UNPACK + {:fn-name "UNPACK", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["87"]}, + :CONC + {:fn-name "CONC", + :call-type "FEXPR", + :implementation "", + :page-nos ["61"]}, + :CAR + {:fn-name "CAR", + :call-type "SUBR", + :implementation "", + :page-nos ["2" "56"]}, + :GENSYM + {:fn-name "GENSYM", + :call-type "SUBR", + :implementation "", + :page-nos ["66"]}, + :PROP + {:fn-name "PROP", + :call-type "SUBR", + :implementation "FUNCTIONAL ", + :page-nos [" 59"]}, + :MEMBER + {:fn-name "MEMBER", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["11" "62"]}, + :UNTRACESET + {:fn-name "UNTRACESET", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["68"]}, + :UNTRACE + {:fn-name "UNTRACE", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["32" "66"]}, + :MINUSP + {:fn-name "MINUSP", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["26" "64"]}, + :F + {:fn-name "F", + :call-type "APVAL", + :implementation "", + :page-nos ["22" "69"]}, + :SPECIAL + {:fn-name "SPECIAL", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["64" "78"]}, + :LPAR + {:fn-name "LPAR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :GO + {:fn-name "GO", + :call-type "FSUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["30" "72"]}, + :MKNAM + {:fn-name "MKNAM", + :call-type "SUBR", + :implementation "", + :page-nos ["86"]}, + :COMMON + {:fn-name "COMMON", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["64" "78"]}, + :NUMBERP + {:fn-name "NUMBERP", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["26" "64"]}, + :CONS + {:fn-name "CONS", + :call-type "SUBR", + :implementation "", + :page-nos ["2" "56"]}, + :PLUS + {:fn-name "PLUS", + :call-type "FSUBR", + :implementation "", + :page-nos ["25" "63"]}, + :SET + {:fn-name "SET", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["30" "71"]}, + :DOLLAR + {:fn-name "DOLLAR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :SASSOC + {:fn-name "SASSOC", + :call-type "SUBR", + :implementation "FUNCTIONAL", + :page-nos ["60"]}, + :SELECT + {:fn-name "SELECT", + :call-type "FEXPR", + :implementation "", + :page-nos ["66"]}, + :OPDEFINE + {:fn-name "OPDEFINE", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["65" "75"]}, + :PAUSE + {:fn-name "PAUSE", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67"]}, + :AND + {:fn-name "AND", + :call-type "FSUBR", + :implementation "PREDICATE", + :page-nos ["21" "58"]}, + :COMMA + {:fn-name "COMMA", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :EFFACE + {:fn-name "EFFACE", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["63"]}, + :CSETQ + {:fn-name "CSETQ", + :call-type "FEXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["59"]}, + :OPCHAR + {:fn-name "OPCHAR", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos [" 87"]}, + :PRINTPROP + {:fn-name "PRINTPROP", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION LIBRARY ", + :page-nos ["68"]}, + :PLB + {:fn-name "PLB", + :call-type "SUBR", + :implementation "PSEUDO- FUNCTION", + :page-nos ["67"]}, + :DIGIT + {:fn-name "DIGIT", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["87"]}, + :PUNCHDEF + {:fn-name "PUNCHDEF", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION LIBRARY", + :page-nos ["68"]}, + :ARRAY + {:fn-name "ARRAY", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["27" "64"]}, + :MAX + {:fn-name "MAX", + :call-type "FSUBR", + :implementation "", + :page-nos ["26" "64"]}, + :INTERN + {:fn-name "INTERN", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67" "87"]}, + :NIL + {:fn-name "NIL", + :call-type "APVAL", + :implementation "", + :page-nos ["22" "69"]}, + :TIMES + {:fn-name "TIMES", + :call-type "FSUBR", + :implementation "", + :page-nos ["26" "64"]}, + :ERROR + {:fn-name "ERROR", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["32" "66"]}, + :PUNCH + {:fn-name "PUNCH", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["65" "84"]}, + :REMPROP + {:fn-name "REMPROP", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["41" "59"]}, + :DIVIDE + {:fn-name "DIVIDE", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :OR + {:fn-name "OR", + :call-type "FSUBR", + :implementation "PREDICATE ", + :page-nos ["21" "58"]}, + :SUBLIS + {:fn-name "SUBLIS", + :call-type "SUBR", + :implementation "", + :page-nos ["12" "61"]}, + :LAP + {:fn-name "LAP", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["65" "73"]}, + :PROG + {:fn-name "PROG", + :call-type "FSUBR", + :implementation "", + :page-nos ["29" "71"]}, + :T + {:fn-name "T", + :call-type "APVAL", + :implementation "", + :page-nos ["22" "69"]}, + :GREATERP + {:fn-name "GREATERP", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["26" "64"]}, + :CSET + {:fn-name "CSET", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["17" "59"]}, + :FUNCTION + {:fn-name "FUNCTION", + :call-type "FSUBR", + :implementation "", + :page-nos ["21" "71"]}, + :LENGTH + {:fn-name "LENGTH", + :call-type "SUBR", + :implementation "", + :page-nos ["62"]}, + :MINUS + {:fn-name "MINUS", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "63"]}, + :COND + {:fn-name "COND", + :call-type "FSUBR", + :implementation "", + :page-nos ["18"]}, + :APPEND + {:fn-name "APPEND", + :call-type "SUBR", + :implementation "", + :page-nos ["11" "61"]}, + :CDR + {:fn-name "CDR", + :call-type "SUBR", + :implementation "", + :page-nos ["3" "56"]}, + :OBLIST + {:fn-name "OBLIST", + :call-type "APVAL", + :implementation "", + :page-nos ["69"]}, + :READ + {:fn-name "READ", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["5" "84"]}, + :ERRORSET + {:fn-name "ERRORSET", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["35" "66"]}, + :UNCOMMON + {:fn-name "UNCOMMON", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["64" "78"]}, + :EVAL + {:fn-name "EVAL", + :call-type "SUBR", + :implementation "", + :page-nos ["71"]}, + :MIN + {:fn-name "MIN", + :call-type "FSUBR", + :implementation "", + :page-nos ["26" "64"]}, + :PAIR + {:fn-name "PAIR", + :call-type "SUBR", + :implementation "", + :page-nos ["60"]}, + :BLANK + {:fn-name "BLANK", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :SETQ + {:fn-name "SETQ", + :call-type "FSUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["30" "71"]}, + :GET + {:fn-name "GET", + :call-type "SUBR", + :implementation "", + :page-nos ["41" "59"]}, + :PRINT + {:fn-name "PRINT", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["65" "84"]}, + :ENDREAD + {:fn-name "ENDREAD", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["8 8"]}, + :RETURN + {:fn-name "RETURN", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["30" "72"]}, + :LITER + {:fn-name "LITER", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["87"]}, + :EOF + {:fn-name "EOF", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "88"]}, + :TRACE + {:fn-name "TRACE", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["32" "66" "79"]}, + :TRACESET + {:fn-name "TRACESET", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION LIBRARY", + :page-nos ["68"]}, + :PACK + {:fn-name "PACK", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["86"]}, + :NULL + {:fn-name "NULL", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["11" "57"]}, + :CLEARBUFF + {:fn-name "CLEARBUFF", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["86"]}, + :LESSP + {:fn-name "LESSP", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos ["26" "64"]}, + :TERPRI + {:fn-name "TERPRI", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["65" "84"]}, + :ONEP + {:fn-name "ONEP", + :call-type "SUBR", + :implementation "PREDICATE ", + :page-nos [" 26" "64"]}, + :EXCISE + {:fn-name "EXCISE", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67" "77"]}, + :REMOB + {:fn-name "REMOB", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["67"]}, + :MAP + {:fn-name "MAP", + :call-type "SUBR", + :implementation "FUNCTIONAL ", + :page-nos ["63"]}, + :COMPILE + {:fn-name "COMPILE", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["64" "76"]}, + :ADD1 + {:fn-name "ADD1", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :ADVANCE + {:fn-name "ADVANCE", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["88"]}, + :SEARCH + {:fn-name "SEARCH", + :call-type "SUBR", + :implementation "FUNCTIONAL", + :page-nos ["63"]}, + :APPLY + {:fn-name "APPLY", + :call-type "SUBR", + :implementation "", + :page-nos ["70"]}, + :READLAP + {:fn-name "READLAP", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION ", + :page-nos ["65" "76"]}, + :UNSPECIAL + {:fn-name "UNSPECIAL", + :call-type "SUBR", + :implementation "", + :page-nos ["64" "78"]}, + :SUBST + {:fn-name "SUBST", + :call-type "SUBR", + :implementation "", + :page-nos ["11" "61"]}, + :COPY + {:fn-name "COPY", + :call-type "SUBR", + :implementation "", + :page-nos ["62"]}, + :LOGOR + {:fn-name "LOGOR", + :call-type "FSUBR", + :implementation "", + :page-nos ["26" "64"]}, + :LABEL + {:fn-name "LABEL", + :call-type "FSUBR", + :implementation "", + :page-nos ["8" "18" "70"]}, + :FIXP + {:fn-name "FIXP", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["26" "64"]}, + :SUB1 + {:fn-name "SUB1", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :ATTRIB + {:fn-name "ATTRIB", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["59"]}, + :DIFFERENCE + {:fn-name "DIFFERENCE", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :REMAINDER + {:fn-name "REMAINDER", + :call-type "SUBR", + :implementation "", + :page-nos ["26" "64"]}, + :REVERSE + {:fn-name "REVERSE", + :call-type "SUBR", + :implementation "", + :page-nos ["6 2"]}, + :EOR + {:fn-name "EOR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "88"]}, + :PLUSS + {:fn-name "PLUSS", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :TEMPUS-FUGIT + {:fn-name "TEMPUS-FUGIT", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67"]}, + :LOAD + {:fn-name "LOAD", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67"]}, + :CHARCOUNT + {:fn-name "CHARCOUNT", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "87"]}, + :RPAR + {:fn-name "RPAR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :COUNT + {:fn-name "COUNT", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["34" "66"]}, + :SPEAK + {:fn-name "SPEAK", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["34" "66 "]}, + :LOGXOR + {:fn-name "LOGXOR", + :call-type "FSUBR", + :implementation "", + :page-nos ["27" "64"]}, + :FLOATP + {:fn-name "FLOATP", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["26" "64"]}, + :ATOM + {:fn-name "ATOM", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["3" "57"]}, + :EQSIGN + {:fn-name "EQSIGN", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :LIST + {:fn-name "LIST", + :call-type "FSUBR", + :implementation "", + :page-nos ["57"]}, + :MAPLIST + {:fn-name "MAPLIST", + :call-type "SUBR", + :implementation "FUNCTIONAL ", + :page-nos ["20" "21" "63"]}, + :LOGAND + {:fn-name "LOGAND", + :call-type "FSUBR", + :implementation "", + :page-nos ["27" "64"]}, + :FLAG + {:fn-name "FLAG", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["41" "60"]}, + :MAPCON + {:fn-name "MAPCON", + :call-type "SUBR", + :implementation "FUNCTIONAL PSEUDO- FUNCTION", + :page-nos ["63"]}, + :STAR + {:fn-name "STAR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "85"]}, + :CURCHAR + {:fn-name "CURCHAR", + :call-type "APVAL", + :implementation "", + :page-nos ["69" "87"]}, + :DUMP + {:fn-name "DUMP", + :call-type "SUBR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["67"]}, + :DEFLIST + {:fn-name "DEFLIST", + :call-type "EXPR", + :implementation "PSEUDO-FUNCTION", + :page-nos ["41" "58"]}, + :LEFTSHIFT + {:fn-name "LEFTSHIFT", + :call-type "SUBR", + :implementation "", + :page-nos ["27" "64"]}, + :ZEROP + {:fn-name "ZEROP", + :call-type "SUBR", + :implementation "PREDICATE", + :page-nos ["26" "64"]}}) + +(defn page-url + "Format the URL for the page in the manual with this `page-no`." + [page-no] + (let [n (read-string page-no) + n' (when (and (number? n) + (ends-with? *manual-url* ".pdf")) + ;; annoyingly, the manual has eight pages of front-matter + ;; before numbering starts. + (+ n 8))] + (format + (if (ends-with? *manual-url* ".pdf") "%s#page=%s" "%s#page%s") + *manual-url* + (or n' (trim (str page-no)))))) + +(defn format-page-references + "Format page references from the manual index for the function whose name + is `fn-symbol`." + [fn-symbol] + (let [k (if (keyword? fn-symbol) fn-symbol (keyword fn-symbol))] + (join ", " + (doall + (map + (fn [n] + (let [p (trim n)] + (format "%s" + (page-url p) p))) + (:page-nos (index k))))))) \ No newline at end of file diff --git a/src/beowulf/read.clj b/src/beowulf/read.clj index 4afbccf..39abf1d 100644 --- a/src/beowulf/read.clj +++ b/src/beowulf/read.clj @@ -16,7 +16,7 @@ (:require [beowulf.reader.char-reader :refer [read-chars]] [beowulf.reader.generate :refer [generate]] [beowulf.reader.parser :refer [parse]] - [beowulf.reader.simplify :refer [remove-optional-space simplify]] + [beowulf.reader.simplify :refer [simplify]] [clojure.string :refer [join split starts-with? trim]]) (:import [java.io InputStream] [instaparse.gll Failure])) @@ -80,15 +80,17 @@ (if (instance? Failure parse-tree) (doall (println (number-lines source parse-tree)) (throw (ex-info "Parse failed" (assoc parse-tree :source source)))) - (generate (simplify (remove-optional-space parse-tree)))))) + (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)] - (if (= (count (re-seq #"\(" r)) + (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)))))) diff --git a/src/beowulf/reader/macros.clj b/src/beowulf/reader/macros.clj index 051b1d1..0ef1907 100644 --- a/src/beowulf/reader/macros.clj +++ b/src/beowulf/reader/macros.clj @@ -47,8 +47,8 @@ (def ^:dynamic *readmacros* {:car {'DEFUN (fn [f] (LIST 'SET (LIST 'QUOTE (second f)) - (CONS 'LAMBDA (rest (rest f))))) - 'SETQ (fn [f] (LIST 'SET (LIST 'QUOTE (second f)) (nth f 2)))}}) + (LIST 'QUOTE (CONS 'LAMBDA (rest (rest f)))))) + 'SETQ (fn [f] (LIST 'SET (LIST 'QUOTE (second f)) (LIST 'QUOTE (nth f 2))))}}) (defn expand-macros [form] diff --git a/src/beowulf/reader/parser.clj b/src/beowulf/reader/parser.clj index 1441c2f..082ecde 100644 --- a/src/beowulf/reader/parser.clj +++ b/src/beowulf/reader/parser.clj @@ -60,8 +60,8 @@ arrow := '->'; args := mexpr | (opt-space mexpr semi-colon opt-space)* opt-space mexpr opt-space; fn-name := mvar; - mvar := #'[a-z]+'; - mconst := #'[A-Z]+'; + mvar := #'[a-z][a-z0-9]*'; + mconst := #'[A-Z][A-Z0-9]*'; semi-colon := ';';" ;; Infix operators appear in mexprs, e.g. on page 7. Ooops! diff --git a/src/beowulf/reader/simplify.clj b/src/beowulf/reader/simplify.clj index 52f1dc2..fdfa3c7 100644 --- a/src/beowulf/reader/simplify.clj +++ b/src/beowulf/reader/simplify.clj @@ -25,7 +25,7 @@ ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(declare simplify) +(declare simplify-tree) (defn remove-optional-space [tree] @@ -48,17 +48,17 @@ (loop [r tree'] (if (and r (vector? r) (keyword? (first r))) (if (= (first r) key) - (recur (simplify (second r) context)) + (recur (simplify-tree (second r) context)) r) r)) tree'))) -(defn simplify +(defn simplify-tree "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`." + parse tree **BEFORE** it is passed to `simplify-tree`." ([p] (if (instance? Failure p) @@ -67,7 +67,7 @@ {:cause :parse-failure :phase :simplify :failure p})) - (simplify p :expr))) + (simplify-tree p :expr))) ([p context] (cond (string? p) p @@ -78,8 +78,8 @@ (case (first p) (:λexpr :args :bindings :body :cond :cond-clause :defn :dot-terminal - :fncall :lhs :quoted-expr :rhs ) (map #(simplify % context) p) - (:arg :expr :coefficient :fn-name :number) (simplify (second p) context) + :fncall :lhs :quoted-expr :rhs ) (map #(simplify-tree % context) p) + (:arg :expr :coefficient :fn-name :number) (simplify-tree (second p) context) (:arrow :dot :e :lpar :lsqb :opt-comment :opt-space :q :quote :rpar :rsqb :semi-colon :sep :space) nil :atom (if @@ -97,28 +97,35 @@ [:fncall [:mvar "cons"] [:args - (simplify (nth p 1) context) - (simplify (nth p 2) context)]] - (map #(simplify % context) p)) - :iexp (simplify (second p) context) + (simplify-tree (nth p 1) context) + (simplify-tree (nth p 2) context)]] + (map #(simplify-tree % context) p)) + :iexp (simplify-tree (second p) context) :iexpr [:iexpr - [:lhs (simplify (second p) context)] - (simplify (nth p 2) context) ;; really should be the operator - [:rhs (simplify (nth p 3) context)]] + [:lhs (simplify-tree (second p) context)] + (simplify-tree (nth p 2) context) ;; really should be the operator + [:rhs (simplify-tree (nth p 3) context)]] :mexpr (if (:strict *options*) (throw (ex-info "Cannot parse meta expressions in strict mode" {:cause :strict})) - (simplify (second p) :mexpr)) + (simplify-tree (second p) :mexpr)) :list (if (= context :mexpr) [:fncall [:mvar "list"] - [:args (apply vector (map simplify (rest p)))]] - (map #(simplify % context) p)) - :raw (first (remove empty? (map simplify (rest p)))) - :sexpr (simplify (second p) :sexpr) + [:args (apply vector (map simplify-tree (rest p)))]] + (map #(simplify-tree % context) p)) + :raw (first (remove empty? (map simplify-tree (rest p)))) + :sexpr (simplify-tree (second p) :sexpr) ;;default p))) :else p))) + +(defn simplify + "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." + [p] + (simplify-tree (remove-optional-space p))) \ No newline at end of file diff --git a/test/beowulf/mexpr_test.clj b/test/beowulf/mexpr_test.clj index 1c38145..719d9e1 100644 --- a/test/beowulf/mexpr_test.clj +++ b/test/beowulf/mexpr_test.clj @@ -6,7 +6,7 @@ [beowulf.read :refer [gsp]] [beowulf.reader.generate :refer [generate]] [beowulf.reader.parser :refer [parse]] - [beowulf.reader.simplify :refer [simplify]])) + [beowulf.reader.simplify :refer [simplify-tree]])) ;; These tests are taken generally from the examples on page 10 of ;; Lisp 1.5 Programmers Manual: @@ -74,7 +74,7 @@ (let [expected "(LABEL FF (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X))))))" actual (print-str (generate - (simplify + (simplify-tree (parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))] (is (= actual expected))))) diff --git a/test/beowulf/reader_macro_test.clj b/test/beowulf/reader_macro_test.clj index 228a6a9..0f94111 100644 --- a/test/beowulf/reader_macro_test.clj +++ b/test/beowulf/reader_macro_test.clj @@ -5,7 +5,7 @@ (deftest macro-expansion (testing "Expanding DEFUN" - (let [expected "(SET (QUOTE FACT) (LAMBDA (X) (COND ((ZEROP X) 1) (T (TIMES X (FACT (SUB1 X)))))))" + (let [expected "(SET (QUOTE FACT) (QUOTE (LAMBDA (X) (COND ((ZEROP X) 1) (T (TIMES X (FACT (SUB1 X))))))))" source "(DEFUN FACT (X) (COND ((ZEROP X) 1) (T (TIMES X (FACT (SUB1 X))))))" actual (print-str (gsp source))] (is (= actual expected))))) \ No newline at end of file