From 8d3859ce7008bc6bd4d2fe4a99217e57d3813830 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sat, 11 Jul 2026 02:28:23 +0200 Subject: [PATCH] refactor(furvm): improve primitive types Improve primitive types and binary operations. Closes: #55 --- furvm/include/furvm/module.hpp | 33 ++-- furvm/include/furvm/thing.hpp | 277 +++++++++++++++++++++++++++------ furvm/src/executor.cpp | 55 ++++--- furvm/src/main.cpp | 30 ++-- furvm/src/module.cpp | 23 ++- 5 files changed, 316 insertions(+), 102 deletions(-) diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 4e45123..b456219 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -18,8 +18,6 @@ namespace furvm { struct mod_type { - using primitive = std::uint64_t; - struct array { mod_type_id typeId; std::size_t size; @@ -31,7 +29,14 @@ struct mod_type { }; enum type { - Primitive = 0, + S8 = 0, + S16, + S32, + S64, + U8, + U16, + U32, + U64, Array, Import, @@ -39,15 +44,11 @@ struct mod_type { } type; union value { std::nullptr_t null = nullptr; - primitive primitive; array array; imprt imprt; value() = default; - value(std::uint64_t primitive) - : primitive(primitive) {} - value(mod_type_id id, std::size_t size) : array({}) { array.typeId = id; @@ -69,8 +70,8 @@ struct mod_type { value& operator=(const value& other) = delete; } value; - mod_type(primitive primitive) - : type(Primitive), value(primitive) {} + mod_type(enum type type) + : type(type) {} mod_type(mod_type_id id, std::size_t size) : type(Array), value(id, size) {} @@ -83,8 +84,6 @@ struct mod_type { switch (type) { case Array: value.array.~array(); break; case Import: value.imprt.~imprt(); break; - case Primitive: - case Count: default: break; } } @@ -92,10 +91,9 @@ struct mod_type { mod_type(mod_type&& other) noexcept : type(other.type) { switch (type) { - case Primitive: new (&value.primitive) primitive(other.value.primitive); break; case Array: new (&value.array) array(other.value.array); break; case Import: new (&value.imprt) imprt(std::move(other.value.imprt)); break; - case Count: break; + default: break; } other.type = Count; } @@ -104,10 +102,9 @@ struct mod_type { if (this == &other) return *this; type = other.type; switch (type) { - case Primitive: new (&value.primitive) primitive(other.value.primitive); break; case Array: new (&value.array) array(other.value.array); break; case Import: new (&value.imprt) imprt(std::move(other.value.imprt)); break; - case Count: break; + default: break; } other.type = Count; return *this; @@ -116,10 +113,9 @@ struct mod_type { mod_type(const mod_type& other) : type(other.type) { switch (type) { - case Primitive: new (&value.primitive) primitive(other.value.primitive); break; case Array: new (&value.array) array(other.value.array); break; case Import: new (&value.imprt) imprt(other.value.imprt); break; - case Count: break; + default: break; } } @@ -127,10 +123,9 @@ struct mod_type { if (this == &other) return *this; type = other.type; switch (type) { - case Primitive: new (&value.primitive) primitive(other.value.primitive); break; case Array: new (&value.array) array(other.value.array); break; case Import: new (&value.imprt) imprt(other.value.imprt); break; - case Count: break; + default: break; } return *this; } diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 595812b..8d15e1e 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -14,13 +14,21 @@ #include #include #include +#include #include #include namespace furvm { struct thing_type { - using primitive = std::uint64_t; + using s8 = std::int8_t; + using s16 = std::int16_t; + using s32 = std::int32_t; + using s64 = std::int64_t; + using u8 = std::uint8_t; + using u16 = std::uint16_t; + using u32 = std::uint32_t; + using u64 = std::uint64_t; struct array { thing_type* type; @@ -28,17 +36,23 @@ struct thing_type { }; enum type { // NOLINT - Primitive = 0, + S8 = 0, + S16, + S32, + S64, + U8, + U16, + U32, + U64, Array, Count, } type; union value { - primitive primitive; - array array; + std::nullptr_t null = nullptr; + array array; - value(std::uint64_t primitive) - : primitive(primitive) {} + value() = default; value(thing_type* type, std::size_t size) : array({}) { @@ -54,7 +68,14 @@ struct thing_type { bool operator==(const thing_type& other) const { if (type != other.type) return false; switch (type) { - case Primitive: return value.primitive == other.value.primitive; + case S8: + case S16: + case S32: + case S64: + case U8: + case U16: + case U32: + case U64: return true; case Array: return *value.array.type == *other.value.array.type && value.array.size == other.value.array.size; case Count: break; } @@ -62,6 +83,38 @@ struct thing_type { } bool operator!=(const thing_type& other) const { return !this->operator==(other); } + + static bool is_primitive(enum type type) { + switch (type) { + case S8: + case S16: + case S32: + case S64: + case U8: + case U16: + case U32: + case U64: return true; + case Array: + case Count: break; + } + return false; + } + + static std::size_t primitive_size(enum type type) { + switch (type) { + case thing_type::S8: return sizeof(s8); + case thing_type::S16: return sizeof(s16); + case thing_type::S32: return sizeof(s32); + case thing_type::S64: return sizeof(s64); + case thing_type::U8: return sizeof(u8); + case thing_type::U16: return sizeof(u16); + case thing_type::U32: return sizeof(u32); + case thing_type::U64: return sizeof(u64); + case Array: + case Count: break; + } + return 0; + } }; namespace detail { @@ -70,10 +123,14 @@ struct thing_type_hash { std::size_t operator()(const thing_type& type) const { std::size_t seed = std::hash{}(type.type); switch (type.type) { - case thing_type::Primitive: - seed = - furlang::utility::hash_combine(seed, std::hash{}(type.value.primitive)); - return seed; + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: return seed; case thing_type::Array: seed = furlang::utility::hash_combine(seed, thing_type_hash{}(*type.value.array.type)); seed = furlang::utility::hash_combine(seed, @@ -116,11 +173,6 @@ class thing final { public: using allocator_type = Allocator; /**< Allocator type. */ public: - using s8 = std::int8_t; - using s16 = std::int16_t; - using s32 = std::int32_t; - using s64 = std::int64_t; - union array { std::byte flat[]; struct { @@ -186,7 +238,14 @@ public: thing res(m_type, m_allocator); switch (m_type.type) { - case thing_type::Primitive: std::memcpy(res.m_data, m_data, m_size); return std::move(res); + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: std::memcpy(res.m_data, m_data, m_size); return std::move(res); case thing_type::Array: copy_list(m_type, res.get(), get()); return std::move(res); case thing_type::Count: break; } @@ -221,8 +280,7 @@ public: */ template T& get() { - std::size_t size = m_size > 0 ? m_size : compute_size_na(m_type); - if (size != sizeof(T)) throw bad_thing_access(); + if (compute_size_na(m_type) != sizeof(T)) throw bad_thing_access(); return *std::launder(reinterpret_cast(m_data)); } @@ -233,8 +291,7 @@ public: */ template const T& get() const { - std::size_t size = m_size > 0 ? m_size : compute_size_na(m_type); - if (size != sizeof(T)) throw bad_thing_access(); + if (compute_size_na(m_type) != sizeof(T)) throw bad_thing_access(); return *std::launder(reinterpret_cast(m_data)); } public: @@ -331,13 +388,16 @@ public: * * @return The integer value. */ - s64 integer() const { - if (m_type.type != thing_type::Primitive) throw bad_thing_access(); - switch (m_type.value.primitive) { - case sizeof(s8): return get(); - case sizeof(s16): return get(); - case sizeof(s32): return get(); - case sizeof(s64): return get(); + thing_type::s64 integer() const { + switch (m_type.type) { + case thing_type::S8: return get(); + case thing_type::S16: return get(); + case thing_type::S32: return get(); + case thing_type::S64: return get(); + case thing_type::U8: return get(); + case thing_type::U16: return get(); + case thing_type::U32: return get(); + case thing_type::U64: return get(); default: throw std::runtime_error("unreachable"); } } @@ -346,7 +406,7 @@ public: constexpr bool is_reference() const { return m_size == 0; } - void resize(s64 newSize) { + void resize(thing_type::u64 newSize) { if (m_type.type != thing_type::Array) throw bad_thing_access(); if (m_type.value.array.size > 0) throw std::runtime_error("cannot resize a static array"); @@ -356,13 +416,13 @@ public: std::byte* newData = new std::byte[innerSize * newSize]; std::memcpy(newData, array.dynamic.data, - innerSize * std::min(static_cast(array.dynamic.size), newSize)); + innerSize * std::min(static_cast(array.dynamic.size), newSize)); array.dynamic.size = newSize; delete[] array.dynamic.data; array.dynamic.data = newData; } - thing at(s64 index) const { + thing at(thing_type::u64 index) const { if (m_type.type != thing_type::Array) throw bad_thing_access(); std::size_t elementSize = compute_size_na(*m_type.value.array.type); @@ -381,6 +441,11 @@ public: if (m_type.type != thing_type::Array) throw bad_thing_access(); return m_type.value.array.size == 0 ? get().dynamic.size : m_type.value.array.size; } + + template >> + T cast_to() const { + return visit_primitive([](auto value) { return static_cast(value); }); + } private: static void copy_list(const thing_type& arrayType, array& dst, const array& src) { if (arrayType.type != thing_type::Array || arrayType.value.array.type == nullptr) @@ -408,7 +473,14 @@ private: } switch (innerType.type) { - case thing_type::Primitive: std::memcpy(dst.flat, src.flat, size); return; + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: std::memcpy(dst.flat, src.flat, size); return; case thing_type::Array: for (std::size_t i = 0; i < size; ++i) { copy_list(*innerType.value.array.type, @@ -423,7 +495,14 @@ private: private: static std::size_t compute_size_na(const thing_type& type) { switch (type.type) { - case thing_type::Primitive: return type.value.primitive; + case thing_type::S8: return sizeof(thing_type::s8); + case thing_type::S16: return sizeof(thing_type::s16); + case thing_type::S32: return sizeof(thing_type::s32); + case thing_type::S64: return sizeof(thing_type::s64); + case thing_type::U8: return sizeof(thing_type::u8); + case thing_type::U16: return sizeof(thing_type::u16); + case thing_type::U32: return sizeof(thing_type::u32); + case thing_type::U64: return sizeof(thing_type::u64); case thing_type::Array: return type.value.array.size == 0 ? sizeof(array) : compute_size_na(*type.value.array.type) * type.value.array.size; @@ -439,23 +518,131 @@ private: thing(const thing_type& type, std::byte* data, const allocator_type& allocator = {}) : m_type(type), m_size(0), m_data(data), m_allocator(allocator) {} private: + template + decltype(auto) visit_primitive(Func&& func) const { + switch (m_type.type) { + case thing_type::S8: return std::forward(func)(get()); + case thing_type::S16: return std::forward(func)(get()); + case thing_type::S32: return std::forward(func)(get()); + case thing_type::S64: return std::forward(func)(get()); + case thing_type::U8: return std::forward(func)(get()); + case thing_type::U16: return std::forward(func)(get()); + case thing_type::U32: return std::forward(func)(get()); + case thing_type::U64: return std::forward(func)(get()); + default: throw bad_thing_access(); + } + } + template thing binary_op(const thing& rhs, const Op& op) const { - if (m_type.type == thing_type::Primitive && rhs.m_type.type == thing_type::Primitive) { - thing_type resultType = m_type.value.primitive >= rhs.m_type.value.primitive ? m_type : rhs.m_type; - std::size_t size = std::max(m_type.value.primitive, rhs.m_type.value.primitive); + if (thing_type::is_primitive(m_type.type) && thing_type::is_primitive(rhs.m_type.type)) { + static constexpr enum thing_type::type promotions[8 * 8] = { + // S8 + thing_type::S8, + thing_type::S16, + thing_type::S32, + thing_type::S64, + thing_type::S16, + thing_type::S16, + thing_type::S32, + thing_type::U64, + // S16 + thing_type::S16, + thing_type::S16, + thing_type::S32, + thing_type::S64, + thing_type::S16, + thing_type::S16, + thing_type::S32, + thing_type::U64, + // S32 + thing_type::S32, + thing_type::S32, + thing_type::S32, + thing_type::S64, + thing_type::S32, + thing_type::S32, + thing_type::U32, + thing_type::U64, + // S64 + thing_type::S64, + thing_type::S64, + thing_type::S64, + thing_type::S64, + thing_type::S64, + thing_type::S64, + thing_type::S64, + thing_type::U64, + // U8 + thing_type::S16, + thing_type::S16, + thing_type::S32, + thing_type::S64, + thing_type::U8, + thing_type::U16, + thing_type::U32, + thing_type::U64, + // U16 + thing_type::S16, + thing_type::S16, + thing_type::S32, + thing_type::S64, + thing_type::U16, + thing_type::U16, + thing_type::U32, + thing_type::U64, + // U32 + thing_type::S32, + thing_type::S32, + thing_type::U32, + thing_type::S64, + thing_type::U32, + thing_type::U32, + thing_type::U32, + thing_type::U64, + // U64 + thing_type::U64, + thing_type::U64, + thing_type::U64, + thing_type::U64, + thing_type::U64, + thing_type::U64, + thing_type::U64, + thing_type::U64, + }; - s64 result = op(integer(), rhs.integer()); + enum thing_type::type resultType = promotions[m_type.type + (rhs.m_type.type * 8)]; - thing res(resultType, m_allocator); - switch (size) { - case sizeof(s8): res.get() = result; break; - case sizeof(s16): res.get() = result; break; - case sizeof(s32): res.get() = result; break; - case sizeof(s64): res.get() = result; break; - default: throw std::runtime_error("unreachable"); + thing res = { thing_type{ resultType }, m_allocator }; + switch (resultType) { + case thing_type::S8: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::S16: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::S32: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::S64: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::U8: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::U16: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::U32: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::U64: + res.get() = Op{}(cast_to(), rhs.cast_to()); + return res; + case thing_type::Array: + case thing_type::Count: break; } - return std::move(res); + throw std::runtime_error("unreachable"); } throw std::runtime_error("unexpected operation"); diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 68583e6..12b6a84 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -21,7 +21,14 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const { type = *mod->type_at(imprt.typeId); } switch (static_cast(type.type)) { - case thing_type::Primitive: return { static_cast(type.type), type.value.primitive }; + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: return { static_cast(type.type) }; case thing_type::Array: { return { static_cast(type.type), { thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; @@ -117,7 +124,7 @@ void executor::step() { switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushB2I: { - push_thing({ (struct thing_type){ thing_type::Primitive, { 4 } }, m_context->thing_alloc() })->get() = + push_thing({ (struct thing_type){ thing_type::S32 }, m_context->thing_alloc() })->get() = frame.mod->byte(frame.position++); } break; case instruction_t::Array: { @@ -215,31 +222,37 @@ void executor::step() { push_thing(lhs->greater_equals(*rhs)); } break; case instruction_t::Pointerof: { - auto thing = pop_thing(); - auto ptr = push_thing( - { (struct thing_type){ thing_type::Primitive, { sizeof(std::uintptr_t) } }, m_context->thing_alloc() }); - switch (thing->type().type) { - case thing_type::Primitive: ptr->get() = reinterpret_cast(thing->raw()); break; - case thing_type::Array: - ptr->get() = reinterpret_cast( - thing->type().value.array.size == 0 ? thing->get::array>().dynamic.data - : thing->get::array>().flat); - break; - case thing_type::Count: throw std::runtime_error("unreachable"); - } + // auto thing = pop_thing(); + // auto ptr = push_thing( + //{ (struct thing_type){ thing_type::Primitive, { sizeof(std::uintptr_t) } }, m_context->thing_alloc() }); + // switch (thing->type().type) { + // case thing_type::Primitive: ptr->get() = reinterpret_cast(thing->raw()); + // break; case thing_type::Array: ptr->get() = reinterpret_cast( + // thing->type().value.array.size == 0 ? thing->get::array>().dynamic.data + //: thing->get::array>().flat); + // break; + // case thing_type::Count: throw std::runtime_error("unreachable"); + // } + throw std::runtime_error("unimplemented"); // TODO: Implement } break; case instruction_t::Sizeof: { auto thing = pop_thing(); - auto size = push_thing( - { (struct thing_type){ thing_type::Primitive, { sizeof(std::size_t) } }, m_context->thing_alloc() }); + auto size = push_thing({ (struct thing_type){ thing_type::U64 }, m_context->thing_alloc() }); switch (thing->type().type) { - case thing_type::Primitive: - size->get() = static_cast(thing->type().value.primitive); + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: + size->get() = static_cast(thing_type::primitive_size(thing->type().type)); break; case thing_type::Array: - size->get() = static_cast((thing->type().value.array.size == 0) - ? thing->get::array>().dynamic.size - : thing->type().value.array.size); + size->get() = static_cast( + (thing->type().value.array.size == 0) ? thing->get::array>().dynamic.size + : thing->type().value.array.size); break; default: throw std::runtime_error("unreachable"); } diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 85981ad..c10cc46 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -11,18 +11,25 @@ #include static void print_thing(const furvm::thing& thing) { + using namespace furvm; + switch (thing.type().type) { - case furvm::thing_type::Primitive: { - std::cout << thing.integer(); - } break; - case furvm::thing_type::Array: { + case thing_type::S8: std::cout << thing.cast_to(); break; + case thing_type::S16: std::cout << thing.get(); break; + case thing_type::S32: std::cout << thing.get(); break; + case thing_type::S64: std::cout << thing.get(); break; + case thing_type::U8: std::cout << thing.get(); break; + case thing_type::U16: std::cout << thing.get(); break; + case thing_type::U32: std::cout << thing.get(); break; + case thing_type::U64: std::cout << thing.get(); break; + case furvm::thing_type::Array: std::cout << "{ "; - for (furvm::thing<>::s64 i = 0; i < thing.size(); ++i) { + for (thing_type::u64 i = 0; i < thing.size(); ++i) { if (i > 0) std::cout << ", "; print_thing(thing.at(i)); } - std::cout << " }\n"; - } break; + std::cout << " }"; + break; default: std::cerr << "{Type not recognized}"; } } @@ -59,12 +66,15 @@ int main(int argc, char** argv) { }; auto mod = context->emplace("main", s_bytecode, s_bytecode + sizeof(s_bytecode)); - auto intType = mod->emplace_type(sizeof(int)); - auto arrayType = mod->emplace_type(intType.id(), 10); + auto charType = mod->emplace_type(furvm::mod_type::S8); + auto arrayType = mod->emplace_type(charType.id(), 10); auto mainFunc = mod->emplace_function("main", furvm::function_sig{}, 0); mod->emplace_function(furvm::function_sig{ { arrayType } }, "print").dispatch(); #endif - mod->set_native_function("print", [](furvm::executor& executor) { print_thing(*executor.load_thing(0)); }); + mod->set_native_function("print", [](furvm::executor& executor) { + print_thing(*executor.load_thing(0)); + std::cout << '\n'; + }); furvm::executor_h executor = context->emplace_executor(context); executor->push_frame(mod, *mainFunc); diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index a70eb58..1a74452 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -27,7 +26,14 @@ std::ostream& mod::serialize(std::ostream& os) const { auto type = *m_types.at(id); switch (type.type) { - case mod_type::Primitive: detail::serialize(os, type.value.primitive); break; + case mod_type::S8: + case mod_type::S16: + case mod_type::S32: + case mod_type::S64: + case mod_type::U8: + case mod_type::U16: + case mod_type::U32: + case mod_type::U64: break; case mod_type::Array: { detail::serialize(os, type.value.array.typeId); detail::serialize(os, type.value.array.size); @@ -101,11 +107,14 @@ mod mod::load(std::istream& is) { if (type == 0xFF) continue; switch ((enum mod_type::type)type) { - case mod_type::Primitive: { - mod_type::primitive primitive = 0; - detail::load(is, primitive); - mod.emplace_type(id, primitive).dispatch(); - } break; + case mod_type::S8: + case mod_type::S16: + case mod_type::S32: + case mod_type::S64: + case mod_type::U8: + case mod_type::U16: + case mod_type::U32: + case mod_type::U64: break; case mod_type::Array: { mod_type_id typeId = 0; detail::load(is, typeId);