1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-20 18:18:51 +03:00
mal/cpp/Types.cpp

322 lines
7.7 KiB
C++
Raw Normal View History

2015-03-26 14:25:50 +03:00
#include "Debug.h"
#include "Environment.h"
2015-03-26 14:25:50 +03:00
#include "Types.h"
#include <algorithm>
#include <memory>
#include <typeinfo>
namespace mal {
2015-03-27 04:52:07 +03:00
malValuePtr boolean(bool value) {
return value ? trueValue() : falseValue();
}
malValuePtr builtin(const String& name, malBuiltIn::ApplyFunc handler) {
return malValuePtr(new malBuiltIn(name, handler));
};
2015-03-26 14:25:50 +03:00
malValuePtr falseValue() {
static malValuePtr c(new malConstant("false"));
return malValuePtr(c);
};
malValuePtr hash(malValueIter argsBegin, malValueIter argsEnd) {
return malValuePtr(new malHash(argsBegin, argsEnd));
}
2015-03-26 14:25:50 +03:00
malValuePtr integer(int value) {
return malValuePtr(new malInteger(value));
};
2015-03-26 14:25:50 +03:00
malValuePtr integer(const String& token) {
return integer(std::stoi(token));
};
malValuePtr keyword(const String& token) {
return malValuePtr(new malKeyword(token));
};
2015-03-27 04:52:07 +03:00
malValuePtr lambda(const StringVec& bindings,
malValuePtr body, malEnvPtr env) {
return malValuePtr(new malLambda(bindings, body, env));
}
2015-03-26 14:25:50 +03:00
malValuePtr list(malValueVec* items) {
return malValuePtr(new malList(items));
};
2015-03-27 04:52:07 +03:00
malValuePtr list(malValueIter begin, malValueIter end) {
return malValuePtr(new malList(begin, end));
};
2015-03-26 14:25:50 +03:00
malValuePtr list(malValuePtr a) {
malValueVec* items = new malValueVec(1);
items->at(0) = a;
return malValuePtr(new malList(items));
}
malValuePtr list(malValuePtr a, malValuePtr b) {
malValueVec* items = new malValueVec(2);
items->at(0) = a;
items->at(1) = b;
return malValuePtr(new malList(items));
}
malValuePtr list(malValuePtr a, malValuePtr b, malValuePtr c) {
malValueVec* items = new malValueVec(3);
items->at(0) = a;
items->at(1) = b;
items->at(2) = c;
return malValuePtr(new malList(items));
}
malValuePtr nilValue() {
static malValuePtr c(new malConstant("nil"));
return malValuePtr(c);
};
malValuePtr string(const String& token) {
return malValuePtr(new malString(token));
}
malValuePtr symbol(const String& token) {
return malValuePtr(new malSymbol(token));
};
malValuePtr trueValue() {
static malValuePtr c(new malConstant("true"));
return malValuePtr(c);
};
malValuePtr vector(malValueVec* items) {
return malValuePtr(new malVector(items));
};
};
malValuePtr malBuiltIn::apply(malValueIter argsBegin,
malValueIter argsEnd,
2015-03-27 03:03:28 +03:00
malEnvPtr env) const
{
return m_handler(m_name, argsBegin, argsEnd, env);
}
2015-03-26 14:25:50 +03:00
static String makeHashKey(malValuePtr key)
{
if (const malString* skey = DYNAMIC_CAST(malString, key)) {
2015-03-26 14:25:50 +03:00
return skey->print(true);
}
else if (const malKeyword* kkey = DYNAMIC_CAST(malKeyword, key)) {
2015-03-26 14:25:50 +03:00
return kkey->print(true);
}
ASSERT(false, "%s is not a string or keyword", key->print(true).c_str());
}
static malHash::Map addToMap(malHash::Map& map,
malValueIter argsBegin, malValueIter argsEnd)
2015-03-26 14:25:50 +03:00
{
// This is intended to be called with pre-evaluated arguments.
for (auto it = argsBegin; it != argsEnd; ++it) {
String key = makeHashKey(*it++);
map[key] = *it;
2015-03-26 14:25:50 +03:00
}
2015-03-26 14:25:50 +03:00
return map;
}
static malHash::Map createMap(malValueIter argsBegin, malValueIter argsEnd)
{
ASSERT(std::distance(argsBegin, argsEnd) % 2 == 0,
"hash-map requires an even-sized list");
malHash::Map map;
return addToMap(map, argsBegin, argsEnd);
}
malHash::malHash(malValueIter argsBegin, malValueIter argsEnd)
: m_map(createMap(argsBegin, argsEnd))
2015-03-26 14:25:50 +03:00
{
}
String malHash::print(bool readably) const
{
String s = "{";
auto it = m_map.begin(), end = m_map.end();
if (it != end) {
s += it->first + " " + it->second->print(readably);
++it;
}
for ( ; it != end; ++it) {
s += " " + it->first + " " + it->second->print(readably);
}
return s + "}";
}
2015-03-27 04:52:07 +03:00
bool malHash::doIsEqualTo(const malValue* rhs) const
{
const malHash::Map& r_map = static_cast<const malHash*>(rhs)->m_map;
if (m_map.size() != r_map.size()) {
return false;
}
for (auto it0 = m_map.begin(), end0 = m_map.end(), it1 = r_map.begin();
it0 != end0; ++it0, ++it1) {
if (it0->first != it1->first) {
return false;
}
if (!it0->second->isEqualTo(it1->second.ptr())) {
return false;
}
}
return true;
}
malLambda::malLambda(const StringVec& bindings,
malValuePtr body, malEnvPtr env)
: m_bindings(bindings)
, m_body(body)
, m_env(env)
{
}
malValuePtr malLambda::apply(malValueIter argsBegin,
malValueIter argsEnd,
malEnvPtr) const
{
return EVAL(m_body, makeEnv(argsBegin, argsEnd));
}
malEnvPtr malLambda::makeEnv(malValueIter argsBegin, malValueIter argsEnd) const
{
return malEnvPtr(new malEnv(m_env, m_bindings, argsBegin, argsEnd));
}
2015-03-27 03:03:28 +03:00
malValuePtr malList::eval(malEnvPtr env)
{
if (count() == 0) {
return malValuePtr(this);
}
std::unique_ptr<malValueVec> items(evalItems(env));
auto it = items->begin();
malValuePtr op = *it;
return APPLY(op, ++it, items->end(), env);
}
2015-03-26 14:25:50 +03:00
String malList::print(bool readably) const
{
return '(' + malSequence::print(readably) + ')';
}
2015-03-27 03:03:28 +03:00
malValuePtr malValue::eval(malEnvPtr env)
{
// Default case of eval is just to return the object itself.
return malValuePtr(this);
}
2015-03-27 04:52:07 +03:00
bool malValue::isEqualTo(const malValue* rhs) const
{
// Special-case. Vectors and Lists can be compared.
bool matchingTypes = (typeid(*this) == typeid(*rhs)) ||
(dynamic_cast<const malSequence*>(this) &&
dynamic_cast<const malSequence*>(rhs));
return matchingTypes && doIsEqualTo(rhs);
}
bool malValue::isTrue() const
{
return (this != mal::falseValue().ptr())
&& (this != mal::nilValue().ptr());
}
2015-03-26 14:25:50 +03:00
malSequence::malSequence(malValueVec* items)
: m_items(items)
{
}
2015-03-27 04:52:07 +03:00
malSequence::malSequence(malValueIter begin, malValueIter end)
: m_items(new malValueVec(begin, end))
{
}
2015-03-26 14:25:50 +03:00
malSequence::~malSequence()
{
delete m_items;
}
2015-03-27 04:52:07 +03:00
bool malSequence::doIsEqualTo(const malValue* rhs) const
{
const malSequence* rhsSeq = static_cast<const malSequence*>(rhs);
if (count() != rhsSeq->count()) {
return false;
}
for (malValueIter it0 = m_items->begin(),
it1 = rhsSeq->begin(),
end = m_items->end(); it0 != end; ++it0, ++it1) {
if (! (*it0)->isEqualTo((*it1).ptr())) {
return false;
}
}
return true;
}
2015-03-27 03:03:28 +03:00
malValueVec* malSequence::evalItems(malEnvPtr env) const
{
malValueVec* items = new malValueVec;;
items->reserve(count());
for (auto it = m_items->begin(), end = m_items->end(); it != end; ++it) {
items->push_back(EVAL(*it, env));
}
return items;
}
2015-03-26 14:25:50 +03:00
String malSequence::print(bool readably) const
{
String str;
auto end = m_items->cend();
auto it = m_items->cbegin();
if (it != end) {
str += (*it)->print(readably);
++it;
}
for ( ; it != end; ++it) {
str += " ";
str += (*it)->print(readably);
}
return str;
}
String malString::escapedValue() const
{
return escape(value());
}
String malString::print(bool readably) const
{
return readably ? escapedValue() : value();
}
2015-03-27 03:03:28 +03:00
malValuePtr malSymbol::eval(malEnvPtr env)
{
2015-03-27 03:03:28 +03:00
return env->get(value());
}
2015-03-27 03:03:28 +03:00
malValuePtr malVector::eval(malEnvPtr env)
{
return mal::vector(evalItems(env));
}
2015-03-26 14:25:50 +03:00
String malVector::print(bool readably) const
{
return '[' + malSequence::print(readably) + ']';
}