1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-19 09:38:28 +03:00
mal/impls/cpp/Types.h
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

375 lines
11 KiB
C++

#ifndef INCLUDE_TYPES_H
#define INCLUDE_TYPES_H
#include "MAL.h"
#include <exception>
#include <map>
class malEmptyInputException : public std::exception { };
class malValue : public RefCounted {
public:
malValue() {
TRACE_OBJECT("Creating malValue %p\n", this);
}
malValue(malValuePtr meta) : m_meta(meta) {
TRACE_OBJECT("Creating malValue %p\n", this);
}
virtual ~malValue() {
TRACE_OBJECT("Destroying malValue %p\n", this);
}
malValuePtr withMeta(malValuePtr meta) const;
virtual malValuePtr doWithMeta(malValuePtr meta) const = 0;
malValuePtr meta() const;
bool isTrue() const;
bool isEqualTo(const malValue* rhs) const;
virtual malValuePtr eval(malEnvPtr env);
virtual String print(bool readably) const = 0;
protected:
virtual bool doIsEqualTo(const malValue* rhs) const = 0;
malValuePtr m_meta;
};
template<class T>
T* value_cast(malValuePtr obj, const char* typeName) {
T* dest = dynamic_cast<T*>(obj.ptr());
MAL_CHECK(dest != NULL, "%s is not a %s",
obj->print(true).c_str(), typeName);
return dest;
}
#define VALUE_CAST(Type, Value) value_cast<Type>(Value, #Type)
#define DYNAMIC_CAST(Type, Value) (dynamic_cast<Type*>((Value).ptr()))
#define STATIC_CAST(Type, Value) (static_cast<Type*>((Value).ptr()))
#define WITH_META(Type) \
virtual malValuePtr doWithMeta(malValuePtr meta) const { \
return new Type(*this, meta); \
} \
class malConstant : public malValue {
public:
malConstant(String name) : m_name(name) { }
malConstant(const malConstant& that, malValuePtr meta)
: malValue(meta), m_name(that.m_name) { }
virtual String print(bool readably) const { return m_name; }
virtual bool doIsEqualTo(const malValue* rhs) const {
return this == rhs; // these are singletons
}
WITH_META(malConstant);
private:
const String m_name;
};
class malInteger : public malValue {
public:
malInteger(int64_t value) : m_value(value) { }
malInteger(const malInteger& that, malValuePtr meta)
: malValue(meta), m_value(that.m_value) { }
virtual String print(bool readably) const {
return std::to_string(m_value);
}
int64_t value() const { return m_value; }
virtual bool doIsEqualTo(const malValue* rhs) const {
return m_value == static_cast<const malInteger*>(rhs)->m_value;
}
WITH_META(malInteger);
private:
const int64_t m_value;
};
class malStringBase : public malValue {
public:
malStringBase(const String& token)
: m_value(token) { }
malStringBase(const malStringBase& that, malValuePtr meta)
: malValue(meta), m_value(that.value()) { }
virtual String print(bool readably) const { return m_value; }
String value() const { return m_value; }
private:
const String m_value;
};
class malString : public malStringBase {
public:
malString(const String& token)
: malStringBase(token) { }
malString(const malString& that, malValuePtr meta)
: malStringBase(that, meta) { }
virtual String print(bool readably) const;
String escapedValue() const;
virtual bool doIsEqualTo(const malValue* rhs) const {
return value() == static_cast<const malString*>(rhs)->value();
}
WITH_META(malString);
};
class malKeyword : public malStringBase {
public:
malKeyword(const String& token)
: malStringBase(token) { }
malKeyword(const malKeyword& that, malValuePtr meta)
: malStringBase(that, meta) { }
virtual bool doIsEqualTo(const malValue* rhs) const {
return value() == static_cast<const malKeyword*>(rhs)->value();
}
WITH_META(malKeyword);
};
class malSymbol : public malStringBase {
public:
malSymbol(const String& token)
: malStringBase(token) { }
malSymbol(const malSymbol& that, malValuePtr meta)
: malStringBase(that, meta) { }
virtual malValuePtr eval(malEnvPtr env);
virtual bool doIsEqualTo(const malValue* rhs) const {
return value() == static_cast<const malSymbol*>(rhs)->value();
}
WITH_META(malSymbol);
};
class malSequence : public malValue {
public:
malSequence(malValueVec* items);
malSequence(malValueIter begin, malValueIter end);
malSequence(const malSequence& that, malValuePtr meta);
virtual ~malSequence();
virtual String print(bool readably) const;
malValueVec* evalItems(malEnvPtr env) const;
int count() const { return m_items->size(); }
bool isEmpty() const { return m_items->empty(); }
malValuePtr item(int index) const { return (*m_items)[index]; }
malValueIter begin() const { return m_items->begin(); }
malValueIter end() const { return m_items->end(); }
virtual bool doIsEqualTo(const malValue* rhs) const;
virtual malValuePtr conj(malValueIter argsBegin,
malValueIter argsEnd) const = 0;
malValuePtr first() const;
virtual malValuePtr rest() const;
private:
malValueVec* const m_items;
};
class malList : public malSequence {
public:
malList(malValueVec* items) : malSequence(items) { }
malList(malValueIter begin, malValueIter end)
: malSequence(begin, end) { }
malList(const malList& that, malValuePtr meta)
: malSequence(that, meta) { }
virtual String print(bool readably) const;
virtual malValuePtr eval(malEnvPtr env);
virtual malValuePtr conj(malValueIter argsBegin,
malValueIter argsEnd) const;
WITH_META(malList);
};
class malVector : public malSequence {
public:
malVector(malValueVec* items) : malSequence(items) { }
malVector(malValueIter begin, malValueIter end)
: malSequence(begin, end) { }
malVector(const malVector& that, malValuePtr meta)
: malSequence(that, meta) { }
virtual malValuePtr eval(malEnvPtr env);
virtual String print(bool readably) const;
virtual malValuePtr conj(malValueIter argsBegin,
malValueIter argsEnd) const;
WITH_META(malVector);
};
class malApplicable : public malValue {
public:
malApplicable() { }
malApplicable(malValuePtr meta) : malValue(meta) { }
virtual malValuePtr apply(malValueIter argsBegin,
malValueIter argsEnd) const = 0;
};
class malHash : public malValue {
public:
typedef std::map<String, malValuePtr> Map;
malHash(malValueIter argsBegin, malValueIter argsEnd, bool isEvaluated);
malHash(const malHash::Map& map);
malHash(const malHash& that, malValuePtr meta)
: malValue(meta), m_map(that.m_map), m_isEvaluated(that.m_isEvaluated) { }
malValuePtr assoc(malValueIter argsBegin, malValueIter argsEnd) const;
malValuePtr dissoc(malValueIter argsBegin, malValueIter argsEnd) const;
bool contains(malValuePtr key) const;
malValuePtr eval(malEnvPtr env);
malValuePtr get(malValuePtr key) const;
malValuePtr keys() const;
malValuePtr values() const;
virtual String print(bool readably) const;
virtual bool doIsEqualTo(const malValue* rhs) const;
WITH_META(malHash);
private:
const Map m_map;
const bool m_isEvaluated;
};
class malBuiltIn : public malApplicable {
public:
typedef malValuePtr (ApplyFunc)(const String& name,
malValueIter argsBegin,
malValueIter argsEnd);
malBuiltIn(const String& name, ApplyFunc* handler)
: m_name(name), m_handler(handler) { }
malBuiltIn(const malBuiltIn& that, malValuePtr meta)
: malApplicable(meta), m_name(that.m_name), m_handler(that.m_handler) { }
virtual malValuePtr apply(malValueIter argsBegin,
malValueIter argsEnd) const;
virtual String print(bool readably) const {
return STRF("#builtin-function(%s)", m_name.c_str());
}
virtual bool doIsEqualTo(const malValue* rhs) const {
return this == rhs; // these are singletons
}
String name() const { return m_name; }
WITH_META(malBuiltIn);
private:
const String m_name;
ApplyFunc* m_handler;
};
class malLambda : public malApplicable {
public:
malLambda(const StringVec& bindings, malValuePtr body, malEnvPtr env);
malLambda(const malLambda& that, malValuePtr meta);
malLambda(const malLambda& that, bool isMacro);
virtual malValuePtr apply(malValueIter argsBegin,
malValueIter argsEnd) const;
malValuePtr getBody() const { return m_body; }
malEnvPtr makeEnv(malValueIter argsBegin, malValueIter argsEnd) const;
virtual bool doIsEqualTo(const malValue* rhs) const {
return this == rhs; // do we need to do a deep inspection?
}
virtual String print(bool readably) const {
return STRF("#user-%s(%p)", m_isMacro ? "macro" : "function", this);
}
bool isMacro() const { return m_isMacro; }
virtual malValuePtr doWithMeta(malValuePtr meta) const;
private:
const StringVec m_bindings;
const malValuePtr m_body;
const malEnvPtr m_env;
const bool m_isMacro;
};
class malAtom : public malValue {
public:
malAtom(malValuePtr value) : m_value(value) { }
malAtom(const malAtom& that, malValuePtr meta)
: malValue(meta), m_value(that.m_value) { }
virtual bool doIsEqualTo(const malValue* rhs) const {
return this->m_value->isEqualTo(rhs);
}
virtual String print(bool readably) const {
return "(atom " + m_value->print(readably) + ")";
};
malValuePtr deref() const { return m_value; }
malValuePtr reset(malValuePtr value) { return m_value = value; }
WITH_META(malAtom);
private:
malValuePtr m_value;
};
namespace mal {
malValuePtr atom(malValuePtr value);
malValuePtr boolean(bool value);
malValuePtr builtin(const String& name, malBuiltIn::ApplyFunc handler);
malValuePtr falseValue();
malValuePtr hash(malValueIter argsBegin, malValueIter argsEnd,
bool isEvaluated);
malValuePtr hash(const malHash::Map& map);
malValuePtr integer(int64_t value);
malValuePtr integer(const String& token);
malValuePtr keyword(const String& token);
malValuePtr lambda(const StringVec&, malValuePtr, malEnvPtr);
malValuePtr list(malValueVec* items);
malValuePtr list(malValueIter begin, malValueIter end);
malValuePtr list(malValuePtr a);
malValuePtr list(malValuePtr a, malValuePtr b);
malValuePtr list(malValuePtr a, malValuePtr b, malValuePtr c);
malValuePtr macro(const malLambda& lambda);
malValuePtr nilValue();
malValuePtr string(const String& token);
malValuePtr symbol(const String& token);
malValuePtr trueValue();
malValuePtr vector(malValueVec* items);
malValuePtr vector(malValueIter begin, malValueIter end);
};
#endif // INCLUDE_TYPES_H