#pragma once #include #include #include #include #include "arena.hpp" #include "pod.hpp" // Forward declarations class Value; class Object { public: virtual Tag tag() = 0; virtual Result copy(Arena& arena) = 0; virtual PodObject* pod() = 0; }; class Nil : public Object { public: Nil() {} Nil(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Nil; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodNil* obj) { return Nil(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena) { auto pod = TRY(arena.alloc()); return Nil(TRY(MkGcRoot(pod, arena))); } virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class String : public Object { public: String() {} String(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::String; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodString* obj) { return String(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, char32_t* chars, int64_t size) { auto pod_string = TRY(arena.alloc(size * sizeof(char32_t))); memcpy(pod_string->data, chars, size * sizeof(char32_t)); pod_string->size = size; return String(TRY(MkGcRoot(pod_string, arena))); } static Result create(Arena& arena, const char* str) { uint64_t size = strlen(str); auto pod_string = TRY(arena.alloc(size * sizeof(char32_t))); for (uint64_t i = 0; i < size; i++) pod_string->data[i] = str[i]; pod_string->size = size; return String(TRY(MkGcRoot(pod_string, arena))); } uint64_t size() { return _value->size; } Result operator[](uint64_t idx) { if (idx >= _value->size) return ErrorCode::IndexOutOfRange; return _value->data[idx]; } virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Symbol : public Object { public: Symbol() {} Symbol(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Symbol; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodSymbol* obj) { return Symbol(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, char32_t* chars, int64_t size) { auto pod_symbol = TRY(arena.alloc(size * sizeof(char32_t))); memcpy(pod_symbol->data, chars, size * sizeof(char32_t)); return Symbol(TRY(MkGcRoot(pod_symbol, arena))); } virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Syntax : public Object { public: Syntax() {} Syntax(GcRoot&& val) : _value(std::move(val)) {} Syntax(String filename, String modulename, Value expression); virtual Tag tag() final { return Tag::Syntax; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodSyntax* obj) { return Syntax(TRY(MkGcRoot(obj, arena))); } Result get_value(Arena& arena); virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Pair : public Object { public: Pair() {} Pair(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Pair; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodPair* obj) { return Pair(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, Value& first, Value& rest); Result first(Arena& arena); Result rest(Arena& arena); virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Int64 : public Object { public: Int64() {} Int64(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Int64; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodInt64* obj) { return Int64(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, double val) { auto pod = TRY(arena.alloc()); pod->value = val; return Int64(TRY(MkGcRoot(pod, arena))); } int64_t value() { return _value->value; } virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Float : public Object { public: Float() {} Float(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Float; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodFloat* obj) { return Float(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, double val) { auto pod = TRY(arena.alloc()); pod->value = val; return Float(TRY(MkGcRoot(pod, arena))); } double value() { return _value->value; } virtual Result copy(Arena& arena) final; private: GcRoot _value; }; // note: this class doesn't perform proper destruction of objects in some cases class Value { public: Value() { new (buf) Nil(); } ~Value() { ((Object*)buf)->~Object(); } Value(Value&& val) { memcpy(buf, val.buf, 24); new (val.buf) Nil(); } Value(const Value&) = delete; template Value(T&& obj) requires std::derived_from { new (buf) T(std::move(obj)); } Value& operator=(Value&& val) { memcpy(buf, val.buf, 24); new (val.buf) Nil(); return *this; } static Result create(Arena& arena, PodObject* obj); template bool is() { return dynamic_cast((Object*)buf) != nullptr; } template T* to() { return dynamic_cast((Object*)buf); } PodObject* pod() { return ((Object*)buf)->pod(); } Object& operator*() { return *(Object*)(buf); } Object* operator->() { return (Object*)(buf); } Result copy(Arena& arena) { return ((Object*)buf)->copy(arena); } private: uint8_t buf[24]; }; Result syntax_unwrap(Value& val); Result reverse(Arena& arena, Value& val);