Haxe: step7-A, hash-maps, metadata, self-hosting.
[jackhill/mal.git] / haxe / Step3_env.hx
1 import types.Types.MalType;
2 import types.Types.*;
3 import reader.*;
4 import printer.*;
5 import env.*;
6
7 class Step3_env {
8 // READ
9 static function READ(str:String):MalType {
10 return Reader.read_str(str);
11 }
12
13 // EVAL
14 static function eval_ast(ast:MalType, env:Env) {
15 return switch (ast) {
16 case MalSymbol(s): env.get(ast);
17 case MalList(l):
18 MalList(l.map(function(x) { return EVAL(x, env); }));
19 case MalVector(l):
20 MalVector(l.map(function(x) { return EVAL(x, env); }));
21 case MalHashMap(m):
22 var new_map = new Map<String,MalType>();
23 for (k in m.keys()) {
24 new_map[k] = EVAL(m[k], env);
25 }
26 MalHashMap(new_map);
27 case _: ast;
28 }
29 }
30
31 static function EVAL(ast:MalType, env:Env):MalType {
32 if (!list_Q(ast)) { return eval_ast(ast, env); }
33
34 // apply
35 var alst = switch (ast) { case MalList(lst): lst; case _: []; }
36
37 switch (alst[0]) {
38 case MalSymbol("def!"):
39 return env.set(alst[1], EVAL(alst[2], env));
40 case MalSymbol("let*"):
41 var let_env = new Env(env);
42 switch (alst[1]) {
43 case MalList(l) | MalVector(l):
44 for (i in 0...l.length) {
45 if ((i%2) > 0) { continue; }
46 let_env.set(l[i], EVAL(l[i+1], let_env));
47 }
48 case _: throw "Invalid let*";
49 }
50 return EVAL(alst[2], let_env);
51 case _:
52 var el = eval_ast(ast, env);
53 var lst = _list(el);
54 switch (first(el)) {
55 case MalFunc(f,_,_,_,_,_): return f(_list(el).slice(1));
56 case _: throw "Call of non-function";
57 }
58 }
59 }
60
61 // PRINT
62 static function PRINT(exp:MalType):String {
63 return Printer.pr_str(exp, true);
64 }
65
66 // repl
67 static function NumOp(op):MalType {
68 return MalFunc(function(args:Array<MalType>) {
69 return switch (args) {
70 case [MalInt(a), MalInt(b)]: MalInt(op(a,b));
71 case _: throw "Invalid numeric op call";
72 }
73
74 },null,null,null,false,nil);
75 }
76 static var repl_env = new Env(null);
77
78 static function rep(line:String):String {
79 return PRINT(EVAL(READ(line), repl_env));
80 }
81
82 public static function main() {
83 #if js
84 #error "JS not supported yet"
85 #end
86 repl_env.set(MalSymbol("+"), NumOp(function(a,b) {return a+b;}));
87 repl_env.set(MalSymbol("-"), NumOp(function(a,b) {return a-b;}));
88 repl_env.set(MalSymbol("*"), NumOp(function(a,b) {return a*b;}));
89 repl_env.set(MalSymbol("/"), NumOp(function(a,b) {return Std.int(a/b);}));
90 while (true) {
91 try {
92 Sys.print("user> ");
93 var line = Sys.stdin().readLine();
94 if (line == "") { continue; }
95 Sys.println(rep(line));
96 } catch (exc:BlankLine) {
97 continue;
98 } catch (exc:haxe.io.Eof) {
99 Sys.exit(0);
100 } catch (exc:Dynamic) {
101 Sys.println(exc);
102 }
103 }
104 }
105 }