From 5e425d7fe4b9edeb594fbc8e765030f8274189a1 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 1 Sep 2026 17:18:01 +0200 Subject: [PATCH] feat(furvm): implement constants Closes: #13 --- furvm/include/furvm/constant.hpp | 79 +++++++------------------------- furvm/include/furvm/module.hpp | 12 ++++- furvm/src/executor.cpp | 20 +++++++- furvm/src/instruction.cpp | 2 +- furvm/src/module.cpp | 29 ++++++++++++ 5 files changed, 76 insertions(+), 66 deletions(-) diff --git a/furvm/include/furvm/constant.hpp b/furvm/include/furvm/constant.hpp index 70ed4b7..606abf4 100644 --- a/furvm/include/furvm/constant.hpp +++ b/furvm/include/furvm/constant.hpp @@ -1,74 +1,29 @@ #ifndef FURVM_CONSTANT_HPP #define FURVM_CONSTANT_HPP -#include "furvm/exceptions.hpp" #include "furvm/fwd.hpp" +#include #include namespace furvm { -enum class constant_t : std::uint8_t { - String, /**< String constant. */ -}; - -class constant { -public: - using string_type = std::string_view; /**< String constant type. */ -public: - /** - * @brief Construct a new string constant. - * - * @param string String. - */ - constant(string_type string) - : m_type(constant_t::String), m_value(string) {} - - ~constant() = default; - - /** - * @brief Move constructor. - */ - constant(constant&&) = default; - - /** - * @brief Move constructor. - */ - constant& operator=(constant&&) = default; - - constant(const constant&) = delete; - constant& operator=(const constant&) = delete; -public: - /** - * @brief Returns this constant's type. - * @see constant_t - * - * @return The constant type. - */ - constexpr constant_t type() const { return m_type; } - - /** - * @brief Returns this constant's string value. - * @throws bad_constant_access if this constant's type is not constant_t::String. - * - * @return The string value. - */ - constexpr string_type string() const { - require_type(constant_t::String); - return m_value.string; - } -private: - void require_type(constant_t type) const { - if (m_type != type) throw bad_constant_access(); - } -private: - constant_t m_type{}; - union value { - string_type string; - - value(string_type sv) - : string(sv) {} - } m_value; +// TODO: Array constants +struct constant { + enum type_e { + S32 = 0, + U32, + S64, + U64, + String, + } type = S32; + union { + std::int32_t s32; + std::uint32_t u32; + std::int64_t s64; + std::uint64_t u64; + std::string_view string; + }; }; } // namespace furvm diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 7a5df9f..4fb6a9f 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -3,6 +3,7 @@ #include "furlang/utility/hash.hpp" #include "furlang/view.hpp" +#include "furvm/constant.hpp" #include "furvm/function.hpp" #include "furvm/fwd.hpp" #include "furvm/handle.hpp" @@ -10,8 +11,6 @@ #include #include -#include -#include #include #include #include @@ -384,6 +383,13 @@ public: if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot"); return m_globalVariables[var]; } +public: + template >> + void emplace_constant(Args&&... args) { + m_constants.emplace_back(std::forward(args)...); + } + + const constant& constant_at(constant_index index) const { return m_constants.at(index); } public: template >> void set_breakpoint(bytecode_pos pos, Fwd&& breakpoint) { @@ -423,6 +429,8 @@ private: std::vector> m_globalVariables; + std::vector m_constants; + std::unordered_map m_nativeFunctions; std::unordered_map m_breakpoints; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index bad5d1c..9697ed9 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -222,6 +222,25 @@ void executor::step() { push_thing({ (struct thing_type){ thing_type::U32 } }).get() = static_cast(instr.arg.u8); } break; + case instruction_t::PushConstant: { + auto constant = frame.mod->constant_at(instr.arg.u16); + switch (constant.type) { + case constant::S32: + push_thing({ (struct thing_type){ thing_type::S32 } }).get() = constant.s32; // NOLINT + break; + case constant::U32: + push_thing({ (struct thing_type){ thing_type::U32 } }).get() = constant.u32; // NOLINT + break; + case constant::S64: + push_thing({ (struct thing_type){ thing_type::S64 } }).get() = constant.s64; // NOLINT + break; + case constant::U64: + push_thing({ (struct thing_type){ thing_type::U64 } }).get() = constant.u64; // NOLINT + break; + case constant::String: throw std::runtime_error("unimplemented"); + default: throw std::runtime_error("invalid constant"); + } + } break; case instruction_t::Array: { const auto& type = *mod_to_thing_type(frame.mod, *frame.mod->type_at(instr.arg.u32)); if (type.type != thing_type::Array || type.value.array.type == nullptr || type.value.array.type == &type) @@ -377,7 +396,6 @@ void executor::step() { pop_frame(); if (m_frames.empty()) m_flags = m_flags | executor_flags::Done; } break; - case instruction_t::PushConstant: throw std::runtime_error("unimplemented"); default: throw std::runtime_error("unknown instruction"); } } diff --git a/furvm/src/instruction.cpp b/furvm/src/instruction.cpp index e4e2e31..d97ba26 100644 --- a/furvm/src/instruction.cpp +++ b/furvm/src/instruction.cpp @@ -22,7 +22,7 @@ const std::size_t instruction_argument::s_sizes[instruction_argument::Count] = { // U32 1, // Constant: - 4, + 2, // Type: 4, // Variable: diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index ef90be5..9005201 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -16,6 +16,19 @@ std::ostream& mod::serialize(std::ostream& os) const { os.write(MAGIC, sizeof(MAGIC)); detail::serialize(os, std::uint32_t(0)); // version + detail::serialize(os, static_cast(m_constants.size())); + for (const auto& constant : m_constants) { + detail::serialize(os, constant.type); + switch (constant.type) { + case constant::S32: + case constant::U32: detail::serialize(os, constant.u32); break; + case constant::S64: + case constant::U64: detail::serialize(os, constant.u64); break; + case constant::String: throw std::runtime_error("unimplemented"); + default: throw std::runtime_error("unreachable"); + } + } + mod_type_id typeCount = mod_type_id(m_types.cend() - m_types.cbegin()); detail::serialize(os, typeCount); for (mod_type_id id = 0; id < typeCount; ++id) { @@ -104,6 +117,22 @@ mod mod::load(std::istream& is) { mod mod; + constant_index constantCount = 0; + detail::load(is, constantCount); + mod.m_constants.reserve(constantCount); + for (; constantCount != 0; --constantCount) { + constant constant{}; + detail::load(is, reinterpret_cast(constant.type)); + switch (constant.type) { + case constant::S32: + case constant::U32: detail::load(is, constant.u32); break; + case constant::S64: + case constant::U64: detail::load(is, constant.u64); break; + case constant::String: throw std::runtime_error("unimplemented"); + default: throw std::runtime_error("unreachable"); + } + } + mod_type_id typeCount = 0; detail::load(is, typeCount); for (mod_type_id id = 0; id < typeCount; ++id) {