From 8702298cd228946c0769d3b3bfbf02eee6638d90 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 28 Jun 2026 12:37:36 +0200 Subject: [PATCH] refactor(furvm): improve functions Define native functions inside the module instead of the function itself (native functions hold only the key to the definition), introduce private functions, add parameter count to function and fix some bugs. Closes: #20 Closes: #25 --- furvm/include/furvm/function.hpp | 50 ++++++++++++++++--------- furvm/include/furvm/module.hpp | 63 ++++++++++++++++++++++++++++++-- furvm/src/executor.cpp | 35 +++++++++++------- furvm/src/function.cpp | 35 ++++++++++++------ furvm/src/main.cpp | 21 ++++++++--- furvm/src/module.cpp | 7 ++-- 6 files changed, 157 insertions(+), 54 deletions(-) diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index 89ebd01..88aed83 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -2,10 +2,12 @@ #define FURVM_FUNCTION_HPP #include "furvm/fwd.hpp" +#include "furvm/handle.hpp" // IWYU pragma: keep -#include +#include #include #include +#include #include namespace furvm { @@ -19,7 +21,7 @@ enum class function_t : std::uint8_t { /** * @brief A native function. */ -using native_function = std::function; +using native_function = std::string; /** * @brief A function import. @@ -35,31 +37,36 @@ public: * @brief Constructs a normal function. * * @param name Name of the function. + * @param paramCount Paremeter count. * @param position Offset in bytecode of the function. */ template - function(Name&& name, bytecode_pos position) - : m_name(std::forward(name)), m_type(function_t::Normal), m_value(position) {} + function(Name&& name, std::uint32_t paramCount, bytecode_pos position) + : m_name(std::forward(name)), m_type(function_t::Normal), m_paramCount(paramCount), m_value(position) {} /** * @brief Constructs a native function. * * @param name Name of the function. - * @param native Native function. + * @param paramCount Paremeter count. + * @param native Native function tag. */ - template - function(Name&& name, const native_function& native) - : m_name(std::forward(name)), m_type(function_t::Native), m_value(native) {} + template >> + function(Name&& name, std::uint32_t paramCount, Native&& native) + : m_name(std::forward(name)), + m_type(function_t::Native), + m_paramCount(paramCount), + m_value(std::forward(native)) {} /** * @brief Constructs an import function. * - * @param name Name of the function. + * @param paramCount Parameter count. * @param imp Import function. */ - template - function(Name&& name, const import_function& imp) - : m_name(std::forward(name)), m_type(function_t::Import), m_value(imp) {} + function(const mod_h& mod, const function_h& function); /** * @brief Destructs a function. @@ -99,6 +106,13 @@ public: * @return The type. */ constexpr function_t type() const { return m_type; } + + /** + * @brief Returns this function's parameter count. + * + * @return The parameter count. + */ + constexpr std::uint32_t param_count() const { return m_paramCount; } public: /** * @brief Returns normal function's value. @@ -123,15 +137,16 @@ public: /** * @brief Returns import function's value. * - * @return The name. + * @return The value. */ const import_function& imp() const { if (m_type != function_t::Import) throw std::runtime_error("function type mismatch"); return m_value.imp; } private: - std::string m_name; - function_t m_type; + std::string m_name; + function_t m_type; + std::uint32_t m_paramCount; union value { std::size_t position = 0; @@ -143,8 +158,9 @@ private: value(std::size_t position) : position(position) {} - value(const native_function& native) - : native(native) {} + template >> + value(Native&& native) + : native(std::forward(native)) {} value(const import_function& imp) : imp(imp) {} diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 2936dde..72bb4e7 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -5,6 +5,7 @@ #include "furvm/fwd.hpp" #include "furvm/handle.hpp" +#include #include #include #include @@ -20,6 +21,8 @@ public: using bytecode_t = std::vector; /**< An alias to a vector of bytes. */ static constexpr char MAGIC[4] = { 'F', 'u', 'r', 'M' }; /** Furvm module file magic. */ + + using native_function = std::function; public: /** * @brief Constructs a module. @@ -71,11 +74,29 @@ public: /** * @brief Emplaces a function in the module's function container. * + * Emplaces the function in module's function container and name to function map and public functions map. + * * @param args Arguments forwarded into the container's emplace_back function. * @return A handle to the emplaced function. */ template function_h emplace_function(Args&&... args) { + function_h function = m_functions.emplace_back(std::forward(args)...); + m_functionMap[function->name()] = function.id(); + m_publicFunctions[function->name()] = function.id(); + return std::move(function); + } + + /** + * @brief Emplaces a function in the module's function container. + * + * Emplaces the function in module's function container and name to function map . + * + * @param args Arguments forwarded into the container's emplace_back function. + * @return A handle to the emplaced function. + */ + template + function_h emplace_function_private(Args&&... args) { function_h function = m_functions.emplace_back(std::forward(args)...); m_functionMap[function->name()] = function.id(); return std::move(function); @@ -87,8 +108,18 @@ public: * @param function Function to insert. */ template - void push_back(Function&& function) { - m_functions.emplace_back(std::forward(function)); + auto push_back(Function&& function) { + return emplace_function(std::forward(function)); + } + + /** + * @brief Inserts a function in the module's function container. + * + * @param function Function to insert. + */ + template + auto push_back_private(Function&& function) { + return emplace_function_private(std::forward(function)); } /** @@ -115,7 +146,7 @@ public: */ template auto function_at(NameFwd&& name) { - return function_at(m_functionMap.at(std::forward(name))); + return function_at(m_publicFunctions.at(std::forward(name))); } /** @@ -126,7 +157,18 @@ public: */ template auto function_at(NameFwd&& name) const { - return function_at(m_functionMap.at(std::forward(name))); + return function_at(m_publicFunctions.at(std::forward(name))); + } + + /** + * @brief Returns an id of a function from the module. + * + * @param name Name of the function. + * @return An id of the function. + */ + template + auto get_function_id(NameFwd&& name) { + return m_functionMap.at(std::forward(name)); } /** @@ -135,6 +177,16 @@ public: * @param id Identifier of the function. */ void erase_function(function_id id) { m_functions.erase(id); } +public: + template + void set_native_function(NameFwd&& name, Func&& func) { + m_nativeFunctions.emplace(std::forward(name), std::forward(func)); + } + + template + native_function get_native_function(NameFwd&& name) const { + return m_nativeFunctions.at(std::forward(name)); + } public: /** * @brief Prints the module in a bytecode form to an output stream. @@ -147,7 +199,10 @@ private: bytecode_t m_bytecode; std::unordered_map m_functionMap; + std::unordered_map m_publicFunctions; handle_container m_functions; + + std::unordered_map m_nativeFunctions; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 5468cf9..e94f7fe 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -9,18 +9,31 @@ #include #include +#include namespace furvm { void executor::push_frame(const mod_h& mod, function function) { + mod_h modInst = mod; while (function.type() == function_t::Import) { - function = *m_context->module_at(function.imp().mod)->function_at(function.imp().function); + modInst = m_context->module_at(function.imp().mod); + function = *modInst->function_at(function.imp().function); } + + std::vector args; + args.reserve(function.param_count()); + for (size_t i = 0; i < function.param_count(); ++i) + args.push_back(pop_thing()); + switch (function.type()) { case function_t::Normal: { - m_frames.emplace((struct executor::frame){ mod, function.position(), m_stack.size() }); + m_frames.emplace((struct executor::frame){ mod, function.position(), m_stack.size(), std::move(args) }); + } break; + case function_t::Native: { + m_frames.emplace((struct executor::frame){ mod, 0, m_stack.size(), std::move(args) }); + modInst->get_native_function(function.name())(*this); + m_frames.pop(); } break; - case function_t::Native: default: throw std::runtime_error("unexpected function type"); } } @@ -54,13 +67,13 @@ thing_h executor::thing() const { void executor::store_thing(variable_t variable, const thing_h& thing) { auto& frame = m_frames.top(); - frame.variables.resize(variable + 1); + if (frame.variables.size() <= variable) frame.variables.resize(variable + 1); frame.variables[variable] = thing; } void executor::store_thing(variable_t variable, thing_h&& thing) { auto& frame = m_frames.top(); - frame.variables.resize(variable + 1); + if (frame.variables.size() <= variable) frame.variables.resize(variable + 1); frame.variables[variable] = std::move(thing); } @@ -160,21 +173,15 @@ void executor::step() { function_id funcId = static_cast(frame.mod->byte(frame.position)) | (static_cast(frame.mod->byte(frame.position + 1)) << 8); frame.position += 2; - - const function_h& function = frame.mod->function_at(funcId); - switch (function->type()) { - case function_t::Normal: - case function_t::Import: push_frame(frame.mod, *function); break; - case function_t::Native: function->native()(*this); break; - } + push_frame(frame.mod, *frame.mod->function_at(funcId)); } break; case instruction_t::Jump: { - frame.position += frame.mod->byte(frame.position++); + frame.position += ((std::int8_t)frame.mod->byte(frame.position)) + 1; } break; case instruction_t::JumpNotZero: { byte offset = frame.mod->byte(frame.position++); auto cond = pop_thing(); - if (cond->int32() != 0) frame.position += offset; + if (cond->int32() != 0) frame.position += (std::int8_t)offset; } break; case instruction_t::Return: { pop_frame(); diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp index e649be8..36fa5a7 100644 --- a/furvm/src/function.cpp +++ b/furvm/src/function.cpp @@ -1,14 +1,21 @@ #include "furvm/function.hpp" +#include "furvm/furvm.hpp" + #include namespace furvm { +function::function(const mod_h& mod, const function_h& function) + : m_type(function_t::Import), m_paramCount(0), m_value(import_function{ mod.id(), function.id() }) {} + function::~function() { switch (m_type) { case function_t::Normal: - case function_t::Native: default: break; + case function_t::Native: { + m_value.native.~native_function(); + } break; case function_t::Import: { m_value.imp.~import_function(); } break; @@ -16,7 +23,7 @@ function::~function() { } function::function(function&& other) noexcept - : m_name(std::move(other.m_name)), m_type(other.m_type) { + : m_name(std::move(other.m_name)), m_type(other.m_type), m_paramCount(other.m_paramCount) { switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -25,8 +32,9 @@ function::function(function&& other) noexcept new (&m_value.native) native_function(std::move(other.m_value.native)); } break; case function_t::Import: { - m_value.imp = std::move(other.m_value.imp); + new (&m_value.imp) import_function(std::move(other.m_value.imp)); } break; + default: break; } other.m_value.position = 0; } @@ -34,8 +42,9 @@ function::function(function&& other) noexcept function& function::operator=(function&& other) noexcept { if (this == &other) return *this; - m_name = std::move(other.m_name); - m_type = other.m_type; + m_name = std::move(other.m_name); + m_type = other.m_type; + m_paramCount = other.m_paramCount; switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -44,8 +53,9 @@ function& function::operator=(function&& other) noexcept { new (&m_value.native) native_function(std::move(other.m_value.native)); } break; case function_t::Import: { - m_value.imp = std::move(other.m_value.imp); + new (&m_value.imp) import_function(std::move(other.m_value.imp)); } break; + default: break; } other.m_value.position = 0; @@ -53,7 +63,7 @@ function& function::operator=(function&& other) noexcept { } function::function(const function& other) - : m_name(other.m_name), m_type(other.m_type) { + : m_name(other.m_name), m_type(other.m_type), m_paramCount(other.m_paramCount) { switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -62,16 +72,18 @@ function::function(const function& other) new (&m_value.native) native_function(other.m_value.native); } break; case function_t::Import: { - m_value.imp = other.m_value.imp; + new (&m_value.imp) import_function(other.m_value.imp); } break; + default: break; } } function& function::operator=(const function& other) { if (this == &other) return *this; - m_name = other.m_name; - m_type = other.m_type; + m_name = other.m_name; + m_type = other.m_type; + m_paramCount = other.m_paramCount; switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -80,8 +92,9 @@ function& function::operator=(const function& other) { new (&m_value.native) native_function(other.m_value.native); } break; case function_t::Import: { - m_value.imp = other.m_value.imp; + new (&m_value.imp) import_function(other.m_value.imp); } break; + default: break; } return *this; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index a8487df..0576d04 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -13,22 +13,33 @@ static constexpr std::array s_bytecode = { 67, furvm::byte(furvm::instruction_t::Clone), furvm::byte(furvm::instruction_t::Add), + furvm::byte(furvm::instruction_t::Call), + 1, + 0, furvm::byte(furvm::instruction_t::Return), }; int main(void) { auto context = std::make_shared(); - furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); - furvm::function_h mainFunc = mainModule->emplace_function("main", 0); + furvm::mod_h furlangModule = context->emplace_module("furlang"); + furvm::function_h printFunc = furlangModule->emplace_function("print", 1, "print"); + furlangModule->set_native_function("print", [](furvm::executor& executor) { + furvm::thing_h thing = executor.load_thing(0); + switch (thing->type()) { + case furvm::thing_t::Int32: { + std::cout << thing->int32() << '\n'; + } break; + } + }); - mainModule->serialize(std::cout); + furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); + furvm::function_h mainFunc = mainModule->emplace_function("main", 0, 0); + mainModule->emplace_function(furlangModule, printFunc).dispatch(); furvm::executor_h executor = context->emplace_executor(context); executor->push_frame(mainModule, *mainFunc); - static constexpr std::size_t FPC = 3; // Frames per collection - while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) { executor->step(); } diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index 97d45f1..2267d0f 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -12,9 +12,10 @@ std::ostream& mod::serialize(std::ostream& os) const { detail::serialize(os, std::uint32_t(0)); // version detail::serialize(os, function_id(m_functionMap.size())); - for (const auto& [name, id] : m_functionMap) { - detail::serialize(os, name); - function_h func = m_functions.at(id); + for (auto* pair : m_functions) { + function_h func = { pair }; + bool isPublic = m_publicFunctions.find(func->name()) != m_publicFunctions.end(); + detail::serialize(os, isPublic ? func->name() : ""); // private functions have empty names detail::serialize(os, std::uint8_t(func->type())); switch (func->type()) { case function_t::Normal: {