Merge pull request #383 from asarhaddon/ada2tco-do
[jackhill/mal.git] / d / step2_eval.d
CommitLineData
f82cb965
DM
1import std.algorithm;
2import std.array;
3import std.stdio;
4import std.string;
5import readline;
6import reader;
7import printer;
8import types;
9
10alias Env = MalType[string];
11
12MalType READ(string str)
13{
14 return read_str(str);
15}
16
17MalType eval_ast(MalType ast, Env env)
18{
bc33c480 19 if (auto sym = cast(MalSymbol)ast)
f82cb965 20 {
f82cb965
DM
21 auto v = (sym.name in env);
22 if (v is null) throw new Exception("'" ~ sym.name ~ "' not found");
23 return *v;
24 }
2eb69541 25 else if (auto lst = cast(MalList)ast)
f82cb965 26 {
f82cb965
DM
27 auto el = array(lst.elements.map!(e => EVAL(e, env)));
28 return new MalList(el);
29 }
2eb69541 30 else if (auto lst = cast(MalVector)ast)
f82cb965 31 {
f82cb965
DM
32 auto el = array(lst.elements.map!(e => EVAL(e, env)));
33 return new MalVector(el);
34 }
2eb69541 35 else if (auto hm = cast(MalHashmap)ast)
f82cb965 36 {
f82cb965
DM
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
50MalType EVAL(MalType ast, Env env)
51{
52 if (typeid(ast) != typeid(MalList))
53 {
54 return eval_ast(ast, env);
55 }
efa2daef
JM
56 if ((cast(MalList) ast).elements.length == 0)
57 {
58 return ast;
59 }
f82cb965
DM
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
67string PRINT(MalType ast)
68{
69 return pr_str(ast);
70}
71
72string rep(string str, Env env)
73{
74 return PRINT(EVAL(READ(str), env));
75}
76
77static 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
85static 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
93static 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
101static 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
109void 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}