c++11: step 2
[jackhill/mal.git] / cpp / step2_eval.cpp
1 #include "MAL.h"
2
3 #include "Environment.h"
4 #include "ReadLine.h"
5 #include "Types.h"
6
7 #include <iostream>
8 #include <memory>
9
10 malValuePtr READ(const String& input);
11 String PRINT(malValuePtr ast);
12
13 static ReadLine s_readLine("~/.mal-history");
14 static malBuiltIn::ApplyFunc
15 builtIn_add, builtIn_sub, builtIn_mul, builtIn_div, builtIn_hash_map;
16
17 int main(int argc, char* argv[])
18 {
19 String prompt = "user> ";
20 String input;
21 malEnv replEnv;
22 replEnv.set("+", mal::builtin("+", &builtIn_add));
23 replEnv.set("-", mal::builtin("-", &builtIn_sub));
24 replEnv.set("*", mal::builtin("+", &builtIn_mul));
25 replEnv.set("/", mal::builtin("/", &builtIn_div));
26 replEnv.set("hash-map", mal::builtin("hash-map", &builtIn_hash_map));
27 while (s_readLine.get(prompt, input)) {
28 String out;
29 try {
30 out = rep(input, replEnv);
31 }
32 catch (malEmptyInputException&) {
33 continue; // no output
34 }
35 catch (String& s) {
36 out = s;
37 };
38 std::cout << out << "\n";
39 }
40 return 0;
41 }
42
43 String rep(const String& input, malEnv& env)
44 {
45 return PRINT(EVAL(READ(input), env));
46 }
47
48 malValuePtr READ(const String& input)
49 {
50 return readStr(input);
51 }
52
53 malValuePtr EVAL(malValuePtr ast, malEnv& env)
54 {
55 return ast->eval(env);
56 }
57
58 String PRINT(malValuePtr ast)
59 {
60 return ast->print(true);
61 }
62
63 malValuePtr APPLY(malValuePtr op, malValueIter argsBegin, malValueIter argsEnd,
64 malEnv& env)
65 {
66 const malApplicable* handler = DYNAMIC_CAST(malApplicable, op);
67 ASSERT(handler != NULL, "\"%s\" is not applicable", op->print(true).c_str());
68
69 return handler->apply(argsBegin, argsEnd, env);
70 }
71
72 #define ARG(type, name) type* name = VALUE_CAST(type, *argsBegin++)
73
74 #define CHECK_ARGS_IS(expected) \
75 checkArgsIs(name.c_str(), expected, std::distance(argsBegin, argsEnd))
76
77 #define CHECK_ARGS_BETWEEN(min, max) \
78 checkArgsBetween(name.c_str(), min, max, std::distance(argsBegin, argsEnd))
79
80
81 static malValuePtr builtIn_add(const String& name,
82 malValueIter argsBegin, malValueIter argsEnd, malEnv& env)
83 {
84 CHECK_ARGS_IS(2);
85 ARG(malInteger, lhs);
86 ARG(malInteger, rhs);
87 return mal::integer(lhs->value() + rhs->value());
88 }
89
90 static malValuePtr builtIn_sub(const String& name,
91 malValueIter argsBegin, malValueIter argsEnd, malEnv& env)
92 {
93 int argCount = CHECK_ARGS_BETWEEN(1, 2);
94 ARG(malInteger, lhs);
95 if (argCount == 1) {
96 return mal::integer(- lhs->value());
97 }
98 ARG(malInteger, rhs);
99 return mal::integer(lhs->value() - rhs->value());
100 }
101
102 static malValuePtr builtIn_mul(const String& name,
103 malValueIter argsBegin, malValueIter argsEnd, malEnv& env)
104 {
105 CHECK_ARGS_IS(2);
106 ARG(malInteger, lhs);
107 ARG(malInteger, rhs);
108 return mal::integer(lhs->value() * rhs->value());
109 }
110
111 static malValuePtr builtIn_div(const String& name,
112 malValueIter argsBegin, malValueIter argsEnd, malEnv& env)
113 {
114 CHECK_ARGS_IS(2);
115 ARG(malInteger, lhs);
116 ARG(malInteger, rhs);
117 ASSERT(rhs->value() != 0, "Division by zero"); \
118 return mal::integer(lhs->value() / rhs->value());
119 }
120
121 static malValuePtr builtIn_hash_map(const String& name,
122 malValueIter argsBegin, malValueIter argsEnd, malEnv& env)
123 {
124 return mal::hash(argsBegin, argsEnd);
125 }