2 // @import types/boxed/*.ck
3 // @import types/MalObject.ck
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
21 // @import types/MalSubr.ck
22 // @import types/subr/*.ck
25 fun MalObject READ(string input)
27 return Reader.read_str(input);
30 fun MalObject EVAL(MalObject m, Env env)
34 if( m.type != "list" )
36 return eval_ast(m, env);
39 if( (m$MalList).value().size() == 0 )
44 (m$MalList).value() @=> MalObject ast[];
46 if( ast[0].type == "symbol" )
48 (ast[0]$MalSymbol).value() => string a0;
52 (ast[1]$MalSymbol).value() => string a1;
54 EVAL(ast[2], env) @=> MalObject value;
55 if( value.type == "error" )
63 else if( a0 == "let*" )
65 Env.create(env) @=> Env let_env;
66 Util.sequenceToMalObjectArray(ast[1]) @=> MalObject bindings[];
68 for( 0 => int i; i < bindings.size(); 2 +=> i)
70 (bindings[i]$MalSymbol).value() => string symbol;
71 EVAL(bindings[i+1], let_env) @=> MalObject value;
73 if( value.type == "error" )
78 let_env.set(symbol, value);
87 MalObject.slice(ast, 1, ast.size()-1) @=> MalObject forms[];
88 eval_ast(MalList.create(forms), env) @=> MalObject value;
90 if( value.type == "error" )
95 // HACK: this assumes do gets at least one argument...
96 ast[ast.size()-1] @=> m;
101 EVAL(ast[1], env) @=> MalObject condition;
103 if( condition.type == "error" )
108 if( !(condition.type == "nil") && !(condition.type == "false") )
117 return Constants.NIL;
126 else if( a0 == "fn*" )
128 (ast[1]$MalList).value() @=> MalObject arg_values[];
129 string args[arg_values.size()];
131 for( 0 => int i; i < arg_values.size(); i++ )
133 (arg_values[i]$MalSymbol).value() => args[i];
136 ast[2] @=> MalObject _ast;
138 return Func.create(env, args, _ast);
142 eval_ast(m, env) @=> MalObject result;
143 if( result.type == "error" )
148 (result$MalList).value() @=> MalObject values[];
149 values[0].type => string type;
150 MalObject.slice(values, 1) @=> MalObject args[];
154 values[0]$MalSubr @=> MalSubr subr;
155 return subr.call(args);
157 else // type == "func"
159 values[0]$Func @=> Func func;
160 Env.create(func.env, func.args, args) @=> Env eval_env;
168 fun MalObject eval_ast(MalObject m, Env env)
170 m.type => string type;
172 if( type == "symbol" )
174 (m$MalSymbol).value() => string symbol;
175 return env.get(symbol);
177 else if( type == "list" || type == "vector" || type == "hashmap" )
179 (m$MalList).value() @=> MalObject values[];
180 MalObject results[values.size()];
182 if( type != "hashmap" )
184 for( 0 => int i; i < values.size(); i++ )
186 EVAL(values[i], env) @=> MalObject result;
188 if( result.type == "error" )
193 result @=> results[i];
198 for( 0 => int i; i < values.size(); i++ )
202 values[i] @=> results[i];
206 EVAL(values[i], env) @=> results[i];
213 return MalList.create(results);
215 else if( type == "vector" )
217 return MalVector.create(results);
219 else if( type == "hashmap" )
221 return MalHashMap.create(results);
230 fun string PRINT(MalObject m)
232 return Printer.pr_str(m, true);
235 Env.create(null) @=> Env repl_env;
236 for( 0 => int i; i < Core.names.size(); i++ )
238 Core.names[i] => string name;
239 repl_env.set(name, Core.ns[name]);
243 class MalEval extends MalSubr
245 fun MalObject call(MalObject args[])
247 args[0] @=> MalObject m;
248 return EVAL(args[0], repl_env);
251 fun MalObject apply(MalObject f, MalObject args[])
253 if( f.type == "subr" )
255 return (f$MalSubr).call(args);
257 else // f.type == "func"
259 f$Func @=> Func func;
260 Env.create(func.env, func.args, args) @=> Env eval_env;
261 return EVAL(func.ast, eval_env);
266 new MalEval @=> MalEval eval;
267 repl_env.set("eval", new MalEval);
268 eval @=> (repl_env.get("swap!")$MalSubr).eval;
270 fun MalObject[] MalArgv(string args[])
274 for( 1 => int i; i < args.size(); i++ )
276 values << MalString.create(args[i]);
282 // NOTE: normally I'd use \0, but strings are null-terminated...
283 String.split(Std.getenv("CHUCK_ARGS"), "\a") @=> string args[];
284 repl_env.set("*ARGV*", MalList.create(MalArgv(args)));
286 fun string errorMessage(MalObject m)
288 (m$MalError).value() @=> MalObject value;
289 return "exception: " + Printer.pr_str(value, true);
292 fun string rep(string input)
294 READ(input) @=> MalObject m;
296 if( m.type == "error" )
298 return errorMessage(m);
301 EVAL(m, repl_env) @=> MalObject result;
302 if( result.type == "error" )
304 return errorMessage(result);
307 return PRINT(result);
310 rep("(def! not (fn* (a) (if a false true)))");
311 rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
319 Readline.readline("user> ") => string input;
323 rep(input) => string output;
325 if( output == "empty input" )
327 // proceed immediately with prompt
331 Util.println(output);
341 if( args.size() > 0 )
343 args[0] => string filename;
344 rep("(load-file \"" + filename + "\")");