@@ -97,9 +97,10 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Pushes a new frame.
|
* @brief Pushes a new frame.
|
||||||
*
|
*
|
||||||
* @param function Function.
|
* @param mod Module.
|
||||||
|
* @param function Function handle.
|
||||||
*/
|
*/
|
||||||
void push_frame(const function_p& function);
|
void push_frame(const mod_p& mod, function_handle function);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pops the top frame.
|
* @brief Pops the top frame.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define FURVM_FUNCTION_HPP
|
#define FURVM_FUNCTION_HPP
|
||||||
|
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/module.hpp" // IWYU pragma: keep
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -20,33 +19,30 @@ enum class function_t : std::uint8_t {
|
|||||||
using native_function = std::function<void(executor&)>;
|
using native_function = std::function<void(executor&)>;
|
||||||
|
|
||||||
class 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:
|
public:
|
||||||
/**
|
template <typename Name>
|
||||||
* @brief Private constructor.
|
function(Name&& name, bytecode_pos position)
|
||||||
*
|
: m_name(std::forward<Name>(name)), m_type(function_t::Normal), m_value(position) {}
|
||||||
* @param id
|
|
||||||
* @param position
|
|
||||||
* @param mod
|
|
||||||
*/
|
|
||||||
function(funkcja, function_handle id, std::size_t position, const mod_p& mod);
|
|
||||||
|
|
||||||
/**
|
function(const char* name, bytecode_pos position)
|
||||||
* @brief Private constructor.
|
: m_name(name), m_type(function_t::Normal), m_value(position) {}
|
||||||
*
|
|
||||||
* @param id
|
template <typename Name>
|
||||||
* @param native
|
function(Name&& name, const native_function& native)
|
||||||
* @param mod
|
: m_name(std::forward<Name>(name)), m_type(function_t::Native), m_value(native) {}
|
||||||
*/
|
|
||||||
function(funkcja, function_handle id, const native_function& native, const mod_p& mod);
|
function(const char* name, const native_function& native)
|
||||||
|
: m_name(name), m_type(function_t::Native), m_value(native) {}
|
||||||
|
|
||||||
|
template <typename Name, typename ModuleName>
|
||||||
|
function(Name&& name, ModuleName&& moduleName, function_handle function)
|
||||||
|
: m_name(std::forward<Name>(name)),
|
||||||
|
m_type(function_t::Import),
|
||||||
|
m_value(std::forward<ModuleName>(moduleName), function) {}
|
||||||
|
|
||||||
|
template <typename ModuleName>
|
||||||
|
function(const char* name, ModuleName&& moduleName, function_handle function)
|
||||||
|
: m_name(name), m_type(function_t::Import), m_value(std::forward<ModuleName>(moduleName), function) {}
|
||||||
|
|
||||||
~function();
|
~function();
|
||||||
|
|
||||||
@@ -64,28 +60,11 @@ public:
|
|||||||
function& operator=(const function&) = delete;
|
function& operator=(const function&) = delete;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a new function.
|
* @brief Returns a name of this function.
|
||||||
*
|
*
|
||||||
* @param mod Module.
|
* @return The name.
|
||||||
* @param args Arguments to pass to the function constructor.
|
|
||||||
* @return The new function.
|
|
||||||
*/
|
*/
|
||||||
template <typename... Args,
|
constexpr const std::string& name() const { return m_name; }
|
||||||
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.
|
* @brief Returns a type of this function.
|
||||||
@@ -93,13 +72,6 @@ public:
|
|||||||
* @return The type.
|
* @return The type.
|
||||||
*/
|
*/
|
||||||
constexpr function_t type() const { return m_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:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a value for normal function.
|
* @brief Returns a value for normal function.
|
||||||
@@ -141,9 +113,8 @@ public:
|
|||||||
return m_value.imp.function;
|
return m_value.imp.function;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
function_handle m_id;
|
std::string m_name;
|
||||||
function_t m_type;
|
function_t m_type;
|
||||||
mod_p m_module;
|
|
||||||
|
|
||||||
union value {
|
union value {
|
||||||
std::size_t position = 0;
|
std::size_t position = 0;
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ namespace furvm {
|
|||||||
*/
|
*/
|
||||||
using byte = std::uint8_t;
|
using byte = std::uint8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An offset into bytecode.
|
||||||
|
*/
|
||||||
|
using bytecode_pos = std::uint64_t;
|
||||||
|
|
||||||
// constant.hpp
|
// constant.hpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
#ifndef FURVM_MODULE_HPP
|
#ifndef FURVM_MODULE_HPP
|
||||||
#define FURVM_MODULE_HPP
|
#define FURVM_MODULE_HPP
|
||||||
|
|
||||||
|
#include "furvm/function.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
@@ -80,6 +86,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
constexpr const bytecode_t& bytecode() const { return m_bytecode; }
|
constexpr const bytecode_t& bytecode() const { return m_bytecode; }
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns a function from this module.
|
||||||
|
*
|
||||||
|
* @param name Name of the function.
|
||||||
|
* @return The function.
|
||||||
|
*/
|
||||||
|
template <typename Name>
|
||||||
|
constexpr const function_p& function_at(Name&& name) const {
|
||||||
|
return m_functions.at(std::forward<Name>(name));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a function from this module.
|
* @brief Returns a function from this module.
|
||||||
*
|
*
|
||||||
@@ -87,9 +104,32 @@ public:
|
|||||||
* @return The function.
|
* @return The function.
|
||||||
*/
|
*/
|
||||||
constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); }
|
constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns an id of a function.
|
||||||
|
*
|
||||||
|
* @param function Function to get the id of.
|
||||||
|
* @return The function's id.
|
||||||
|
*/
|
||||||
|
function_handle function_id(const function_p& function) const {
|
||||||
|
if (auto it = std::find(m_functions.begin(), m_functions.end(), function); it != m_functions.end())
|
||||||
|
return it - m_functions.begin();
|
||||||
|
throw std::runtime_error("function not in the module");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
function_handle emplace_function(Args&&... args) {
|
||||||
|
function_p function = std::make_shared<class function>(std::forward<Args>(args)...);
|
||||||
|
m_functionMap.emplace(function->name(), function);
|
||||||
|
function_handle id = m_functions.size();
|
||||||
|
m_functions.emplace_back(std::move(function));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
bytecode_t m_bytecode;
|
bytecode_t m_bytecode;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, function_p> m_functionMap;
|
||||||
std::vector<function_p> m_functions;
|
std::vector<function_p> m_functions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ executor_p executor::create(const context_p& context) {
|
|||||||
return std::move(ex);
|
return std::move(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::push_frame(const function_p& function) {
|
void executor::push_frame(const mod_p& mod, function_handle function) {
|
||||||
if (function->type() != function_t::Normal) return;
|
const auto& func = mod->function_at(function);
|
||||||
m_frames.emplace((struct executor::frame){ function->mod(), function->position(), m_stack.size() });
|
if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type");
|
||||||
|
m_frames.emplace((struct executor::frame){ mod, func->position(), m_stack.size() });
|
||||||
}
|
}
|
||||||
|
|
||||||
struct executor::frame executor::pop_frame() {
|
struct executor::frame executor::pop_frame() {
|
||||||
@@ -185,11 +186,11 @@ void executor::step() {
|
|||||||
|
|
||||||
const function_p& function = frame.mod->function_at(funcId);
|
const function_p& function = frame.mod->function_at(funcId);
|
||||||
switch (function->type()) {
|
switch (function->type()) {
|
||||||
case function_t::Normal: push_frame(function); break;
|
case function_t::Normal: push_frame(frame.mod, funcId); break;
|
||||||
case function_t::Native: function->native()(*this); break;
|
case function_t::Native: function->native()(*this); break;
|
||||||
case function_t::Import: {
|
case function_t::Import: {
|
||||||
const mod_p& impMod = m_context->m_modules.at(function->imported_module());
|
const mod_p& impMod = m_context->m_modules.at(function->imported_module());
|
||||||
push_frame(impMod->function_at(function->imported_function()));
|
push_frame(frame.mod, function->imported_function());
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
|
|
||||||
namespace furvm {
|
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::~function() {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case function_t::Normal:
|
case function_t::Normal:
|
||||||
@@ -22,7 +16,7 @@ function::~function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function::function(function&& other) noexcept
|
function::function(function&& other) noexcept
|
||||||
: m_id(other.m_id), m_type(other.m_type), m_module(std::move(other.m_module)) {
|
: m_name(std::move(other.m_name)), m_type(other.m_type) {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case function_t::Normal: {
|
case function_t::Normal: {
|
||||||
m_value.position = other.m_value.position;
|
m_value.position = other.m_value.position;
|
||||||
@@ -41,9 +35,8 @@ function::function(function&& other) noexcept
|
|||||||
function& function::operator=(function&& other) noexcept {
|
function& function::operator=(function&& other) noexcept {
|
||||||
if (this == &other) return *this;
|
if (this == &other) return *this;
|
||||||
|
|
||||||
m_id = other.m_id;
|
m_name = std::move(other.m_name);
|
||||||
m_type = other.m_type;
|
m_type = other.m_type;
|
||||||
m_module = std::move(other.m_module);
|
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case function_t::Normal: {
|
case function_t::Normal: {
|
||||||
m_value.position = other.m_value.position;
|
m_value.position = other.m_value.position;
|
||||||
|
|||||||
+2
-3
@@ -25,14 +25,13 @@ int main(void) {
|
|||||||
auto context = std::make_shared<furvm::context>();
|
auto context = std::make_shared<furvm::context>();
|
||||||
|
|
||||||
auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end());
|
auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end());
|
||||||
|
mainModule->emplace_function("main", 0);
|
||||||
auto mainFunction = furvm::function::create(mainModule, 0);
|
|
||||||
|
|
||||||
std::ofstream file("./test.furm", std::ios::binary);
|
std::ofstream file("./test.furm", std::ios::binary);
|
||||||
furvm::serializer::serialize_module(file, mainModule);
|
furvm::serializer::serialize_module(file, mainModule);
|
||||||
|
|
||||||
auto executor = furvm::executor::create(context);
|
auto executor = furvm::executor::create(context);
|
||||||
executor->push_frame(mainFunction);
|
executor->push_frame(mainModule, 0);
|
||||||
|
|
||||||
static constexpr std::size_t FPC = 3; // Frames per collection
|
static constexpr std::size_t FPC = 3; // Frames per collection
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "furvm/serializer.hpp"
|
#include "furvm/serializer.hpp"
|
||||||
|
|
||||||
#include "furvm/function.hpp" // IWYU pragma: keep
|
#include "furvm/function.hpp" // IWYU pragma: keep
|
||||||
|
#include "furvm/fwd.hpp"
|
||||||
|
#include "furvm/module.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -73,8 +75,9 @@ bool serializer::serialize_module(std::ostream& os, const mod_p& mod) {
|
|||||||
write_u32(os, VERSION);
|
write_u32(os, VERSION);
|
||||||
|
|
||||||
write_u32(os, mod->m_functions.size());
|
write_u32(os, mod->m_functions.size());
|
||||||
for (const auto& func : mod->m_functions) {
|
for (function_handle id = 0; id < static_cast<function_handle>(mod->m_functions.size()); ++id) {
|
||||||
write_u16(os, func->id());
|
const auto& func = mod->m_functions[id];
|
||||||
|
write_u16(os, id);
|
||||||
write_u8(os, static_cast<std::uint8_t>(func->type()));
|
write_u8(os, static_cast<std::uint8_t>(func->type()));
|
||||||
switch (func->type()) {
|
switch (func->type()) {
|
||||||
case function_t::Normal: {
|
case function_t::Normal: {
|
||||||
|
|||||||
Reference in New Issue
Block a user