diff --git a/src/common.cpp b/src/common.cpp index 8b8f52e..287cc90 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -4,6 +4,7 @@ #include "error.hpp" #include "pod.hpp" #include "utf8.hpp" +#include "writer.hpp" Syntax::Syntax(String filename, String modulename, Value expression) {} @@ -163,6 +164,12 @@ Result debug_print(Arena& arena, String& val) { return Result(); } +Result debug_print(Arena& arena, Value& val) { + auto w = Writer(arena); + auto s = TRY(w.write_one(val)); + return debug_print(arena, s); +} + Result Array::get(Arena& arena, uint64_t idx) { if (idx >= _value->size) return ErrorCode::IndexOutOfRange; auto val = _value->data[idx].get(pod()); diff --git a/src/common.hpp b/src/common.hpp index 4b49e99..d5d0b99 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -330,7 +330,26 @@ 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 Result cmp(String& rhs) final { + auto lsize = size(); + auto rsize = 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)); } @@ -654,6 +673,10 @@ class Value { return Value(TRY(Int64::create(arena, value))); } + static Result create(Arena& arena, const char* value) { + return Value(TRY(String::create(arena, value))); + } + template bool is() { return dynamic_cast((Object*)buf) != nullptr; @@ -688,6 +711,7 @@ Result syntax_unwrap(Value& val); Result reverse(Arena& arena, Value& val); Result debug_print(Arena& arena, String& val); +Result debug_print(Arena& arena, Value& val); template Result Dict::insert(Arena& arena, const K& key, const V& value) { diff --git a/src/writer.cpp b/src/writer.cpp index 35026c8..6ab1182 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -216,3 +216,8 @@ Result Writer::write_dict(Dict& val) { res = TRY(res.concat(_arena, "}")); return res; } + +Result write_one(Arena& arena, Value& value) { + auto w = Writer(arena); + return w.write_one(value); +} diff --git a/src/writer.hpp b/src/writer.hpp index 8384e1d..c2a49be 100644 --- a/src/writer.hpp +++ b/src/writer.hpp @@ -25,3 +25,14 @@ class Writer { Arena& _arena; }; + +Result write_one(Arena& arena, Value& value); + +template +Result write_one(Arena& arena, T& value) + requires std::derived_from +{ + auto w = Writer(arena); + auto v = DIEX(value.copy(arena)); + return w.write_one(v); +} diff --git a/test/dict.cpp b/test/dict.cpp index 38a410f..0ed6494 100644 --- a/test/dict.cpp +++ b/test/dict.cpp @@ -15,10 +15,7 @@ TEST_CASE(dict_insert) { d = DIEX(d.insert(arena, 0, 5)); d = DIEX(d.insert(arena, 2, 6)); - auto w = Writer(arena); + auto s = DIEX(write_one(arena, d)); - auto dd = DIEX(d.copy(arena)); - auto s = DIEX(w.write_one(dd)); - - DIEX(debug_print(arena, s)); + ASSERT_EQUALS(s, "{0 5 1 3 2 6 3 3}"); } diff --git a/test/test.hpp b/test/test.hpp index 120669f..0d889bf 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -1,6 +1,11 @@ #pragma once +#include #include +#include + +#include "common.hpp" +#include "result.hpp" const uint64_t MAX_TESTS = 1024 * 1024; static void (*tests[MAX_TESTS])() = {0}; @@ -37,4 +42,51 @@ bool run_tests() { #define TEST_CASE(fun_) TEST_CASE_IMPL(MACRO_CONCAT(fun_, _COUNTER_)) +template +struct Capture { + Capture(T& value) : value(value) {} + T& value; +}; + +template +struct Capture { + Capture(T& value) : value(value) {} + T& value; +}; + +template +struct Capture { + Capture(T&& value) : value(value) {} + T value; +}; + +Value& to_value(Arena& arena, Value& val) { return val; } + +template + requires std::derived_from +Value to_value(Arena& arena, T& val) { + return DIEX(val.copy(arena)); +} + +template + requires(!std::derived_from) +Value to_value(Arena& arena, T& val) { + return DIEX(Value::create(arena, val)); +} + +#define ASSERT_EQUALS(lhs, rhs) \ + do { \ + auto l = Capture(lhs); \ + auto r = Capture(rhs); \ + auto lv = to_value(arena, l.value); \ + auto rv = to_value(arena, r.value); \ + short c = DIEX(lv.cmp(rv)); \ + if (c != 0) { \ + fprintf(stderr, "Values not equal at %s:%d\n", __FILE__, __LINE__); \ + debug_print(arena, lv); \ + debug_print(arena, rv); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + int main() { return run_tests() ? 0 : 1; }