Skip to content

Commit

Permalink
Merge branch 'extend'
Browse files Browse the repository at this point in the history
  • Loading branch information
NJdevPro committed Oct 31, 2024
2 parents 25a0b66 + 783e001 commit 8761982
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ bestline.o:
minilisp: bestline.o
cd src && $(CC) $(CFLAGS) -c gc.c minilisp.c repl.c
cd src && $(CC) $(LDFLAGS) -o minilisp ../bestline/bestline.o gc.o minilisp.o repl.o
cd src && mv minilisp ..
mv src/minilisp .

clean:
cd bestline && $(MAKE) clean
Expand Down
103 changes: 90 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ MiniLisp with REPL
==================

Foreword by N. Janin:
This is my attempt at making Rui Ueyama (rui314)'s MiniLisp slightly more user friendly.
This is my attempt at making Rui Ueyama (rui314)'s MiniLisp slightly more user friendly and powerful.
Not being limited by the 1000 lines challenge, I've added a few basic primitives
to the original program, while trying to keep the goal of simplicity and conciseness.
Namely operators >, >=, <=, or, and, not, and functions progn, length.
This has the side effect of being faster as well, since these primitives are compiled
The whole program compiles to less than 100 kb without debugging symbols and should be able to run on low powered devices.

The added primitives:
* strings
* operators >, >=, <=, or, and, not,
* functions length, reverse, progn, load.
This has the side effect of being much faster as well, since all these primitives are compiled
instead of being interpreted.

Among the bells and whistles, I've added a REPL based on Justine Tunney (jart)'s bestline.
Expand Down Expand Up @@ -66,24 +71,26 @@ CTRL-Z SUSPEND PROCESS
```

The REPL also saves the history of commands in the file history.txt
This file is loaded at startup, so one can recall previous commands.

Future improvements:
- floating point numbers
- data files

Known bugs:
* Operators "and" and "or" do not work like their typical Lisp counterpart
because they evaluate all their operands at the same time instead of one
by one.
* The pasting in the REPL doesn't work well.
* Multiline inputs are recalled as different lines
* the paste function does not work very well.
* recall of multiline commands does not work as expected.


Original README
Original README (completed)
---------------

One day I wanted to see what I can do with 1k lines of C and
decided to write a Lisp interpreter. That turned to be a
fun weekend project, and the outcome is a mini lisp implementation
that supports

- integers, symbols, cons cells,
- integers, symbols, cons cells
- global variables,
- lexically-scoped local variables,
- closures,
Expand Down Expand Up @@ -163,6 +170,13 @@ car.
(setcar cell 'x)
cell ; -> (x . b)

`length` and `reverse` operate on a whole list. They can also operate on their arguments.

(length '(1 2 3)) ; -> 3
(length 1 2 t) ; -> 3
(reverse '(a b c)) ; -> (c b a)
(reverse '(a) b c) ; -> (c b (a))

### Numeric operators

`+` returns the sum of the arguments.
Expand Down Expand Up @@ -193,6 +207,28 @@ the second.
(< 3 3) ; -> ()
(< 4 3) ; -> ()

The other comparison operators `>`, `<=`, `>=` work in a similar fashion.

`and` takes two or more arguments, evaluates them, and returns the last argument
that returns true, if all the arguments return true, or () otherwise.

(and 1 t 2) ; -> 2
(and 1 t (- 3 4)) ; -> -1
(and 1 () 2) ; -> ()
(and) ; t

`or` takes two or more arguments, evaluates them, and returns the first argument
that returns true.

(or 1 () 2) ; -> 1
(or () ()) ; -> ()
(or) ; -> ()

NB: because all the arguments are evaluated, `and` and `or` do not operate like
their counterparts written in Lisp, as those stop evaluation at the first argument
that returns. If the arguments have side effects, this may affect the program
differently.

### Conditionals

`(if cond then else)` is the only conditional in the language. It first
Expand All @@ -209,18 +245,50 @@ loop by tail recursion in MiniLisp. The answer is no. Tail calls consume stack
space in MiniLisp, so a loop written as recursion will fail with the memory
exhaustion error.

### Imperative programming

`progn` executes several expressions consecutively.

(progn (print 'I 'own)
(defun add(x y)(+ x y)
(println (add 3 7) 'cents))) ; -> I own
10 cents

### Equivalence test operators

`eq` takes two arguments and returns `t` if the objects are the same. What `eq`
really does is a pointer comparison, so two objects happened to have the same
contents but actually different are considered to not be the same by `eq`.

### String functions

`string=` compares two strings.

(string= "Hello" "Hello") ; -> t
(string= "Hello" "World") ; -> ()

`string-concat` concatenates strings.

(string-concat) ; -> ""
(string-concat "A" "B" "C" "D") ; -> "ABCD"

`symbol->string` turns a symbol into a string.

(define sym 'hello) ; -> hello
(symbol->string sym) ; -> "hello"

`string->symbol` turns a string into a symbol of the same name.

(string->symbol "hello") ; -> hello

### Output operators

`println` prints a given object to the standard output.
`print` prints a given object to the standard output.

(print 3) ; prints "3"
(print '(hello world)) ; prints "(hello world)"

(println 3) ; prints "3"
(println '(hello world)) ; prints "(hello world)"
`println` does the same, adding a return at the end.

### Definitions

Expand Down Expand Up @@ -277,6 +345,15 @@ is not defined.
(define val (+ 3 5))
(setq val (+ val 1)) ; increment "val"

### system functions
`load` loads a Lisp file and evaluates all its content, adding it to the environment.

(load 'example/nqueens.lisp) -> run the file and store its evaluated functions and macros

`exit` quits the interpreter and returns integer passed as parameter.

(exit 0) -> quit with success

### Macros

Macros look similar to functions, but they are different that macros take an
Expand Down
25 changes: 4 additions & 21 deletions examples/hanoi.lisp
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
;(defun list (x . y) (cons x y))

;(defun list2 (a b) (cons a (cons b ())))
;(defun list3 (a b c) (cons a (cons b (cons c ()))))

(defmacro cond (rest)
(if (= () rest)
()
(if (= (car (car rest)) t)
(car (cdr (car rest)))
(list 'if
(car (car rest))
(car (cdr (car rest)))
(cond (cdr rest))))))
(defun list (x . y) (cons x y))

(defun mapc1 (fn xs)
(if (= () xs)
Expand All @@ -21,13 +8,9 @@
(mapc1 fn (cdr xs)))))

(defun hanoi-print (disk from to)
(println (cons 'Move
(cons 'disk
(cons disk
(cons 'from
(cons from
(cons 'to
(cons to ())))))))))
(println (string-concat "Move disk " disk
" from " (symbol->string from)
" to " (symbol->string to) )))

(defun hanoi-move (n from to via)
(if (= n 1)
Expand Down
4 changes: 2 additions & 2 deletions examples/life.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

;; (progn expr ...)
;; => ((lambda () expr ...))
(defmacro progn (expr . rest)
(list (cons 'lambda (cons () (cons expr rest)))))
;(defmacro progn (expr . rest)
; (list (cons 'lambda (cons () (cons expr rest)))))

(defun list (x . y)
(cons x y))
Expand Down
4 changes: 2 additions & 2 deletions examples/nqueens.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

;; (progn expr ...)
;; => ((lambda () expr ...))
(defmacro progn (expr . rest)
(list (cons 'lambda (cons () (cons expr rest)))))
;(defmacro progn (expr . rest)
; (list (cons 'lambda (cons () (cons expr rest)))))

(defun list (x . y) (cons x y))

Expand Down
Loading

0 comments on commit 8761982

Please sign in to comment.