#pragma once #include #include #include #include #include "arena.hpp" #include "error.hpp" #include "opcode.hpp" #include "pod.hpp" #include "sourcerange.hpp" #include "stdlib.hpp" #include "utf8.hpp" // Forward declarations class Value; class String; class Nil; class Int64; class Float; class Bool; class String; class Symbol; class SrcLoc; class Symbol; class Syntax; class Pair; class Array; class Dict; class ByteArray; class Writer; class Opcode; class StackFrame; class Error; class Function; class StdlibFunction; class Module; class Continuation; class Task; class TaskResult; short cmp_tag(Tag lhs, Tag rhs); class Object { public: virtual Tag tag() const = 0; virtual Result copy_value() const = 0; virtual PodObject* pod() const = 0; virtual void move(Object*) = 0; virtual ~Object() = default; virtual Result cmp(const Object&) const = 0; virtual Result cmp(const Nil&) const { return cmp_tag(tag(), Tag::Nil); } virtual Result cmp(const Int64&) const { return cmp_tag(tag(), Tag::Int64); } virtual Result cmp(const Float&) const { return cmp_tag(tag(), Tag::Float); } virtual Result cmp(const Bool&) const { return cmp_tag(tag(), Tag::Bool); } virtual Result cmp(const String&) const { return cmp_tag(tag(), Tag::String); } virtual Result cmp(const Symbol&) const { return cmp_tag(tag(), Tag::Symbol); } virtual Result cmp(const SrcLoc&) const { return cmp_tag(tag(), Tag::SrcLoc); } virtual Result cmp(const Syntax&) const { return cmp_tag(tag(), Tag::Syntax); } virtual Result cmp(const Pair&) const { return cmp_tag(tag(), Tag::Pair); } virtual Result cmp(const Array&) const { return cmp_tag(tag(), Tag::Array); } virtual Result cmp(const Dict&) const { return cmp_tag(tag(), Tag::Dict); } virtual Result cmp(const ByteArray&) const { return cmp_tag(tag(), Tag::ByteArray); } virtual Result cmp(const Opcode& rhs) const { return cmp_tag(tag(), Tag::Opcode); } virtual Result cmp(const Function& rhs) const { return cmp_tag(tag(), Tag::Function); } virtual Result cmp(const StdlibFunction& rhs) const { return cmp_tag(tag(), Tag::StdlibFunction); } virtual Result cmp(const Module& rhs) const { return cmp_tag(tag(), Tag::Module); } virtual Result cmp(const char* rhs) const { return ERROR(NotImplemented); } virtual Result cmp(const StackFrame& rhs) const { return ERROR(NotImplemented); } virtual Result cmp(const Error& rhs) const { return cmp_tag(tag(), Tag::Error); } virtual Result cmp(const Continuation& rhs) const { return cmp_tag(tag(), Tag::Continuation); } virtual Result cmp(const Task& rhs) const { return cmp_tag(tag(), Tag::Task); } virtual Result cmp(const TaskResult& rhs) const { return cmp_tag(tag(), Tag::TaskResult); } virtual Result add(const Object&) const; virtual Result add(const Int64&) const; virtual Result add(const Float&) const; virtual Result sub(const Object&) const; virtual Result sub_inv(const Int64&) const; virtual Result sub_inv(const Float&) const; virtual Result mul(const Object&) const; virtual Result mul(const Int64&) const; virtual Result mul(const Float&) const; virtual Result div(const Object&) const; virtual Result div_inv(const Int64&) const; virtual Result div_inv(const Float&) const; virtual Result get(const Value& key) const; virtual Result set_value(const Value& key, const Value& value) const; virtual Result first() const; virtual Result second() const; virtual Result third() const; virtual Result rest() const; virtual Result size() const; 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() const final { return Tag::Nil; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Nil& rhs) const final { return 0; } static Result create(PodNil* obj) { return Nil(TRY(MkGcRoot(obj))); } static Result create() { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Nil; return Nil(TRY(MkGcRoot(pod))); } virtual Result copy_value() const final; Result copy() const; virtual Result size() const { return 0; } virtual void move(Object* obj) final { new (obj) Nil(std::move(_value)); } private: GcRoot _value; }; class Array : public Object { public: friend class Dict; Array() {} Array(Array&& rhs) : _value(std::move(rhs._value)) {} Array(GcRoot&& val) : _value(std::move(val)) {} Array& operator=(Array&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::Array; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Array& rhs) const final; virtual void move(Object* obj) final { new (obj) Array(std::move(_value)); } static Result create(PodArray* obj) { return Array(TRY(MkGcRoot(obj))); } static Result create() { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Array; pod->size = 0; return Array(TRY(MkGcRoot(pod))); } virtual Result size() const { return _value->size; } virtual Result copy_value() const final; Result copy() const; Result get(uint64_t idx) const; virtual Result get(const Value& key) const final; Result set(uint64_t idx, const Value& value) const; Result set(const Value& key, const Value& value) const; virtual Result set_value(const Value& key, const Value& value) const final; Result append(const Value& rhs) const; template Result append(const V& value) const; Result concat(Array& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(PodObject*))); pod->header.tag = Tag::Array; pod->size = res_size; for (uint64_t i = 0; i < lhs_size; i++) { pod->data[i] = _value->data[i].get(); } for (uint64_t i = 0; i < rhs_size; i++) { pod->data[lhs_size + i] = rhs._value->data[i].get(); } return Array(TRY(MkGcRoot(pod))); } Result slice(uint64_t start, uint64_t end) const { if (start > end) return ERROR(IndexOutOfRange); uint64_t res_size = end - start; auto pod = TRY(arena_alloc(res_size * sizeof(PodObject*))); pod->header.tag = Tag::Array; pod->size = res_size; for (uint64_t i = 0; i < end - start; i++) { pod->data[i] = _value->data[start + i]; } return Array(TRY(MkGcRoot(pod))); } 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() const final { return Tag::ByteArray; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const ByteArray& rhs) const final { return 0; } virtual void move(Object* obj) final { new (obj) ByteArray(std::move(_value)); } static Result create(PodByteArray* obj) { return ByteArray(TRY(MkGcRoot(obj))); } static Result create(char* chars, int64_t size) { auto pod = TRY(arena_alloc(size * sizeof(char))); pod->header.tag = Tag::ByteArray; memcpy(pod->data, chars, size * sizeof(char32_t)); pod->size = size; return ByteArray(TRY(MkGcRoot(pod))); } static Result create(const char* str) { uint64_t size = strlen(str); auto pod = TRY(arena_alloc(size * sizeof(char32_t))); pod->header.tag = Tag::ByteArray; memcpy(pod->data, str, size); pod->size = size; return ByteArray(TRY(MkGcRoot(pod))); } static Result create(const String& str); virtual Result size() const final { return _value->size; } virtual Result copy_value() const final; Result copy() const; Result operator[](uint64_t idx) const { if (idx >= _value->size) return ERROR(IndexOutOfRange); return _value->data[idx]; } Result concat(const char* rhs) { uint64_t rhs_size = strlen(rhs); uint64_t lhs_size = TRY(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))); } Result concat(const char* rhs, uint64_t rhs_size) { uint64_t lhs_size = TRY(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))); } Result concat(ByteArray& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t lhs_size = TRY(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))); } Result slice(uint64_t start, uint64_t end) const { if (start > end) return ERROR(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))); } private: GcRoot _value; }; class Dict : public Object { public: friend class Writer; using Object::get; Dict() {} Dict(Dict&& rhs) : _value(std::move(rhs._value)) {} Dict(GcRoot&& val) : _value(std::move(val)) {} Dict& operator=(Dict&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::Dict; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Dict& rhs) const final; virtual void move(Object* obj) final { new (obj) Dict(std::move(_value)); } static Result create(PodDict* obj) { return Dict(TRY(MkGcRoot(obj))); } static Result create(const Array& arr); static Result create() { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Dict; pod->size = 0; return Dict(TRY(MkGcRoot(pod))); } virtual Result copy_value() const final; Result copy() const; virtual Result get(const Value& key) const final; Result set(const Value& key, const Value& value) const; virtual Result set_value(const Value& key, const Value& value) const final; template Result set(const K& key, const V& value) const; Result concat(Dict& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(2 * res_size * sizeof(PodObject*))); pod->size = res_size; for (uint64_t i = 0; i < 2 * lhs_size; i++) { pod->data[i] = _value->data[i]; } for (uint64_t i = 2 * lhs_size; i < 2 * rhs_size; i++) { pod->data[i] = rhs._value->data[i]; } return Dict(TRY(MkGcRoot(pod))); } virtual Result size() const final { return _value->size; } private: Result find(const Value& key) const; 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() const final { return Tag::String; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const String& rhs) const final { auto lsize = TRY(size()); auto rsize = TRY(rhs.size()); uint64_t i = 0; uint64_t j = 0; while (1) { if (i == lsize && j == lsize) return 0; short cmp = short(i == lsize) - short(j == rsize); if (cmp != 0) return cmp; char32_t lc = _value->data[i]; char32_t rc = rhs._value->data[j]; cmp = (lc > rc) - (lc < rc); if (cmp != 0) return cmp; i++; j++; } return 0; } virtual void move(Object* obj) final { new (obj) String(std::move(_value)); } static Result create(PodString* obj) { return String(TRY(MkGcRoot(obj))); } static Result create(char32_t* chars, int64_t size) { auto pod = TRY(arena_alloc(size * sizeof(char32_t))); pod->header.tag = Tag::String; memcpy(pod->data, chars, size * sizeof(char32_t)); pod->size = size; return String(TRY(MkGcRoot(pod))); } static Result create(const Symbol& sym); static Result create(const char* str) { uint64_t size = strlen(str); auto pod = TRY(arena_alloc(size * sizeof(char32_t))); pod->header.tag = Tag::String; for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i]; pod->size = size; return String(TRY(MkGcRoot(pod))); } virtual Result size() const final { return _value->size; } virtual Result copy_value() const final; Result copy() const; Result operator[](uint64_t idx) const { if (idx >= _value->size) return ERROR(IndexOutOfRange); return _value->data[idx]; } Result concat(const char* rhs, uint64_t rhs_size) { uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->header.tag = Tag::String; 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))); } Result concat(const char* rhs) { return concat(rhs, strlen(rhs)); } Result concat(const char32_t* rhs, uint64_t rhs_size) { uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->header.tag = Tag::String; 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))); } Result concat(String& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->header.tag = Tag::String; 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))); } Result slice(uint64_t start, uint64_t end) const { if (start > end) return ERROR(IndexOutOfRange); uint64_t res_size = end - start; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->header.tag = Tag::String; pod->size = res_size; memcpy(pod->data, _value->data + start, sizeof(char32_t) * res_size); return String(TRY(MkGcRoot(pod))); } friend class Symbol; private: GcRoot _value; }; class Symbol : public Object { public: friend class String; Symbol() {} Symbol(Symbol&& rhs) : _value(std::move(rhs._value)) {} Symbol(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Symbol; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Symbol& rhs) const final { auto lsize = TRY(size()); auto rsize = TRY(rhs.size()); uint64_t i = 0; uint64_t j = 0; while (1) { if (i == lsize && j == lsize) return 0; short cmp = short(i == lsize) - short(j == rsize); if (cmp != 0) return cmp; char32_t lc = _value->data[i]; char32_t rc = rhs._value->data[j]; cmp = (lc > rc) - (lc < rc); if (cmp != 0) return cmp; i++; j++; } return 0; } virtual Result cmp(const char* rhs) const final { auto lsize = TRY(size()); auto rsize = strlen(rhs); uint64_t i = 0; uint64_t j = 0; while (1) { if (i == lsize && j == rsize) return 0; short cmp = short(i == lsize) - short(j == rsize); if (cmp != 0) return cmp; char32_t lc = _value->data[i]; char32_t rc = rhs[j]; cmp = (lc > rc) - (lc < rc); if (cmp != 0) return cmp; i++; j++; } return 0; } virtual void move(Object* obj) final { new (obj) Symbol(std::move(_value)); } static Result create(PodSymbol* obj) { return Symbol(TRY(MkGcRoot(obj))); } static Result create(char32_t* chars, int64_t size) { auto pod = TRY(arena_alloc(size * sizeof(char32_t))); pod->header.tag = Tag::Symbol; memcpy(pod->data, chars, size * sizeof(char32_t)); return Symbol(TRY(MkGcRoot(pod))); } static Result create(const char* str) { uint64_t size = strlen(str); auto pod = TRY(arena_alloc(size * sizeof(char32_t))); pod->header.tag = Tag::Symbol; for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i]; pod->size = size; return Symbol(TRY(MkGcRoot(pod))); } static Result create(String& rhs); virtual Result copy_value() const final; Result copy() const; virtual Result size() const final { return _value->size; } Result operator[](uint64_t idx) const { if (idx >= _value->size) return ERROR(IndexOutOfRange); return _value->data[idx]; } private: GcRoot _value; }; class SrcLoc : public Object { public: SrcLoc() {} SrcLoc(SrcLoc&& rhs) : _value(std::move(rhs._value)) {} SrcLoc(GcRoot&& val) : _value(std::move(val)) {} static Result create(const SourceRange& sourcerange); virtual Tag tag() const final { return Tag::SrcLoc; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const SrcLoc& rhs) const final; virtual void move(Object* obj) final { new (obj) SrcLoc(std::move(_value)); } static Result create(PodSrcLoc* obj) { return SrcLoc(TRY(MkGcRoot(obj))); } static Result create(const SourcePosition& start, const SourcePosition& end) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::SrcLoc; pod->sourcerange.start = start; pod->sourcerange.end = end; return SrcLoc(TRY(MkGcRoot(pod))); } SourceRange sourcerange() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Syntax : public Object { public: Syntax() {} Syntax(Syntax&& rhs) : _value(std::move(rhs._value)) {} Syntax(GcRoot&& val) : _value(std::move(val)) {} static Result create(const String& filename, const SrcLoc& srcloc, const Value& expression); static Result create(const String& filename, const SourcePosition& start, const SourcePosition& end, const Value& expression); virtual Tag tag() const final { return Tag::Syntax; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Syntax& rhs) const final; virtual void move(Object* obj) final { new (obj) Syntax(std::move(_value)); } static Result create(PodSyntax* obj) { return Syntax(TRY(MkGcRoot(obj))); } Result filename() const; Result srcloc() const; Result expression() const; Result first() const final; Result second() const final; Result third() const final; Result rest() const final; Result size() const final; virtual Result copy_value() const final; Result copy() const; 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() const final { return Tag::Pair; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Pair& rhs) const final { return 0; } virtual void move(Object* obj) final { new (obj) Pair(std::move(_value)); } static Result create(PodPair* obj) { return Pair(TRY(MkGcRoot(obj))); } static Result create(const Value& first, const Value& rest); static Result create(const Array& arr); virtual Result get(const Value& key) const final; Result first() const final; Result second() const final; Result third() const final; Result rest() const final; virtual Result size() const final; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Int64 : public Object { public: friend class Float; Int64() {} Int64(Int64&& rhs) : _value(std::move(rhs._value)) {} Int64(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Int64; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Int64& rhs) const final { return (_value->value > rhs._value->value) - (_value->value < rhs._value->value); } virtual Result cmp(const Float& rhs) const final; virtual Result add(const Object& rhs) const final; virtual Result add(const Int64& rhs) const final; virtual Result add(const Float& rhs) const final; virtual Result mul(const Object& rhs) const final; virtual Result mul(const Int64& rhs) const final; virtual Result mul(const Float& rhs) const final; virtual Result sub(const Object& rhs) const final; virtual Result sub_inv(const Int64& rhs) const final; virtual Result sub_inv(const Float& rhs) const final; virtual Result div(const Object& rhs) const final; virtual Result div_inv(const Int64& rhs) const final; virtual Result div_inv(const Float& rhs) const final; virtual void move(Object* obj) final { new (obj) Int64(std::move(_value)); } static Result create(PodInt64* obj) { return Int64(TRY(MkGcRoot(obj))); } static Result create(double val) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Int64; pod->value = val; return Int64(TRY(MkGcRoot(pod))); } int64_t value() const { return _value->value; } virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Float : public Object { public: friend class Int64; Float() {} Float(Float&& rhs) : _value(std::move(rhs._value)) {} Float(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Float; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Float& rhs) const final { return (_value->value > rhs._value->value) - (_value->value < rhs._value->value); } virtual Result cmp(const Int64& rhs) const final; virtual Result add(const Object& rhs) const final; virtual Result add(const Int64& rhs) const final; virtual Result add(const Float& rhs) const final; virtual Result mul(const Object& rhs) const final; virtual Result mul(const Int64& rhs) const final; virtual Result mul(const Float& rhs) const final; virtual Result sub(const Object& rhs) const final; virtual Result sub_inv(const Int64& rhs) const final; virtual Result sub_inv(const Float& rhs) const final; virtual Result div(const Object& rhs) const final; virtual Result div_inv(const Int64& rhs) const final; virtual Result div_inv(const Float& rhs) const final; virtual void move(Object* obj) final { new (obj) Float(std::move(_value)); } static Result create(PodFloat* obj) { return Float(TRY(MkGcRoot(obj))); } static Result create(double val) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Float; pod->value = val; return Float(TRY(MkGcRoot(pod))); } double value() const { return _value->value; } virtual Result copy_value() const final; Result copy() const; 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() const final { return Tag::Bool; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Bool& rhs) const final { return (_value->value > rhs._value->value) - (_value->value < rhs._value->value); } virtual void move(Object* obj) final { new (obj) Bool(std::move(_value)); } static Result create(PodBool* obj) { return Bool(TRY(MkGcRoot(obj))); } static Result create(bool val) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Bool; pod->value = val; return Bool(TRY(MkGcRoot(pod))); } bool value() const { return _value->value; } virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Opcode : public Object { public: Opcode() {} Opcode(Opcode&& rhs) : _value(std::move(rhs._value)) {} Opcode(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Opcode; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Opcode& rhs) const final { return 0; } virtual void move(Object* obj) final { new (obj) Opcode(std::move(_value)); } static Result create(PodOpcode* obj) { return Opcode(TRY(MkGcRoot(obj))); } static Result create(Oc opcode, OpArg arg1 = {0, 0}, OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0}, OpArg arg4 = {0, 0}) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Opcode; pod->opcode = opcode; pod->arg1 = arg1; pod->arg2 = arg2; pod->arg3 = arg3; pod->arg4 = arg4; return Opcode(TRY(MkGcRoot(pod))); } Oc opcode() const { return _value->opcode; } OpArg arg1() const { return _value->arg1; } OpArg arg2() const { return _value->arg2; } OpArg arg3() const { return _value->arg3; } OpArg arg4() const { return _value->arg4; } virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Function : public Object { public: Function() {} Function(Function&& rhs) : _value(std::move(rhs._value)) {} Function(GcRoot&& val) : _value(std::move(val)) {} Function& operator=(Function&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::Function; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Function& rhs) const final; virtual void move(Object* obj) final { new (obj) Function(std::move(_value)); } static Result create(PodFunction* obj) { return Function(TRY(MkGcRoot(obj))); } static Result create(const Function& prototype, const Array& closure); static Result create(const Value& name, uint64_t arity, const Array& constants, const Array& code, const Array& closure); uint64_t arity() const { return _value->arity; } Result name() const; Result code() const; Result constants() const; Result closure() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class StdlibFunction : public Object { public: StdlibFunction() {} StdlibFunction(StdlibFunction&& rhs) : _value(std::move(rhs._value)) {} StdlibFunction(GcRoot&& val) : _value(std::move(val)) {} StdlibFunction& operator=(StdlibFunction&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::StdlibFunction; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const StdlibFunction& rhs) const final; virtual void move(Object* obj) final { new (obj) StdlibFunction(std::move(_value)); } static Result create(PodStdlibFunction* obj) { return StdlibFunction(TRY(MkGcRoot(obj))); } static Result create(StdlibFunctionId fun_id); Result name() const; StdlibFunctionId fun_id() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Module : public Object { public: Module() {} Module(Module&& rhs) : _value(std::move(rhs._value)) {} Module(GcRoot&& val) : _value(std::move(val)) {} Module& operator=(Module&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::Module; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Module& rhs) const final; virtual void move(Object* obj) final { new (obj) Module(std::move(_value)); } static Result create(PodModule* obj) { return Module(TRY(MkGcRoot(obj))); } static Result create(const Value& name, const Function& fun); Result name() const; Result fun() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class StackFrame : public Object { public: StackFrame() {} StackFrame(StackFrame&& rhs) : _value(std::move(rhs._value)) {} StackFrame(GcRoot&& val) : _value(std::move(val)) {} StackFrame& operator=(StackFrame&& rhs) { _value = std::move(rhs._value); return *this; } virtual Tag tag() const final { return Tag::StackFrame; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const StackFrame& rhs) const final { return 0; } virtual void move(Object* obj) final { new (obj) StackFrame(std::move(_value)); } static Result create(PodStackFrame* obj) { return StackFrame(TRY(MkGcRoot(obj))); } using Object::get; Result get(uint64_t idx) const; Result set(uint64_t idx, const Value& val) const; Result settop(uint64_t idx) const; Result parent() const; Result fun() const; uint64_t pc() const; Result setpc(uint64_t pc); Result incpc(); Result size() const { return _value->size; } static Result create(const Value& parent, const Value& fun); Result slice(uint64_t start, uint64_t end) const { if (start > end || end > _value->size) return ERROR(IndexOutOfRange); uint64_t res_size = end - start; auto pod = TRY(arena_alloc(res_size * sizeof(PodObject*))); pod->header.tag = Tag::Array; pod->size = res_size; for (uint64_t i = 0; i < end - start; i++) { pod->data[i] = _value->data[start + i]; } return Array(TRY(MkGcRoot(pod))); } Result call(const Value& fun, uint64_t start, uint64_t end) const; Result ret(uint64_t regno) const; virtual Result copy_value() const final; Result copy() const; Result backtrace(uint64_t indent = 0) const; private: GcRoot _value; }; class Error : public Object { public: Error() {} Error(Error&& rhs) : _value(std::move(rhs._value)) {} Error(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Error; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Error& rhs) const final; virtual void move(Object* obj) final { new (obj) Error(std::move(_value)); } static Result create(PodError* obj) { return Error(TRY(MkGcRoot(obj))); } static Result create(const char* name, const char* message) { auto name_str = TRY(Symbol::create(name)); auto message_str = TRY(String::create(message)); auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Error; pod->name = name_str.pod(); pod->message = message_str.pod(); return Error(TRY(MkGcRoot(pod))); } static Result create(const Symbol& name, const String& message) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Error; pod->name = name.pod(); pod->message = message.pod(); return Error(TRY(MkGcRoot(pod))); } Result name() const; Result message() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Continuation : public Object { public: Continuation() {} Continuation(Continuation&& rhs) : _value(std::move(rhs._value)) {} Continuation(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Continuation; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Continuation& rhs) const final; virtual void move(Object* obj) final { new (obj) Continuation(std::move(_value)); } static Result create(PodContinuation* obj) { return Continuation(TRY(MkGcRoot(obj))); } static Result create(const Value& value, const StackFrame& frame); Result value() const; Result frame() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class Task : public Object { public: Task() {} Task(Task&& rhs) : _value(std::move(rhs._value)) {} Task(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::Task; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const Task& rhs) const final; virtual void move(Object* obj) final { new (obj) Task(std::move(_value)); } static Result create(PodTask* obj) { return Task(TRY(MkGcRoot(obj))); } static Result create(uint64_t task_id, const Array& params); Result name() const; uint64_t task_id() const; Result params() const; virtual Result copy_value() const final; Result copy() const; private: GcRoot _value; }; class TaskResult : public Object { public: TaskResult() {} TaskResult(TaskResult&& rhs) : _value(std::move(rhs._value)) {} TaskResult(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() const final { return Tag::TaskResult; } virtual PodObject* pod() const final { return _value.get(); } virtual Result cmp(const Object& rhs) const final { return -TRY(rhs.cmp(*this)); } virtual Result cmp(const TaskResult& rhs) const final; virtual void move(Object* obj) final { new (obj) TaskResult(std::move(_value)); } static Result create(PodTaskResult* obj) { return TaskResult(TRY(MkGcRoot(obj))); } static Result create(const Value& result, const Value& error); Result result() const; Result error() const; virtual Result copy_value() const final; Result copy() const; 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) { ((Object*)val.buf)->move((Object*)buf); 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) { ((Object*)buf)->~Object(); ((Object*)val.buf)->move((Object*)buf); new (val.buf) Nil(); return *this; } static Result create(PodObject* obj); static Result create(const int64_t& value) { return Value(TRY(Int64::create(value))); } static Result create(const char* value) { return Value(TRY(String::create(value))); } template bool is() const { return dynamic_cast((Object*)buf) != nullptr; } template T* to() const { return dynamic_cast((Object*)buf); } PodObject* pod() const { return ((Object*)buf)->pod(); } Tag tag() const { return ((Object*)buf)->tag(); } Object& operator*() { return *(Object*)(buf); } Object* operator->() { return (Object*)(buf); } Result cmp(const Value& rhs) const { return ((Object*)buf)->cmp(*(Object*)rhs.buf); } Result add(const Value& rhs) const { return ((Object*)buf)->add(*(Object*)rhs.buf); } Result mul(const Value& rhs) const { return ((Object*)buf)->mul(*(Object*)rhs.buf); } Result sub(const Value& rhs) const { return ((Object*)buf)->sub(*(Object*)rhs.buf); } Result div(const Value& rhs) const { return ((Object*)buf)->div(*(Object*)rhs.buf); } Result get(Value& key) const { return ((Object*)buf)->get(key); } Result get(int64_t key) const { Value k = TRY(Int64::create(key)); return ((Object*)buf)->get(k); } Result set(Value& key, Value& value) const { return ((Object*)buf)->set_value(key, value); } Result first() const { return ((Object*)buf)->first(); } Result second() const { return ((Object*)buf)->second(); } Result third() const { return ((Object*)buf)->third(); } Result rest() const { return ((Object*)buf)->rest(); } Result size() const { return ((Object*)buf)->size(); } // TODO: cmp() probably doesn't need arena parameter // Result operator==(Value& rhs) { return TRY(cmp(rhs)) == 0; } // Result operator!=(Value& rhs) { return TRY(cmp(rhs)) != 0; } Result copy() const { return ((Object*)buf)->copy_value(); } private: uint8_t buf[24]; }; Result syntax_unwrap(Value& val); Result reverse(Value& val); Result debug_print(const String& val); Result debug_print(const Value& val); Result debug_print(const char* val); template Result debug_print(const T& val) requires std::derived_from { return debug_print(TRY(val.copy_value())); } template Result Dict::set(const K& key, const V& value) const { Value k = TRY(Value::create(key)); Value v = TRY(Value::create(value)); return set(k, v); } template Result Array::append(const V& value) const { Value v = TRY(Value::create(value)); return append(v); } Result syntax_is_list(const Value& value); Result syntax_is_nil(const Value& value); Result syntax_unwrap(const Value& value); Result syntax_unwrap_all(const Value& value); Result build_string(const Value& value); Result build_string(const String& value); Result build_string(const char* value); Result build_string(int64_t value); Result build_string(uint64_t value); template Result build_string(const T& value, Args&&... args) { auto first = TRY(build_string(value)); auto rest = TRY(build_string(std::forward(args)...)); first = TRY(first.concat(rest)); return first; } Result print_string(const String& s);