c++11: step 2
[jackhill/mal.git] / cpp / Types.cpp
index 59882ea..9b6ebde 100644 (file)
@@ -1,4 +1,5 @@
 #include "Debug.h"
+#include "Environment.h"
 #include "Types.h"
 
 #include <algorithm>
@@ -6,18 +7,22 @@
 #include <typeinfo>
 
 namespace mal {
+    malValuePtr builtin(const String& name, malBuiltIn::ApplyFunc handler) {
+        return malValuePtr(new malBuiltIn(name, handler));
+    };
+
     malValuePtr falseValue() {
         static malValuePtr c(new malConstant("false"));
         return malValuePtr(c);
     };
 
-    malValuePtr hash(malValueVec* items) {
-        return malValuePtr(new malHash(items));
-    };
+    malValuePtr hash(malValueIter argsBegin, malValueIter argsEnd) {
+        return malValuePtr(new malHash(argsBegin, argsEnd));
+    }
 
     malValuePtr integer(int value) {
         return malValuePtr(new malInteger(value));
-    }
+    };
 
     malValuePtr integer(const String& token) {
         return integer(std::stoi(token));
@@ -75,31 +80,47 @@ namespace mal {
     };
 };
 
+malValuePtr malBuiltIn::apply(malValueIter argsBegin,
+                              malValueIter argsEnd,
+                              malEnv& env) const
+{
+    return m_handler(m_name, argsBegin, argsEnd, env);
+}
+
 static String makeHashKey(malValuePtr key)
 {
-    if (malString* skey = dynamic_cast<malString*>(key.ptr())) {
+    if (const malString* skey = DYNAMIC_CAST(malString, key)) {
         return skey->print(true);
     }
-    else if (malKeyword* kkey = dynamic_cast<malKeyword*>(key.ptr())) {
+    else if (const malKeyword* kkey = DYNAMIC_CAST(malKeyword, key)) {
         return kkey->print(true);
     }
     ASSERT(false, "%s is not a string or keyword", key->print(true).c_str());
 }
 
-static malHash::Map createMap(malValueVec* items)
+static malHash::Map addToMap(malHash::Map& map,
+    malValueIter argsBegin, malValueIter argsEnd)
 {
-    int itemCount = items->size();
-    ASSERT(itemCount % 2 == 0, "hash-map requires an even-sized list");
-
-    malHash::Map map;
-    for (int i = 0; i < itemCount; i += 2) {
-        map[makeHashKey(items->at(i))] = items->at(i+1);
+    // This is intended to be called with pre-evaluated arguments.
+    for (auto it = argsBegin; it != argsEnd; ++it) {
+        String key = makeHashKey(*it++);
+        map[key] = *it;
     }
+
     return map;
 }
 
-malHash::malHash(malValueVec* items)
-: m_map(createMap(items))
+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))
 {
 
 }
@@ -120,11 +141,29 @@ String malHash::print(bool readably) const
     return s + "}";
 }
 
+malValuePtr malList::eval(malEnv& 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);
+}
+
 String malList::print(bool readably) const
 {
     return '(' + malSequence::print(readably) + ')';
 }
 
+malValuePtr malValue::eval(malEnv& env)
+{
+    // Default case of eval is just to return the object itself.
+    return malValuePtr(this);
+}
+
 malSequence::malSequence(malValueVec* items)
 : m_items(items)
 {
@@ -136,6 +175,16 @@ malSequence::~malSequence()
     delete m_items;
 }
 
+malValueVec* malSequence::evalItems(malEnv& 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;
+}
+
 String malSequence::print(bool readably) const
 {
     String str;
@@ -162,6 +211,16 @@ String malString::print(bool readably) const
     return readably ? escapedValue() : value();
 }
 
+malValuePtr malSymbol::eval(malEnv& env)
+{
+    return env.get(value());
+}
+
+malValuePtr malVector::eval(malEnv& env)
+{
+    return mal::vector(evalItems(env));
+}
+
 String malVector::print(bool readably) const
 {
     return '[' + malSequence::print(readably) + ']';