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

501 lines
12 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 09:24:20 +03:00
malValuePtr atom(malValuePtr value) {
return malValuePtr(new malAtom(value));
};
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);
};
2015-03-27 08:38:23 +03:00
malValuePtr hash(const malHash::Map& map) {
return malValuePtr(new malHash(map));
}
malValuePtr hash(malValueIter argsBegin, malValueIter argsEnd,
bool isEvaluated) {
return malValuePtr(new malHash(argsBegin, argsEnd, isEvaluated));
}
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));
}
2015-03-27 08:35:47 +03:00
malValuePtr macro(const malLambda& lambda) {
return malValuePtr(new malLambda(lambda, true));
};
2015-03-26 14:25:50 +03:00
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));
};
2015-03-27 08:38:23 +03:00
malValuePtr vector(malValueIter begin, malValueIter end) {
return malValuePtr(new malVector(begin, end));
};
2015-03-26 14:25:50 +03:00
};
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);
}
MAL_FAIL("%s is not a string or keyword", key->print(true).c_str());
2015-03-26 14:25:50 +03:00
}
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)
{
MAL_CHECK(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, bool isEvaluated)
: m_map(createMap(argsBegin, argsEnd))
, m_isEvaluated(isEvaluated)
2015-03-26 14:25:50 +03:00
{
}
2015-03-27 08:38:23 +03:00
malHash::malHash(const malHash::Map& map)
: m_map(map)
, m_isEvaluated(true)
2015-03-27 08:38:23 +03:00
{
}
malValuePtr
malHash::assoc(malValueIter argsBegin, malValueIter argsEnd) const
{
MAL_CHECK(std::distance(argsBegin, argsEnd) % 2 == 0,
2015-03-27 08:38:23 +03:00
"assoc requires an even-sized list");
malHash::Map map(m_map);
return mal::hash(addToMap(map, argsBegin, argsEnd));
}
bool malHash::contains(malValuePtr key) const
{
auto it = m_map.find(makeHashKey(key));
return it != m_map.end();
}
malValuePtr
malHash::dissoc(malValueIter argsBegin, malValueIter argsEnd) const
{
malHash::Map map(m_map);
for (auto it = argsBegin; it != argsEnd; ++it) {
String key = makeHashKey(*it);
map.erase(key);
}
return mal::hash(map);
}
malValuePtr malHash::eval(malEnvPtr env)
{
if (m_isEvaluated) {
return malValuePtr(this);
}
malHash::Map map;
for (auto it = m_map.begin(), end = m_map.end(); it != end; ++it) {
map[it->first] = EVAL(it->second, env);
}
return mal::hash(map);
}
2015-03-27 08:38:23 +03:00
malValuePtr malHash::get(malValuePtr key) const
{
auto it = m_map.find(makeHashKey(key));
return it == m_map.end() ? mal::nilValue() : it->second;
}
malValuePtr malHash::keys() const
{
malValueVec* keys = new malValueVec();
keys->reserve(m_map.size());
for (auto it = m_map.begin(), end = m_map.end(); it != end; ++it) {
if (it->first[0] == '"') {
keys->push_back(mal::string(unescape(it->first)));
}
else {
keys->push_back(mal::keyword(it->first));
}
}
return mal::list(keys);
}
malValuePtr malHash::values() const
{
malValueVec* keys = new malValueVec();
keys->reserve(m_map.size());
for (auto it = m_map.begin(), end = m_map.end(); it != end; ++it) {
keys->push_back(it->second);
}
return mal::list(keys);
}
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)
2015-03-27 08:35:47 +03:00
, m_isMacro(false)
{
}
2015-03-27 09:24:20 +03:00
malLambda::malLambda(const malLambda& that, malValuePtr meta)
: malApplicable(meta)
, m_bindings(that.m_bindings)
, m_body(that.m_body)
, m_env(that.m_env)
, m_isMacro(that.m_isMacro)
{
}
2015-03-27 08:35:47 +03:00
malLambda::malLambda(const malLambda& that, bool isMacro)
2015-03-27 09:24:20 +03:00
: malApplicable(that.m_meta)
, m_bindings(that.m_bindings)
2015-03-27 08:35:47 +03:00
, m_body(that.m_body)
, m_env(that.m_env)
, m_isMacro(isMacro)
2015-03-27 04:52:07 +03:00
{
}
malValuePtr malLambda::apply(malValueIter argsBegin,
malValueIter argsEnd,
malEnvPtr) const
{
return EVAL(m_body, makeEnv(argsBegin, argsEnd));
}
2015-03-27 09:24:20 +03:00
malValuePtr malLambda::doWithMeta(malValuePtr meta) const
{
return new malLambda(*this, meta);
}
2015-03-27 04:52:07 +03:00
malEnvPtr malLambda::makeEnv(malValueIter argsBegin, malValueIter argsEnd) const
{
return malEnvPtr(new malEnv(m_env, m_bindings, argsBegin, argsEnd));
}
2015-03-27 09:24:20 +03:00
malValuePtr malList::conj(malValueIter argsBegin,
malValueIter argsEnd) const
{
int oldItemCount = std::distance(begin(), end());
int newItemCount = std::distance(argsBegin, argsEnd);
malValueVec* items = new malValueVec(oldItemCount + newItemCount);
std::reverse_copy(argsBegin, argsEnd, items->begin());
std::copy(begin(), end(), items->begin() + newItemCount);
return mal::list(items);
}
2015-03-27 03:03:28 +03:00
malValuePtr malList::eval(malEnvPtr env)
{
2015-03-27 08:07:46 +03:00
// Note, this isn't actually called since the TCO updates, but
// is required for the earlier steps, so don't get rid of it.
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-27 09:24:20 +03:00
malValuePtr malValue::meta() const
{
return m_meta.ptr() == NULL ? mal::nilValue() : m_meta;
}
malValuePtr malValue::withMeta(malValuePtr meta) const
{
return doWithMeta(meta);
}
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-27 09:24:20 +03:00
malSequence::malSequence(const malSequence& that, malValuePtr meta)
: malValue(meta)
, m_items(new malValueVec(*(that.m_items)))
{
}
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-27 08:19:02 +03:00
malValuePtr malSequence::first() const
{
return count() == 0 ? mal::nilValue() : item(0);
}
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;
}
2015-03-27 08:19:02 +03:00
malValuePtr malSequence::rest() const
{
malValueIter start = (count() > 0) ? begin() + 1 : end();
return mal::list(start, end());
}
2015-03-26 14:25:50 +03:00
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 09:24:20 +03:00
malValuePtr malVector::conj(malValueIter argsBegin,
malValueIter argsEnd) const
{
int oldItemCount = std::distance(begin(), end());
int newItemCount = std::distance(argsBegin, argsEnd);
malValueVec* items = new malValueVec(oldItemCount + newItemCount);
std::copy(begin(), end(), items->begin());
std::copy(argsBegin, argsEnd, items->begin() + oldItemCount);
return mal::vector(items);
}
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) + ']';
}