Merge pull request #256 from vvakame/impl-ts
[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;
16
17 int main(int argc, char* argv[])
18 {
19 String prompt = "user> ";
20 String input;
21 malEnvPtr replEnv(new malEnv);
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 while (s_readLine.get(prompt, input)) {
27 String out;
28 try {
29 out = rep(input, replEnv);
30 }
31 catch (malEmptyInputException&) {
32 continue; // no output
33 }
34 catch (String& s) {
35 out = s;
36 };
37 std::cout << out << "\n";
38 }
39 return 0;
40 }
41
42 String rep(const String& input, malEnvPtr env)
43 {
44 return PRINT(EVAL(READ(input), env));
45 }
46
47 malValuePtr READ(const String& input)
48 {
49 return readStr(input);
50 }
51
52 malValuePtr EVAL(malValuePtr ast, malEnvPtr env)
53 {
54 return ast->eval(env);
55 }
56
57 String PRINT(malValuePtr ast)
58 {
59 return ast->print(true);
60 }
61
62 malValuePtr APPLY(malValuePtr op, malValueIter argsBegin, malValueIter argsEnd)
63 {
64 const malApplicable* handler = DYNAMIC_CAST(malApplicable, op);
65 MAL_CHECK(handler != NULL,
66 "\"%s\" is not applicable", op->print(true).c_str());
67
68 return handler->apply(argsBegin, argsEnd);
69 }
70
71 #define ARG(type, name) type* name = VALUE_CAST(type, *argsBegin++)
72
73 #define CHECK_ARGS_IS(expected) \
74 checkArgsIs(name.c_str(), expected, std::distance(argsBegin, argsEnd))
75
76 #define CHECK_ARGS_BETWEEN(min, max) \
77 checkArgsBetween(name.c_str(), min, max, std::distance(argsBegin, argsEnd))
78
79
80 static malValuePtr builtIn_add(const String& name,
81 malValueIter argsBegin, malValueIter argsEnd)
82 {
83 CHECK_ARGS_IS(2);
84 ARG(malInteger, lhs);
85 ARG(malInteger, rhs);
86 return mal::integer(lhs->value() + rhs->value());
87 }
88
89 static malValuePtr builtIn_sub(const String& name,
90 malValueIter argsBegin, malValueIter argsEnd)
91 {
92 int argCount = CHECK_ARGS_BETWEEN(1, 2);
93 ARG(malInteger, lhs);
94 if (argCount == 1) {
95 return mal::integer(- lhs->value());
96 }
97 ARG(malInteger, rhs);
98 return mal::integer(lhs->value() - rhs->value());
99 }
100
101 static malValuePtr builtIn_mul(const String& name,
102 malValueIter argsBegin, malValueIter argsEnd)
103 {
104 CHECK_ARGS_IS(2);
105 ARG(malInteger, lhs);
106 ARG(malInteger, rhs);
107 return mal::integer(lhs->value() * rhs->value());
108 }
109
110 static malValuePtr builtIn_div(const String& name,
111 malValueIter argsBegin, malValueIter argsEnd)
112 {
113 CHECK_ARGS_IS(2);
114 ARG(malInteger, lhs);
115 ARG(malInteger, rhs);
116 MAL_CHECK(rhs->value() != 0, "Division by zero"); \
117 return mal::integer(lhs->value() / rhs->value());
118 }