138b967838a201cc87160a836ded24b87a71bee8
[jackhill/mal.git] / gst / step4_if_fn_do.st
1 FileStream fileIn: 'readline.st'.
2 FileStream fileIn: 'reader.st'.
3 FileStream fileIn: 'printer.st'.
4 FileStream fileIn: 'env.st'.
5 FileStream fileIn: 'core.st'.
6
7 Object subclass: MAL [
8 MAL class >> READ: input [
9 ^Reader readStr: input
10 ]
11
12 MAL class >> evalAst: sexp env: env [
13 sexp type = #symbol ifTrue: [
14 ^env get: sexp value
15 ].
16
17 sexp type = #list ifTrue: [
18 ^self evalList: sexp env: env class: MALList
19 ].
20 sexp type = #vector ifTrue: [
21 ^self evalList: sexp env: env class: MALVector
22 ].
23 sexp type = #map ifTrue: [
24 ^self evalList: sexp env: env class: MALMap
25 ].
26
27 ^sexp
28 ]
29
30 MAL class >> evalList: sexp env: env class: aClass [
31 | items |
32 items := sexp value collect:
33 [ :item | self EVAL: item env: env ].
34 ^aClass new: items
35 ]
36
37 MAL class >> EVAL: sexp env: env [
38 | ast a0_ a1 a1_ a1_n a2 a3 forms function args |
39 sexp type ~= #list ifTrue: [
40 ^self evalAst: sexp env: env
41 ].
42 sexp value isEmpty ifTrue: [
43 ^sexp
44 ].
45
46 ast := sexp value.
47 a0_ := ast first value.
48 a0_ = #'def!' ifTrue: [
49 | result |
50 a1_ := ast second value.
51 a2 := ast third.
52 result := self EVAL: a2 env: env.
53 env set: a1_ value: result.
54 ^result
55 ].
56
57 a0_ = #'let*' ifTrue: [
58 | env_ |
59 env_ := Env new: env.
60 a1_ := ast second value.
61 a2 := ast third.
62 1 to: a1_ size by: 2 do:
63 [ :i | env_ set: (a1_ at: i) value
64 value: (self EVAL: (a1_ at: i + 1) env: env_) ].
65 ^self EVAL: a2 env: env_
66 ].
67
68 a0_ = #do ifTrue: [
69 a1_n := ast allButFirst.
70 ^(a1_n collect: [ :item | self EVAL: item env: env]) last
71 ].
72
73 a0_ = #if ifTrue: [
74 | condition |
75 a1 := ast second.
76 a2 := ast third.
77 a3 := ast at: 4 ifAbsent: [ MALObject Nil ].
78 condition := self EVAL: a1 env: env.
79
80 (condition type = #false or: [ condition type = #nil ]) ifTrue: [
81 ^self EVAL: a3 env: env
82 ] ifFalse: [
83 ^self EVAL: a2 env: env
84 ]
85 ].
86
87 a0_ = #'fn*' ifTrue: [
88 | binds |
89 a1_ := ast second value.
90 binds := a1_ collect: [ :item | item value ].
91 a2 := ast third.
92 ^[ :args | self EVAL: a2 env:
93 (Env new: env binds: binds exprs: args) ]
94 ].
95
96 forms := (self evalAst: sexp env: env) value.
97 function := forms first.
98 args := forms allButFirst asArray.
99 ^function value: args
100 ]
101
102 MAL class >> PRINT: sexp [
103 ^Printer prStr: sexp printReadably: true
104 ]
105
106 MAL class >> rep: input env: env [
107 ^self PRINT: (self EVAL: (self READ: input) env: env)
108 ]
109 ]
110
111 | input historyFile replEnv |
112
113 historyFile := '.mal_history'.
114 ReadLine readHistory: historyFile.
115 replEnv := Env new: nil.
116
117 Core Ns keysAndValuesDo: [ :op :block | replEnv set: op value: block ].
118
119 MAL rep: '(def! not (fn* (a) (if a false true)))' env: replEnv.
120
121 [ input := ReadLine readLine: 'user> '. input isNil ] whileFalse: [
122 input isEmpty ifFalse: [
123 ReadLine addHistory: input.
124 ReadLine writeHistory: historyFile.
125 [ (MAL rep: input env: replEnv) displayNl ]
126 on: MALEmptyInput do: [ #return ]
127 on: MALError do:
128 [ :err | ('error: ', err messageText) displayNl. #return ].
129 ]
130 ]
131
132 '' displayNl.