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: {