Merge branch 'feature/1' into develop
This commit is contained in:
commit
49aa58ea8a
7
doc/further_reading.md
Normal file
7
doc/further_reading.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Further Reading
|
||||||
|
|
||||||
|
1. [CODING for the MIT-IBM 704 COMPUTER, October 1957](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf)
|
||||||
|
2. [MIT AI Memo 1, John McCarthy, September 1958](https://www.softwarepreservation.org/projects/LISP/MIT/AIM-001.pdf)
|
||||||
|
3. [Lisp 1 Programmer's Manual, Phyllis Fox, March 1960](https://bitsavers.org/pdf/mit/rle_lisp/LISP_I_Programmers_Manual_Mar60.pdf)
|
||||||
|
4. [Lisp 1.5 Programmer's Manual, Michael I. Levin, August 1962](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=81)
|
||||||
|
5. [Early LISP History (1956 - 1959), Herbert Stoyan, August 1984](https://dl.acm.org/doi/pdf/10.1145/800055.802047#page=3)
|
1442
doc/lisp1.5.md
1442
doc/lisp1.5.md
File diff suppressed because it is too large
Load diff
|
@ -47,6 +47,22 @@ O14 (read lines O and 1)
|
||||||
|
|
||||||
Of course, this isn't proof. If `CAR` and `CDR` used here are standard IBM 704 assembler mnemonics -- as I believe they are -- then what is `CONS`? It's used in a syntactically identical way. If it also is an assembler mnemonic, then it's hard to believe that, as legend relates, it is short for 'construct'; on the other hand, if it's a label representing an entry point into a subroutine, then why should `CAR` and `CDR` not also be labels?
|
Of course, this isn't proof. If `CAR` and `CDR` used here are standard IBM 704 assembler mnemonics -- as I believe they are -- then what is `CONS`? It's used in a syntactically identical way. If it also is an assembler mnemonic, then it's hard to believe that, as legend relates, it is short for 'construct'; on the other hand, if it's a label representing an entry point into a subroutine, then why should `CAR` and `CDR` not also be labels?
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
**Edited 3<sup>rd</sup> April to add:** I've found a document, not related to Lisp (although John McCarthy is credited as one of the authors), which does confirm -- or strictly, amend -- the story. This is the [CODING for the MIT-IBM 704 COMPUTER](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf), dating from October 1957. The registers of the 704 were divided into four parts, named respectively the prefix part, the address part, the tag part, and the decrement part, of 3, 15, 3, and 15 bits respectively. The decrement part was not used in addressing; that part of the folklore I was taught isn't right. But the names are correct. Consider [this excerpt](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=145) :
|
||||||
|
|
||||||
|
> The address, tag and decrement parts of symbolic instructions are given in that order. In some cases the decrement, tag or address parts are not necessary; therefore the following combinations where OP represents the instruction abbreviation are permissible.
|
||||||
|
|
||||||
|
This doesn't prove there were individual machine instructions with the mnemonics `CAR` and `CDR`; in fact, I'm going to say with some confidence that there were not, by reference to [the table of instructions](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=170) appended to the same document. The instructions do have three letter mnemonics, and they do use 'A' and 'D' as abbreviations for 'address' and 'decrement' respectively, but `CAR` and `CDR` are not included.
|
||||||
|
|
||||||
|
So it seems probable that `CAR` and `CDR` were labels for subroutines, as I hypothesised above. But they were quite likely pre-existing subroutines, in use before the instantiation of the Lisp project, because they would be generally useful; and the suggestion that they are contractions of 'contents of the address part' and 'contents of the decrement part', respectively, seem confirmed.
|
||||||
|
|
||||||
|
And, going further down the rabbit hole, [there's this](https://dl.acm.org/doi/pdf/10.1145/800055.802047#page=3). In 1957, before work on the Lisp project started, McCarthy was writing functions to add list processing to the then-new FORTRAN language, on the very same IBM 704 machine.
|
||||||
|
|
||||||
|
> in this time any function that delivered integer values had to have a first letter X. Any function (as opposited to subroutines) had to have a last letter F in its name. Therefore the functions selecting parts of the IBM704 memory register (word) were introduced to be XCSRF, XCPRF, XCDRF, XCTRF and XCARF
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
I think that the answer has to be that if `CAR` and `CDR` had been named by the early Lisp team -- John McCarthy and his immediate colleagues -- they would not have been named as they were. If not `FRST` and `REST`, as in more modern Lisps, then something like `P1` and `P2`. `CAR` and `CDR` are distinctive and memorable (and therefore in my opinion worth preserving) because they very specifically name the parts of a cons cell and of nothing else.
|
I think that the answer has to be that if `CAR` and `CDR` had been named by the early Lisp team -- John McCarthy and his immediate colleagues -- they would not have been named as they were. If not `FRST` and `REST`, as in more modern Lisps, then something like `P1` and `P2`. `CAR` and `CDR` are distinctive and memorable (and therefore in my opinion worth preserving) because they very specifically name the parts of a cons cell and of nothing else.
|
||||||
|
|
||||||
Let's be clear, here: when `CAR` and `CDR` are used in Lisp, they are returning pointers, certainly -- but not in the sense that one points to a page and the other to a word. Each is an offset into a cell array, which is almost certainly an array of single 36 bit words held on a single page. So both are in effect being used as decrements. Their use in Lisp is an overload onto their original semantic meaning; they are no longer being used for the purpose for which they are named.
|
Let's be clear, here: when `CAR` and `CDR` are used in Lisp, they are returning pointers, certainly -- but not in the sense that one points to a page and the other to a word. Each is an offset into a cell array, which is almost certainly an array of single 36 bit words held on a single page. So both are in effect being used as decrements. Their use in Lisp is an overload onto their original semantic meaning; they are no longer being used for the purpose for which they are named.
|
||||||
|
@ -262,6 +278,49 @@ Lisp 1.5 doesn't have `PUT`, `PUTPROP` or `DEFUN` because setting properties ind
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
## Deeper delving
|
||||||
|
|
||||||
|
After writing, and publishing, this essay, I went on procrastinating, which is what I do when I'm sure I'm missing something; and to procrastinate, I went on reading the earliest design documents of Lisp I could find. And so I came across the MIT AI team's first ever memo, written by John McCarthy in September 1958. And in that, I find this:
|
||||||
|
|
||||||
|
> 3.2.1. First we have those that extract parts of a 704 word and form a word from parts. We shall distinguish the following parts of a word and indicate each of them by a characteristic letter.
|
||||||
|
>
|
||||||
|
> | Letter | Description |
|
||||||
|
> | ---- | ---------------------------- |
|
||||||
|
> | w | the whole word |
|
||||||
|
> | p | the prefix (bits s, 1, 2) |
|
||||||
|
> | i | the indicator (bits 1 and 2) |
|
||||||
|
> | s | the sign bit |
|
||||||
|
> | d | the decrement (bits 3-17) |
|
||||||
|
> | t | the tag (bits 18-20) |
|
||||||
|
> | a | the address (bits 21-35) |
|
||||||
|
|
||||||
|
In the discussion of functions which access properties on [page 58 of the Lisp 1.5 programmer's manual](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=66), the word 'indicator' is used in preference to 'symbol' for the name of a property: for example
|
||||||
|
|
||||||
|
> The function `deflist` is a more general defining function. Its first argument is a list of pairs as for define. Its second argument is the *indicator* that is to be used. After `deflist` has been executed with (u<sub>i</sub> v<sub>i</sub>) among its first argument, the property list of u<sub>i</sub> will begin:
|
||||||
|
>
|
||||||
|
> If `deflist` or `define` is used twice on the same object with the same *indicator*, the old value will be replaced by the new one.
|
||||||
|
|
||||||
|
(my emphasis).
|
||||||
|
|
||||||
|
That use of 'indicator' has been nagging at me for a week. It looks like a term of art. If it's just an ordinary atomic symbol, why isn't it called a symbol?
|
||||||
|
|
||||||
|
Is it an indicator in the special sense of the indicator part of the machine word? If it were, then the property list could just be a flat list of values. And what's been worrying and surprising me is that property lists are shown in the manual as flat lists. Eureka? I don't *think* so.
|
||||||
|
|
||||||
|
The reason I don't think so is that there are only two bits in the indicator part of the word, so only four distinct values; whereas we know that Lisp 1.5 has (at least) five distinct indicator values, `APVAL`, `EXPR`, `FEXPR`, `SUBR` and `FSUBR`.
|
||||||
|
|
||||||
|
Furthermore, on [page 39](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=47), we have:
|
||||||
|
|
||||||
|
> A property list is characterized by having the special constant 77777<sub>8</sub> (i. e., minus 1)
|
||||||
|
> as the first element of the list. The rest of the list contains various properties of the
|
||||||
|
> atomic symbol. Each property is preceded by an *atomic symbol* which is called its
|
||||||
|
> *indicator*.
|
||||||
|
|
||||||
|
(again, my emphasis)
|
||||||
|
|
||||||
|
But I'm going to hypothesise that the properties were originally intended to be discriminated by the indicator bits in the cons cell, that they were originally coded that way, and that there was some code which depended on property lists being flat lists; and that, when it was discovered that four indicators were not enough and that something else was going to have to be used, the new format of the property list using atomic symbols as indicators was bodged in.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
So what this is about is I've spent most of a whole day procrastinating, because I'm not exactly sure how I'm going to make the change I've got to make. Versions of Beowulf up to and including 0.2.1 used the naive understanding of the architecture; version 0.3.0 *should* use the corrected version. But before it can, I need to be reasonably confident that I understand what the correct solution is.
|
So what this is about is I've spent most of a whole day procrastinating, because I'm not exactly sure how I'm going to make the change I've got to make. Versions of Beowulf up to and including 0.2.1 used the naive understanding of the architecture; version 0.3.0 *should* use the corrected version. But before it can, I need to be reasonably confident that I understand what the correct solution is.
|
||||||
|
|
||||||
I *shall* implement `PUT`, even though it isn't in the spec, because it's a useful building block on which to build `DEFINE` and `DEFLIS`, both of which are. And also, because `PUT` would have been very easy for the Lisp 1.5 implementers to implement, if it had been relevant to their working environment.
|
I *shall* implement `PUT`, even though it isn't in the spec, because it's a useful building block on which to build `DEFINE` and `DEFLIS`, both of which are. And also, because `PUT` would have been very easy for the Lisp 1.5 implementers to implement, if it had been relevant to their working environment. And I shall implement property list as flat lists of interleaved 'indicator' symbols and values, even with that nonsense 77777<sub>8</sub> as a prefix, because now I know (or think I know) that it was a bodge, it seems right in the spirit of historical reconstruction to reconstruct the bodge.
|
||||||
|
|
1
docs/index.html
Symbolic link
1
docs/index.html
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
codox/intro.html
|
|
@ -1,150 +1,223 @@
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Beowulf Sysout file generated at 2023-03-31T02:24:08.808
|
;; Beowulf 0.3.0-SNAPSHOT Sysout file generated at 2023-04-05T23:30:32.954
|
||||||
;; generated by simon
|
;; generated by simon
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
((NIL)
|
((NIL 32767 APVAL NIL)
|
||||||
(T . T)
|
(T 32767 APVAL T)
|
||||||
(F)
|
(F 32767 APVAL NIL)
|
||||||
(ADD1)
|
(ADD1 32767 SUBR (BEOWULF HOST ADD1))
|
||||||
(AND)
|
(AND 32767 SUBR (BEOWULF HOST AND))
|
||||||
(APPEND LAMBDA
|
(APPEND
|
||||||
(X Y) (COND ((NULL X) Y) ((QUOTE T) (CONS (CAR X) (APPEND (CDR X) Y)))))
|
32767
|
||||||
(APPLY)
|
EXPR
|
||||||
(ASSOC LAMBDA (X L)
|
(LAMBDA
|
||||||
|
(X Y) (COND ((NULL X) Y) (T (CONS (CAR X) (APPEND (CDR X) Y))))))
|
||||||
|
(APPLY 32767 SUBR (BEOWULF BOOTSTRAP APPLY))
|
||||||
|
(ASSOC
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(X L)
|
||||||
(COND
|
(COND
|
||||||
((NULL L) (QUOTE NIL))
|
((NULL L) NIL)
|
||||||
((AND (CONSP (CAR L)) (EQ (CAAR L) X)) (CAR L))
|
((AND (CONSP (CAR L)) (EQ (CAAR L) X)) (CAR L))
|
||||||
((QUOTE T) (ASSOC X (CDR L)))))
|
(T (ASSOC X (CDR L)))))
|
||||||
(ATOM)
|
SUBR (BEOWULF HOST ASSOC))
|
||||||
(CAR)
|
(ATOM 32767 SUBR (BEOWULF HOST ATOM))
|
||||||
(CAAAAR LAMBDA (X) (CAR (CAR (CAR (CAR X)))))
|
(CAR 32767 SUBR (BEOWULF HOST CAR))
|
||||||
(CAAADR LAMBDA (X) (CAR (CAR (CAR (CDR X)))))
|
(CAAAAR 32767 EXPR (LAMBDA (X) (CAR (CAR (CAR (CAR X))))))
|
||||||
(CAAAR LAMBDA (X) (CAR (CAR (CAR X))))
|
(CAAADR 32767 EXPR (LAMBDA (X) (CAR (CAR (CAR (CDR X))))))
|
||||||
(CAADAR LAMBDA (X) (CAR (CAR (CDR (CAR X)))))
|
(CAAAR 32767 EXPR (LAMBDA (X) (CAR (CAR (CAR X)))))
|
||||||
(CAADDR LAMBDA (X) (CAR (CAR (CDR (CDR X)))))
|
(CAADAR 32767 EXPR (LAMBDA (X) (CAR (CAR (CDR (CAR X))))))
|
||||||
(CAADR LAMBDA (X) (CAR (CAR (CDR X))))
|
(CAADDR 32767 EXPR (LAMBDA (X) (CAR (CAR (CDR (CDR X))))))
|
||||||
(CAAR LAMBDA (X) (CAR (CAR X)))
|
(CAADR 32767 EXPR (LAMBDA (X) (CAR (CAR (CDR X)))))
|
||||||
(CADAAR LAMBDA (X) (CAR (CDR (CAR (CAR X)))))
|
(CAAR 32767 EXPR (LAMBDA (X) (CAR (CAR X))))
|
||||||
(CADADR LAMBDA (X) (CAR (CDR (CAR (CDR X)))))
|
(CADAAR 32767 EXPR (LAMBDA (X) (CAR (CDR (CAR (CAR X))))))
|
||||||
(CADAR LAMBDA (X) (CAR (CDR (CAR X))))
|
(CADADR 32767 EXPR (LAMBDA (X) (CAR (CDR (CAR (CDR X))))))
|
||||||
(CADDAR LAMBDA (X) (CAR (CDR (CDR (CAR X)))))
|
(CADAR 32767 EXPR (LAMBDA (X) (CAR (CDR (CAR X)))))
|
||||||
(CADDDR LAMBDA (X) (CAR (CDR (CDR (CDR X)))))
|
(CADDAR 32767 EXPR (LAMBDA (X) (CAR (CDR (CDR (CAR X))))))
|
||||||
(CADDR LAMBDA (X) (CAR (CDR (CDR X))))
|
(CADDDR 32767 EXPR (LAMBDA (X) (CAR (CDR (CDR (CDR X))))))
|
||||||
(CADR LAMBDA (X) (CAR (CDR X)))
|
(CADDR 32767 EXPR (LAMBDA (X) (CAR (CDR (CDR X)))))
|
||||||
(CDAAAR LAMBDA (X) (CDR (CAR (CAR (CAR X)))))
|
(CADR 32767 EXPR (LAMBDA (X) (CAR (CDR X))))
|
||||||
(CDAADR LAMBDA (X) (CDR (CAR (CAR (CDR X)))))
|
(CDAAAR 32767 EXPR (LAMBDA (X) (CDR (CAR (CAR (CAR X))))))
|
||||||
(CDAAR LAMBDA (X) (CDR (CAR (CAR X))))
|
(CDAADR 32767 EXPR (LAMBDA (X) (CDR (CAR (CAR (CDR X))))))
|
||||||
(CDADAR LAMBDA (X) (CDR (CAR (CDR (CAR X)))))
|
(CDAAR 32767 EXPR (LAMBDA (X) (CDR (CAR (CAR X)))))
|
||||||
(CDADDR LAMBDA (X) (CDR (CAR (CDR (CDR X)))))
|
(CDADAR 32767 EXPR (LAMBDA (X) (CDR (CAR (CDR (CAR X))))))
|
||||||
(CDADR LAMBDA (X) (CDR (CAR (CDR X))))
|
(CDADDR 32767 EXPR (LAMBDA (X) (CDR (CAR (CDR (CDR X))))))
|
||||||
(CDAR LAMBDA (X) (CDR (CAR X)))
|
(CDADR 32767 EXPR (LAMBDA (X) (CDR (CAR (CDR X)))))
|
||||||
(CDDAAR LAMBDA (X) (CDR (CDR (CAR (CAR X)))))
|
(CDAR 32767 EXPR (LAMBDA (X) (CDR (CAR X))))
|
||||||
(CDDADR LAMBDA (X) (CDR (CDR (CAR (CDR X)))))
|
(CDDAAR 32767 EXPR (LAMBDA (X) (CDR (CDR (CAR (CAR X))))))
|
||||||
(CDDAR LAMBDA (X) (CDR (CDR (CAR X))))
|
(CDDADR 32767 EXPR (LAMBDA (X) (CDR (CDR (CAR (CDR X))))))
|
||||||
(CDDDAR LAMBDA (X) (CDR (CDR (CDR (CAR X)))))
|
(CDDAR 32767 EXPR (LAMBDA (X) (CDR (CDR (CAR X)))))
|
||||||
(CDDDDR LAMBDA (X) (CDR (CDR (CDR (CDR X)))))
|
(CDDDAR 32767 EXPR (LAMBDA (X) (CDR (CDR (CDR (CAR X))))))
|
||||||
(CDDDR LAMBDA (X) (CDR (CDR (CDR X))))
|
(CDDDDR 32767 EXPR (LAMBDA (X) (CDR (CDR (CDR (CDR X))))))
|
||||||
(CDDR LAMBDA (X) (CDR (CDR X)))
|
(CDDDR 32767 EXPR (LAMBDA (X) (CDR (CDR (CDR X)))))
|
||||||
(CDR)
|
(CDDR 32767 EXPR (LAMBDA (X) (CDR (CDR X))))
|
||||||
(CONS)
|
(CDR 32767 SUBR (BEOWULF HOST CDR))
|
||||||
(CONSP)
|
(CONS 32767 SUBR (BEOWULF HOST CONS))
|
||||||
|
(CONSP 32767 SUBR (BEOWULF HOST CONSP))
|
||||||
(COPY
|
(COPY
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(X)
|
(X)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) (QUOTE NIL))
|
((NULL X) NIL)
|
||||||
((ATOM X) X) ((QUOTE T) (CONS (COPY (CAR X)) (COPY (CDR X))))))
|
((ATOM X) X) (T (CONS (COPY (CAR X)) (COPY (CDR X)))))))
|
||||||
(DEFINE)
|
(DEFINE 32767 SUBR (BEOWULF HOST DEFINE))
|
||||||
(DIFFERENCE)
|
(DIFFERENCE 32767 SUBR (BEOWULF HOST DIFFERENCE))
|
||||||
(DIVIDE
|
(DIVIDE
|
||||||
LAMBDA (X Y) (CONS (QUOTIENT X Y) (CONS (REMAINDER X Y) (QUOTE NIL))))
|
32767
|
||||||
(DOC)
|
EXPR
|
||||||
|
(LAMBDA (X Y) (CONS (QUOTIENT X Y) (CONS (REMAINDER X Y) NIL))))
|
||||||
|
(DOC 32767 SUBR (BEOWULF HOST DOC))
|
||||||
(EFFACE
|
(EFFACE
|
||||||
LAMBDA (X L) (COND ((NULL L) (QUOTE NIL))
|
32767
|
||||||
((EQUAL X (CAR L)) (CDR L))
|
EXPR
|
||||||
((QUOTE T) (RPLACD L (EFFACE X (CDR L))))))
|
(LAMBDA
|
||||||
(ERROR)
|
(X L)
|
||||||
(EQ)
|
(COND
|
||||||
(EQUAL)
|
((NULL L) NIL)
|
||||||
(EVAL)
|
((EQUAL X (CAR L)) (CDR L)) (T (RPLACD L (EFFACE X (CDR L)))))))
|
||||||
|
(ERROR 32767 SUBR (BEOWULF HOST ERROR))
|
||||||
|
(EQ 32767 SUBR (BEOWULF HOST EQ))
|
||||||
|
(EQUAL 32767 SUBR (BEOWULF HOST EQUAL))
|
||||||
|
(EVAL 32767 SUBR (BEOWULF BOOTSTRAP EVAL))
|
||||||
(FACTORIAL
|
(FACTORIAL
|
||||||
LAMBDA (N) (COND ((EQ N 1) 1) (T (TIMES N (FACTORIAL (SUB1 N))))))
|
32767
|
||||||
(FIXP)
|
EXPR (LAMBDA (N) (COND ((EQ N 1) 1) (T (TIMES N (FACTORIAL (SUB1 N)))))))
|
||||||
(GENSYM)
|
(FIXP 32767 SUBR (BEOWULF HOST FIXP))
|
||||||
|
(GENSYM 32767 SUBR (BEOWULF HOST GENSYM))
|
||||||
(GET
|
(GET
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(X Y)
|
(X Y)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) (QUOTE NIL))
|
((NULL X) NIL)
|
||||||
((EQ (CAR X) Y) (CAR (CDR X))) ((QUOTE T) (GET (CDR X) Y))))
|
((EQ (CAR X) Y) (CAR (CDR X))) (T (GET (CDR X) Y))))
|
||||||
(GREATERP)
|
SUBR (BEOWULF HOST GET))
|
||||||
(INTEROP)
|
(GREATERP 32767 SUBR (BEOWULF HOST GREATERP))
|
||||||
|
(INTEROP 32767 SUBR (BEOWULF INTEROP INTEROP))
|
||||||
(INTERSECTION
|
(INTERSECTION
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(X Y)
|
(X Y)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) (QUOTE NIL))
|
((NULL X) NIL)
|
||||||
((MEMBER (CAR X) Y) (CONS (CAR X) (INTERSECTION (CDR X) Y)))
|
((MEMBER (CAR X) Y) (CONS (CAR X) (INTERSECTION (CDR X) Y)))
|
||||||
((QUOTE T) (INTERSECTION (CDR X) Y))))
|
(T (INTERSECTION (CDR X) Y)))))
|
||||||
(LENGTH
|
(LENGTH
|
||||||
LAMBDA
|
32767
|
||||||
(L) (COND ((EQ NIL L) 0) ((CONSP (CDR L)) (ADD1 (LENGTH (CDR L)))) (T 0)))
|
EXPR
|
||||||
(LESSP)
|
(LAMBDA
|
||||||
(MAPLIST LAMBDA (L F) (COND ((NULL L) NIL) ((QUOTE T) (CONS (F (CAR L)) (MAPLIST (CDR L) F)))))
|
(L)
|
||||||
|
(COND ((EQ NIL L) 0) ((CONSP (CDR L)) (ADD1 (LENGTH (CDR L)))) (T 0))))
|
||||||
|
(LESSP 32767 SUBR (BEOWULF HOST LESSP))
|
||||||
|
(MAPLIST
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(L F)
|
||||||
|
(COND
|
||||||
|
((NULL L) NIL) (T (CONS (F (CAR L)) (MAPLIST (CDR L) F))))))
|
||||||
(MEMBER
|
(MEMBER
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(A X)
|
(A X)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) (QUOTE F))
|
((NULL X) (QUOTE F))
|
||||||
((EQ A (CAR X)) (QUOTE T)) ((QUOTE T) (MEMBER A (CDR X)))))
|
((EQ A (CAR X)) T) (T (MEMBER A (CDR X))))))
|
||||||
(MINUSP LAMBDA (X) (LESSP X 0))
|
(MINUSP 32767 EXPR (LAMBDA (X) (LESSP X 0)))
|
||||||
(NOT LAMBDA (X) (COND (X (QUOTE NIL)) ((QUOTE T) (QUOTE T))))
|
(NOT 32767 EXPR (LAMBDA (X) (COND (X NIL) (T T))))
|
||||||
(NULL LAMBDA (X) (COND ((EQUAL X NIL) (QUOTE T)) (T (QUOTE F))))
|
(NULL
|
||||||
(NUMBERP)
|
32767 EXPR (LAMBDA (X) (COND ((EQUAL X NIL) T) (T (QUOTE F)))))
|
||||||
(OBLIST)
|
(NUMBERP 32767 SUBR (BEOWULF HOST NUMBERP))
|
||||||
(ONEP LAMBDA (X) (EQ X 1))
|
(OBLIST 32767 SUBR (BEOWULF HOST OBLIST))
|
||||||
|
(ONEP 32767 EXPR (LAMBDA (X) (EQ X 1)))
|
||||||
(PAIR
|
(PAIR
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(X Y)
|
(X Y)
|
||||||
(COND
|
(COND
|
||||||
((AND (NULL X) (NULL Y)) NIL)
|
((AND (NULL X) (NULL Y)) NIL)
|
||||||
((NULL X) (ERROR (QUOTE F2)))
|
((NULL X) (ERROR (QUOTE F2)))
|
||||||
((NULL Y) (ERROR (QUOTE F3)))
|
((NULL Y) (ERROR (QUOTE F3)))
|
||||||
(T (CONS (CONS (CAR X) (CAR Y)) (PAIR (CDR X) (CDR Y))))))
|
(T (CONS (CONS (CAR X) (CAR Y)) (PAIR (CDR X) (CDR Y)))))))
|
||||||
(PAIRLIS LAMBDA (X Y A)
|
(PAIRLIS
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(X Y A)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) A)
|
((NULL X) A)
|
||||||
((QUOTE T) (CONS (CONS (CAR X) (CAR Y)) (PAIRLIS (CDR X) (CDR Y) A)))))
|
(T (CONS (CONS (CAR X) (CAR Y)) (PAIRLIS (CDR X) (CDR Y) A)))))
|
||||||
(PLUS)
|
SUBR (BEOWULF HOST PAIRLIS))
|
||||||
(PRETTY)
|
(PLUS 32767 SUBR (BEOWULF HOST PLUS))
|
||||||
(PRINT)
|
(PRETTY 32767)
|
||||||
|
(PRINT 32767)
|
||||||
(PROP
|
(PROP
|
||||||
LAMBDA
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
(X Y U)
|
(X Y U)
|
||||||
(COND
|
(COND
|
||||||
((NULL X) (U)) ((EQ (CAR X) Y) (CDR X)) ((QUOTE T) (PROP (CDR X) Y U))))
|
((NULL X) (U))
|
||||||
(QUOTE LAMBDA (X) X)
|
((EQ (CAR X) Y) (CDR X)) (T (PROP (CDR X) Y U)))))
|
||||||
(QUOTIENT)
|
(QUOTE 32767 EXPR (LAMBDA (X) X))
|
||||||
(RANGE LAMBDA (N M) (COND ((LESSP M N) (QUOTE NIL)) ((QUOTE T) (CONS N (RANGE (ADD1 N) M)))))
|
(QUOTIENT 32767 SUBR (BEOWULF HOST QUOTIENT))
|
||||||
(READ)
|
(RANGE
|
||||||
(REMAINDER)
|
32767
|
||||||
(REPEAT
|
EXPR
|
||||||
LAMBDA (N X) (COND ((EQ N 0) NIL) (T (CONS X (REPEAT (SUB1 N) X)))))
|
(LAMBDA
|
||||||
(RPLACA)
|
(N M)
|
||||||
(RPLACD)
|
|
||||||
(SET)
|
|
||||||
(SUB1 LAMBDA (N) (DIFFERENCE N 1))
|
|
||||||
(SUB2 LAMBDA (A Z)
|
|
||||||
(COND
|
(COND
|
||||||
((NULL A) Z)
|
((LESSP M N) NIL) (T (CONS N (RANGE (ADD1 N) M))))))
|
||||||
((EQ (CAAR A) Z) (CDAR A))
|
(READ 32767 SUBR (BEOWULF READ READ))
|
||||||
((QUOTE T) (SUB2 (CDAR A) Z))))
|
(REMAINDER 32767 SUBR (BEOWULF HOST REMAINDER))
|
||||||
(SUBLIS LAMBDA (A Y) (COND ((ATOM Y) (SUB2 A Y)) ((QUOTE T) (CONS))))
|
(REPEAT
|
||||||
(SUBST LAMBDA (X Y Z)
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA (N X) (COND ((EQ N 0) NIL) (T (CONS X (REPEAT (SUB1 N) X))))))
|
||||||
|
(RPLACA 32767 SUBR (BEOWULF HOST RPLACA))
|
||||||
|
(RPLACD 32767 SUBR (BEOWULF HOST RPLACD))
|
||||||
|
(SET 32767 SUBR (BEOWULF HOST SET))
|
||||||
|
(SUB1 32767 EXPR (LAMBDA (N) (DIFFERENCE N 1)) SUBR (BEOWULF HOST SUB1))
|
||||||
|
(SUB2
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(A Z)
|
||||||
|
(COND
|
||||||
|
((NULL A) Z) ((EQ (CAAR A) Z) (CDAR A)) (T (SUB2 (CDAR A) Z)))))
|
||||||
|
(SUBLIS
|
||||||
|
32767 EXPR (LAMBDA (A Y) (COND ((ATOM Y) (SUB2 A Y)) (T (CONS)))))
|
||||||
|
(SUBST
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(X Y Z)
|
||||||
(COND
|
(COND
|
||||||
((EQUAL Y Z) X)
|
((EQUAL Y Z) X)
|
||||||
((ATOM Z) Z)
|
((ATOM Z) Z)
|
||||||
((QUOTE T) (CONS (SUBST X Y (CAR Z)) (SUBST X Y (CDR Z))))))
|
(T (CONS (SUBST X Y (CAR Z)) (SUBST X Y (CDR Z)))))))
|
||||||
(SYSIN)
|
(SYSIN 32767 SUBR (BEOWULF IO SYSIN))
|
||||||
(SYSOUT) (TERPRI) (TIMES) (TRACE) (UNTRACE) (ZEROP LAMBDA (N) (EQ N 0)))
|
(SYSOUT 32767 SUBR (BEOWULF IO SYSOUT))
|
||||||
|
(TERPRI 32767)
|
||||||
|
(TIMES 32767 SUBR (BEOWULF HOST TIMES))
|
||||||
|
(TRACE 32767 SUBR (BEOWULF HOST TRACE))
|
||||||
|
(UNION
|
||||||
|
32767
|
||||||
|
EXPR
|
||||||
|
(LAMBDA
|
||||||
|
(X Y)
|
||||||
|
(COND
|
||||||
|
((NULL X) Y)
|
||||||
|
((MEMBER (CAR X) Y) (UNION (CDR X) Y))
|
||||||
|
(T (CONS (CAR X) (UNION (CDR X) Y))))))
|
||||||
|
(UNTRACE 32767 SUBR (BEOWULF HOST UNTRACE))
|
||||||
|
(ZEROP 32767 EXPR (LAMBDA (N) (EQ N 0))))
|
||||||
|
|
0
resources/mexpr/properties.mexpr.lsp
Normal file
0
resources/mexpr/properties.mexpr.lsp
Normal file
|
@ -9,18 +9,10 @@
|
||||||
ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that
|
ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that
|
||||||
therefore all arguments must be numbers, symbols or `beowulf.cons_cell.ConsCell`
|
therefore all arguments must be numbers, symbols or `beowulf.cons_cell.ConsCell`
|
||||||
objects."
|
objects."
|
||||||
(:require [clojure.string :as s]
|
(:require [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell T]]
|
||||||
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell
|
[beowulf.host :refer [ASSOC ATOM CAAR CADAR CADDR CADR CAR CDR GET
|
||||||
pretty-print T F]]
|
LIST NUMBERP PAIRLIS traced?]]
|
||||||
[beowulf.host :refer [ADD1 AND ASSOC ATOM ATOM? CAR CDR CONS DEFINE
|
[beowulf.oblist :refer [*options* NIL oblist]])
|
||||||
DIFFERENCE DOC EQ EQUAL ERROR FIXP GENSYM
|
|
||||||
GREATERP lax? LESSP LIST NUMBERP OBLIST PAIRLIS
|
|
||||||
PLUS
|
|
||||||
QUOTIENT REMAINDER RPLACA RPLACD SET
|
|
||||||
TIMES TRACE traced? UNTRACE]]
|
|
||||||
[beowulf.io :refer [SYSIN SYSOUT]]
|
|
||||||
[beowulf.oblist :refer [*options* oblist NIL]]
|
|
||||||
[beowulf.read :refer [READ]])
|
|
||||||
(:import [beowulf.cons_cell ConsCell]
|
(:import [beowulf.cons_cell ConsCell]
|
||||||
[clojure.lang Symbol]))
|
[clojure.lang Symbol]))
|
||||||
|
|
||||||
|
@ -46,253 +38,67 @@
|
||||||
|
|
||||||
(declare APPLY EVAL)
|
(declare APPLY EVAL)
|
||||||
|
|
||||||
(defmacro QUOTE
|
(defn try-resolve-subroutine
|
||||||
"Quote, but in upper case for LISP 1.5"
|
"Attempt to resolve this `subr` with these `arg`."
|
||||||
[f]
|
[subr args]
|
||||||
`(quote ~f))
|
(when (and subr (not= subr NIL))
|
||||||
|
(try @(resolve subr)
|
||||||
|
(catch Throwable any
|
||||||
|
(throw (ex-info "Failed to resolve subroutine"
|
||||||
|
{:phase :apply
|
||||||
|
:function subr
|
||||||
|
:args args
|
||||||
|
:type :beowulf}
|
||||||
|
any))))))
|
||||||
|
|
||||||
(defn uaf
|
(defn- trace-call
|
||||||
"Universal access function; `l` is expected to be an arbitrary LISP list, `path`
|
"Show a trace of a call to the function named by this `function-symbol`
|
||||||
a (clojure) list of the characters `a` and `d`. Intended to make declaring
|
with these `args` at this depth."
|
||||||
all those fiddly `#'c[ad]+r'` functions a bit easier"
|
[function-symbol args depth]
|
||||||
[l path]
|
(when (traced? function-symbol)
|
||||||
(cond
|
|
||||||
(= l NIL) NIL
|
|
||||||
(empty? path) l
|
|
||||||
:else
|
|
||||||
(try
|
|
||||||
(case (last path)
|
|
||||||
\a (uaf (.first l) (butlast path))
|
|
||||||
\d (uaf (.getCdr l) (butlast path))
|
|
||||||
(throw (ex-info (str "uaf: unexpected letter in path (only `a` and `d` permitted): " (last path))
|
|
||||||
{:cause :uaf
|
|
||||||
:detail :unexpected-letter
|
|
||||||
:expr (last path)})))
|
|
||||||
(catch ClassCastException e
|
|
||||||
(throw (ex-info
|
|
||||||
(str "uaf: Not a LISP list? " (type l))
|
|
||||||
{:cause :uaf
|
|
||||||
:detail :not-a-lisp-list
|
|
||||||
:expr l}))))))
|
|
||||||
|
|
||||||
(defmacro CAAR [x] `(uaf ~x '(\a \a)))
|
|
||||||
(defmacro CADR [x] `(uaf ~x '(\a \d)))
|
|
||||||
(defmacro CDDR [x] `(uaf ~x '(\d \d)))
|
|
||||||
(defmacro CDAR [x] `(uaf ~x '(\d \a)))
|
|
||||||
|
|
||||||
(defmacro CAAAR [x] `(uaf ~x '(\a \a \a)))
|
|
||||||
(defmacro CAADR [x] `(uaf ~x '(\a \a \d)))
|
|
||||||
(defmacro CADAR [x] `(uaf ~x '(\a \d \a)))
|
|
||||||
(defmacro CADDR [x] `(uaf ~x '(\a \d \d)))
|
|
||||||
(defmacro CDDAR [x] `(uaf ~x '(\d \d \a)))
|
|
||||||
(defmacro CDDDR [x] `(uaf ~x '(\d \d \d)))
|
|
||||||
(defmacro CDAAR [x] `(uaf ~x '(\d \a \a)))
|
|
||||||
(defmacro CDADR [x] `(uaf ~x '(\d \a \d)))
|
|
||||||
|
|
||||||
(defmacro CAAAAR [x] `(uaf ~x '(\a \a \a \a)))
|
|
||||||
(defmacro CAADAR [x] `(uaf ~x '(\a \a \d \a)))
|
|
||||||
(defmacro CADAAR [x] `(uaf ~x '(\a \d \a \a)))
|
|
||||||
(defmacro CADDAR [x] `(uaf ~x '(\a \d \d \a)))
|
|
||||||
(defmacro CDDAAR [x] `(uaf ~x '(\d \d \a \a)))
|
|
||||||
(defmacro CDDDAR [x] `(uaf ~x '(\d \d \d \a)))
|
|
||||||
(defmacro CDAAAR [x] `(uaf ~x '(\d \a \a \a)))
|
|
||||||
(defmacro CDADAR [x] `(uaf ~x '(\d \a \d \a)))
|
|
||||||
(defmacro CAAADR [x] `(uaf ~x '(\a \a \a \d)))
|
|
||||||
(defmacro CAADDR [x] `(uaf ~x '(\a \a \d \d)))
|
|
||||||
(defmacro CADADR [x] `(uaf ~x '(\a \d \a \d)))
|
|
||||||
(defmacro CADDDR [x] `(uaf ~x '(\a \d \d \d)))
|
|
||||||
(defmacro CDDADR [x] `(uaf ~x '(\d \d \a \d)))
|
|
||||||
(defmacro CDDDDR [x] `(uaf ~x '(\d \d \d \d)))
|
|
||||||
(defmacro CDAADR [x] `(uaf ~x '(\d \a \a \d)))
|
|
||||||
(defmacro CDADDR [x] `(uaf ~x '(\d \a \d \d)))
|
|
||||||
|
|
||||||
;;;; INTEROP feature ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defn interop-interpret-q-name
|
|
||||||
"For interoperation with Clojure, it will often be necessary to pass
|
|
||||||
qualified names that are not representable in Lisp 1.5. This function
|
|
||||||
takes a sequence in the form `(PART PART PART... NAME)` and returns
|
|
||||||
a symbol in the form `PART.PART.PART/NAME`. This symbol will then be
|
|
||||||
tried in both that form and lower-cased. Names with hyphens or
|
|
||||||
underscores cannot be represented with this scheme."
|
|
||||||
[l]
|
|
||||||
(if
|
|
||||||
(seq? l)
|
|
||||||
(symbol
|
|
||||||
(s/reverse
|
|
||||||
(s/replace-first
|
|
||||||
(s/reverse
|
|
||||||
(s/join "." (map str l)))
|
|
||||||
"."
|
|
||||||
"/")))
|
|
||||||
l))
|
|
||||||
|
|
||||||
(defn to-beowulf
|
|
||||||
"Return a beowulf-native representation of the Clojure object `o`.
|
|
||||||
Numbers and symbols are unaffected. Collections have to be converted;
|
|
||||||
strings must be converted to symbols."
|
|
||||||
[o]
|
|
||||||
(cond
|
|
||||||
(coll? o) (make-beowulf-list o)
|
|
||||||
(string? o) (symbol (s/upper-case o))
|
|
||||||
:else o))
|
|
||||||
|
|
||||||
(defn to-clojure
|
|
||||||
"If l is a `beowulf.cons_cell.ConsCell`, return a Clojure list having the
|
|
||||||
same members in the same order."
|
|
||||||
[l]
|
|
||||||
(cond
|
|
||||||
(not (instance? beowulf.cons_cell.ConsCell l))
|
|
||||||
l
|
|
||||||
(= (CDR l) NIL)
|
|
||||||
(list (to-clojure (CAR l)))
|
|
||||||
:else
|
|
||||||
(conj (to-clojure (CDR l)) (to-clojure (CAR l)))))
|
|
||||||
|
|
||||||
(defn 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."
|
|
||||||
[fn-symbol args]
|
|
||||||
(if-not (:strict *options*)
|
|
||||||
(let
|
|
||||||
[q-name (if
|
|
||||||
(seq? fn-symbol)
|
|
||||||
(interop-interpret-q-name fn-symbol)
|
|
||||||
fn-symbol)
|
|
||||||
l-name (symbol (s/lower-case q-name))
|
|
||||||
f (cond
|
|
||||||
(try
|
|
||||||
(fn? (eval l-name))
|
|
||||||
(catch java.lang.ClassNotFoundException _ nil)) l-name
|
|
||||||
(try
|
|
||||||
(fn? (eval q-name))
|
|
||||||
(catch java.lang.ClassNotFoundException _ nil)) q-name
|
|
||||||
:else (throw
|
|
||||||
(ex-info
|
|
||||||
(str "INTEROP: unknown function `" fn-symbol "`")
|
|
||||||
{:cause :interop
|
|
||||||
:detail :not-found
|
|
||||||
:name fn-symbol
|
|
||||||
:also-tried l-name})))
|
|
||||||
args' (to-clojure args)]
|
|
||||||
(print (str "INTEROP: evaluating `" (cons f args') "`"))
|
|
||||||
(flush)
|
|
||||||
(let [result (eval (conj args' f))] ;; this has the potential to blow up the world
|
|
||||||
(println (str "; returning `" result "`"))
|
|
||||||
|
|
||||||
(cond
|
|
||||||
(instance? beowulf.cons_cell.ConsCell result) result
|
|
||||||
(coll? result) (make-beowulf-list result)
|
|
||||||
(symbol? result) result
|
|
||||||
(string? result) (symbol result)
|
|
||||||
(number? result) result
|
|
||||||
:else (throw
|
|
||||||
(ex-info
|
|
||||||
(str "INTEROP: Cannot return `" result "` to Lisp 1.5.")
|
|
||||||
{:cause :interop
|
|
||||||
:detail :not-representable
|
|
||||||
:result result})))))
|
|
||||||
(throw
|
|
||||||
(ex-info
|
|
||||||
(str "INTEROP not allowed in strict mode.")
|
|
||||||
{:cause :interop
|
|
||||||
:detail :strict}))))
|
|
||||||
|
|
||||||
(defn- traced-apply
|
|
||||||
"Like `APPLY`, but with trace output to console."
|
|
||||||
[function-symbol args lisp-fn environment depth]
|
|
||||||
(let [indent (apply str (repeat depth "-"))]
|
(let [indent (apply str (repeat depth "-"))]
|
||||||
(println (str indent "> " function-symbol " " args))
|
(println (str indent "> " function-symbol " " args)))))
|
||||||
(let [r (APPLY lisp-fn args environment depth)]
|
|
||||||
(println (str "<" indent " " r))
|
|
||||||
r)))
|
|
||||||
|
|
||||||
(defn- safe-apply
|
(defn- trace-response
|
||||||
"We've a real problem with varargs functions when `args` is `NIL`, because
|
"Show a trace of this `response` from the function named by this
|
||||||
Clojure does not see `NIL` as an empty sequence."
|
`function-symbol` at this depth."
|
||||||
[clj-fn args]
|
[function-symbol response depth]
|
||||||
(let [args' (when (instance? ConsCell args) args)]
|
(when (traced? function-symbol)
|
||||||
(apply clj-fn args')))
|
(let [indent (apply str (repeat depth "-"))]
|
||||||
|
(println (str "<" indent " " function-symbol " " response))))
|
||||||
|
response)
|
||||||
|
|
||||||
|
(defn- value
|
||||||
|
"Seek a value for this symbol `s` by checking each of these indicators in
|
||||||
|
turn."
|
||||||
|
([s]
|
||||||
|
(value s (list 'APVAL 'EXPR 'FEXPR 'SUBR 'FSUBR)))
|
||||||
|
([s indicators]
|
||||||
|
(when (symbol? s)
|
||||||
|
(first (remove #(= % NIL) (map #(GET s %)
|
||||||
|
indicators))))))
|
||||||
|
|
||||||
(defn- apply-symbolic
|
(defn- apply-symbolic
|
||||||
"Apply this `funtion-symbol` to these `args` in this `environment` and
|
"Apply this `funtion-symbol` to these `args` in this `environment` and
|
||||||
return the result."
|
return the result."
|
||||||
[^Symbol function-symbol args ^ConsCell environment depth]
|
[^Symbol function-symbol args ^ConsCell environment depth]
|
||||||
(let [lisp-fn (try (EVAL function-symbol environment depth)
|
(trace-call function-symbol args depth)
|
||||||
(catch Throwable any (when (:trace *options*)
|
(let [lisp-fn ;; (try
|
||||||
(println any))))]
|
(value function-symbol '(EXPR FEXPR))
|
||||||
(if (and lisp-fn
|
;; (catch Exception any (when (traced? function-symbol)
|
||||||
(not= lisp-fn NIL)) (if (traced? function-symbol)
|
;; (println any))))
|
||||||
(traced-apply function-symbol
|
subr (value function-symbol '(SUBR FSUBR))
|
||||||
args
|
host-fn (try-resolve-subroutine subr args)
|
||||||
lisp-fn
|
result (cond (and lisp-fn
|
||||||
environment
|
(not= lisp-fn NIL)) (APPLY lisp-fn args environment depth)
|
||||||
depth)
|
host-fn (apply host-fn (when (instance? ConsCell args) args))
|
||||||
(APPLY lisp-fn args environment depth))
|
:else (ex-info "No function found"
|
||||||
(case function-symbol ;; there must be a better way of doing this!
|
{:phase :apply
|
||||||
ADD1 (safe-apply ADD1 args)
|
|
||||||
AND (safe-apply AND args)
|
|
||||||
APPLY (APPLY (first args) (rest args) environment depth)
|
|
||||||
ATOM (ATOM? (CAR args))
|
|
||||||
CAR (safe-apply CAR args)
|
|
||||||
CDR (safe-apply CDR args)
|
|
||||||
CONS (safe-apply CONS args)
|
|
||||||
DEFINE (DEFINE (CAR args))
|
|
||||||
DIFFERENCE (DIFFERENCE (CAR args) (CADR args))
|
|
||||||
DOC (DOC (first args))
|
|
||||||
EQ (safe-apply EQ args)
|
|
||||||
EQUAL (safe-apply EQUAL args)
|
|
||||||
ERROR (safe-apply ERROR args)
|
|
||||||
;; think about EVAL. Getting the environment right is subtle
|
|
||||||
FIXP (safe-apply FIXP args)
|
|
||||||
GENSYM (GENSYM)
|
|
||||||
GREATERP (safe-apply GREATERP args)
|
|
||||||
INTEROP (when (lax? INTEROP) (safe-apply INTEROP args))
|
|
||||||
LESSP (safe-apply LESSP args)
|
|
||||||
LIST (safe-apply LIST args)
|
|
||||||
NUMBERP (safe-apply NUMBERP args)
|
|
||||||
OBLIST (OBLIST)
|
|
||||||
PLUS (safe-apply PLUS args)
|
|
||||||
PRETTY (when (lax? 'PRETTY)
|
|
||||||
(safe-apply pretty-print args))
|
|
||||||
PRINT (safe-apply print args)
|
|
||||||
QUOTIENT (safe-apply QUOTIENT args)
|
|
||||||
READ (READ)
|
|
||||||
REMAINDER (safe-apply REMAINDER args)
|
|
||||||
RPLACA (safe-apply RPLACA args)
|
|
||||||
RPLACD (safe-apply RPLACD args)
|
|
||||||
SET (safe-apply SET args)
|
|
||||||
SYSIN (when (lax? 'SYSIN)
|
|
||||||
(safe-apply SYSIN args))
|
|
||||||
SYSOUT (when (lax? 'SYSOUT)
|
|
||||||
(safe-apply SYSOUT args))
|
|
||||||
TERPRI (println)
|
|
||||||
TIMES (safe-apply TIMES args)
|
|
||||||
TRACE (safe-apply TRACE args)
|
|
||||||
UNTRACE (safe-apply UNTRACE args)
|
|
||||||
;; else
|
|
||||||
(ex-info "No function found"
|
|
||||||
{:context "APPLY"
|
|
||||||
:function function-symbol
|
:function function-symbol
|
||||||
:args args})))))
|
:args args
|
||||||
|
:type :beowulf}))]
|
||||||
|
(trace-response function-symbol result depth)
|
||||||
|
result))
|
||||||
|
|
||||||
(defn APPLY
|
(defn APPLY
|
||||||
"Apply this `function` to these `arguments` in this `environment` and return
|
"Apply this `function` to these `arguments` in this `environment` and return
|
||||||
|
@ -302,14 +108,16 @@
|
||||||
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
All args are assumed to be symbols or `beowulf.cons-cell/ConsCell` objects.
|
||||||
See page 13 of the Lisp 1.5 Programmers Manual."
|
See page 13 of the Lisp 1.5 Programmers Manual."
|
||||||
[function args environment depth]
|
[function args environment depth]
|
||||||
(cond
|
(trace-call 'APPLY (list function args environment) depth)
|
||||||
|
(let [result (cond
|
||||||
(= NIL function) (if (:strict *options*)
|
(= NIL function) (if (:strict *options*)
|
||||||
NIL
|
NIL
|
||||||
(throw (ex-info "NIL is not a function"
|
(throw (ex-info "NIL is not a function"
|
||||||
{:context "APPLY"
|
{:phase :apply
|
||||||
:function "NIL"
|
:function "NIL"
|
||||||
:args args})))
|
:args args
|
||||||
(= (ATOM? function) T) (apply-symbolic function args environment (inc depth))
|
:type :beowulf})))
|
||||||
|
(= (ATOM function) T) (apply-symbolic function args environment (inc depth))
|
||||||
:else (case (first function)
|
:else (case (first function)
|
||||||
LABEL (APPLY
|
LABEL (APPLY
|
||||||
(CADDR function)
|
(CADDR function)
|
||||||
|
@ -328,7 +136,9 @@
|
||||||
{:phase :apply
|
{:phase :apply
|
||||||
:function function
|
:function function
|
||||||
:args args
|
:args args
|
||||||
:type :beowulf})))))
|
:type :beowulf}))))]
|
||||||
|
(trace-response 'APPLY result depth)
|
||||||
|
result))
|
||||||
|
|
||||||
(defn- EVCON
|
(defn- EVCON
|
||||||
"Inner guts of primitive COND. All `clauses` are assumed to be
|
"Inner guts of primitive COND. All `clauses` are assumed to be
|
||||||
|
@ -355,14 +165,25 @@
|
||||||
(EVAL (CAR args) env depth)
|
(EVAL (CAR args) env depth)
|
||||||
(EVLIS (CDR args) env depth))))
|
(EVLIS (CDR args) env depth))))
|
||||||
|
|
||||||
(defn- eval-symbolic [^Symbol s env]
|
(defn- eval-symbolic
|
||||||
(let [binding (ASSOC s env)]
|
[expr env depth]
|
||||||
(if (= binding NIL)
|
(let [v (value expr (list 'APVAL))
|
||||||
(throw (ex-info (format "No binding for symbol `%s`" s)
|
indent (apply str (repeat depth "-"))]
|
||||||
|
(when (traced? 'EVAL)
|
||||||
|
(println (str indent ": EVAL: deep binding (" expr " . " (or v "nil") ")")))
|
||||||
|
(if (and v (not= v NIL))
|
||||||
|
v
|
||||||
|
(let [v' (ASSOC expr env)]
|
||||||
|
(when (traced? 'EVAL)
|
||||||
|
(println (str indent ": EVAL: shallow binding: " (or v' "nil"))))
|
||||||
|
(if (and v' (not= v' NIL))
|
||||||
|
(.getCdr v')
|
||||||
|
(throw (ex-info "No binding for symbol found"
|
||||||
{:phase :eval
|
{:phase :eval
|
||||||
:symbol s}))
|
:function 'EVAL
|
||||||
(CDR binding))))
|
:args (list expr env depth)
|
||||||
|
:type :lisp
|
||||||
|
:code :A8})))))))
|
||||||
|
|
||||||
(defn EVAL
|
(defn EVAL
|
||||||
"Evaluate this `expr` and return the result. If `environment` is not passed,
|
"Evaluate this `expr` and return the result. If `environment` is not passed,
|
||||||
|
@ -370,13 +191,20 @@
|
||||||
argument is part of the tracing system and should not be set by user code.
|
argument is part of the tracing system and should not be set by user code.
|
||||||
|
|
||||||
All args are assumed to be numbers, symbols or `beowulf.cons-cell/ConsCell`
|
All args are assumed to be numbers, symbols or `beowulf.cons-cell/ConsCell`
|
||||||
objects."
|
objects. However, if called with just a single arg, `expr`, I'll assume it's
|
||||||
|
being called from the Clojure REPL and will coerce the `expr` to `ConsCell`."
|
||||||
([expr]
|
([expr]
|
||||||
(EVAL expr @oblist 0))
|
(let [expr' (if (and (coll? expr) (not (instance? ConsCell expr)))
|
||||||
|
(make-beowulf-list expr)
|
||||||
|
expr)]
|
||||||
|
(EVAL expr' @oblist 0)))
|
||||||
([expr env depth]
|
([expr env depth]
|
||||||
(cond
|
(trace-call 'EVAL (list expr env depth) depth)
|
||||||
|
(let [result (cond
|
||||||
|
(= NIL expr) NIL ;; it was probably a mistake to make Lisp
|
||||||
|
;; NIL distinct from Clojure nil
|
||||||
(= (NUMBERP expr) T) expr
|
(= (NUMBERP expr) T) expr
|
||||||
(symbol? expr) (eval-symbolic expr env)
|
(symbol? expr) (eval-symbolic expr env depth)
|
||||||
(string? expr) (if (:strict *options*)
|
(string? expr) (if (:strict *options*)
|
||||||
(throw
|
(throw
|
||||||
(ex-info
|
(ex-info
|
||||||
|
@ -385,9 +213,7 @@
|
||||||
:detail :strict
|
:detail :strict
|
||||||
:expr expr}))
|
:expr expr}))
|
||||||
(symbol expr))
|
(symbol expr))
|
||||||
(=
|
(= (ATOM (CAR expr)) T) (case (CAR expr)
|
||||||
(ATOM? (CAR expr))
|
|
||||||
T) (case (CAR expr)
|
|
||||||
QUOTE (CADR expr)
|
QUOTE (CADR expr)
|
||||||
FUNCTION (LIST 'FUNARG (CADR expr))
|
FUNCTION (LIST 'FUNARG (CADR expr))
|
||||||
COND (EVCON (CDR expr) env depth)
|
COND (EVCON (CDR expr) env depth)
|
||||||
|
@ -401,5 +227,7 @@
|
||||||
(CAR expr)
|
(CAR expr)
|
||||||
(EVLIS (CDR expr) env depth)
|
(EVLIS (CDR expr) env depth)
|
||||||
env
|
env
|
||||||
depth))))
|
depth))]
|
||||||
|
(trace-response 'EVAL result depth)
|
||||||
|
result)))
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
"Essentially, the `-main` function and the bootstrap read-eval-print loop."
|
"Essentially, the `-main` function and the bootstrap read-eval-print loop."
|
||||||
(:require [beowulf.bootstrap :refer [EVAL]]
|
(:require [beowulf.bootstrap :refer [EVAL]]
|
||||||
[beowulf.io :refer [default-sysout SYSIN]]
|
[beowulf.io :refer [default-sysout SYSIN]]
|
||||||
|
[beowulf.oblist :refer [*options* NIL]]
|
||||||
[beowulf.read :refer [READ read-from-console]]
|
[beowulf.read :refer [READ read-from-console]]
|
||||||
[beowulf.oblist :refer [*options* oblist]]
|
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.pprint :refer [pprint]]
|
[clojure.pprint :refer [pprint]]
|
||||||
[clojure.string :refer [trim]]
|
[clojure.string :refer [trim]]
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
(defn- re
|
(defn- re
|
||||||
"Like REPL, but it isn't a loop and doesn't print."
|
"Like REPL, but it isn't a loop and doesn't print."
|
||||||
[input]
|
[input]
|
||||||
(EVAL (READ input) @oblist 0))
|
(EVAL (READ input) NIL 0))
|
||||||
|
|
||||||
(defn repl
|
(defn repl
|
||||||
"Read/eval/print loop."
|
"Read/eval/print loop."
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
"provides Lisp 1.5 functions which can't be (or can't efficiently
|
"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
|
be) implemented in Lisp 1.5, which therefore need to be implemented in the
|
||||||
host language, in this case Clojure."
|
host language, in this case Clojure."
|
||||||
(:require [clojure.string :refer [upper-case]]
|
(:require [beowulf.cons-cell :refer [F make-beowulf-list make-cons-cell T]] ;; note hyphen - this is Clojure...
|
||||||
[beowulf.cons-cell :refer [F make-cons-cell make-beowulf-list
|
|
||||||
pretty-print T]]
|
|
||||||
;; note hyphen - this is Clojure...
|
|
||||||
[beowulf.gendoc :refer [open-doc]]
|
[beowulf.gendoc :refer [open-doc]]
|
||||||
[beowulf.oblist :refer [*options* oblist NIL]])
|
[beowulf.oblist :refer [*options* NIL oblist]]
|
||||||
(:import [beowulf.cons_cell ConsCell]
|
[clojure.set :refer [union]]
|
||||||
;; note underscore - same namespace, but Java.
|
[clojure.string :refer [upper-case]])
|
||||||
|
(:import [beowulf.cons_cell ConsCell] ;; note underscore - same namespace, but Java.
|
||||||
))
|
))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -164,17 +162,32 @@
|
||||||
(number? value)
|
(number? value)
|
||||||
(symbol? value)
|
(symbol? value)
|
||||||
(= value NIL))
|
(= value NIL))
|
||||||
(do
|
(try
|
||||||
(.rplaca cell value)
|
(.rplaca cell value)
|
||||||
cell)
|
cell
|
||||||
|
(catch Throwable any
|
||||||
|
(throw (ex-info
|
||||||
|
(str (.getMessage any) " in RPLACA: `")
|
||||||
|
{:cause :upstream-error
|
||||||
|
:phase :host
|
||||||
|
:function :rplaca
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf}
|
||||||
|
any))))
|
||||||
(throw (ex-info
|
(throw (ex-info
|
||||||
(str "Invalid value in RPLACA: `" value "` (" (type value) ")")
|
(str "Invalid value in RPLACA: `" value "` (" (type value) ")")
|
||||||
{:cause :bad-value
|
{:cause :bad-value
|
||||||
:detail :rplaca})))
|
:phase :host
|
||||||
|
:function :rplaca
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf})))
|
||||||
(throw (ex-info
|
(throw (ex-info
|
||||||
(str "Invalid cell in RPLACA: `" cell "` (" (type cell) ")")
|
(str "Invalid cell in RPLACA: `" cell "` (" (type cell) ")")
|
||||||
{:cause :bad-value
|
{:cause :bad-cell
|
||||||
:detail :rplaca}))))
|
:phase :host
|
||||||
|
:function :rplaca
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf}))))
|
||||||
|
|
||||||
(defn RPLACD
|
(defn RPLACD
|
||||||
"Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
|
"Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
|
||||||
|
@ -189,17 +202,32 @@
|
||||||
(number? value)
|
(number? value)
|
||||||
(symbol? value)
|
(symbol? value)
|
||||||
(= value NIL))
|
(= value NIL))
|
||||||
(do
|
(try
|
||||||
(.rplacd cell value)
|
(.rplacd cell value)
|
||||||
cell)
|
cell
|
||||||
|
(catch Throwable any
|
||||||
|
(throw (ex-info
|
||||||
|
(str (.getMessage any) " in RPLACD: `")
|
||||||
|
{:cause :upstream-error
|
||||||
|
:phase :host
|
||||||
|
:function :rplacd
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf}
|
||||||
|
any))))
|
||||||
(throw (ex-info
|
(throw (ex-info
|
||||||
(str "Invalid value in RPLACD: `" value "` (" (type value) ")")
|
(str "Invalid value in RPLACD: `" value "` (" (type value) ")")
|
||||||
{:cause :bad-value
|
{:cause :bad-value
|
||||||
:detail :rplaca})))
|
:phase :host
|
||||||
|
:function :rplacd
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf})))
|
||||||
(throw (ex-info
|
(throw (ex-info
|
||||||
(str "Invalid cell in RPLACD: `" cell "` (" (type cell) ")")
|
(str "Invalid cell in RPLACD: `" cell "` (" (type cell) ")")
|
||||||
{:cause :bad-value
|
{:cause :bad-cell
|
||||||
:detail :rplaca}))));; PLUS
|
:phase :host
|
||||||
|
:detail :rplacd
|
||||||
|
:args (list cell value)
|
||||||
|
:type :beowulf}))));; PLUS
|
||||||
|
|
||||||
(defn LIST
|
(defn LIST
|
||||||
[& args]
|
[& args]
|
||||||
|
@ -260,9 +288,20 @@
|
||||||
In `beowulf.host` principally because I don't yet feel confident to define
|
In `beowulf.host` principally because I don't yet feel confident to define
|
||||||
varargs functions in Lisp."
|
varargs functions in Lisp."
|
||||||
[& args]
|
[& args]
|
||||||
(if (empty? (filter #(or (= 'F %) (= NIL %) (nil? %)) args))
|
(cond (= NIL args) T
|
||||||
'T
|
(not (#{NIL F} (.getCar args))) (AND (.getCdr args))
|
||||||
'F))
|
:else T))
|
||||||
|
|
||||||
|
(defn OR
|
||||||
|
"`T` if and only if at least one of my `args` evaluates to something other
|
||||||
|
than either `F` or `NIL`, else `F`.
|
||||||
|
|
||||||
|
In `beowulf.host` principally because I don't yet feel confident to define
|
||||||
|
varargs functions in Lisp."
|
||||||
|
[& args]
|
||||||
|
(cond (= NIL args) F
|
||||||
|
(not (#{NIL F} (.getCar args))) T
|
||||||
|
:else (OR (.getCdr args))))
|
||||||
|
|
||||||
;;;; Operations on lists ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Operations on lists ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
|
@ -394,38 +433,87 @@
|
||||||
(make-beowulf-list (map CAR @oblist))
|
(make-beowulf-list (map CAR @oblist))
|
||||||
NIL))
|
NIL))
|
||||||
|
|
||||||
|
(def magic-marker
|
||||||
|
"The unexplained magic number which marks the start of a property list."
|
||||||
|
(Integer/parseInt "77777" 8))
|
||||||
|
|
||||||
|
(defn PUT
|
||||||
|
"Put this `value` as the value of the property indicated by this `indicator`
|
||||||
|
of this `symbol`. Return `value` on success.
|
||||||
|
|
||||||
|
NOTE THAT there is no `PUT` defined in the manual, but it would have been
|
||||||
|
easy to have defined it so I don't think this fully counts as an extension."
|
||||||
|
[symbol indicator value]
|
||||||
|
(if-let [binding (ASSOC symbol @oblist)]
|
||||||
|
(if-let [prop (ASSOC indicator (CDDR binding))]
|
||||||
|
(RPLACD prop value)
|
||||||
|
(RPLACD binding
|
||||||
|
(make-cons-cell
|
||||||
|
magic-marker
|
||||||
|
(make-cons-cell
|
||||||
|
indicator
|
||||||
|
(make-cons-cell value (CDDR binding))))))
|
||||||
|
(swap!
|
||||||
|
oblist
|
||||||
|
(fn [ob s p v]
|
||||||
|
(make-cons-cell
|
||||||
|
(make-beowulf-list (list s magic-marker p v))
|
||||||
|
ob))
|
||||||
|
symbol indicator value)))
|
||||||
|
|
||||||
|
(defn GET
|
||||||
|
"From the manual:
|
||||||
|
|
||||||
|
'`get` is somewhat like `prop`; however its value is car of the rest of
|
||||||
|
the list if the `indicator` is found, and NIL otherwise.'
|
||||||
|
|
||||||
|
It's clear that `GET` is expected to be defined in terms of `PROP`, but
|
||||||
|
we can't implement `PROP` here because we lack `EVAL`; and we can't have
|
||||||
|
`EVAL` here because both it and `APPLY` depends on `GET`.
|
||||||
|
|
||||||
|
OK, It's worse than that: the statement of the definition of `GET` (and
|
||||||
|
of) `PROP` on page 59 says that the first argument to each must be a list;
|
||||||
|
But the in the definition of `ASSOC` on page 70, when `GET` is called its
|
||||||
|
first argument is always an atom. Since it's `ASSOC` and `EVAL` which I
|
||||||
|
need to make work, I'm going to assume that page 59 is wrong."
|
||||||
|
[symbol indicator]
|
||||||
|
(let [binding (ASSOC symbol @oblist)]
|
||||||
|
(cond
|
||||||
|
(= binding NIL) NIL
|
||||||
|
(= magic-marker (CADR binding)) (loop [b binding]
|
||||||
|
(cond (= b NIL) NIL
|
||||||
|
(= (CAR b) indicator) (CADR b)
|
||||||
|
:else (recur (CDR b))))
|
||||||
|
:else (throw
|
||||||
|
(ex-info "Misformatted property list (missing magic marker)"
|
||||||
|
{:phase :host
|
||||||
|
:function :get
|
||||||
|
:args (list symbol indicator)
|
||||||
|
:type :beowulf})))))
|
||||||
|
|
||||||
|
(defn DEFLIST
|
||||||
|
"For each pair in this association list `a-list`, set the property with this
|
||||||
|
`indicator` of the symbol which is the first element of the pair to the
|
||||||
|
value which is the second element of the pair. See page 58 of the manual."
|
||||||
|
[a-list indicator]
|
||||||
|
(map
|
||||||
|
#(PUT (CAR %) indicator (CDR %))
|
||||||
|
a-list))
|
||||||
|
|
||||||
(defn DEFINE
|
(defn DEFINE
|
||||||
"Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten
|
"Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten
|
||||||
in LISP.
|
in LISP.
|
||||||
|
|
||||||
The single argument to `DEFINE` should be an assoc list which should be
|
The single argument to `DEFINE` should be an association list of symbols to
|
||||||
nconc'ed onto the front of the oblist. Broadly,
|
lambda functions. See page 58 of the manual."
|
||||||
(SETQ OBLIST (NCONC ARG1 OBLIST))"
|
[a-list]
|
||||||
[args]
|
(DEFLIST a-list 'EXPR))
|
||||||
(swap!
|
|
||||||
oblist
|
|
||||||
(fn [ob arg1]
|
|
||||||
(loop [cursor arg1 a arg1]
|
|
||||||
(if (= (CDR cursor) NIL)
|
|
||||||
(do
|
|
||||||
(.rplacd cursor @oblist)
|
|
||||||
(pretty-print a)
|
|
||||||
a)
|
|
||||||
(recur (CDR cursor) a))))
|
|
||||||
(CAR args)))
|
|
||||||
|
|
||||||
(defn SET
|
(defn SET
|
||||||
"Implementation of SET in Clojure. Add to the `oblist` a binding of the
|
"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!"
|
value of `var` to the value of `val`. NOTE WELL: this is not SETQ!"
|
||||||
[symbol val]
|
[symbol val]
|
||||||
(when
|
(PUT symbol 'APVAL val))
|
||||||
(swap!
|
|
||||||
oblist
|
|
||||||
(fn [ob s v] (if-let [binding (ASSOC symbol ob)]
|
|
||||||
(RPLACD binding v)
|
|
||||||
(make-cons-cell (make-cons-cell s v) ob)))
|
|
||||||
symbol val)
|
|
||||||
val))
|
|
||||||
|
|
||||||
;;;; TRACE and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; TRACE and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -437,19 +525,26 @@
|
||||||
"Return `true` iff `s` is a symbol currently being traced, else `nil`."
|
"Return `true` iff `s` is a symbol currently being traced, else `nil`."
|
||||||
[s]
|
[s]
|
||||||
(try (contains? @traced-symbols s)
|
(try (contains? @traced-symbols s)
|
||||||
(catch Throwable _)))
|
(catch Throwable _ nil)))
|
||||||
|
|
||||||
(defn TRACE
|
(defn TRACE
|
||||||
"Add this symbol `s` to the set of symbols currently being traced. If `s`
|
"Add this `s` to the set of symbols currently being traced. If `s`
|
||||||
is not a symbol, does nothing."
|
is not a symbol or sequence of symbols, does nothing."
|
||||||
[s]
|
[s]
|
||||||
(when (symbol? s)
|
(swap! traced-symbols
|
||||||
(swap! traced-symbols #(conj % s))))
|
#(cond
|
||||||
|
(symbol? s) (conj % s)
|
||||||
|
(and (seq? s) (every? symbol? s)) (union % (set s))
|
||||||
|
:else %)))
|
||||||
|
|
||||||
(defn UNTRACE
|
(defn UNTRACE
|
||||||
|
"Remove this `s` from the set of symbols currently being traced. If `s`
|
||||||
|
is not a symbol or sequence of symbols, does nothing."
|
||||||
[s]
|
[s]
|
||||||
(when (symbol? s)
|
(cond
|
||||||
(swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))))
|
(symbol? s) (swap! traced-symbols #(set (remove (fn [x] (= s x)) %)))
|
||||||
|
(and (seq? s) (every? symbol? s)) (map UNTRACE s))
|
||||||
|
@traced-symbols)
|
||||||
|
|
||||||
;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -470,4 +565,4 @@
|
||||||
argument was, or was not, a cons cell."
|
argument was, or was not, a cons cell."
|
||||||
[o]
|
[o]
|
||||||
(when (lax? 'CONSP)
|
(when (lax? 'CONSP)
|
||||||
(if (instance? o ConsCell) 'T 'F)))
|
(if (instance? ConsCell o) 'T 'F)))
|
129
src/beowulf/interop.clj
Normal file
129
src/beowulf/interop.clj
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
(ns beowulf.interop
|
||||||
|
(:require [beowulf.cons-cell :refer [make-beowulf-list]]
|
||||||
|
[beowulf.host :refer [CAR CDR]]
|
||||||
|
[beowulf.oblist :refer [*options* NIL]]
|
||||||
|
[clojure.string :as s :refer [last-index-of lower-case split
|
||||||
|
upper-case]]))
|
||||||
|
|
||||||
|
;;;; INTEROP feature ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defn listify-qualified-name
|
||||||
|
"We need to be able to print something we can link to the particular Clojure
|
||||||
|
function `subr` in a form in which Lisp 1.5 is able to read it back in and
|
||||||
|
relink it.
|
||||||
|
|
||||||
|
This assumes `subr` is either
|
||||||
|
1. a string in the format `#'beowulf.io/SYSIN` or `beowulf.io/SYSIN`; or
|
||||||
|
2. something which, when coerced to a string with `str`, will have such
|
||||||
|
a format."
|
||||||
|
[subr]
|
||||||
|
(make-beowulf-list
|
||||||
|
(map
|
||||||
|
#(symbol (upper-case %))
|
||||||
|
(remove empty? (split (str subr) #"[#'./]")))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn interpret-qualified-name
|
||||||
|
"For interoperation with Clojure, it will often be necessary to pass
|
||||||
|
qualified names that are not representable in Lisp 1.5. This function
|
||||||
|
takes a sequence in the form `(PART PART PART... NAME)` and returns
|
||||||
|
a symbol in the form `part.part.part/NAME`. This symbol will then be
|
||||||
|
tried in both that form and lower-cased. Names with hyphens or
|
||||||
|
underscores cannot be represented with this scheme."
|
||||||
|
([l]
|
||||||
|
(symbol
|
||||||
|
(let [n (s/join "."
|
||||||
|
(concat (map #(lower-case (str %)) (butlast l))
|
||||||
|
(list (last l))))
|
||||||
|
s (last-index-of n ".")]
|
||||||
|
(if s
|
||||||
|
(str (subs n 0 s) "/" (subs n (inc s)))
|
||||||
|
n)))))
|
||||||
|
|
||||||
|
(defn to-beowulf
|
||||||
|
"Return a beowulf-native representation of the Clojure object `o`.
|
||||||
|
Numbers and symbols are unaffected. Collections have to be converted;
|
||||||
|
strings must be converted to symbols."
|
||||||
|
[o]
|
||||||
|
(cond
|
||||||
|
(coll? o) (make-beowulf-list o)
|
||||||
|
(string? o) (symbol (s/upper-case o))
|
||||||
|
:else o))
|
||||||
|
|
||||||
|
(defn to-clojure
|
||||||
|
"If l is a `beowulf.cons_cell.ConsCell`, return a Clojure list having the
|
||||||
|
same members in the same order."
|
||||||
|
[l]
|
||||||
|
(cond
|
||||||
|
(not (instance? beowulf.cons_cell.ConsCell l))
|
||||||
|
l
|
||||||
|
(= (CDR l) NIL)
|
||||||
|
(list (to-clojure (CAR l)))
|
||||||
|
:else
|
||||||
|
(conj (to-clojure (CDR l)) (to-clojure (CAR l)))))
|
||||||
|
|
||||||
|
(defn 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."
|
||||||
|
[fn-symbol args]
|
||||||
|
(if-not (:strict *options*)
|
||||||
|
(let
|
||||||
|
[q-name (if
|
||||||
|
(seq? fn-symbol)
|
||||||
|
(interpret-qualified-name fn-symbol)
|
||||||
|
fn-symbol)
|
||||||
|
l-name (symbol (s/lower-case q-name))
|
||||||
|
f (cond
|
||||||
|
(try
|
||||||
|
(fn? (eval l-name))
|
||||||
|
(catch java.lang.ClassNotFoundException _ nil)) l-name
|
||||||
|
(try
|
||||||
|
(fn? (eval q-name))
|
||||||
|
(catch java.lang.ClassNotFoundException _ nil)) q-name
|
||||||
|
:else (throw
|
||||||
|
(ex-info
|
||||||
|
(str "INTEROP: unknown function `" fn-symbol "`")
|
||||||
|
{:cause :interop
|
||||||
|
:detail :not-found
|
||||||
|
:name fn-symbol
|
||||||
|
:also-tried l-name})))
|
||||||
|
args' (to-clojure args)]
|
||||||
|
(print (str "INTEROP: evaluating `" (cons f args') "`"))
|
||||||
|
(flush)
|
||||||
|
(let [result (eval (conj args' f))] ;; this has the potential to blow up the world
|
||||||
|
(println (str "; returning `" result "`"))
|
||||||
|
(cond
|
||||||
|
(instance? beowulf.cons_cell.ConsCell result) result
|
||||||
|
(coll? result) (make-beowulf-list result)
|
||||||
|
(symbol? result) result
|
||||||
|
(string? result) (symbol result)
|
||||||
|
(number? result) result
|
||||||
|
:else (throw
|
||||||
|
(ex-info
|
||||||
|
(str "INTEROP: Cannot return `" result "` to Lisp 1.5.")
|
||||||
|
{:cause :interop
|
||||||
|
:detail :not-representable
|
||||||
|
:result result})))))
|
||||||
|
(throw
|
||||||
|
(ex-info
|
||||||
|
(str "INTEROP not allowed in strict mode.")
|
||||||
|
{:cause :interop
|
||||||
|
:detail :strict}))))
|
|
@ -15,8 +15,12 @@
|
||||||
oblist with data from that file.
|
oblist with data from that file.
|
||||||
|
|
||||||
Hence functions SYSOUT and SYSIN, which do just that."
|
Hence functions SYSOUT and SYSIN, which do just that."
|
||||||
(:require [beowulf.cons-cell :refer [pretty-print]]
|
(:require [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell
|
||||||
[beowulf.oblist :refer [*options* oblist]]
|
pretty-print]]
|
||||||
|
[beowulf.host :refer [CADR CAR CDDR CDR]]
|
||||||
|
[beowulf.interop :refer [interpret-qualified-name
|
||||||
|
listify-qualified-name]]
|
||||||
|
[beowulf.oblist :refer [*options* NIL oblist]]
|
||||||
[beowulf.read :refer [READ]]
|
[beowulf.read :refer [READ]]
|
||||||
[clojure.java.io :refer [file resource]]
|
[clojure.java.io :refer [file resource]]
|
||||||
[clojure.string :refer [ends-with?]]
|
[clojure.string :refer [ends-with?]]
|
||||||
|
@ -59,6 +63,24 @@
|
||||||
""
|
""
|
||||||
".lsp")))
|
".lsp")))
|
||||||
|
|
||||||
|
;; (find-var (symbol "beowulf.io/SYSIN"))
|
||||||
|
;; (@(resolve (symbol "beowulf.host/TIMES")) 2 2)
|
||||||
|
|
||||||
|
(defn safely-wrap-subr
|
||||||
|
[entry]
|
||||||
|
(cond (= entry NIL) NIL
|
||||||
|
(= (CAR entry) 'SUBR) (make-cons-cell
|
||||||
|
(CAR entry)
|
||||||
|
(make-cons-cell
|
||||||
|
(listify-qualified-name (CADR entry))
|
||||||
|
(CDDR entry)))
|
||||||
|
:else (make-cons-cell
|
||||||
|
(CAR entry) (safely-wrap-subr (CDR entry)))))
|
||||||
|
|
||||||
|
(defn safely-wrap-subrs
|
||||||
|
[objects]
|
||||||
|
(make-beowulf-list (map safely-wrap-subr objects)))
|
||||||
|
|
||||||
(defn SYSOUT
|
(defn SYSOUT
|
||||||
"Dump the current content of the object list to file. If no `filepath` is
|
"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
|
specified, a file name will be constructed of the symbol `Sysout` and
|
||||||
|
@ -79,7 +101,38 @@
|
||||||
(println (format ";; generated by %s" (System/getenv "USER"))))
|
(println (format ";; generated by %s" (System/getenv "USER"))))
|
||||||
(println (apply str (repeat 79 ";")))
|
(println (apply str (repeat 79 ";")))
|
||||||
(println)
|
(println)
|
||||||
(pretty-print @oblist)))))
|
(let [output (safely-wrap-subrs @oblist)]
|
||||||
|
(pretty-print output)
|
||||||
|
)))))
|
||||||
|
|
||||||
|
(defn- resolve-subr
|
||||||
|
"If this oblist `entry` references a subroutine, attempt to fix up that
|
||||||
|
reference."
|
||||||
|
[entry]
|
||||||
|
(cond (= entry NIL) NIL
|
||||||
|
(= (CAR entry) 'SUBR) (try
|
||||||
|
(make-cons-cell
|
||||||
|
(CAR entry)
|
||||||
|
(make-cons-cell
|
||||||
|
(interpret-qualified-name
|
||||||
|
(CADR entry))
|
||||||
|
(CDDR entry)))
|
||||||
|
(catch Exception _
|
||||||
|
(print "Warning: failed to resolve "
|
||||||
|
(CADR entry))
|
||||||
|
(CDDR entry)))
|
||||||
|
:else (make-cons-cell
|
||||||
|
(CAR entry) (resolve-subr (CDR entry)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- resolve-subroutines
|
||||||
|
"Attempt to fix up the references to subroutines (Clojure functions) among
|
||||||
|
these `objects`, being new content for the object list."
|
||||||
|
[objects]
|
||||||
|
(make-beowulf-list
|
||||||
|
(map
|
||||||
|
resolve-subr
|
||||||
|
objects)))
|
||||||
|
|
||||||
(defn SYSIN
|
(defn SYSIN
|
||||||
"Read the contents of the file at this `filename` into the object list.
|
"Read the contents of the file at this `filename` into the object list.
|
||||||
|
@ -110,4 +163,6 @@
|
||||||
{:context "SYSIN"
|
{:context "SYSIN"
|
||||||
:filepath fp}
|
:filepath fp}
|
||||||
any))))]
|
any))))]
|
||||||
(swap! oblist #(when (or % (seq content)) content)))))
|
(swap! oblist
|
||||||
|
#(when (or % (seq content))
|
||||||
|
(resolve-subroutines content))))))
|
||||||
|
|
|
@ -64,7 +64,8 @@
|
||||||
cond := lsqb (opt-space cond-clause semi-colon opt-space)* cond-clause rsqb;
|
cond := lsqb (opt-space cond-clause semi-colon opt-space)* cond-clause rsqb;
|
||||||
cond-clause := mexpr opt-space arrow opt-space mexpr opt-space;
|
cond-clause := mexpr opt-space arrow opt-space mexpr opt-space;
|
||||||
arrow := '->';
|
arrow := '->';
|
||||||
args := mexpr | (opt-space mexpr semi-colon opt-space)* opt-space mexpr opt-space;
|
args := arg | (opt-space arg semi-colon opt-space)* opt-space arg opt-space;
|
||||||
|
arg := mexpr | sexpr;
|
||||||
fn-name := mvar;
|
fn-name := mvar;
|
||||||
mvar := #'[a-z][a-z0-9]*';
|
mvar := #'[a-z][a-z0-9]*';
|
||||||
mconst := #'[A-Z][A-Z0-9]*';
|
mconst := #'[A-Z][A-Z0-9]*';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns beowulf.interop-test
|
(ns beowulf.interop-test
|
||||||
(:require [clojure.test :refer [deftest is testing]]
|
(:require [clojure.test :refer [deftest is testing]]
|
||||||
[beowulf.bootstrap :refer [EVAL INTEROP]]
|
[beowulf.bootstrap :refer [EVAL]]
|
||||||
|
[beowulf.interop :refer [INTEROP]]
|
||||||
[beowulf.read :refer [gsp]]))
|
[beowulf.read :refer [gsp]]))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue