From e7e5f36380ecf9fe8d5d96a2426dac629ae37ad5 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sat, 6 Jun 2026 23:30:25 +0200 Subject: [PATCH] feat(furvm): add step function to executor --- furvm/include/furvm/executor.hpp | 6 ++++ furvm/include/furvm/fwd.hpp | 6 ++++ furvm/include/furvm/module.hpp | 8 ++++++ furvm/include/furvm/thing.hpp | 49 +++++++++++++++++++++++++++++++- furvm/src/executor.cpp | 32 +++++++++++++++++++++ furvm/src/main.cpp | 4 +++ furvm/src/thing.cpp | 12 +++++++- 7 files changed, 115 insertions(+), 2 deletions(-) diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index b556201..27e6b1a 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -9,6 +9,7 @@ namespace furvm { enum class executor_flags : std::uint32_t { Suspended = (1 << 0), /**< Execution suspended. */ + Done = (1 << 1), /**< Execution is finished. */ }; static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) { @@ -132,6 +133,11 @@ public: * @return The thing. */ thing_p thing() const; +public: + /** + * @brief Executes next instruction. + */ + void step(); private: executor_handle m_id; executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index dac2a9f..78a1a42 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -75,6 +75,12 @@ using module_handle = std::uint32_t; */ enum class thing_t : std::uint8_t; +/** + * @class bad_thing_access + * @brief Bad thing access exception. + */ +class bad_thing_access; + /** * @class thing * @brief Furvm thing. diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index c8497d1..451be5b 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -42,6 +42,14 @@ public: * @return The id. */ constexpr module_handle id() const { return m_id; } + + /** + * @brief Returns a byte from bytecode of this module. + * + * @param offset An offset of the byte. + * @return The byte. + */ + constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } private: module_handle m_id; bytecode_t m_bytecode; diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 17c96f8..934d18f 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -6,7 +6,7 @@ namespace furvm { enum class thing_t : std::uint8_t { - Int, + Int32, }; /** @@ -17,6 +17,39 @@ enum class thing_t : std::uint8_t { */ std::size_t thing_type_size(thing_t type); +class bad_thing_access : public std::exception { +public: + bad_thing_access() = default; + ~bad_thing_access() override = default; + + /** + * @brief Move constructor. + */ + bad_thing_access(bad_thing_access&&) noexcept = default; + + /** + * @brief Move constructor. + */ + bad_thing_access& operator=(bad_thing_access&&) noexcept = default; + + /** + * @brief Copy constructor. + */ + bad_thing_access(const bad_thing_access&) = default; + + /** + * @brief Copy constructor. + */ + bad_thing_access& operator=(const bad_thing_access&) = default; +public: + /** + * @brief Returns a C-style string describing the cause of the error. + * + * @return The cause of the error. + */ + const char* what() const noexcept override { return "bad thing access"; } +}; + class thing { friend class executor; private: @@ -61,6 +94,20 @@ public: * @return Shared pointer to the new thing. */ static thing_p create(const context_p& context, thing_t type); +public: + /** + * @brief Returns an int32 value from this thing. + * + * @return The value. + */ + std::int32_t& int32(); + + /** + * @brief Returns an int32 value from this thing. + * + * @return The value. + */ + const std::int32_t& int32() const; private: thing_handle m_id; thing_t m_type; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 110a3a2..6fe69ba 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -1,6 +1,10 @@ #include "furvm/executor.hpp" #include "furvm/context.hpp" // IWYU pragma: keep +#include "furvm/instruction.hpp" +#include "furvm/thing.hpp" + +#include namespace furvm { @@ -47,4 +51,32 @@ thing_p executor::thing() const { return m_stack.top(); } +void executor::step() { + if ((m_flags & executor_flags::Suspended) == executor_flags::Suspended) return; + + struct frame& frame = m_frames.top(); + + instruction_t instr = static_cast(frame.mod->byte(frame.position++)); + switch (instr) { + case instruction_t::NoOperation: break; + case instruction_t::Return: { + pop_frame(); + if (m_frames.empty()) m_flags = m_flags | executor_flags::Done; + } break; + case instruction_t::PushB2I: { + auto thing = thing::create(m_context, thing_t::Int32); + thing->int32() = frame.mod->byte(frame.position++); + m_stack.push(std::move(thing)); + } break; + case instruction_t::Drop: { + m_stack.pop(); + } break; + case instruction_t::PushConstant: + case instruction_t::Duplicate: + case instruction_t::ReturnValue: { + throw std::runtime_error("unimplemented"); + } + } +} + } // namespace furvm \ No newline at end of file diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index e2f119f..f6b25a8 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -22,6 +22,10 @@ int main(void) { auto executor = furvm::executor::create(context); executor->push_frame(mainModule, 0); + while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) { + executor->step(); + } + return 0; } diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index 0676651..80fbd0e 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -10,7 +10,7 @@ namespace furvm { std::size_t thing_type_size(thing_t type) { switch (type) { - case thing_t::Int: return 4; + case thing_t::Int32: return 4; } return 0; } @@ -28,6 +28,16 @@ thing_p thing::create(const context_p& context, thing_t type) { return std::move(th); } +std::int32_t& thing::int32() { + if (m_type != thing_t::Int32) throw bad_thing_access(); + return *static_cast(m_data); +} + +const std::int32_t& thing::int32() const { + if (m_type != thing_t::Int32) throw bad_thing_access(); + return *static_cast(m_data); +} + } // namespace furvm // NOLINTEND(cppcoreguidelines-no-malloc) \ No newline at end of file