From a3724e1c78fcfb979ec51abfb8fcd1515692db9c Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Thu, 1 Aug 2024 18:56:38 +0100 Subject: [PATCH] Add dicts and super primitive test suite --- CMakeLists.txt | 1 + src/arena.cpp | 6 +++ src/arena.hpp | 1 + src/common.cpp | 30 ++++++++++++ src/common.hpp | 122 ++++++++++++++++++++++++++++++++++++++++++++++- src/compiler.cpp | 2 + src/die.hpp | 9 ++-- src/pod.hpp | 9 ++++ src/writer.cpp | 6 +++ src/writer.hpp | 1 + test/dict.cpp | 4 ++ test/test.hpp | 40 ++++++++++++++++ 12 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 test/dict.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 059aee1..f3dceaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ install(TARGETS vli) enable_testing() set(CPP_TESTS + dict ) diff --git a/src/arena.cpp b/src/arena.cpp index c513d6f..3838c46 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -74,6 +74,8 @@ Result Arena::gc_pod(PodObject* obj) { return gc_array((PodArray*)obj); case Tag::ByteArray: return gc_bytearray((PodByteArray*)obj); + case Tag::Dict: + return gc_dict((PodDict*)obj); } return ErrorCode::TypeMismatch; @@ -161,3 +163,7 @@ Result Arena::gc_bytearray(PodByteArray* obj) { memcpy(nobj->data, obj->data, obj->size); return nobj; } + +Result Arena::gc_dict(PodDict* obj) { + return ErrorCode::NotImplemented; +} diff --git a/src/arena.hpp b/src/arena.hpp index eee463a..0514aba 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -153,6 +153,7 @@ class Arena { Result gc_pair(PodPair* obj); Result gc_array(PodArray* obj); Result gc_bytearray(PodByteArray* obj); + Result gc_dict(PodDict* obj); void add_root(GcRootList* node) { _gcroot.insert(node); } diff --git a/src/common.cpp b/src/common.cpp index 5cdc45d..f71318a 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -25,6 +25,8 @@ Result Value::create(Arena& arena, PodObject* obj) { return Value(TRY(Array::create(arena, (PodArray*)obj))); case Tag::ByteArray: return Value(TRY(ByteArray::create(arena, (PodByteArray*)obj))); + case Tag::Dict: + return Value(TRY(Dict::create(arena, (PodDict*)obj))); case Tag::String: return Value(TRY(String::create(arena, (PodString*)obj))); case Tag::Symbol: @@ -92,6 +94,10 @@ Result ByteArray::copy(Arena& arena) { return Value(ByteArray(TRY(_value.copy(arena)))); } +Result Dict::copy(Arena& arena) { + return Value(Dict(TRY(_value.copy(arena)))); +} + Result String::copy(Arena& arena) { return Value(String(TRY(_value.copy(arena)))); } @@ -173,3 +179,27 @@ Result Array::append(Arena& arena, Value& rhs) { return Array(TRY(MkGcRoot(pod, arena))); } + +short cmp_tag(Tag lhs, Tag rhs) { + if (lhs < rhs) return -1; + if (rhs < lhs) return 1; + return 0; +} + +Result Dict::get(Arena& arena, Value& key) { + return ErrorCode::TypeMismatch; +} + +Result Dict::insert(Arena& arena, Value& key, Value& value) { + return ErrorCode::TypeMismatch; +} + +Result Int64::cmp(Float& rhs) { + return (_value->value > rhs._value->value) - + (_value->value < rhs._value->value); +} + +Result Float::cmp(Int64& rhs) { + return (_value->value > rhs._value->value) - + (_value->value < rhs._value->value); +} diff --git a/src/common.hpp b/src/common.hpp index 7779416..7151e3e 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -13,6 +13,18 @@ class Value; class String; +class Nil; +class Int64; +class Float; +class Bool; +class String; +class Symbol; +class Syntax; +class Pair; +class Array; +class ByteArray; + +short cmp_tag(Tag lhs, Tag rhs); class Object { public: @@ -21,6 +33,21 @@ class Object { virtual PodObject* pod() = 0; virtual void move(Object*) = 0; virtual ~Object() = default; + + virtual Result cmp(Object&) = 0; + virtual Result cmp(Nil&) { return cmp_tag(tag(), Tag::Nil); } + virtual Result cmp(Int64&) { return cmp_tag(tag(), Tag::Int64); } + virtual Result cmp(Float&) { return cmp_tag(tag(), Tag::Float); } + virtual Result cmp(Bool&) { return cmp_tag(tag(), Tag::Bool); } + virtual Result cmp(String&) { return cmp_tag(tag(), Tag::String); } + virtual Result cmp(Symbol&) { return cmp_tag(tag(), Tag::Symbol); } + virtual Result cmp(Syntax&) { return cmp_tag(tag(), Tag::Syntax); } + virtual Result cmp(Pair&) { return cmp_tag(tag(), Tag::Pair); } + virtual Result cmp(Array&) { return cmp_tag(tag(), Tag::Array); } + virtual Result cmp(ByteArray&) { + return cmp_tag(tag(), Tag::ByteArray); + } + Object() = default; Object(const Object&) = delete; }; @@ -34,6 +61,9 @@ class Nil : public Object { virtual Tag tag() final { return Tag::Nil; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Nil& rhs) final { return 0; } + static Result create(Arena& arena, PodNil* obj) { return Nil(TRY(MkGcRoot(obj, arena))); } @@ -66,6 +96,8 @@ class Array : public Object { virtual Tag tag() final { return Tag::Array; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Array& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) Array(std::move(_value)); } @@ -129,6 +161,8 @@ class ByteArray : public Object { virtual Tag tag() final { return Tag::ByteArray; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(ByteArray& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) ByteArray(std::move(_value)); @@ -220,6 +254,61 @@ class ByteArray : public Object { GcRoot _value; }; +class Dict : public Object { + public: + 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() final { return Tag::Dict; } + virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Array& rhs) final { return 0; } + + virtual void move(Object* obj) final { new (obj) Dict(std::move(_value)); } + + static Result create(Arena& arena, PodDict* obj) { + return Dict(TRY(MkGcRoot(obj, arena))); + } + + static Result create(Arena& arena) { + auto pod = TRY(arena.alloc()); + pod->header.tag = Tag::Dict; + + pod->size = 0; + + return Dict(TRY(MkGcRoot(pod, arena))); + } + + virtual Result copy(Arena& arena) final; + + Result get(Arena& arena, Value& key); + + Result insert(Arena& arena, Value& key, Value& value); + + Result concat(Arena& arena, Dict& 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(PodObject*))); + pod->size = res_size; + memcpy(pod->data, _value->data, sizeof(PodObject*) * lhs_size); + memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char) * rhs_size); + + return Dict(TRY(MkGcRoot(pod, arena))); + } + + private: + uint64_t size() { return _value->size; } + GcRoot _value; +}; + class String : public Object { public: String() {} @@ -233,6 +322,8 @@ class String : public Object { virtual Tag tag() final { return Tag::String; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(String& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) String(std::move(_value)); } @@ -333,6 +424,8 @@ class Symbol : public Object { Symbol(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Symbol; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Symbol& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) Symbol(std::move(_value)); } @@ -371,6 +464,8 @@ class Syntax : public Object { Syntax(String filename, String modulename, Value expression); virtual Tag tag() final { return Tag::Syntax; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Syntax& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) Syntax(std::move(_value)); } @@ -393,6 +488,8 @@ class Pair : public Object { Pair(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Pair; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Pair& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) Pair(std::move(_value)); } @@ -412,11 +509,19 @@ class Pair : public Object { 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() final { return Tag::Int64; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Int64& rhs) final { + return (_value->value > rhs._value->value) - + (_value->value < rhs._value->value); + } + virtual Result cmp(Float& rhs) final; virtual void move(Object* obj) final { new (obj) Int64(std::move(_value)); } @@ -442,11 +547,19 @@ class Int64 : public Object { 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() final { return Tag::Float; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Float& rhs) final { + return (_value->value > rhs._value->value) - + (_value->value < rhs._value->value); + } + virtual Result cmp(Int64& rhs) final; virtual void move(Object* obj) final { new (obj) Float(std::move(_value)); } @@ -478,6 +591,8 @@ class Bool : public Object { virtual Tag tag() final { return Tag::Bool; } virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Bool& rhs) final { return 0; } virtual void move(Object* obj) final { new (obj) Bool(std::move(_value)); } @@ -507,7 +622,6 @@ class Value { Value() { new (buf) Nil(); } ~Value() { ((Object*)buf)->~Object(); } Value(Value&& val) { - // TODO: repoint the gc root properly ((Object*)val.buf)->move((Object*)buf); new (val.buf) Nil(); } @@ -545,6 +659,12 @@ class Value { Object& operator*() { return *(Object*)(buf); } Object* operator->() { return (Object*)(buf); } + Result cmp(Value& rhs) { + return ((Object*)buf)->cmp(*(Object*)rhs.buf); + } + + Result operator==(Value& rhs) { return TRY(cmp(rhs)) == 0; } + Result copy(Arena& arena) { return ((Object*)buf)->copy(arena); } private: diff --git a/src/compiler.cpp b/src/compiler.cpp index db2711a..a9e15f6 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -21,11 +21,13 @@ Result Compiler::compile_expr(Value& expr) { case Tag::Syntax: case Tag::Array: case Tag::ByteArray: + case Tag::Dict: return ErrorCode::TypeMismatch; } return ErrorCode::TypeMismatch; } Result Compiler::compile_list(Pair& expr) { + auto first = TRY(expr.first(_arena)); return ErrorCode::TypeMismatch; } diff --git a/src/die.hpp b/src/die.hpp index cf6a3b6..3a101e9 100644 --- a/src/die.hpp +++ b/src/die.hpp @@ -1,8 +1,9 @@ #pragma once #include +#include -#define die(message) \ - do { \ - fprintf(stderr, "ERROR: %s", message); \ - exit(EXIT_FAILURE); \ +#define die(message) \ + do { \ + fprintf(stderr, "ERROR: %s:%d %s\n", __FILE__, __LINE__, message); \ + exit(EXIT_FAILURE); \ } while (0) diff --git a/src/pod.hpp b/src/pod.hpp index 4c3a0b7..5ccf7ad 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -16,6 +16,7 @@ enum class Tag : uint8_t { Pair, Array, ByteArray, + Dict, }; template @@ -92,6 +93,14 @@ class PodByteArray final : public PodObject { char data[]; }; +class PodDict final : public PodObject { + public: + PodDict() : PodObject(Tag::Dict){}; + + uint64_t size; + OffPtr data[]; +}; + class PodString final : public PodObject { public: PodString() : PodObject(Tag::String){}; diff --git a/src/writer.cpp b/src/writer.cpp index 2c24205..f595a74 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -14,6 +14,8 @@ Result Writer::write_one(Value& obj) { return write_array(*obj.to()); case Tag::ByteArray: return write_bytearray(*obj.to()); + case Tag::Dict: + return write_dict(*obj.to()); case Tag::String: return write_string(*obj.to()); case Tag::Symbol: @@ -186,3 +188,7 @@ Result Writer::write_array(Array& val) { res = TRY(res.concat(_arena, "]")); return res; } + +Result Writer::write_dict(Dict& val) { + return ErrorCode::NotImplemented; +} diff --git a/src/writer.hpp b/src/writer.hpp index 61930b8..8384e1d 100644 --- a/src/writer.hpp +++ b/src/writer.hpp @@ -19,6 +19,7 @@ class Writer { Result write_bool(Bool& val); Result write_array(Array& val); Result write_bytearray(ByteArray& val); + Result write_dict(Dict& val); Result write_symbol(Symbol& val); Result write_syntax(Syntax& val); diff --git a/test/dict.cpp b/test/dict.cpp new file mode 100644 index 0000000..d92f128 --- /dev/null +++ b/test/dict.cpp @@ -0,0 +1,4 @@ +#include "die.hpp" +#include "test.hpp" + +TEST_CASE(dict_insert) { die("test"); } diff --git a/test/test.hpp b/test/test.hpp index e69de29..120669f 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +const uint64_t MAX_TESTS = 1024 * 1024; +static void (*tests[MAX_TESTS])() = {0}; + +const char* add_test(void (*fun)(void)) { + for (uint64_t i = 0; i < MAX_TESTS; ++i) { + if (tests[i] == 0) { + tests[i] = fun; + break; + } + } + + return 0; +} + +bool run_tests() { + for (uint64_t i = 0; i < MAX_TESTS; ++i) { + if (tests[i] == 0) break; + + tests[i](); + } + + return true; +} + +#define CONCAT_IMPL(x, y) x##y +#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y) + +#define TEST_CASE_IMPL(ID, ...) \ + static void ID(); \ + static const char* MACRO_CONCAT(test_id_, __COUNTER__) [[maybe_unused]] = \ + add_test(&ID); \ + void ID() + +#define TEST_CASE(fun_) TEST_CASE_IMPL(MACRO_CONCAT(fun_, _COUNTER_)) + +int main() { return run_tests() ? 0 : 1; }