Commit | Line | Data |
---|---|---|
1b18f359 VS |
1 | FileStream fileIn: 'readline.st'. |
2 | FileStream fileIn: 'reader.st'. | |
3 | FileStream fileIn: 'printer.st'. | |
4 | ||
5 | Object subclass: MAL [ | |
6 | MAL class >> READ: input [ | |
7 | ^Reader readStr: input | |
8 | ] | |
9 | ||
10 | MAL class >> evalAst: sexp env: env [ | |
11 | sexp type = #symbol ifTrue: [ | |
12 | ^env at: sexp value ifAbsent: [ | |
13 | ^MALUnknownSymbol new signal: sexp value | |
14 | ]. | |
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 | | 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 | forms := (self evalAst: sexp env: env) value. | |
47 | function := forms first. | |
48 | args := forms allButFirst asArray. | |
49 | ^function valueWithArguments: args | |
50 | ] | |
51 | ||
52 | MAL class >> PRINT: sexp [ | |
53 | ^Printer prStr: sexp printReadably: true | |
54 | ] | |
55 | ||
56 | MAL class >> rep: input env: env [ | |
57 | ^self PRINT: (self EVAL: (self READ: input) env: env) | |
58 | ] | |
59 | ] | |
60 | ||
61 | | input historyFile replEnv | | |
62 | ||
63 | historyFile := '.mal_history'. | |
64 | ReadLine readHistory: historyFile. | |
65 | replEnv := Dictionary from: | |
66 | { #+ -> [ :a :b | MALNumber new: a value + b value ]. | |
67 | #- -> [ :a :b | MALNumber new: a value - b value ]. | |
68 | #* -> [ :a :b | MALNumber new: a value * b value ]. | |
69 | #/ -> [ :a :b | MALNumber new: a value // b value ] }. | |
70 | ||
71 | [ input := ReadLine readLine: 'user> '. input isNil ] whileFalse: [ | |
72 | input isEmpty ifFalse: [ | |
73 | ReadLine addHistory: input. | |
74 | ReadLine writeHistory: historyFile. | |
75 | [ (MAL rep: input env: replEnv) displayNl ] | |
76 | on: MALEmptyInput do: [ #return ] | |
77 | on: MALError do: | |
78 | [ :err | ('error: ', err messageText) displayNl. #return ]. | |
79 | ] | |
80 | ] | |
81 | ||
82 | '' displayNl. |