1 FileStream fileIn: 'readline.st'.
2 FileStream fileIn: 'reader.st'.
3 FileStream fileIn: 'printer.st'.
4 FileStream fileIn: 'env.st'.
5 FileStream fileIn: 'func.st'.
6 FileStream fileIn: 'core.st'.
9 MAL class >>
READ: input
[
10 ^Reader readStr: input
13 MAL class >>
evalAst: sexp
env: env
[
14 sexp class
= BlockClosure ifTrue: [^sexp
].
16 sexp type
= #symbol ifTrue: [
20 sexp type
= #list ifTrue: [
21 ^self evalList: sexp
env: env
class: MALList
23 sexp type
= #vector ifTrue: [
24 ^self evalList: sexp
env: env
class: MALVector
26 sexp type
= #map ifTrue: [
27 ^self evalList: sexp
env: env
class: MALMap
33 MAL class >>
evalList: sexp
env: env
class: aClass
[
35 items
:= sexp value
collect:
36 [ :item |
self EVAL: item
env: env
].
40 MAL class >>
EVAL: aSexp
env: anEnv
[
41 | sexp env ast a0 a0_ a1 a1_ a2 a3 forms function args |
43 "NOTE: redefinition of method arguments is not allowed"
49 (sexp class
= BlockClosure or: [ sexp type ~
= #list ]) ifTrue: [
50 ^self evalAst: sexp
env: env
52 sexp value isEmpty
ifTrue: [
59 a0 class ~
= BlockClosure ifTrue: [
60 a0_
:= ast first value
.
61 a0_
= #'def!' ifTrue: [
63 a1_
:= ast second value
.
65 result
:= self EVAL: a2
env: env
.
66 env
set: a1_
value: result
.
70 a0_
= #'let*' ifTrue: [
73 a1_
:= ast second value
.
75 1 to: a1_ size
by: 2 do:
76 [ :i | env_
set: (a1_
at: i
) value
77 value: (self EVAL: (a1_
at: i
+ 1)
86 ast size <
2 ifTrue: [
88 last
:= MALObject Nil.
90 forms
:= ast
copyFrom: 2 to: ast size
- 1.
94 forms
do: [ :form |
self EVAL: form
env: env
].
103 a3
:= ast
at: 4 ifAbsent: [ MALObject Nil ].
104 condition
:= self EVAL: a1
env: env
.
106 (condition type
= #false or:
107 [ condition type
= #nil ]) ifTrue: [
115 a0_
= #'fn*' ifTrue: [
117 a1_
:= ast second value
.
118 binds
:= a1_
collect: [ :item | item value
].
122 (Env new: env
binds: binds
exprs: args
) ].
123 ^Func new: a2
params: binds
env: env
fn: fn
127 forms
:= (self evalAst: sexp
env: env
) value
.
128 function
:= forms first
.
129 args
:= forms allButFirst asArray
.
131 function class
= BlockClosure ifTrue: [ ^function
value: args
].
132 function class
= Func ifTrue: [
134 sexp
:= function ast
.
135 env_
:= Env new: function env
binds: function params
144 MAL class >>
PRINT: sexp
[
145 ^Printer prStr: sexp
printReadably: true
148 MAL class >>
rep: input
env: env
[
149 ^self PRINT: (self EVAL: (self READ: input
) env: env
)
153 | input historyFile replEnv argv |
155 historyFile
:= '.mal_history'.
156 ReadLine readHistory: historyFile
.
157 replEnv
:= Env new: nil.
159 argv
:= Smalltalk arguments
.
160 argv notEmpty
ifTrue: [ argv
:= argv allButFirst
].
161 argv
:= OrderedCollection from: (argv
collect: [ :arg |
MALString new: arg
]).
163 Core Ns keysAndValuesDo: [ :op :block | replEnv
set: op
value: block
].
164 replEnv
set: #eval value: [ :args |
MAL EVAL: args first
env: replEnv
].
165 replEnv
set: #'*ARGV*' value: (MALList new: argv
).
167 MAL rep: '(def! not (fn* (a) (if a false true)))' env: replEnv
.
168 MAL rep: '(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))' env: replEnv
.
170 Smalltalk arguments notEmpty
ifTrue: [
171 MAL rep: '(load-file "',
Smalltalk arguments first,
'")' env: replEnv
173 [ input
:= ReadLine readLine: 'user> '. input isNil
] whileFalse: [
174 input isEmpty
ifFalse: [
175 ReadLine addHistory: input
.
176 ReadLine writeHistory: historyFile
.
177 [ (MAL rep: input
env: replEnv
) displayNl
]
178 on: MALEmptyInput do: [ #return ]
180 [ :err |
('error: ', err messageText
) displayNl
. #return ].