feat(furvm): add basic function

This commit is contained in:
2026-06-11 14:46:17 +02:00
parent 5472b77ea0
commit ba39f5ab27
7 changed files with 244 additions and 8 deletions
+2 -3
View File
@@ -94,10 +94,9 @@ public:
/** /**
* @brief Pushes a new frame. * @brief Pushes a new frame.
* *
* @param mod A shared pointer to a furvm module. * @param function Function.
* @param position Position in the module's bytecode.
*/ */
void push_frame(const mod_p& mod, std::size_t position); void push_frame(const function_p& function);
/** /**
* @brief Pops the top frame. * @brief Pops the top frame.
+148
View File
@@ -0,0 +1,148 @@
#ifndef FURVM_FUNCTION_HPP
#define FURVM_FUNCTION_HPP
#include "furvm/fwd.hpp"
#include "furvm/module.hpp" // IWYU pragma: keep
#include <functional>
#include <stdexcept>
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<void(const executor_p&)>;
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 <typename... Args,
typename = std::enable_if_t<std::is_constructible_v<function, funkcja, function_handle, Args..., const mod_p&>>>
static function_p create(const mod_p& mod, Args&&... args) {
function_handle id = mod->m_functions.size();
auto func = std::make_shared<function>(funkcja{}, id, std::forward<Args>(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
+31
View File
@@ -10,6 +10,11 @@
*/ */
namespace furvm { namespace furvm {
/**
* @brief A byte.
*
* There's nothing more to it.
*/
using byte = std::uint8_t; using byte = std::uint8_t;
// constant.hpp // constant.hpp
@@ -47,6 +52,32 @@ enum class instruction_t : byte;
*/ */
struct instruction; 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<function>;
/**
* @brief Furvm function's index.
*/
using function_handle = std::uint16_t;
// module.hpp // module.hpp
/** /**
+4 -2
View File
@@ -8,6 +8,7 @@
namespace furvm { namespace furvm {
class mod { class mod {
friend class function;
public: public:
using bytecode_t = std::vector<byte>; /**< An alias to a vector of bytes. */ using bytecode_t = std::vector<byte>; /**< An alias to a vector of bytes. */
public: public:
@@ -51,8 +52,9 @@ public:
*/ */
constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); }
private: private:
module_handle m_id; module_handle m_id;
bytecode_t m_bytecode; bytecode_t m_bytecode;
std::vector<function_p> m_functions;
}; };
} // namespace furvm } // namespace furvm
+4 -2
View File
@@ -2,6 +2,7 @@
#include "furvm/context.hpp" // IWYU pragma: keep #include "furvm/context.hpp" // IWYU pragma: keep
#include "furvm/exceptions.hpp" #include "furvm/exceptions.hpp"
#include "furvm/function.hpp" // IWYU pragma: keep
#include "furvm/instruction.hpp" #include "furvm/instruction.hpp"
#include "furvm/thing.hpp" #include "furvm/thing.hpp"
@@ -22,8 +23,9 @@ executor_p executor::create(const context_p& context) {
return std::move(ex); return std::move(ex);
} }
void executor::push_frame(const mod_p& mod, std::size_t position) { void executor::push_frame(const function_p& function) {
m_frames.emplace((struct executor::frame){ mod, position, m_stack.size() }); 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() { struct executor::frame executor::pop_frame() {
+43
View File
@@ -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
+12 -1
View File
@@ -2,10 +2,13 @@
#include "furvm/context.hpp" #include "furvm/context.hpp"
#include "furvm/executor.hpp" #include "furvm/executor.hpp"
#include "furvm/function.hpp"
#include "furvm/instruction.hpp" #include "furvm/instruction.hpp"
#include "furvm/thing.hpp"
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <iostream>
#include <memory> #include <memory>
static constexpr std::array<furvm::byte, 6> s_bytecode = { static constexpr std::array<furvm::byte, 6> s_bytecode = {
@@ -17,13 +20,21 @@ static constexpr std::array<furvm::byte, 6> s_bytecode = {
furvm::byte(furvm::instruction_t::Return), furvm::byte(furvm::instruction_t::Return),
}; };
void print(const furvm::executor_p& exec) {
std::cout << exec->pop_thing()->int32() << '\n';
}
int main(void) { int main(void) {
auto context = std::make_shared<furvm::context>(); auto context = std::make_shared<furvm::context>();
auto mainModule = context->emplace(s_bytecode.begin(), s_bytecode.end()); 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); 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 static constexpr std::size_t FPC = 3; // Frames per collection