Merge pull request #361 from asarhaddon/exercise-native-implementations
[jackhill/mal.git] / d / step2_eval.d
1 import std.algorithm;
2 import std.array;
3 import std.stdio;
4 import std.string;
5 import readline;
6 import reader;
7 import printer;
8 import types;
9
10 alias Env = MalType[string];
11
12 MalType READ(string str)
13 {
14 return read_str(str);
15 }
16
17 MalType eval_ast(MalType ast, Env env)
18 {
19 if (auto sym = cast(MalSymbol)ast)
20 {
21 auto v = (sym.name in env);
22 if (v is null) throw new Exception("'" ~ sym.name ~ "' not found");
23 return *v;
24 }
25 else if (auto lst = cast(MalList)ast)
26 {
27 auto el = array(lst.elements.map!(e => EVAL(e, env)));
28 return new MalList(el);
29 }
30 else if (auto lst = cast(MalVector)ast)
31 {
32 auto el = array(lst.elements.map!(e => EVAL(e, env)));
33 return new MalVector(el);
34 }
35 else if (auto hm = cast(MalHashmap)ast)
36 {
37 typeof(hm.data) new_data;
38 foreach (string k, MalType v; hm.data)
39 {
40 new_data[k] = EVAL(v, env);
41 }
42 return new MalHashmap(new_data);
43 }
44 else
45 {
46 return ast;
47 }
48 }
49
50 MalType EVAL(MalType ast, Env env)
51 {
52 if (typeid(ast) != typeid(MalList))
53 {
54 return eval_ast(ast, env);
55 }
56 if ((cast(MalList) ast).elements.length == 0)
57 {
58 return ast;
59 }
60
61 auto el = verify_cast!MalList(eval_ast(ast, env));
62 auto fobj = verify_cast!MalBuiltinFunc(el.elements[0]);
63 auto args = el.elements[1..$];
64 return fobj.fn(args);
65 }
66
67 string PRINT(MalType ast)
68 {
69 return pr_str(ast);
70 }
71
72 string rep(string str, Env env)
73 {
74 return PRINT(EVAL(READ(str), env));
75 }
76
77 static MalType mal_add(MalType[] a ...)
78 {
79 verify_args_count(a, 2);
80 MalInteger i0 = verify_cast!MalInteger(a[0]);
81 MalInteger i1 = verify_cast!MalInteger(a[1]);
82 return new MalInteger(i0.val + i1.val);
83 }
84
85 static MalType mal_sub(MalType[] a ...)
86 {
87 verify_args_count(a, 2);
88 MalInteger i0 = verify_cast!MalInteger(a[0]);
89 MalInteger i1 = verify_cast!MalInteger(a[1]);
90 return new MalInteger(i0.val - i1.val);
91 }
92
93 static MalType mal_mul(MalType[] a ...)
94 {
95 verify_args_count(a, 2);
96 MalInteger i0 = verify_cast!MalInteger(a[0]);
97 MalInteger i1 = verify_cast!MalInteger(a[1]);
98 return new MalInteger(i0.val * i1.val);
99 }
100
101 static MalType mal_div(MalType[] a ...)
102 {
103 verify_args_count(a, 2);
104 MalInteger i0 = verify_cast!MalInteger(a[0]);
105 MalInteger i1 = verify_cast!MalInteger(a[1]);
106 return new MalInteger(i0.val / i1.val);
107 }
108
109 void main()
110 {
111 Env repl_env;
112 repl_env["+"] = new MalBuiltinFunc(&mal_add, "+");
113 repl_env["-"] = new MalBuiltinFunc(&mal_sub, "-");
114 repl_env["*"] = new MalBuiltinFunc(&mal_mul, "*");
115 repl_env["/"] = new MalBuiltinFunc(&mal_div, "/");
116
117 for (;;)
118 {
119 string line = _readline("user> ");
120 if (line is null) break;
121 if (line.length == 0) continue;
122 try
123 {
124 writeln(rep(line, repl_env));
125 }
126 catch (Exception e)
127 {
128 writeln("Error: ", e.msg);
129 }
130 }
131 writeln("");
132 }