From ba39f5ab27d06c74f9ac972c34ea80b9c49e6512 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Thu, 11 Jun 2026 14:46:17 +0200 Subject: [PATCH] feat(furvm): add basic function --- furvm/include/furvm/executor.hpp | 5 +- furvm/include/furvm/function.hpp | 148 +++++++++++++++++++++++++++++++ furvm/include/furvm/fwd.hpp | 31 +++++++ furvm/include/furvm/module.hpp | 6 +- furvm/src/executor.cpp | 6 +- furvm/src/function.cpp | 43 +++++++++ furvm/src/main.cpp | 13 ++- 7 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 furvm/include/furvm/function.hpp create mode 100644 furvm/src/function.cpp diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 118c44c..15f6af1 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -94,10 +94,9 @@ public: /** * @brief Pushes a new frame. * - * @param mod A shared pointer to a furvm module. - * @param position Position in the module's bytecode. + * @param function Function. */ - void push_frame(const mod_p& mod, std::size_t position); + void push_frame(const function_p& function); /** * @brief Pops the top frame. diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp new file mode 100644 index 0000000..e8c84ac --- /dev/null +++ b/furvm/include/furvm/function.hpp @@ -0,0 +1,148 @@ +#ifndef FURVM_FUNCTION_HPP +#define FURVM_FUNCTION_HPP + +#include "furvm/fwd.hpp" +#include "furvm/module.hpp" // IWYU pragma: keep + +#include +#include + +namespace furvm { + +enum class function_t : std::uint8_t { + Normal = 0, /**< A normal bytecode function. */ + Native, /**< A native function implemented through furvm API. */ +}; + +using native_function = std::function; + +class function { +private: + /** + * @brief A private token for the private constructor. + * + * Also `funkcja` in Polish translates to `function` from what I heard. + */ + struct funkcja { + explicit funkcja() = default; + }; +public: + /** + * @brief Private constructor. + * + * @param id + * @param position + * @param mod + */ + function(funkcja, function_handle id, std::size_t position, const mod_p& mod); + + /** + * @brief Private constructor. + * + * @param id + * @param native + * @param mod + */ + function(funkcja, function_handle id, const native_function& native, const mod_p& mod); + + ~function() = default; + + /** + * @brief Move constructor. + */ + function(function&&) noexcept; + + /** + * @brief Move constructor. + */ + function& operator=(function&&) noexcept; + + function(const function&) = delete; + function& operator=(const function&) = delete; +public: + /** + * @brief Returns a new function. + * + * @param mod Module. + * @param args Arguments to pass to the function constructor. + * @return The new function. + */ + template >> + static function_p create(const mod_p& mod, Args&&... args) { + function_handle id = mod->m_functions.size(); + + auto func = std::make_shared(funkcja{}, id, std::forward(args)..., mod); + mod->m_functions.emplace(mod->m_functions.begin() + id, func); + return std::move(func); + } +public: + /** + * @brief Returns an id of this function. + * + * @return The id. + */ + constexpr function_handle id() const { return m_id; } + + /** + * @brief Returns a type of this function. + * + * @return The type. + */ + constexpr function_t type() const { return m_type; } + + /** + * @brief Returns a parent module of this function. + * + * @return A shared pointer to the module. + */ + const mod_p& mod() const { return m_module; } +public: + /** + * @brief Returns a value for normal function. + * + * @return The value. + */ + std::size_t position() const { + if (m_type == function_t::Normal) throw std::runtime_error("function type mismatch"); + return m_value.position; + } + + /** + * @brief Returns a value for native function. + * + * @return The value. + */ + const native_function& native() const { + if (m_type == function_t::Native) throw std::runtime_error("function type mismatch"); + return m_value.native; + } +private: + function_handle m_id; + function_t m_type; + mod_p m_module; + + union value { + std::size_t position = 0; + native_function native; + + value() = default; + + value(std::size_t position) + : position(position) {} + + value(const native_function& native) + : native(native) {} + + ~value() {} + + value(value&& other) = delete; + value& operator=(value&& other) = delete; + value(const value& other) = delete; + value& operator=(const value& other) = delete; + } m_value; +}; + +} // namespace furvm + +#endif // FURVM_FUNCTION_HPP \ No newline at end of file diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index e6548dd..c7bb8ff 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -10,6 +10,11 @@ */ namespace furvm { +/** + * @brief A byte. + * + * There's nothing more to it. + */ using byte = std::uint8_t; // constant.hpp @@ -47,6 +52,32 @@ enum class instruction_t : byte; */ struct instruction; +// function.hpp + +/** + * @enum function_t + * @brief Function type. + */ +enum class function_t : std::uint8_t; + +/** + * @class function + * @brief Function. + * + * A furvm function. + */ +class function; + +/** + * @brief An alias to a function shared pointer. + */ +using function_p = std::shared_ptr; + +/** + * @brief Furvm function's index. + */ +using function_handle = std::uint16_t; + // module.hpp /** diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 451be5b..4b557ad 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -8,6 +8,7 @@ namespace furvm { class mod { + friend class function; public: using bytecode_t = std::vector; /**< An alias to a vector of bytes. */ public: @@ -51,8 +52,9 @@ public: */ constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } private: - module_handle m_id; - bytecode_t m_bytecode; + module_handle m_id; + bytecode_t m_bytecode; + std::vector m_functions; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index c523d28..e694d59 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -2,6 +2,7 @@ #include "furvm/context.hpp" // IWYU pragma: keep #include "furvm/exceptions.hpp" +#include "furvm/function.hpp" // IWYU pragma: keep #include "furvm/instruction.hpp" #include "furvm/thing.hpp" @@ -22,8 +23,9 @@ executor_p executor::create(const context_p& context) { return std::move(ex); } -void executor::push_frame(const mod_p& mod, std::size_t position) { - m_frames.emplace((struct executor::frame){ mod, position, m_stack.size() }); +void executor::push_frame(const function_p& function) { + if (function->type() != function_t::Normal) return; + m_frames.emplace((struct executor::frame){ function->mod(), function->position(), m_stack.size() }); } struct executor::frame executor::pop_frame() { diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp new file mode 100644 index 0000000..4d1ca25 --- /dev/null +++ b/furvm/src/function.cpp @@ -0,0 +1,43 @@ +#include "furvm/function.hpp" + +namespace furvm { + +function::function(funkcja, function_handle id, std::size_t position, const mod_p& mod) + : m_id(id), m_type(function_t::Normal), m_module(mod), m_value(position) {} + +function::function(funkcja, function_handle id, const native_function& native, const mod_p& mod) + : m_id(id), m_type(function_t::Native), m_module(mod), m_value(native) {} + +function::function(function&& other) noexcept + : m_id(other.m_id), m_type(other.m_type), m_module(std::move(other.m_module)) { + switch (m_type) { + case function_t::Normal: { + m_value.position = other.m_value.position; + } break; + case function_t::Native: { + new (&m_value.native) native_function(std::move(other.m_value.native)); + } break; + } + other.m_value.position = 0; +} + +function& function::operator=(function&& other) noexcept { + if (this == &other) return *this; + + m_id = other.m_id; + m_type = other.m_type; + m_module = std::move(other.m_module); + switch (m_type) { + case function_t::Normal: { + m_value.position = other.m_value.position; + } break; + case function_t::Native: { + new (&m_value.native) native_function(std::move(other.m_value.native)); + } break; + } + other.m_value.position = 0; + + return *this; +} + +} // namespace furvm \ No newline at end of file diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index d09fff2..7ae9113 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -2,10 +2,13 @@ #include "furvm/context.hpp" #include "furvm/executor.hpp" +#include "furvm/function.hpp" #include "furvm/instruction.hpp" +#include "furvm/thing.hpp" #include #include +#include #include static constexpr std::array s_bytecode = { @@ -17,13 +20,21 @@ static constexpr std::array s_bytecode = { furvm::byte(furvm::instruction_t::Return), }; +void print(const furvm::executor_p& exec) { + std::cout << exec->pop_thing()->int32() << '\n'; +} + int main(void) { auto context = std::make_shared(); auto mainModule = context->emplace(s_bytecode.begin(), s_bytecode.end()); + auto mainFunction = furvm::function::create(mainModule, 0); + + auto printFunction = furvm::function::create(mainModule, print); + auto executor = furvm::executor::create(context); - executor->push_frame(mainModule, 0); + executor->push_frame(mainFunction); static constexpr std::size_t FPC = 3; // Frames per collection