Right, there's an awful lot of Lisp actually working...
This commit is contained in:
		
							parent
							
								
									c3b327f760
								
							
						
					
					
						commit
						1f16241af7
					
				
					 31 changed files with 250 additions and 97 deletions
				
			
		
							
								
								
									
										12
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGELOG.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -7,11 +7,19 @@ All notable changes to this project will be documented in this file. This change
 | 
			
		|||
- this is fundamentally a working Lisp. The reader reads S-Expressions fully and M-Expressions at least partially. It is not (yet) a feature complete Lisp 1.5.
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
- working EVAL, APPLY, READ and 24 other basic functions, of which at least four are not actually parts of the Lisp 1.5 specification. However, sufficient are present to allow the
 | 
			
		||||
- working `EVAL`, `APPLY`, `READ` and 24 other basic functions, of which at least four are not actually parts of the Lisp 1.5 specification. However, sufficient are present to allow the
 | 
			
		||||
vast majority of Lisp 1.5 functions to be defined.
 | 
			
		||||
 | 
			
		||||
### Known to be missing
 | 
			
		||||
- property lists.
 | 
			
		||||
 | 
			
		||||
- the array feature: `ARRAY`: planned, but not yet implemented.
 | 
			
		||||
- constants: `CSET`, `CSETQ`: planned, but not yet implemented.
 | 
			
		||||
- the compiler: `COMMON`, `COMPILE`, `LAP`, `OPDEFINE`, `READLAP`, `SPECIAL`, `UNCOMMON`, `UNSPECIAL`: not currently planned.
 | 
			
		||||
- property lists: `ATTRIB`, `GETPROP`, `PUTPROP`; these are planned, but not yet implemented.
 | 
			
		||||
- obsolete hardware related functions: `PUNCH`; not currently planned.
 | 
			
		||||
- memory debugging: `COUNT`; not currently planned.
 | 
			
		||||
- character I/O functions: `ADVANCE`, `CLEARBUFF`, `ENDREAD`, `INTERN`, `MKNAM`, `NUMOB`, `STARTREAD`, `UNPACK`; These are planned, but depend on working character I/O at Clojure level, which depends on JLine and looks like a lot of work.
 | 
			
		||||
- character classifying predicates: `LITER`, `DIGIT`, `OPCHAR`, `DASH`; these are planned but will probably wait for character I/O. Characters are not at this stage first class objects.
 | 
			
		||||
 | 
			
		||||
[Unreleased]: https://github.com/your-name/beowulf/compare/0.1.1...HEAD
 | 
			
		||||
[0.1.1]: https://github.com/your-name/beowulf/compare/0.1.0...0.1.1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								TEST.lsp
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								TEST.lsp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,35 +0,0 @@
 | 
			
		|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;; Beowulf  Sysout file generated at 2023-03-29T12:34:39.278
 | 
			
		||||
;; generated by simon
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
 | 
			
		||||
((NULL
 | 
			
		||||
    LAMBDA (X) (COND ((EQUAL X (QUOTE NIL)) (QUOTE T)) ((QUOTE T) (QUOTE F))))
 | 
			
		||||
  (GCD
 | 
			
		||||
    LAMBDA
 | 
			
		||||
    (X Y)
 | 
			
		||||
    (COND
 | 
			
		||||
      ((GREATERP X Y) (GCD Y X))
 | 
			
		||||
      ((EQUAL (REMAINDER Y X) 0) X) ((QUOTE T) (GCD (REMAINDER Y X) X))))
 | 
			
		||||
  (NIL)
 | 
			
		||||
  (T . T)
 | 
			
		||||
  (F)
 | 
			
		||||
  (ADD1)
 | 
			
		||||
  (APPEND)
 | 
			
		||||
  (APPLY)
 | 
			
		||||
  (ATOM)
 | 
			
		||||
  (CAR)
 | 
			
		||||
  (CDR)
 | 
			
		||||
  (CONS)
 | 
			
		||||
  (DEFINE)
 | 
			
		||||
  (DIFFERENCE)
 | 
			
		||||
  (EQ)
 | 
			
		||||
  (EQUAL)
 | 
			
		||||
  (EVAL)
 | 
			
		||||
  (FIXP)
 | 
			
		||||
  (INTEROP)
 | 
			
		||||
  (NUMBERP)
 | 
			
		||||
  (OBLIST)
 | 
			
		||||
  (PLUS)
 | 
			
		||||
  (PRETTY)
 | 
			
		||||
  (QUOTIENT) (REMAINDER) (RPLACA) (RPLACD) (SET) (SYSIN) (SYSOUT) (TIMES))
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +53,9 @@ Is the value of `NIL` the atom `NIL`, or is it the empty list `()`? If the forme
 | 
			
		|||
 | 
			
		||||
> This is a predicate useful for deciding when a list is exhausted. It is true if and only if its argument is `NIL`.
 | 
			
		||||
 | 
			
		||||
I think there is an ambiguity in referencing constants which are not bound to themselves in the M-Expression notation as given in the manual. This is particularly problematic with regards to `NIL`, but there may be others instances.
 | 
			
		||||
`NIL` is used explicitly in an M-Expression for example in the definition of `intersection` (Ibid, p15).
 | 
			
		||||
 | 
			
		||||
I think there is an ambiguity in referencing constants which are not bound to themselves in the M-Expression notation as given in the manual. This is particularly problematic with regards to `NIL` and `F`, but there may be others instances.
 | 
			
		||||
 | 
			
		||||
### Curly braces
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
                 [clojure.java-time "1.2.0"]
 | 
			
		||||
                 [environ "1.2.0"]
 | 
			
		||||
                 [instaparse "1.4.12"]
 | 
			
		||||
                 [org.jline/jline "3.23.0"]
 | 
			
		||||
                 [rhizome "0.2.9"] ;; not needed in production builds
 | 
			
		||||
                 ]
 | 
			
		||||
  :main ^:skip-aot beowulf.core
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,2 +0,0 @@
 | 
			
		|||
(COMMENT '(THIS FILE WILL CONTAIN FUNCTION DEFINITIONS TO BOOTSTRAP LISP FULLSTOP
 | 
			
		||||
  AT PRESENT WE HAVE NO COMMENT SYNTAX))
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
(DEFUN LENGTH (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L))))))
 | 
			
		||||
| 
						 | 
				
			
			@ -1,37 +1,77 @@
 | 
			
		|||
;; Test comment
 | 
			
		||||
((NIL . NIL)
 | 
			
		||||
(T . T)
 | 
			
		||||
;; many functions return 'F on fail, but to make this mean fail I'm binding 
 | 
			
		||||
;; it to NIL
 | 
			
		||||
(F . NIL)
 | 
			
		||||
;; Binding all system functions to NIL so that you can see on the OBLIST that
 | 
			
		||||
;; they exist.
 | 
			
		||||
(ADD1 . NIL)
 | 
			
		||||
(AND . NIL)
 | 
			
		||||
(APPEND . NIL)
 | 
			
		||||
(APPLY . NIL)
 | 
			
		||||
(ATOM . NIL)
 | 
			
		||||
(CAR . NIL)
 | 
			
		||||
(CDR . NIL)
 | 
			
		||||
(CONS . NIL)
 | 
			
		||||
(DEFINE . NIL)
 | 
			
		||||
(DIFFERENCE . NIL)
 | 
			
		||||
(EQ . NIL)
 | 
			
		||||
(EQUAL . NIL)
 | 
			
		||||
(EVAL)
 | 
			
		||||
(FIXP . NIL)
 | 
			
		||||
(INTEROP . NIL)
 | 
			
		||||
(NUMBERP . NIL)
 | 
			
		||||
(OBLIST . NIL)
 | 
			
		||||
(PLUS . NIL)
 | 
			
		||||
(PRETTY . NIL)
 | 
			
		||||
(QUOTIENT . NIL)
 | 
			
		||||
(READ . NIL)
 | 
			
		||||
(REMAINDER)
 | 
			
		||||
(RPLACA . NIL)
 | 
			
		||||
(RPLACD . NIL)
 | 
			
		||||
(SET . NIL)
 | 
			
		||||
(SYSIN . NIL)
 | 
			
		||||
(SYSOUT . NIL)
 | 
			
		||||
(TIMES . NIL)
 | 
			
		||||
)
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;; Beowulf  Sysout file generated at 2023-03-30T09:40:36.483
 | 
			
		||||
;; generated by simon
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
 | 
			
		||||
((NIL)
 | 
			
		||||
  (T . T)
 | 
			
		||||
  (F)
 | 
			
		||||
  (ADD1)
 | 
			
		||||
  (AND)
 | 
			
		||||
  (APPEND)
 | 
			
		||||
  (APPLY)
 | 
			
		||||
  (ATOM)
 | 
			
		||||
  (CAR)
 | 
			
		||||
  (CDR)
 | 
			
		||||
  (CONS)
 | 
			
		||||
  (COPY LAMBDA (X) 
 | 
			
		||||
    (COND ((NULL X) (QUOTE NIL)) 
 | 
			
		||||
      ((ATOM X) X) 
 | 
			
		||||
      ((QUOTE T) (CONS (COPY (CAR X)) (COPY (CDR X))))))
 | 
			
		||||
  (DEFINE)
 | 
			
		||||
  (DIFFERENCE)
 | 
			
		||||
  (DIVIDE LAMBDA (X Y) (CONS (QUOTIENT X Y) (CONS (REMAINDER X Y) (QUOTE NIL))))
 | 
			
		||||
  (ERROR)
 | 
			
		||||
  (EQ)
 | 
			
		||||
  (EQUAL)
 | 
			
		||||
  (EVAL)
 | 
			
		||||
  (FIXP)
 | 
			
		||||
  (GENSYM)
 | 
			
		||||
  (GET LAMBDA (X Y) 
 | 
			
		||||
    (COND ((NULL X) (QUOTE NIL)) 
 | 
			
		||||
      ((EQ (CAR X) Y) (CAR (CDR X))) 
 | 
			
		||||
      ((QUOTE T) (GET (CDR X) Y))))
 | 
			
		||||
  (GREATERP)
 | 
			
		||||
  (INTEROP)
 | 
			
		||||
  (INTERSECTION LAMBDA (X Y) 
 | 
			
		||||
    (COND ((NULL X) (QUOTE NIL)) 
 | 
			
		||||
      ((MEMBER (CAR X) Y) (CONS (CAR X) (INTERSECTION (CDR X) Y))) 
 | 
			
		||||
      ((QUOTE T) (INTERSECTION (CDR X) Y))))
 | 
			
		||||
  (LENGTH LAMBDA (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L))))))
 | 
			
		||||
  (LESSP)
 | 
			
		||||
  (MEMBER LAMBDA (A X) 
 | 
			
		||||
    (COND ((NULL X) (QUOTE F)) 
 | 
			
		||||
        ((EQ A (CAR X)) (QUOTE T)) 
 | 
			
		||||
        ((QUOTE T) (MEMBER A (CDR X)))))
 | 
			
		||||
  (MINUSP LAMBDA (X) (LESSP X 0))
 | 
			
		||||
  (NULL LAMBDA (X) (COND ((EQUAL X NIL) (QUOTE T)) (T (QUOTE F))))
 | 
			
		||||
  (NUMBERP)
 | 
			
		||||
  (OBLIST)
 | 
			
		||||
  (ONEP LAMBDA (X) (EQ X 1))
 | 
			
		||||
  (PAIR LAMBDA (X Y) 
 | 
			
		||||
    (COND ((AND (NULL X) (NULL Y)) NIL)
 | 
			
		||||
        ((NULL X) (ERROR 'F2))
 | 
			
		||||
        ((NULL Y) (ERROR 'F3))
 | 
			
		||||
        (T (CONS (CONS (CAR X) (CAR Y)) (PAIR (CDR X) (CDR Y))))))
 | 
			
		||||
  (PLUS)
 | 
			
		||||
  (PRETTY)
 | 
			
		||||
  (PRINT)
 | 
			
		||||
  (PROP LAMBDA (X Y U) 
 | 
			
		||||
    (COND ((NULL X) (U)) 
 | 
			
		||||
      ((EQ (CAR X) Y) (CDR X)) 
 | 
			
		||||
      ((QUOTE T) (PROP (CDR X) Y U))))
 | 
			
		||||
  (QUOTIENT)
 | 
			
		||||
  (READ)
 | 
			
		||||
  (REMAINDER) 
 | 
			
		||||
  (REPEAT LAMBDA (N X)
 | 
			
		||||
    (COND ((EQ N 0) NIL)
 | 
			
		||||
        (T (CONS X (REPEAT (SUB1 N) X)))))
 | 
			
		||||
  (RPLACA) 
 | 
			
		||||
  (RPLACD) 
 | 
			
		||||
  (SET)
 | 
			
		||||
  (SUB1 LAMBDA (N) (DIFFERENCE N 1)) 
 | 
			
		||||
  (SYSIN) 
 | 
			
		||||
  (SYSOUT) 
 | 
			
		||||
  (TERPRI)
 | 
			
		||||
  (TIMES)
 | 
			
		||||
  (ZEROP LAMBDA (N) (EQ N 0)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								resources/mexpr/copy.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								resources/mexpr/copy.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
copy[x] = [null[x] -> NIL; 
 | 
			
		||||
    atom[x] -> x; 
 | 
			
		||||
    T -> cons[ copy[ car[x]]; copy[ cdr[x]]]]
 | 
			
		||||
							
								
								
									
										3
									
								
								resources/mexpr/divide.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								resources/mexpr/divide.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
;; page 26
 | 
			
		||||
 | 
			
		||||
divide[x; y] = cons[ quotient[x; y]; cons[ remainder[x; y]; NIL]]
 | 
			
		||||
| 
						 | 
				
			
			@ -2,4 +2,4 @@ gcd[x;y] = [x>y -> gcd[y;x];
 | 
			
		|||
            rem[y;x] = 0 -> x;
 | 
			
		||||
            T -> gcd[rem[y;x];x]]
 | 
			
		||||
 | 
			
		||||
;; gcd[x;y] = [x>y -> gcd[y;x]; rem[y;x] = 0 -> x; T -> gcd[rem[y;x];x]]
 | 
			
		||||
;; gcd[x;y] = [x>y -> gcd[y;x]; remainder[y;x] = 0 -> x; T -> gcd[remainder[y;x];x]]
 | 
			
		||||
							
								
								
									
										6
									
								
								resources/mexpr/get.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								resources/mexpr/get.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
;; page 59; slightly modified because I don't at this stage want to
 | 
			
		||||
;; assume the existence of CADR
 | 
			
		||||
 | 
			
		||||
get[x; y] = [null[x] -> NIL;
 | 
			
		||||
    eq[car[x]; y] -> car[cdr[x]];
 | 
			
		||||
    T -> get[cdr[x]; y]]
 | 
			
		||||
							
								
								
									
										5
									
								
								resources/mexpr/intersection.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								resources/mexpr/intersection.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
;; page 15
 | 
			
		||||
 | 
			
		||||
intersection[x;y] = [null[x] -> NIL;
 | 
			
		||||
    member[car[x]; y] -> cons[car[x]; intersection[cdr[x]; y]];
 | 
			
		||||
    T -> intersection[cdr[x]; y]]
 | 
			
		||||
							
								
								
									
										4
									
								
								resources/mexpr/member.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								resources/mexpr/member.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
;; page 15
 | 
			
		||||
member[a; x] = [null[x] -> F;
 | 
			
		||||
    eq[a; car[x]] -> T;
 | 
			
		||||
    T-> member[a; cdr[x]]]
 | 
			
		||||
							
								
								
									
										7
									
								
								resources/mexpr/null.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								resources/mexpr/null.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
null[x] = [x = NIL -> T; T -> F]
 | 
			
		||||
 | 
			
		||||
(SETQ NULL 
 | 
			
		||||
    '(LAMBDA (X)
 | 
			
		||||
        (COND 
 | 
			
		||||
            ((EQUAL X NIL) 'T) 
 | 
			
		||||
            (T (QUOTE F)))))
 | 
			
		||||
							
								
								
									
										4
									
								
								resources/mexpr/prop.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								resources/mexpr/prop.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
;; page 59
 | 
			
		||||
prop[x;y;u] = [null[x] -> u[];
 | 
			
		||||
    eq[car[x]; y] -> cdr[x];
 | 
			
		||||
    T -> prop[cdr[x]; y; u]]
 | 
			
		||||
							
								
								
									
										4
									
								
								resources/mexpr/union.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								resources/mexpr/union.mexpr.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
;; page 15
 | 
			
		||||
union[x; y] = [null[x] -> y;
 | 
			
		||||
    member[car[x]; y] -> union[cdr[x]; y];
 | 
			
		||||
    T -> cons[car[x]; union[cdr[x]; y]]]
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
null[x] = [x = NIL -> T; T -> F]
 | 
			
		||||
							
								
								
									
										1
									
								
								resources/sexpr/conc.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								resources/sexpr/conc.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
;; TODO
 | 
			
		||||
							
								
								
									
										1
									
								
								resources/sexpr/length.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								resources/sexpr/length.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
(SETQ LENGTH '(LAMBDA (L) (COND ((EQ NIL L) 0) (T (ADD1 (LENGTH (CDR L)))))))
 | 
			
		||||
							
								
								
									
										11
									
								
								resources/sexpr/pair.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								resources/sexpr/pair.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
;; PAIR is defined on page 60 of the manual, but the definition depends on both
 | 
			
		||||
;; PROG and GO, and I haven't got those working yet; so this is a pure 
 | 
			
		||||
;; functional implementation.
 | 
			
		||||
;; Return a list of pairs from lists `x` and `y`, required both to have the same
 | 
			
		||||
;; length.
 | 
			
		||||
 | 
			
		||||
(DEFUN PAIR (X Y) 
 | 
			
		||||
    (COND ((AND (NULL X) (NULL Y)) NIL)
 | 
			
		||||
        ((NULL X) (ERROR 'F2))
 | 
			
		||||
        ((NULL Y) (ERROR 'F3))
 | 
			
		||||
        (T (CONS (CONS (CAR X) (CAR Y)) (PAIR (CDR X) (CDR Y))))))
 | 
			
		||||
							
								
								
									
										6
									
								
								resources/sexpr/repeat.lsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								resources/sexpr/repeat.lsp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
;; REPEAT is not present in the Lisp 1.5 manual, but it's so simple and so
 | 
			
		||||
;; useful that it seems a legitimate extension.
 | 
			
		||||
 | 
			
		||||
(DEFUN REPEAT (N X)
 | 
			
		||||
    (COND ((EQ N 0) NIL)
 | 
			
		||||
        (T (CONS X (REPEAT (SUB1 N) X)))))
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +13,8 @@
 | 
			
		|||
            [clojure.tools.trace :refer [deftrace]]
 | 
			
		||||
            [beowulf.cons-cell :refer [CAR CDR CONS LIST make-beowulf-list make-cons-cell
 | 
			
		||||
                                       pretty-print T F]]
 | 
			
		||||
            [beowulf.host :refer [AND ADD1 DIFFERENCE FIXP NUMBERP PLUS QUOTIENT
 | 
			
		||||
            [beowulf.host :refer [AND ADD1 DIFFERENCE ERROR FIXP GENSYM GREATERP LESSP 
 | 
			
		||||
                                  NUMBERP PLUS QUOTIENT
 | 
			
		||||
                                  REMAINDER RPLACA RPLACD SUB1 TIMES]]
 | 
			
		||||
            [beowulf.io :refer [SYSIN SYSOUT]]
 | 
			
		||||
            [beowulf.oblist :refer [*options* oblist NIL]]
 | 
			
		||||
| 
						 | 
				
			
			@ -353,9 +354,11 @@
 | 
			
		|||
       :detail :strict}))))
 | 
			
		||||
 | 
			
		||||
(defn OBLIST
 | 
			
		||||
  "Not certain whether or not this is part of LISP 1.5; adapted from PSL. 
 | 
			
		||||
  return the current value of the object list. Note that in PSL this function
 | 
			
		||||
  returns a list of the symbols bound, not the whole association list."
 | 
			
		||||
  "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."
 | 
			
		||||
  []
 | 
			
		||||
  (when (lax? 'OBLIST)
 | 
			
		||||
    (if (instance? ConsCell @oblist)
 | 
			
		||||
| 
						 | 
				
			
			@ -415,23 +418,33 @@
 | 
			
		|||
        DIFFERENCE (DIFFERENCE (CAR args) (CADR args))
 | 
			
		||||
        EQ (apply EQ args)
 | 
			
		||||
        EQUAL (apply EQUAL args)
 | 
			
		||||
        ERROR (apply ERROR args)
 | 
			
		||||
        ;; think about EVAL. Getting the environment right is subtle
 | 
			
		||||
        FIXP (apply FIXP args)
 | 
			
		||||
        GENSYM (GENSYM)
 | 
			
		||||
        GREATERP (apply GREATERP args)
 | 
			
		||||
        INTEROP (when (lax? INTEROP) (apply INTEROP args))
 | 
			
		||||
        LESSP (apply LESSP args)
 | 
			
		||||
        LIST (apply LIST args)
 | 
			
		||||
        NUMBERP (apply NUMBERP args)
 | 
			
		||||
        OBLIST (OBLIST)
 | 
			
		||||
        PLUS (apply PLUS args)
 | 
			
		||||
        PRETTY (when (lax? 'PRETTY)
 | 
			
		||||
                 (apply pretty-print args))
 | 
			
		||||
        PRINT (apply print args)
 | 
			
		||||
        QUOTIENT (apply QUOTIENT args)
 | 
			
		||||
        READ (READ)
 | 
			
		||||
        REMAINDER (apply REMAINDER args)
 | 
			
		||||
        RPLACA (apply RPLACA args)
 | 
			
		||||
        RPLACD (apply RPLACD args)
 | 
			
		||||
        SET (apply SET args)
 | 
			
		||||
        SYSIN (when (lax? 'SYSIN) (apply SYSIN args))
 | 
			
		||||
        SYSOUT (when (lax? 'SYSOUT) (apply SYSOUT args))
 | 
			
		||||
        SYSIN (when (lax? 'SYSIN) 
 | 
			
		||||
                (apply SYSIN args))
 | 
			
		||||
        SYSOUT (when (lax? 'SYSOUT)
 | 
			
		||||
                 (if (empty? args)
 | 
			
		||||
                   (SYSOUT)
 | 
			
		||||
                   (apply SYSOUT args)))
 | 
			
		||||
        TERPRI (println)
 | 
			
		||||
        TIMES (apply TIMES args)
 | 
			
		||||
        ;; else
 | 
			
		||||
        (ex-info "No function found"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,8 @@
 | 
			
		|||
  "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."
 | 
			
		||||
  (:require [beowulf.cons-cell :refer [F make-beowulf-list T]]
 | 
			
		||||
  (:require [clojure.string :refer [upper-case]]
 | 
			
		||||
            [beowulf.cons-cell :refer [F make-beowulf-list T]]
 | 
			
		||||
            ;; note hyphen - this is Clojure...
 | 
			
		||||
            [beowulf.oblist :refer [NIL]])
 | 
			
		||||
  (:import [beowulf.cons_cell ConsCell]
 | 
			
		||||
| 
						 | 
				
			
			@ -14,13 +15,13 @@
 | 
			
		|||
;; portability.
 | 
			
		||||
 | 
			
		||||
(defn AND 
 | 
			
		||||
  "True if and only if none of my `args` evaluate to either `F` or `NIL`,
 | 
			
		||||
  "`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."
 | 
			
		||||
  [& args]
 | 
			
		||||
  (if (empty? (filter #(or (= 'F %) (empty? %)) args))
 | 
			
		||||
  (if (empty? (filter #(or (= 'F %) (= NIL %) (nil? %)) args))
 | 
			
		||||
    'T
 | 
			
		||||
    'F))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -116,3 +117,22 @@
 | 
			
		|||
(defn NUMBERP
 | 
			
		||||
  [x]
 | 
			
		||||
  (if (number? x) T F))
 | 
			
		||||
 | 
			
		||||
(defn GENSYM
 | 
			
		||||
  "Generate a unique symbol."
 | 
			
		||||
  []
 | 
			
		||||
  (symbol (upper-case (str (gensym "SYM")))))
 | 
			
		||||
 | 
			
		||||
(defn ERROR
 | 
			
		||||
  "Throw an error"
 | 
			
		||||
  [& args]
 | 
			
		||||
  (throw (ex-info "LISP ERROR" {:cause (apply vector args)
 | 
			
		||||
                                :phase :eval})))
 | 
			
		||||
 | 
			
		||||
(defn LESSP
 | 
			
		||||
  [x y]
 | 
			
		||||
  (< x y))
 | 
			
		||||
 | 
			
		||||
(defn GREATERP
 | 
			
		||||
  [x y]
 | 
			
		||||
  (> x y))
 | 
			
		||||
| 
						 | 
				
			
			@ -83,4 +83,3 @@
 | 
			
		|||
                                        :filepath fp}
 | 
			
		||||
                                       any))))]
 | 
			
		||||
    (swap! oblist #(when (or % (seq content)) content))))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,8 @@
 | 
			
		|||
 | 
			
		||||
  Both these extensions can be disabled by using the `--strict` command line
 | 
			
		||||
  switch."
 | 
			
		||||
  (:require [beowulf.reader.generate :refer [generate]]
 | 
			
		||||
  (: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]]
 | 
			
		||||
            [clojure.string :refer [join split starts-with? trim]])
 | 
			
		||||
| 
						 | 
				
			
			@ -78,10 +79,10 @@
 | 
			
		|||
  the final Lisp reader. `input` should be either a string representation of a LISP
 | 
			
		||||
  expression, or else an input stream. A single form will be read."
 | 
			
		||||
  ([]
 | 
			
		||||
   (gsp (read-from-console)))
 | 
			
		||||
   (gsp (read-chars)))
 | 
			
		||||
  ([input]
 | 
			
		||||
   (cond
 | 
			
		||||
     (empty? input) (gsp (read-from-console))
 | 
			
		||||
     (empty? input) (READ)
 | 
			
		||||
     (string? input) (gsp input)
 | 
			
		||||
     (instance? InputStream input) (READ (slurp input))
 | 
			
		||||
     :else    (throw (ex-info "READ: `input` should be a string or an input stream" {})))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								src/beowulf/reader/char_reader.clj
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/beowulf/reader/char_reader.clj
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
(ns 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)
 | 
			
		||||
   
 | 
			
		||||
   1. Carriage return **does not** cause input to be returned, **unless**
 | 
			
		||||
       a. the number of open brackets `(` and closing brackets `)` match; and
 | 
			
		||||
       b. the number of open square brackets `[` and closing square brackets `]` also match;
 | 
			
		||||
   2. <Ctrl-D> aborts editing and returns the string `STOP`;
 | 
			
		||||
   3. <Up-arrow> and <down-arrow> scroll back and forward through history, but ideally I'd like 
 | 
			
		||||
      this to be the Lisp history (i.e. the history of S-Expressions actually read by `READ`, 
 | 
			
		||||
      rather than the strings which were supplied to `READ`);
 | 
			
		||||
   4. <Tab> offers potential auto-completions taken from the value of `(OBLIST)`, ideally the
 | 
			
		||||
      current value, not the value at the time the session started;
 | 
			
		||||
   5. <Back-arrow> and <Forward-arrow> offer movement and editing within the line."
 | 
			
		||||
  (:import [org.jline.reader LineReader LineReaderBuilder]
 | 
			
		||||
           [org.jline.terminal TerminalBuilder]))
 | 
			
		||||
 | 
			
		||||
;; It looks from the example given [here](https://github.com/jline/jline3/blob/master/demo/src/main/java/org/jline/demo/Repl.java)
 | 
			
		||||
;; as though JLine could be used to build a perfect line-reader for Beowulf; but it also
 | 
			
		||||
;; looks as though you'd need a DPhil in JLine to write it, and I don't have
 | 
			
		||||
;; the time.
 | 
			
		||||
 | 
			
		||||
(def get-reader
 | 
			
		||||
  "Return a reader, first constructing it if necessary.
 | 
			
		||||
   
 | 
			
		||||
   **NOTE THAT** this is not settled API. The existence and call signature of
 | 
			
		||||
   this function is not guaranteed in future versions."
 | 
			
		||||
  (memoize (fn []
 | 
			
		||||
  (let [term (.build (.system (TerminalBuilder/builder) true))]
 | 
			
		||||
    (.build (.terminal (LineReaderBuilder/builder) term))))))
 | 
			
		||||
 | 
			
		||||
(defn read-chars
 | 
			
		||||
  "A drop-in replacement for `clojure.core/read-line`, except that line editing
 | 
			
		||||
   and history should be enabled.
 | 
			
		||||
   
 | 
			
		||||
   **NOTE THAT** this does not work yet, but it is in the API because I hope 
 | 
			
		||||
   that it will work later!"
 | 
			
		||||
  [] 
 | 
			
		||||
    (let [eddie (get-reader)]
 | 
			
		||||
      (loop [s (.readLine eddie)]
 | 
			
		||||
      (if (and (= (count (re-seq #"\(" s))
 | 
			
		||||
           (count (re-seq #"\)" s)))
 | 
			
		||||
               (= (count (re-seq #"\[]" s))
 | 
			
		||||
                  (count (re-seq #"\]" s))))
 | 
			
		||||
        s
 | 
			
		||||
        (recur (str s " " (.readLine eddie)))))))
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,9 @@
 | 
			
		|||
;; 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
 | 
			
		||||
 | 
			
		||||
(def ^:dynamic *readmacros*
 | 
			
		||||
  {:car {'DEFUN (fn [f]
 | 
			
		||||
                  (LIST 'SET (LIST 'QUOTE (second f))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,9 +27,9 @@
 | 
			
		|||
    "mexpr := λexpr | fncall | defn | cond | mvar | mconst | iexpr | number | mexpr comment;
 | 
			
		||||
      λexpr := λ lsqb bindings semi-colon body rsqb;
 | 
			
		||||
      λ := 'λ';
 | 
			
		||||
      bindings := lsqb args rsqb;
 | 
			
		||||
      bindings := lsqb args rsqb | lsqb rsqb;
 | 
			
		||||
      body := (mexpr semi-colon opt-space)* mexpr;
 | 
			
		||||
      fncall := fn-name lsqb args rsqb;
 | 
			
		||||
      fncall := fn-name bindings;
 | 
			
		||||
      lsqb := '[';
 | 
			
		||||
      rsqb := ']';
 | 
			
		||||
       lbrace := '{';
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
      cond := lsqb (opt-space cond-clause semi-colon opt-space)* cond-clause rsqb;
 | 
			
		||||
      cond-clause := mexpr opt-space arrow opt-space mexpr opt-space;
 | 
			
		||||
      arrow := '->';
 | 
			
		||||
      args := (opt-space mexpr semi-colon opt-space)* mexpr;
 | 
			
		||||
      args := mexpr | (opt-space mexpr semi-colon opt-space)* opt-space mexpr opt-space;
 | 
			
		||||
      fn-name := mvar;
 | 
			
		||||
      mvar := #'[a-z]+';
 | 
			
		||||
      mconst := #'[A-Z]+';
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@
 | 
			
		|||
 | 
			
		||||
      ;; Lisp 1.5 supported octal as well as decimal and scientific notation
 | 
			
		||||
    "number := integer | decimal | scientific | octal;
 | 
			
		||||
      integer := #'-?[1-9][0-9]*';
 | 
			
		||||
      integer := #'-?[0-9]+';
 | 
			
		||||
      decimal := integer dot integer;
 | 
			
		||||
      scientific := coefficient e exponent;
 | 
			
		||||
      coefficient := decimal | integer;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue