Implement step 6
[jackhill/mal.git] / chuck / step4_if_fn_do.ck
CommitLineData
674e1c56
VS
1// @import types/boxed/*.ck
2// @import types/MalObject.ck
3// @import types/mal/*.ck
4// @import util/*.ck
5// @import reader.ck
6// @import printer.ck
aa0ac94f 7// @import env.ck
674e1c56
VS
8// @import types/MalSubr.ck
9// @import types/subr/*.ck
674e1c56
VS
10// @import core.ck
11// @import func.ck
12
13fun MalObject READ(string input)
14{
15 return Reader.read_str(input);
16}
17
18fun MalObject EVAL(MalObject m, Env env)
19{
20 if( m.type == "list" )
21 {
22 if( (m$MalList).value().size() == 0 )
23 {
24 return m;
25 }
26
27 (m$MalList).value() @=> MalObject ast[];
28
29 if( ast[0].type == "symbol" )
30 {
31 (ast[0]$MalSymbol).value() => string a0;
32
33 if( a0 == "def!" )
34 {
35 (ast[1]$MalSymbol).value() => string a1;
36
37 EVAL(ast[2], env) @=> MalObject value;
38 if( value.type == "error" )
39 {
40 return value;
41 }
42
43 env.set(a1, value);
44 return value;
45 }
46 else if( a0 == "let*" )
47 {
48 Env.create(env) @=> Env let_env;
49 Util.sequenceToMalObjectArray(ast[1]) @=> MalObject bindings[];
50
51 for( 0 => int i; i < bindings.size(); 2 +=> i)
52 {
53 (bindings[i]$MalSymbol).value() => string symbol;
54 EVAL(bindings[i+1], let_env) @=> MalObject value;
55
56 if( value.type == "error" )
57 {
58 return value;
59 }
60
61 let_env.set(symbol, value);
62 }
63
64 return EVAL(ast[2], let_env);
65 }
66 else if( a0 == "do" )
67 {
68 MalObject.slice(ast, 1) @=> MalObject forms[];
69 eval_ast(MalList.create(forms), env) @=> MalObject value;
70
71 if( value.type == "error" )
72 {
73 return value;
74 }
75
76 (value$MalList).value() @=> MalObject values[];
77
78 return values[values.size()-1];
79 }
80 else if( a0 == "if" )
81 {
82 EVAL(ast[1], env) @=> MalObject condition;
83
84 if( condition.type == "error" )
85 {
86 return condition;
87 }
88
89 if( !(condition.type == "nil") && !(condition.type == "false") )
90 {
91 return EVAL(ast[2], env);
92 }
93 else
94 {
95 if( ast.size() < 4 )
96 {
f823ec25 97 return Constants.NIL;
674e1c56
VS
98 }
99 else
100 {
101 return EVAL(ast[3], env);
102 }
103 }
104 }
105 else if( a0 == "fn*" )
106 {
107 (ast[1]$MalList).value() @=> MalObject arg_values[];
108 string args[arg_values.size()];
109
110 for( 0 => int i; i < arg_values.size(); i++ )
111 {
112 (arg_values[i]$MalSymbol).value() => args[i];
113 }
114
115 ast[2] @=> MalObject _ast;
116
117 return Func.create(env, args, _ast);
118 }
119 }
120
121 eval_ast(m, env) @=> MalObject result;
122 if( result.type == "error" )
123 {
124 return result;
125 }
126
127 (result$MalList).value() @=> MalObject values[];
128 values[0].type => string type;
129 MalObject.slice(values, 1) @=> MalObject args[];
130
131 if( type == "subr" )
132 {
133 values[0]$MalSubr @=> MalSubr subr;
134 return subr.call(args);
135 }
136 else // type == "func"
137 {
138 values[0]$Func @=> Func func;
139 Env.create(func.env, func.args, args) @=> Env eval_env;
140 return EVAL(func.ast, eval_env);
141 }
142 }
143 else
144 {
145 eval_ast(m, env) @=> MalObject result;
146 return result;
147 }
148}
149
150fun MalObject eval_ast(MalObject m, Env env)
151{
152 m.type => string type;
153
154 if( type == "symbol" )
155 {
156 (m$MalSymbol).value() => string symbol;
157 return env.get(symbol);
158 }
159 else if( type == "list" || type == "vector" || type == "hashmap" )
160 {
161 (m$MalList).value() @=> MalObject values[];
162 MalObject results[values.size()];
163
164 if( type != "hashmap" )
165 {
166 for( 0 => int i; i < values.size(); i++ )
167 {
168 EVAL(values[i], env) @=> MalObject result;
169
170 if( result.type == "error" )
171 {
172 return result;
173 }
174
175 result @=> results[i];
176 }
177 }
178 else
179 {
180 for( 0 => int i; i < values.size(); i++ )
181 {
182 if( i % 2 == 0 )
183 {
184 values[i] @=> results[i];
185 }
186 else
187 {
188 EVAL(values[i], env) @=> results[i];
189 }
190 }
191 }
192
193 if( type == "list" )
194 {
195 return MalList.create(results);
196 }
197 else if( type == "vector" )
198 {
199 return MalVector.create(results);
200 }
201 else if( type == "hashmap" )
202 {
203 return MalHashMap.create(results);
204 }
205 }
206 else
207 {
208 return m;
209 }
210}
211
212fun string PRINT(MalObject m)
213{
214 return Printer.pr_str(m, true);
215}
216
217Env.create(null) @=> Env repl_env;
218for( 0 => int i; i < Core.names.size(); i++ )
219{
220 Core.names[i] => string name;
221 repl_env.set(name, Core.ns[name]);
222}
223
224fun string rep(string input)
225{
226 READ(input) @=> MalObject m;
227
228 if( m.type == "error" )
229 {
230 return Status.toMessage(m$MalError);
231 }
232
233 EVAL(m, repl_env) @=> MalObject result;
234 if( result.type == "error" )
235 {
236 return Status.toMessage(result$MalError);
237 }
238
239 return PRINT(result);
240}
241
242rep("(def! not (fn* (a) (if a false true)))");
243
244fun void main()
245{
246 ConsoleInput stdin;
247 string input;
248
249 while( true )
250 {
251 stdin.prompt("user>") => now;
252 stdin.getLine() => input;
253 rep(input) => string output;
254
255 if( output == "empty input" )
256 {
257 // proceed immediately with prompt
258 }
259 else
260 {
261 Util.println(output);
262 }
263 }
264}
265
266main();