Commit | Line | Data |
---|---|---|
2e3d457e | 1 | // @import readline.ck |
0c8b871a VS |
2 | // @import types/boxed/*.ck |
3 | // @import types/MalObject.ck | |
98c1ecf2 VS |
4 | // @import types/mal/MalAtom.ck |
5 | // @import types/mal/MalError.ck | |
6 | // @import types/mal/MalNil.ck | |
7 | // @import types/mal/MalFalse.ck | |
8 | // @import types/mal/MalTrue.ck | |
9 | // @import types/mal/MalInt.ck | |
10 | // @import types/mal/MalString.ck | |
11 | // @import types/mal/MalSymbol.ck | |
12 | // @import types/mal/MalKeyword.ck | |
13 | // @import types/mal/MalList.ck | |
14 | // @import types/mal/MalVector.ck | |
15 | // @import types/mal/MalHashMap.ck | |
0c8b871a VS |
16 | // @import util/*.ck |
17 | // @import reader.ck | |
18 | // @import printer.ck | |
aa0ac94f | 19 | // @import env.ck |
f823ec25 VS |
20 | // @import types/MalSubr.ck |
21 | // @import types/subr/*.ck | |
0c8b871a VS |
22 | |
23 | fun MalObject READ(string input) | |
24 | { | |
25 | return Reader.read_str(input); | |
26 | } | |
27 | ||
28 | fun MalObject EVAL(MalObject m, Env env) | |
29 | { | |
30 | if( m.type == "list" ) | |
31 | { | |
32 | if( (m$MalList).value().size() == 0 ) | |
33 | { | |
34 | return m; | |
35 | } | |
36 | ||
37 | (m$MalList).value() @=> MalObject ast[]; | |
38 | (ast[0]$MalSymbol).value() => string a0; | |
39 | ||
40 | if( a0 == "def!" ) | |
41 | { | |
42 | (ast[1]$MalSymbol).value() => string a1; | |
43 | ||
44 | EVAL(ast[2], env) @=> MalObject value; | |
45 | if( value.type == "error" ) | |
46 | { | |
47 | return value; | |
48 | } | |
49 | ||
50 | env.set(a1, value); | |
51 | return value; | |
52 | } | |
53 | else if( a0 == "let*" ) | |
54 | { | |
55 | Env.create(env) @=> Env let_env; | |
56 | Util.sequenceToMalObjectArray(ast[1]) @=> MalObject bindings[]; | |
57 | ||
58 | for( 0 => int i; i < bindings.size(); 2 +=> i) | |
59 | { | |
60 | (bindings[i]$MalSymbol).value() => string symbol; | |
61 | EVAL(bindings[i+1], let_env) @=> MalObject value; | |
62 | ||
63 | if( value.type == "error" ) | |
64 | { | |
65 | return value; | |
66 | } | |
67 | ||
68 | let_env.set(symbol, value); | |
69 | } | |
70 | ||
71 | return EVAL(ast[2], let_env); | |
72 | } | |
73 | ||
74 | eval_ast(m, env) @=> MalObject result; | |
75 | if( result.type == "error" ) | |
76 | { | |
77 | return result; | |
78 | } | |
79 | ||
80 | (result$MalList).value() @=> MalObject values[]; | |
81 | values[0]$MalSubr @=> MalSubr subr; | |
82 | MalObject.slice(values, 1) @=> MalObject args[]; | |
83 | ||
84 | return subr.call(args); | |
85 | } | |
86 | else | |
87 | { | |
88 | eval_ast(m, env) @=> MalObject result; | |
89 | return result; | |
90 | } | |
91 | } | |
92 | ||
93 | fun MalObject eval_ast(MalObject m, Env env) | |
94 | { | |
95 | m.type => string type; | |
96 | ||
97 | if( type == "symbol" ) | |
98 | { | |
99 | (m$MalSymbol).value() => string symbol; | |
100 | return env.get(symbol); | |
101 | } | |
102 | else if( type == "list" || type == "vector" || type == "hashmap" ) | |
103 | { | |
104 | (m$MalList).value() @=> MalObject values[]; | |
105 | MalObject results[values.size()]; | |
106 | ||
107 | if( type != "hashmap" ) | |
108 | { | |
109 | for( 0 => int i; i < values.size(); i++ ) | |
110 | { | |
111 | EVAL(values[i], env) @=> MalObject result; | |
112 | ||
113 | if( result.type == "error" ) | |
114 | { | |
115 | return result; | |
116 | } | |
117 | ||
118 | result @=> results[i]; | |
119 | } | |
120 | } | |
121 | else | |
122 | { | |
123 | for( 0 => int i; i < values.size(); i++ ) | |
124 | { | |
125 | if( i % 2 == 0 ) | |
126 | { | |
127 | values[i] @=> results[i]; | |
128 | } | |
129 | else | |
130 | { | |
131 | EVAL(values[i], env) @=> results[i]; | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | if( type == "list" ) | |
137 | { | |
138 | return MalList.create(results); | |
139 | } | |
140 | else if( type == "vector" ) | |
141 | { | |
142 | return MalVector.create(results); | |
143 | } | |
144 | else if( type == "hashmap" ) | |
145 | { | |
146 | return MalHashMap.create(results); | |
147 | } | |
148 | } | |
149 | else | |
150 | { | |
151 | return m; | |
152 | } | |
153 | } | |
154 | ||
155 | fun string PRINT(MalObject m) | |
156 | { | |
157 | return Printer.pr_str(m, true); | |
158 | } | |
159 | ||
160 | Env.create(null) @=> Env repl_env; | |
161 | repl_env.set("+", new MalAdd); | |
162 | repl_env.set("-", new MalSub); | |
163 | repl_env.set("*", new MalMul); | |
164 | repl_env.set("/", new MalDiv); | |
165 | ||
98c1ecf2 VS |
166 | fun string errorMessage(MalObject m) |
167 | { | |
168 | (m$MalError).value() @=> MalObject value; | |
169 | ||
170 | if( value.type == "string" ) | |
171 | { | |
172 | return Printer.pr_str(value, false); | |
173 | } | |
174 | else | |
175 | { | |
176 | return "exception: " + Printer.pr_str(value, true); | |
177 | } | |
178 | } | |
179 | ||
0c8b871a VS |
180 | fun string rep(string input) |
181 | { | |
182 | READ(input) @=> MalObject m; | |
183 | ||
184 | if( m.type == "error" ) | |
185 | { | |
98c1ecf2 | 186 | return errorMessage(m); |
0c8b871a VS |
187 | } |
188 | ||
189 | EVAL(m, repl_env) @=> MalObject result; | |
190 | if( result.type == "error" ) | |
191 | { | |
98c1ecf2 | 192 | return errorMessage(result); |
0c8b871a VS |
193 | } |
194 | ||
195 | return PRINT(result); | |
196 | } | |
197 | ||
198 | fun void main() | |
199 | { | |
2e3d457e | 200 | int done; |
0c8b871a | 201 | |
2e3d457e | 202 | while( !done ) |
0c8b871a | 203 | { |
2e3d457e | 204 | Readline.readline("user> ") => string input; |
0c8b871a | 205 | |
2e3d457e | 206 | if( input != null ) |
0c8b871a | 207 | { |
2e3d457e VS |
208 | rep(input) => string output; |
209 | ||
210 | if( output == "empty input" ) | |
211 | { | |
212 | // proceed immediately with prompt | |
213 | } | |
214 | else | |
215 | { | |
216 | Util.println(output); | |
217 | } | |
0c8b871a VS |
218 | } |
219 | else | |
220 | { | |
2e3d457e | 221 | true => done; |
0c8b871a VS |
222 | } |
223 | } | |
224 | } | |
225 | ||
226 | main(); |