4
4
"bufio"
5
5
"errors"
6
6
"fmt"
7
+ "io"
7
8
"log"
8
9
"math"
9
10
"os"
@@ -12,12 +13,17 @@ import (
12
13
"strings"
13
14
)
14
15
15
- type Token int
16
- type Number float64
17
- type Atom string
16
+ // Item is an Atom, Number, String, or Function
18
17
type Item interface {}
18
+
19
+ // ItemList is a fundamental data type.
19
20
type ItemList []Item
20
21
22
+ type Number float64
23
+ type Atom string
24
+ type String string
25
+ type NativeFunc func (... Item ) (Item , error )
26
+
21
27
var ErrorEOF = errors .New ("End of File" )
22
28
23
29
func (items ItemList ) String () string {
@@ -32,17 +38,23 @@ func (items ItemList) String() string {
32
38
return s
33
39
}
34
40
41
+ func (s String ) String () string {
42
+ return fmt .Sprintf ("\" %s\" " , string (s ))
43
+ }
44
+
35
45
func read (s * Scanner ) (Item , error ) {
36
46
tok , lit := s .Scan ()
37
47
if tok == WS {
38
48
tok , lit = s .Scan ()
39
49
}
40
- // fmt .Println("scan:", tok, lit)
50
+ //log .Println("scan:", tok, lit)
41
51
switch tok {
42
52
case LEFT_PAREN :
43
53
return readList (s )
44
54
case ATOM :
45
55
return Atom (lit ), nil
56
+ case QUOTE :
57
+ return readQuote (s )
46
58
case NUMBER :
47
59
v , err := strconv .ParseFloat (lit , 64 )
48
60
if err != nil {
@@ -53,10 +65,21 @@ func read(s *Scanner) (Item, error) {
53
65
return nil , nil
54
66
case EOF :
55
67
return nil , ErrorEOF
68
+ case STRING :
69
+ return String (lit ), nil
56
70
}
57
71
return nil , errors .New ("Malformed input" )
58
72
}
59
73
74
+ func readQuote (s * Scanner ) (Item , error ) {
75
+ l := ItemList {Atom ("quote" )}
76
+ c , err := read (s )
77
+ if err != nil {
78
+ return nil , fmt .Errorf ("Failed to complete list: %v\n " , err )
79
+ }
80
+ return append (l , c ), nil
81
+ }
82
+
60
83
func readList (s * Scanner ) (Item , error ) {
61
84
var l ItemList
62
85
for {
@@ -110,6 +133,8 @@ func eval(expr Item, env *Env) (interface{}, error) {
110
133
}
111
134
case Number :
112
135
return e , nil
136
+ case String :
137
+ return e , nil
113
138
case ItemList :
114
139
switch car , _ := e [0 ].(Atom ); car {
115
140
case "quote" :
@@ -147,14 +172,12 @@ func eval(expr Item, env *Env) (interface{}, error) {
147
172
default :
148
173
proc , err := eval (e [0 ], env )
149
174
if err != nil {
150
- log .Println ("Error1" , err )
151
- return nil , err
175
+ return nil , fmt .Errorf ("undefined-function: %v" , err )
152
176
}
153
177
args := make (ItemList , len (e )- 1 )
154
178
for i , a := range e [1 :] {
155
179
args [i ], err = eval (a , env )
156
180
if err != nil {
157
- log .Println ("Error2" , err )
158
181
return nil , err
159
182
}
160
183
}
@@ -185,7 +208,7 @@ func evalLambda(expr ItemList, env *Env) (interface{}, error) {
185
208
case Atom :
186
209
l .params = append (l .params , p )
187
210
case []interface {}:
188
- log . Fatal ("combo param not supported:" , x )
211
+ return nil , fmt . Errorf ("combo param not supported: %v " , x )
189
212
}
190
213
191
214
}
@@ -195,35 +218,39 @@ func evalLambda(expr ItemList, env *Env) (interface{}, error) {
195
218
return & l , nil
196
219
197
220
}
221
+
198
222
func apply (proc Item , args ItemList , env * Env ) (Item , error ) {
199
223
// log.Printf("apply: %v args: %v\n", proc, args)
200
224
switch f := proc .(type ) {
201
- case func ( ... Item ) Item :
202
- return f (args ... ), nil
225
+ case NativeFunc :
226
+ return f (args ... )
203
227
case * Lambda :
204
228
if len (f .params ) != len (args ) {
205
- log . Fatalf ("parameter mismatch %v != %v" , f .params , args )
229
+ return nil , fmt . Errorf ("parameter mismatch %v != %v" , f .params , args )
206
230
}
207
231
for i , p := range f .params {
208
232
f .envt .vars [p ] = args [i ]
209
233
}
210
234
return eval (f .body , f .envt )
211
235
default :
212
- log . Fatalf ("apply to a non function: %#v" , proc )
236
+ return nil , fmt . Errorf ("apply to a non function: %#v" , proc )
213
237
}
214
238
return nil , nil
215
239
}
216
240
217
- func repl (in string , env * Env ) (interface {}, error ) {
218
- s := NewScanner (strings . NewReader ( in ) )
241
+ func replReader (in io. Reader , env * Env ) (interface {}, error ) {
242
+ s := NewScanner (in )
219
243
var result interface {}
220
244
for {
221
245
var err error
222
246
expr , err := read (s )
223
247
if err != nil {
248
+ if err == ErrorEOF {
249
+ return result , nil
250
+ }
224
251
return result , err
225
252
}
226
- //fmt.Println(expr)
253
+ // fmt.Println(expr)
227
254
228
255
result , err = eval (expr , env )
229
256
if err != nil {
@@ -232,38 +259,69 @@ func repl(in string, env *Env) (interface{}, error) {
232
259
}
233
260
}
234
261
262
+ func repl (in string , env * Env ) (interface {}, error ) {
263
+ return replReader (strings .NewReader (in ), env )
264
+ }
265
+
235
266
func replCLI (env * Env ) {
236
- reader := ( bufio .NewReader (os .Stdin ) )
267
+ reader := bufio .NewReader (os .Stdin )
237
268
for {
238
- fmt .Print (">>> " )
269
+ fmt .Print ("* " )
239
270
text , _ := reader .ReadString ('\n' )
240
271
result , err := repl (text , env )
241
272
if err != nil && err != ErrorEOF {
242
- fmt .Println ("New Error:" , err )
273
+ fmt .Println ("Error:" , err )
274
+ } else {
275
+ fmt .Println (result )
243
276
}
244
- fmt .Println ("===>" , result )
245
277
}
246
278
}
247
279
248
- var defaultEnv * Env
249
-
250
- func ApplyNumeric (f func (Number , Number ) Number ) func (a ... Item ) Item {
251
- return func (a ... Item ) Item {
280
+ func ApplyNumeric (f func (Number , Number ) Number ) NativeFunc {
281
+ return func (a ... Item ) (Item , error ) {
252
282
v , ok := a [0 ].(Number )
253
283
if ! ok {
254
- log . Fatalf ("Not a number: %v" , a [0 ])
284
+ return nil , fmt . Errorf ("Not a number: %v" , a [0 ])
255
285
}
256
286
for _ , n := range a [1 :] {
257
287
i , ok := n .(Number )
258
288
if ! ok {
259
- log . Fatalf ("Not a number: %v" , a [ 0 ] )
289
+ return nil , fmt . Errorf ("Not a number: %v" , n )
260
290
}
261
291
v = f (v , i )
262
292
}
263
- return v
293
+ return v , nil
294
+ }
295
+ }
296
+
297
+ func ApplyNumericBool (f func (Number , Number ) bool ) NativeFunc {
298
+ return func (a ... Item ) (Item , error ) {
299
+ var ret bool
300
+ v , ok := a [0 ].(Number )
301
+ if ! ok {
302
+ return nil , fmt .Errorf ("Not a number: %v" , a [0 ])
303
+ }
304
+ for _ , n := range a [1 :] {
305
+ i , ok := n .(Number )
306
+ if ! ok {
307
+ return nil , fmt .Errorf ("Not a number: %v" , n )
308
+ }
309
+ ret = f (v , i )
310
+ v = i
311
+ if ! ret {
312
+ return ret , nil
313
+ }
314
+ }
315
+ return Item (ret ), nil
264
316
}
265
317
}
266
318
319
+ func isItemList (i Item ) bool {
320
+ if _ , ok := i .(ItemList ); ok {
321
+ return true
322
+ }
323
+ return false
324
+ }
267
325
func DefaultEnv () * Env {
268
326
return & Env {
269
327
Binding {
@@ -279,40 +337,71 @@ func DefaultEnv() *Env {
279
337
"-" : ApplyNumeric (func (x , y Number ) Number {
280
338
return x - y
281
339
}),
282
- "<=" : func (a ... Item ) Item {
283
- return a [0 ].(Number ) <= a [1 ].(Number )
284
- },
285
- "equal?" : func (a ... Item ) Item {
286
- return reflect .DeepEqual (a [0 ], a [1 ])
287
- },
340
+ "<" : ApplyNumericBool (func (x , y Number ) bool {
341
+ return x < y
342
+ }),
343
+ "<=" : ApplyNumericBool (func (x , y Number ) bool {
344
+ return x <= y
345
+ }),
346
+ ">" : ApplyNumericBool (func (x , y Number ) bool {
347
+ return x > y
348
+ }),
349
+ ">=" : ApplyNumericBool (func (x , y Number ) bool {
350
+ return x >= y
351
+ }),
352
+ "=" : ApplyNumericBool (func (x , y Number ) bool {
353
+ return x == y
354
+ }),
355
+ "number?" : NativeFunc (func (a ... Item ) (Item , error ) {
356
+ if len (a ) > 1 {
357
+ return nil , fmt .Errorf ("Too many arguments for number?: %v" , a )
358
+ }
359
+ if _ , ok := a [0 ].(Number ); ok {
360
+ return Item (true ), nil
361
+ }
362
+ return Item (false ), nil
363
+ }),
364
+ "car" : NativeFunc (func (a ... Item ) (Item , error ) {
365
+ if ! isItemList (a [0 ]) {
366
+ return nil , fmt .Errorf ("Not a list: %#v" , a [0 ])
367
+ }
368
+ il := a [0 ].(ItemList )
369
+ if len (il ) == 0 {
370
+ return []ItemList {}, nil
371
+ }
372
+ return a [0 ].(ItemList )[0 ], nil
373
+ }),
374
+ "cdr" : NativeFunc (func (a ... Item ) (Item , error ) {
375
+ if ! isItemList (a [0 ]) {
376
+ return nil , fmt .Errorf ("Not a list: %#v" , a [0 ])
377
+ }
378
+ il := a [0 ].(ItemList )
379
+ if len (il ) < 2 {
380
+ return []ItemList {}, nil
381
+ }
382
+ return il [1 :], nil
383
+ }),
384
+ "cons" : NativeFunc (func (a ... Item ) (Item , error ) {
385
+ if len (a ) != 2 {
386
+ return nil , fmt .Errorf ("wrong number of arguments given to cons" )
387
+ }
388
+ l := ItemList {a [0 ]}
389
+ if il , ok := a [1 ].(ItemList ); ok {
390
+ l = append (l , il ... )
391
+ } else {
392
+ l = append (l , a [1 ])
393
+ }
394
+ return l , nil
395
+ }),
396
+ "equal?" : NativeFunc (func (a ... Item ) (Item , error ) {
397
+ return reflect .DeepEqual (a [0 ], a [1 ]), nil
398
+ }),
288
399
"pi" : Number (math .Pi ),
289
400
},
290
401
nil ,
291
402
}
292
403
}
293
- func init () {
294
- defaultEnv = DefaultEnv ()
295
- }
296
404
297
405
func main () {
298
- env := defaultEnv
299
- /*
300
- repl("(define r 10)\n(define n 12)", env)
301
- repl("(begin (define r 10)\n(define n 12))", env)
302
- repl("(define radius (* pi (* r r)))", env)
303
- repl("(if (<= 4 2) (* 10 2))", env)
304
- repl("(if (<= 4 2) (* 10 2) (+ 1 2))", env)
305
- repl("(/ radius 10)", env)
306
- repl("(quote (1 1))", env)
307
- repl("123", env)
308
- repl("(lambda () (+ 1 1))", env)
309
- repl("((lambda () (+ 1 1)))", env)
310
- repl("((lambda () (+ 1 1)))", env)
311
- repl("(define foo (begin (define count 0) (lambda () (set! count (+ count 1)))))", env)
312
- repl("(foo) (foo)", env)
313
- repl("(foo) (foo)", env)
314
- repl("(define plus (lambda (a b) (+ a b)))", env)
315
- repl("(define counter (lambda (n) (lambda () (set! n (+ n 1)))))", env)
316
- */
317
- replCLI (env )
406
+ replCLI (DefaultEnv ())
318
407
}
0 commit comments