Merge pull request #256 from vvakame/impl-ts
[jackhill/mal.git] / cpp / step3_env.cpp
CommitLineData
dc9b184b
ST
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
10malValuePtr READ(const String& input);
11String PRINT(malValuePtr ast);
12
13static ReadLine s_readLine("~/.mal-history");
14
494c1608
ST
15static malEnvPtr replEnv(new malEnv);
16
dc9b184b
ST
17int main(int argc, char* argv[])
18{
19 String prompt = "user> ";
20 String input;
dc9b184b
ST
21 installCore(replEnv);
22 while (s_readLine.get(prompt, input)) {
23 String out;
24 try {
25 out = rep(input, replEnv);
26 }
27 catch (malEmptyInputException&) {
28 continue; // no output
29 }
30 catch (String& s) {
31 out = s;
32 };
33 std::cout << out << "\n";
34 }
35 return 0;
36}
37
38String rep(const String& input, malEnvPtr env)
39{
40 return PRINT(EVAL(READ(input), env));
41}
42
43malValuePtr READ(const String& input)
44{
45 return readStr(input);
46}
47
48malValuePtr EVAL(malValuePtr ast, malEnvPtr env)
49{
494c1608
ST
50 if (!env) {
51 env = replEnv;
52 }
dc9b184b
ST
53 const malList* list = DYNAMIC_CAST(malList, ast);
54 if (!list || (list->count() == 0)) {
55 return ast->eval(env);
56 }
57
58 // From here on down we are evaluating a non-empty list.
59 // First handle the special forms.
60 if (const malSymbol* symbol = DYNAMIC_CAST(malSymbol, list->item(0))) {
61 String special = symbol->value();
62 int argCount = list->count() - 1;
63
64 if (special == "def!") {
65 checkArgsIs("def!", 2, argCount);
66 const malSymbol* id = VALUE_CAST(malSymbol, list->item(1));
67 return env->set(id->value(), EVAL(list->item(2), env));
68 }
69
70 if (special == "let*") {
71 checkArgsIs("let*", 2, argCount);
72 const malSequence* bindings =
73 VALUE_CAST(malSequence, list->item(1));
74 int count = checkArgsEven("let*", bindings->count());
75 malEnvPtr inner(new malEnv(env));
76 for (int i = 0; i < count; i += 2) {
77 const malSymbol* var =
78 VALUE_CAST(malSymbol, bindings->item(i));
79 inner->set(var->value(), EVAL(bindings->item(i+1), inner));
80 }
81 return EVAL(list->item(2), inner);
82 }
83 }
84
85 // Now we're left with the case of a regular list to be evaluated.
86 std::unique_ptr<malValueVec> items(list->evalItems(env));
87 malValuePtr op = items->at(0);
494c1608 88 return APPLY(op, items->begin()+1, items->end());
dc9b184b
ST
89}
90
91String PRINT(malValuePtr ast)
92{
93 return ast->print(true);
94}
95
494c1608 96malValuePtr APPLY(malValuePtr op, malValueIter argsBegin, malValueIter argsEnd)
dc9b184b
ST
97{
98 const malApplicable* handler = DYNAMIC_CAST(malApplicable, op);
0997015d
ST
99 MAL_CHECK(handler != NULL,
100 "\"%s\" is not applicable", op->print(true).c_str());
dc9b184b 101
494c1608 102 return handler->apply(argsBegin, argsEnd);
dc9b184b 103}
cb252845
ST
104
105// Added to keep the linker happy at step A
106malValuePtr readline(const String& prompt)
107{
108 String input;
109 if (s_readLine.get(prompt, input)) {
110 return mal::string(input);
111 }
112 return mal::nilValue();
113}
114