Skip to content

Commit b66a01e

Browse files
committed
Update README
1 parent c1872d7 commit b66a01e

File tree

1 file changed

+131
-75
lines changed

1 file changed

+131
-75
lines changed

README.md

Lines changed: 131 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,228 @@
11
# lwhlisp
22
lwhlisp is a lisp interpreter written in rust, based on [this tutorial](https://www.lwh.jp/lisp/index.html "Building LISP").
33

4-
# Getting started
4+
## Getting started
55

66
Install [Rust](https://www.rust-lang.org/ "Rust Programming Language") and clone this repository.
77
Then, inside the repository:
88

99
```sh
10-
cargo run
10+
cargo run --release
1111
```
1212

13-
This will compile the project, then start an interactive session (no compilation is required on subsequent runs).
13+
This will compile the project and launch a REPL. The finished binary is `target/release/lwhlisp`.
14+
15+
**NOTE**:
1416
The interactive session will start by loading the small included standard library (you can find the library in lib/lib.lisp).
1517

16-
It should look something like this:
18+
If no such file is found, it will fail to load and you will get an error that looks like this:
19+
20+
```sh
21+
Error:
22+
0: While opening library file
23+
1: While opening file lib/lib.lisp
24+
2: No such file or directory (os error 2)
25+
```
26+
27+
You can solve this problem by manually indicating where lwhlisp can find the library file:
28+
29+
```sh
30+
cargo run --release -- --library /path/to/library/file.lisp
31+
```
32+
(The `--` separates arguments to cargo and arguments to lwhlisp. It can be omited when calling the `lwhlisp` binary directly.)
33+
34+
The REPL should look something like this:
1735

1836
```common-lisp
19-
Loading standard library...
20-
(define eq? =) => eq?
21-
(define (abs x) (if (< x 0) (- 0 x) x)) => abs
22-
(define (foldl proc init list) (if list (foldl proc (proc init (car list)) (cdr list)) init)) => foldl
23-
[snip]
24-
Finished.
2537
user>
2638
```
2739

28-
As you can see, each s-expression from the library file is parsed, evaluated, and then the parsed expression is printed, along with the result.
29-
3040
Once you are at the `user>` prompt, you may enter lisp code to be evaluated.
3141

32-
**Note:**
33-
`()` is converted into `nil` at parse time.
42+
```common-lisp
43+
user> (+ 1 2 3)
44+
=> 6
45+
user> (if (> 5 4) (println "Five is bigger than Four") (println "Five is smaller than Four"))
46+
Five is bigger than Four
47+
=> "Five is bigger than Four"
48+
```
3449

35-
# Special forms
50+
You can also run files:
3651

37-
## `quote`
52+
```sh
53+
cargo run --release -- -f file.lisp
54+
```
55+
56+
**factorial.lisp**:
57+
58+
```common-lisp
59+
(define (factorial x)
60+
(if (= x 0)
61+
1
62+
(* x (factorial (- x 1)))))
63+
64+
(println (factorial 10))
65+
```
66+
67+
```sh
68+
$ cargo run --release -- -f file.lisp
69+
3628800
70+
```
71+
72+
## Syntax
73+
`()` is converted into `nil` at parse time.
74+
75+
### `quote`
3876

3977
Takes a single argument, and returns it without evaluating
40-
``` common-lisp
41-
(quote (a b c)) => (a b c)
78+
```common-lisp
79+
user> (quote (a b c))
80+
=> (a b c)
4281
```
4382

44-
Since this is a bit long to write, a shorthand is provided:
45-
``` common-lisp
46-
'(a b c) => (a b c)
83+
Since this is used frequently, a shorthand is provided:
84+
```common-lisp
85+
user> '(a b c)
86+
=> (a b c)
4787
```
4888

4989
The shorthand gets converted into the full version at parse time.
5090

51-
## `lambda`
91+
### `lambda`
5292

53-
``` common-lisp
54-
(lambda (x) (* x x)) => (lambda (x) ((* x x)))
55-
(lambda (x) (+ x x) (* x x)) => (lambda (x) ((+ x x) (* x x)))
93+
```common-lisp
94+
user> (lambda (x) (* x x))
95+
=> (lambda (x) (* x x))
5696
```
5797

58-
**NOTE:**
59-
The printing of lambda expressions is flawed.
60-
Since lambda expressions can contain multiple statements, they are internally stored as a list, and the printing reflects that.
61-
Ignore the extra set of parenthesis around the body.
98+
You can have multiple s-expressions in the body:
6299

63-
Evaluation:
64-
``` common-lisp
65-
((lambda (x) (* x x)) 7) => 49
66-
((lambda (x) (+ x x) (* x x)) 7) => 49
100+
```common-lisp
101+
user> (lambda (x) (println x) (* x x))
102+
=> (lambda (x) (println x) (* x x))
67103
```
68104

69-
Only the last s-expression is returned.
105+
Lambdas can be directly evaluated:
106+
```common-lisp
107+
user> ((lambda (x) (* x x)) 7)
108+
=> 49
109+
user> ((lambda (x) (println x) (* x x)) 7)
110+
7
111+
=> 49
112+
```
70113

71-
## `define`
114+
Note that only the last s-expression is returned.
115+
116+
### `define`
72117

73118
Binds a symbol to a value.
74119

75120
Basic syntax:
76-
``` common-lisp
77-
(define x 7) => x
78-
x => 7
121+
```common-lisp
122+
user> (define x 7)
123+
=> x
124+
user> x
125+
=> 7
79126
```
80127

81128
Creating a function:
82-
``` common-lisp
83-
(define square (lambda (x) (* x x))) => square
84-
(square 7) => 49
129+
```common-lisp
130+
user> (define square (lambda (x) (* x x)))
131+
=> square
132+
user> (square 7)
133+
=> 49
85134
```
86135

87136
Since this is a frequent action, there is special syntax for this:
88-
``` common-lisp
89-
(define (square x) (* x x)) => square
90-
(square 7) => 49
137+
```common-lisp
138+
user> (define (square x) (* x x))
139+
=> square
140+
user> (square 7)
141+
=> 49
91142
```
92143

93144
You can choose to get the arguments as a list instead:
94-
``` common-lisp
95-
(define (x . a) a) => x
96-
(x 1 2 3) => (1 2 3)
145+
```common-lisp
146+
user> (define (x . a) a)
147+
=> x
148+
user> (x 1 2 3)
149+
=> (1 2 3)
97150
```
98151

99152
Or have one (or more) required arguments, and get the rest as a list:
100153

101-
``` common-lisp
102-
(define (x a . b) (list a b)) => x
103-
(x 1 2 3) => (1 (2 3))
154+
```common-lisp
155+
user> (define (x a . b) (println a) (println b))
156+
=> x
157+
user> (x 1 2 3)
158+
1
159+
(2 3)
160+
=> "(2 3)"
104161
```
105162

106-
(list is a function from the standard library that constructs a list will all of its arguments)
163+
(list is a function from the standard library that constructs a list from all of its arguments)
107164

108-
## `defmacro`
165+
### `defmacro`
109166

110-
Macros work the exact same way as function, except that the arguments to macros are not evaluated.
167+
Macros work the same way as function, except that the arguments to macros are not evaluated.
111168

112169
Macros use the following syntax:
113-
``` common-lisp
170+
```common-lisp
114171
(defmacro (name arg...) body...)
115172
```
116173

117174
For example, consider the following macro:
118-
``` common-lisp
119-
(defmacro (ignore x) (cons 'quote (cons x nil))) => ignore
175+
```common-lisp
176+
(defmacro (ignore x)
177+
(cons 'quote (cons x nil)))
120178
```
121179

122180
If we then evaluate the expression
123-
``` common-lisp
124-
(ignore foo) => foo
181+
```common-lisp
182+
user> (ignore foo)
183+
=> foo
125184
```
126185
where foo is a (potentially unbound) symbol, the body of `ignore` will be evaluated with the argument `x` bound to the *unevaluated* symbol `foo`.
127186
The result of this is:
128-
``` common-lisp
187+
```common-lisp
129188
(quote . (foo . nil))
130189
```
131190
which is equivalent to:
132-
``` common-lisp
191+
```common-lisp
133192
(quote foo)
134193
```
135194
or
136-
``` common-lisp
195+
```common-lisp
137196
'foo
138197
```
139198

140199
Finally, evaluating this value will give us the result of evaluating the macro body:
141-
``` common-lisp
200+
```common-lisp
142201
foo
143202
```
144203

145-
## `if`
204+
### `if`
146205

147206
The syntax is as follows:
148-
``` common-lisp
207+
```common-lisp
149208
(if test true-expr false-expr)
150209
```
151210

152211
If `test` is not nil, the result of evaluating this expression will be `false-expr`. Else, it will be `true-expr`.
153212

154-
# Example
213+
## Example
155214
This is a simple program that calculates factorials in a recursive fashion:
156-
``` common-lisp
215+
```common-lisp
157216
(define (factorial x)
158-
(if (= x 0)
159-
1
160-
(* x (factorial (- x 1)))))
217+
(if (= x 0)
218+
1
219+
(* x (factorial (- x 1)))))
161220
```
162221

163222
The base case, if `x=0`, will return `1`.
164223
In all other cases, we will return `fact(x - 1) * x`.
165224

166-
``` common-lisp
167-
(factorial 10) => 3628800
225+
```common-lisp
226+
user> (factorial 10)
227+
=> 3628800
168228
```
169-
170-
171-
# TODO
172-
- [X] When redefining recursive functions, the old version persists in the environment of the new functions, causing recursion to use the old version of the function.

0 commit comments

Comments
 (0)