c++11: step 6
[jackhill/mal.git] / cpp / Core.cpp
1 #include "MAL.h"
2 #include "Environment.h"
3 #include "StaticList.h"
4 #include "Types.h"
5
6 #include <fstream>
7 #include <iostream>
8
9 #define CHECK_ARGS_IS(expected) \
10 checkArgsIs(name.c_str(), expected, \
11 std::distance(argsBegin, argsEnd))
12
13 #define CHECK_ARGS_BETWEEN(min, max) \
14 checkArgsBetween(name.c_str(), min, max, \
15 std::distance(argsBegin, argsEnd))
16
17 #define CHECK_ARGS_AT_LEAST(expected) \
18 checkArgsAtLeast(name.c_str(), expected, \
19 std::distance(argsBegin, argsEnd))
20
21 static String printValues(malValueIter begin, malValueIter end,
22 const String& sep, bool readably);
23
24 static StaticList<malBuiltIn*> handlers;
25
26 #define ARG(type, name) type* name = VALUE_CAST(type, *argsBegin++)
27
28 #define FUNCNAME(uniq) builtIn ## uniq
29 #define HRECNAME(uniq) handler ## uniq
30 #define BUILTIN_DEF(uniq, symbol) \
31 static malBuiltIn::ApplyFunc FUNCNAME(uniq); \
32 static StaticList<malBuiltIn*>::Node HRECNAME(uniq) \
33 (handlers, new malBuiltIn(symbol, FUNCNAME(uniq))); \
34 malValuePtr FUNCNAME(uniq)(const String& name, \
35 malValueIter argsBegin, malValueIter argsEnd, malEnvPtr env)
36
37 #define BUILTIN(symbol) BUILTIN_DEF(__LINE__, symbol)
38
39 #define BUILTIN_ISA(symbol, type) \
40 BUILTIN(symbol) { \
41 CHECK_ARGS_IS(1); \
42 return mal::boolean(DYNAMIC_CAST(type, *argsBegin)); \
43 }
44
45 #define BUILTIN_INTOP(op, checkDivByZero) \
46 BUILTIN(#op) { \
47 CHECK_ARGS_IS(2); \
48 ARG(malInteger, lhs); \
49 ARG(malInteger, rhs); \
50 if (checkDivByZero) { \
51 ASSERT(rhs->value() != 0, "Division by zero"); \
52 } \
53 return mal::integer(lhs->value() op rhs->value()); \
54 }
55
56 BUILTIN_ISA("list?", malList);
57
58 BUILTIN_INTOP(+, false);
59 BUILTIN_INTOP(/, true);
60 BUILTIN_INTOP(*, false);
61 BUILTIN_INTOP(%, true);
62
63 BUILTIN("-")
64 {
65 int argCount = CHECK_ARGS_BETWEEN(1, 2);
66 ARG(malInteger, lhs);
67 if (argCount == 1) {
68 return mal::integer(- lhs->value());
69 }
70
71 ARG(malInteger, rhs);
72 return mal::integer(lhs->value() - rhs->value());
73 }
74
75 BUILTIN("<=")
76 {
77 CHECK_ARGS_IS(2);
78 ARG(malInteger, lhs);
79 ARG(malInteger, rhs);
80
81 return mal::boolean(lhs->value() <= rhs->value());
82 }
83
84 BUILTIN("=")
85 {
86 CHECK_ARGS_IS(2);
87 const malValue* lhs = (*argsBegin++).ptr();
88 const malValue* rhs = (*argsBegin++).ptr();
89
90 return mal::boolean(lhs->isEqualTo(rhs));
91 }
92
93 BUILTIN("count")
94 {
95 CHECK_ARGS_IS(1);
96 if (*argsBegin == mal::nilValue()) {
97 return mal::integer(0);
98 }
99
100 ARG(malSequence, seq);
101 return mal::integer(seq->count());
102 }
103
104 BUILTIN("empty?")
105 {
106 CHECK_ARGS_IS(1);
107 ARG(malSequence, seq);
108
109 return mal::boolean(seq->isEmpty());
110 }
111
112 BUILTIN("eval")
113 {
114 CHECK_ARGS_IS(1);
115 return EVAL(*argsBegin, env->getRoot());
116 }
117
118 BUILTIN("hash-map")
119 {
120 return mal::hash(argsBegin, argsEnd);
121 }
122
123 BUILTIN("pr-str")
124 {
125 return mal::string(printValues(argsBegin, argsEnd, " ", true));
126 }
127
128 BUILTIN("println")
129 {
130 std::cout << printValues(argsBegin, argsEnd, " ", false) << "\n";
131 return mal::nilValue();
132 }
133
134 BUILTIN("prn")
135 {
136 std::cout << printValues(argsBegin, argsEnd, " ", true) << "\n";
137 return mal::nilValue();
138 }
139
140 BUILTIN("read-string")
141 {
142 CHECK_ARGS_IS(1);
143 ARG(malString, str);
144
145 return readStr(str->value());
146 }
147
148 BUILTIN("slurp")
149 {
150 CHECK_ARGS_IS(1);
151 ARG(malString, filename);
152
153 std::ios_base::openmode openmode =
154 std::ios::ate | std::ios::in | std::ios::binary;
155 std::ifstream file(filename->value().c_str(), openmode);
156 ASSERT(!file.fail(), "Cannot open %s", filename->value().c_str());
157
158 String data;
159 data.reserve(file.tellg());
160 file.seekg(0, std::ios::beg);
161 data.append(std::istreambuf_iterator<char>(file.rdbuf()),
162 std::istreambuf_iterator<char>());
163
164 return mal::string(data);
165 }
166
167 BUILTIN("str")
168 {
169 return mal::string(printValues(argsBegin, argsEnd, "", false));
170 }
171
172 void installCore(malEnvPtr env) {
173 for (auto it = handlers.begin(), end = handlers.end(); it != end; ++it) {
174 malBuiltIn* handler = *it;
175 env->set(handler->name(), handler);
176 }
177 }
178
179 static String printValues(malValueIter begin, malValueIter end,
180 const String& sep, bool readably)
181 {
182 String out;
183
184 if (begin != end) {
185 out += (*begin)->print(readably);
186 ++begin;
187 }
188
189 for ( ; begin != end; ++begin) {
190 out += sep;
191 out += (*begin)->print(readably);
192 }
193
194 return out;
195 }