2 String >> loadRelative
[
3 | scriptPath scriptDirectory |
4 scriptPath
:= thisContext currentFileName
.
5 scriptDirectory
:= FilePath stripFileNameFor: scriptPath
.
6 FileStream fileIn: (FilePath append: self to: scriptDirectory
)
10 'readline.st' loadRelative
.
11 'util.st' loadRelative
.
12 'types.st' loadRelative
.
13 'reader.st' loadRelative
.
14 'printer.st' loadRelative
.
15 'env.st' loadRelative
.
17 Object subclass: MAL [
18 MAL class >>
READ: input
[
19 ^Reader readStr: input
22 MAL class >>
evalAst: sexp
env: env
[
23 sexp type
= #symbol ifTrue: [
27 sexp type
= #list ifTrue: [
28 ^self evalList: sexp
env: env
class: MALList
30 sexp type
= #vector ifTrue: [
31 ^self evalList: sexp
env: env
class: MALVector
33 sexp type
= #map ifTrue: [
34 ^self evalList: sexp
env: env
class: MALMap
40 MAL class >>
evalList: sexp
env: env
class: aClass
[
42 items
:= sexp value
collect:
43 [ :item |
self EVAL: item
env: env
].
47 MAL class >>
EVAL: sexp
env: env
[
48 | ast a0_ a1_ a2 forms function args |
49 sexp type ~
= #list ifTrue: [
50 ^self evalAst: sexp
env: env
52 sexp value isEmpty
ifTrue: [
57 a0_
:= ast first value
.
58 a0_
= #'def!' ifTrue: [
60 a1_
:= ast second value
.
62 result
:= self EVAL: a2
env: env
.
63 env
set: a1_
value: result
.
67 a0_
= #'let*' ifTrue: [
70 a1_
:= ast second value
.
72 1 to: a1_ size
by: 2 do:
73 [ :i | env_
set: (a1_
at: i
) value
74 value: (self EVAL: (a1_
at: i
+ 1) env: env_
) ].
75 ^self EVAL: a2
env: env_
78 forms
:= (self evalAst: sexp
env: env
) value
.
79 function
:= forms first
.
80 args
:= forms allButFirst asArray
.
81 ^function
valueWithArguments: args
84 MAL class >>
PRINT: sexp
[
85 ^Printer prStr: sexp
printReadably: true
88 MAL class >>
rep: input
env: env
[
89 ^self PRINT: (self EVAL: (self READ: input
) env: env
)
93 | input historyFile replEnv |
95 historyFile
:= '.mal_history'.
96 ReadLine readHistory: historyFile
.
97 replEnv
:= Env new: nil.
99 replEnv
set: #+ value: [ :a :b |
MALNumber new: a value
+ b value
].
100 replEnv
set: #- value: [ :a :b |
MALNumber new: a value
- b value
].
101 replEnv
set: #* value: [ :a :b |
MALNumber new: a value
* b value
].
102 replEnv
set: #/ value: [ :a :b |
MALNumber new: a value
// b value
].
104 [ input
:= ReadLine readLine: 'user> '. input isNil
] whileFalse: [
105 input isEmpty
ifFalse: [
106 ReadLine addHistory: input
.
107 ReadLine writeHistory: historyFile
.
108 [ (MAL rep: input
env: replEnv
) displayNl
]
109 on: MALEmptyInput do: [ #return ]
111 [ :err |
('error: ', err messageText
) displayNl
. #return ].