1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-20 10:07:45 +03:00
mal/cpp/step2_eval.cpp
Stephen Thirlwall 494c160856 Don't pass an env to apply
Due to some initial confusion about which env to pass to the eval
builtin, I'd been needlessly passing an env to apply all along.

No need.
2015-12-15 11:22:25 +11:00

119 lines
3.0 KiB
C++

#include "MAL.h"
#include "Environment.h"
#include "ReadLine.h"
#include "Types.h"
#include <iostream>
#include <memory>
malValuePtr READ(const String& input);
String PRINT(malValuePtr ast);
static ReadLine s_readLine("~/.mal-history");
static malBuiltIn::ApplyFunc
builtIn_add, builtIn_sub, builtIn_mul, builtIn_div;
int main(int argc, char* argv[])
{
String prompt = "user> ";
String input;
malEnvPtr replEnv(new malEnv);
replEnv->set("+", mal::builtin("+", &builtIn_add));
replEnv->set("-", mal::builtin("-", &builtIn_sub));
replEnv->set("*", mal::builtin("+", &builtIn_mul));
replEnv->set("/", mal::builtin("/", &builtIn_div));
while (s_readLine.get(prompt, input)) {
String out;
try {
out = rep(input, replEnv);
}
catch (malEmptyInputException&) {
continue; // no output
}
catch (String& s) {
out = s;
};
std::cout << out << "\n";
}
return 0;
}
String rep(const String& input, malEnvPtr env)
{
return PRINT(EVAL(READ(input), env));
}
malValuePtr READ(const String& input)
{
return readStr(input);
}
malValuePtr EVAL(malValuePtr ast, malEnvPtr env)
{
return ast->eval(env);
}
String PRINT(malValuePtr ast)
{
return ast->print(true);
}
malValuePtr APPLY(malValuePtr op, malValueIter argsBegin, malValueIter argsEnd)
{
const malApplicable* handler = DYNAMIC_CAST(malApplicable, op);
MAL_CHECK(handler != NULL,
"\"%s\" is not applicable", op->print(true).c_str());
return handler->apply(argsBegin, argsEnd);
}
#define ARG(type, name) type* name = VALUE_CAST(type, *argsBegin++)
#define CHECK_ARGS_IS(expected) \
checkArgsIs(name.c_str(), expected, std::distance(argsBegin, argsEnd))
#define CHECK_ARGS_BETWEEN(min, max) \
checkArgsBetween(name.c_str(), min, max, std::distance(argsBegin, argsEnd))
static malValuePtr builtIn_add(const String& name,
malValueIter argsBegin, malValueIter argsEnd)
{
CHECK_ARGS_IS(2);
ARG(malInteger, lhs);
ARG(malInteger, rhs);
return mal::integer(lhs->value() + rhs->value());
}
static malValuePtr builtIn_sub(const String& name,
malValueIter argsBegin, malValueIter argsEnd)
{
int argCount = CHECK_ARGS_BETWEEN(1, 2);
ARG(malInteger, lhs);
if (argCount == 1) {
return mal::integer(- lhs->value());
}
ARG(malInteger, rhs);
return mal::integer(lhs->value() - rhs->value());
}
static malValuePtr builtIn_mul(const String& name,
malValueIter argsBegin, malValueIter argsEnd)
{
CHECK_ARGS_IS(2);
ARG(malInteger, lhs);
ARG(malInteger, rhs);
return mal::integer(lhs->value() * rhs->value());
}
static malValuePtr builtIn_div(const String& name,
malValueIter argsBegin, malValueIter argsEnd)
{
CHECK_ARGS_IS(2);
ARG(malInteger, lhs);
ARG(malInteger, rhs);
MAL_CHECK(rhs->value() != 0, "Division by zero"); \
return mal::integer(lhs->value() / rhs->value());
}