#pragma once #include #include #include #include #include "arena.hpp" #include "pod.hpp" #include "utf8.hpp" // Forward declarations class Value; class String; class Object { public: virtual Tag tag() = 0; virtual Result copy(Arena& arena) = 0; virtual PodObject* pod() = 0; virtual ~Object() = default; Object() = default; Object(const Object&) = delete; }; class Nil : public Object { public: Nil() {} Nil(Nil&& rhs) : _value(std::move(rhs._value)) {} 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 ByteArray : public Object { public: ByteArray() {} ByteArray(ByteArray&& rhs) : _value(std::move(rhs._value)) {} ByteArray(GcRoot&& val) : _value(std::move(val)) {} ByteArray& operator=(ByteArray&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() final { return Tag::String; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodByteArray* obj) { return ByteArray(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, char* chars, int64_t size) { auto pod = TRY(arena.alloc(size * sizeof(char))); memcpy(pod->data, chars, size * sizeof(char32_t)); pod->size = size; return ByteArray(TRY(MkGcRoot(pod, arena))); } static Result create(Arena& arena, const char* str) { uint64_t size = strlen(str); auto pod = TRY(arena.alloc(size * sizeof(char32_t))); memcpy(pod->data, str, size); pod->size = size; return ByteArray(TRY(MkGcRoot(pod, arena))); } static Result create(Arena& arena, String& str); uint64_t size() { return _value->size; } virtual Result copy(Arena& arena) final; Result operator[](uint64_t idx) { if (idx >= _value->size) return ErrorCode::IndexOutOfRange; return _value->data[idx]; } Result concat(Arena& arena, const char* rhs) { uint64_t rhs_size = strlen(rhs); uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size); return ByteArray(TRY(MkGcRoot(pod, arena))); } Result concat(Arena& arena, const char* rhs, uint64_t rhs_size) { uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size); return ByteArray(TRY(MkGcRoot(pod, arena))); } Result concat(Arena& arena, ByteArray& rhs) { uint64_t rhs_size = rhs.size(); uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char) * rhs_size); return ByteArray(TRY(MkGcRoot(pod, arena))); } Result sub(Arena& arena, uint64_t start, uint64_t end) { if (start > end) return ErrorCode::IndexOutOfRange; uint64_t res_size = end - start; auto pod = TRY(arena.alloc(res_size * sizeof(char))); pod->size = res_size; memcpy(pod->data, _value->data + start, sizeof(char) * res_size); return ByteArray(TRY(MkGcRoot(pod, arena))); } private: GcRoot _value; }; class String : public Object { public: String() {} String(String&& rhs) : _value(std::move(rhs._value)) {} String(GcRoot&& val) : _value(std::move(val)) {} String& operator=(String&& rhs) { _value = std::move(rhs._value); return *this; } 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; } virtual Result copy(Arena& arena) final; Result operator[](uint64_t idx) { if (idx >= _value->size) return ErrorCode::IndexOutOfRange; return _value->data[idx]; } Result concat(Arena& arena, const char* rhs) { uint64_t rhs_size = strlen(rhs); uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size); for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i]; return String(TRY(MkGcRoot(pod, arena))); } Result concat(Arena& arena, const char32_t* rhs, uint64_t rhs_size) { uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size); for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i]; return String(TRY(MkGcRoot(pod, arena))); } Result concat(Arena& arena, String& rhs) { uint64_t rhs_size = rhs.size(); uint64_t lhs_size = size(); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena.alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size); memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char32_t) * rhs_size); return String(TRY(MkGcRoot(pod, arena))); } Result sub(Arena& arena, uint64_t start, uint64_t end) { if (start > end) return ErrorCode::IndexOutOfRange; uint64_t res_size = end - start; auto pod = TRY(arena.alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, _value->data + start, sizeof(char32_t) * res_size); return String(TRY(MkGcRoot(pod, arena))); } friend class Symbol; private: GcRoot _value; }; class Symbol : public Object { public: Symbol() {} Symbol(Symbol&& rhs) : _value(std::move(rhs._value)) {} 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))); } static Result create(Arena& arena, String& rhs); virtual Result copy(Arena& arena) final; private: GcRoot _value; }; class Syntax : public Object { public: Syntax() {} Syntax(Syntax&& rhs) : _value(std::move(rhs._value)) {} 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(Pair&& rhs) : _value(std::move(rhs._value)) {} 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(Int64&& rhs) : _value(std::move(rhs._value)) {} 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(Float&& rhs) : _value(std::move(rhs._value)) {} 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; }; class Bool : public Object { public: Bool() {} Bool(Bool&& rhs) : _value(std::move(rhs._value)) {} Bool(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Bool; } virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodBool* obj) { return Bool(TRY(MkGcRoot(obj, arena))); } static Result create(Arena& arena, bool val) { auto pod = TRY(arena.alloc()); pod->value = val; return Bool(TRY(MkGcRoot(pod, arena))); } bool 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);