Commit | Line | Data |
---|---|---|
f82cb965 DM |
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 | { | |
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 | ||
50 | MalType 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 | ||
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 | } |