feat: implement module loading
I couldn't care less to commit all the changes separately after fight with this stupid codebase. Also I am closing the issue since serializing contexts meant doing something like jars which I don't want to do right now. I'll reopen the issue though for sure clueless. Closes: #23
This commit is contained in:
@@ -16,6 +16,14 @@ namespace detail {
|
|||||||
* @return The output stream.
|
* @return The output stream.
|
||||||
*/
|
*/
|
||||||
std::ostream& serialize(std::ostream& os, std::int8_t value);
|
std::ostream& serialize(std::ostream& os, std::int8_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serializes an integer.
|
||||||
|
*
|
||||||
|
* @param os Output stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The output stream.
|
||||||
|
*/
|
||||||
std::ostream& serialize(std::ostream& os, std::int16_t value);
|
std::ostream& serialize(std::ostream& os, std::int16_t value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +34,14 @@ std::ostream& serialize(std::ostream& os, std::int16_t value);
|
|||||||
* @return The output stream.
|
* @return The output stream.
|
||||||
*/
|
*/
|
||||||
std::ostream& serialize(std::ostream& os, std::int32_t value);
|
std::ostream& serialize(std::ostream& os, std::int32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serializes an integer.
|
||||||
|
*
|
||||||
|
* @param os Output stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The output stream.
|
||||||
|
*/
|
||||||
std::ostream& serialize(std::ostream& os, std::int64_t value);
|
std::ostream& serialize(std::ostream& os, std::int64_t value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +89,87 @@ std::ostream& serialize(std::ostream& os, std::uint64_t value);
|
|||||||
*/
|
*/
|
||||||
std::ostream& serialize(std::ostream& os, const std::string& value);
|
std::ostream& serialize(std::ostream& os, const std::string& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::int8_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::int16_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::int32_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::int64_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::uint8_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::uint16_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::uint32_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes an integer.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value Integer.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::uint64_t& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes a string.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @param value String.
|
||||||
|
* @return The input stream.
|
||||||
|
*/
|
||||||
|
std::istream& load(std::istream& is, std::string& value);
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,18 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Constructs an import function.
|
* @brief Constructs an import function.
|
||||||
*
|
*
|
||||||
* @param paramCount Parameter count.
|
* @param mod Module's id.
|
||||||
* @param imp Import function.
|
* @param function Function's id.
|
||||||
|
*/
|
||||||
|
template <typename ModFwd, typename = std::enable_if_t<std::is_constructible_v<mod_id, ModFwd>>>
|
||||||
|
function(ModFwd&& mod, function_id function)
|
||||||
|
: m_type(function_t::Import), m_paramCount(0), m_value(import_function{ std::forward<ModFwd>(mod), function }) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs an import function.
|
||||||
|
*
|
||||||
|
* @param mod Module.
|
||||||
|
* @param function Function.
|
||||||
*/
|
*/
|
||||||
function(const mod_h& mod, const function_h& function);
|
function(const mod_h& mod, const function_h& function);
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ public:
|
|||||||
using const_pointer = const Value*; /** Constant pointer type. */
|
using const_pointer = const Value*; /** Constant pointer type. */
|
||||||
public:
|
public:
|
||||||
using id_type = typename Header::id_type; /** Id type of the header. */
|
using id_type = typename Header::id_type; /** Id type of the header. */
|
||||||
|
|
||||||
|
using header_type = Header;
|
||||||
public:
|
public:
|
||||||
using pair_type = std::pair<Header, Value>; /** Type of a header-value pair. */
|
using pair_type = std::pair<Header, Value>; /** Type of a header-value pair. */
|
||||||
public:
|
public:
|
||||||
@@ -362,9 +364,16 @@ public:
|
|||||||
delete m_pairs[id];
|
delete m_pairs[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
pair_type* newPair = new pair_type(std::piecewise_construct,
|
pair_type* newPair = nullptr;
|
||||||
std::forward_as_tuple(id, 0, [&](const id_type& id) { erase(id); }),
|
if constexpr (detail::header_has_refcount_v<typename Handle::header_type>) {
|
||||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
newPair = new pair_type(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(id, 0, [&](const id_type& id) { erase(id); }),
|
||||||
|
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
|
} else {
|
||||||
|
newPair = new pair_type(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(id),
|
||||||
|
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
m_pairs[id] = newPair;
|
m_pairs[id] = newPair;
|
||||||
return { newPair };
|
return { newPair };
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
#include "furvm/type.hpp" // IWYU pragma: keep
|
#include "furvm/type.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -82,7 +84,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
function_h emplace_function(Args&&... args) {
|
function_h emplace_function(Args&&... args) {
|
||||||
function_h function = m_functions.emplace_back(std::forward<Args>(args)...);
|
function_h function;
|
||||||
|
if constexpr (std::is_constructible_v<class function, Args...>) {
|
||||||
|
function = m_functions.emplace_back(std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
function = m_functions.emplace(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
m_functionMap[function->name()] = function.id();
|
m_functionMap[function->name()] = function.id();
|
||||||
m_publicFunctions[function->name()] = function.id();
|
m_publicFunctions[function->name()] = function.id();
|
||||||
return std::move(function);
|
return std::move(function);
|
||||||
@@ -145,7 +153,7 @@ public:
|
|||||||
* @param name Name of the function.
|
* @param name Name of the function.
|
||||||
* @return A handle to the function.
|
* @return A handle to the function.
|
||||||
*/
|
*/
|
||||||
template <typename NameFwd>
|
template <typename NameFwd, typename = std::enable_if_t<std::is_constructible_v<std::string, NameFwd>>>
|
||||||
auto function_at(NameFwd&& name) {
|
auto function_at(NameFwd&& name) {
|
||||||
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
||||||
}
|
}
|
||||||
@@ -156,7 +164,7 @@ public:
|
|||||||
* @param name Name of the function.
|
* @param name Name of the function.
|
||||||
* @return A handle to the function.
|
* @return A handle to the function.
|
||||||
*/
|
*/
|
||||||
template <typename NameFwd>
|
template <typename NameFwd, typename = std::enable_if_t<std::is_constructible_v<std::string, NameFwd>>>
|
||||||
auto function_at(NameFwd&& name) const {
|
auto function_at(NameFwd&& name) const {
|
||||||
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
||||||
}
|
}
|
||||||
@@ -197,7 +205,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto emplace_type(Args&&... args) {
|
auto emplace_type(Args&&... args) {
|
||||||
return m_types.emplace_back(std::forward<Args>(args)...);
|
if constexpr (std::is_constructible_v<type_p, Args...>) {
|
||||||
|
return m_types.emplace_back(std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
return m_types.emplace(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,6 +251,14 @@ public:
|
|||||||
* @return The output stream.
|
* @return The output stream.
|
||||||
*/
|
*/
|
||||||
std::ostream& serialize(std::ostream& os) const;
|
std::ostream& serialize(std::ostream& os) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads a module in a bytecode form from an input stream.
|
||||||
|
*
|
||||||
|
* @param is Input stream.
|
||||||
|
* @return The loaded module.
|
||||||
|
*/
|
||||||
|
static mod load(std::istream& is);
|
||||||
private:
|
private:
|
||||||
bytecode_t m_bytecode;
|
bytecode_t m_bytecode;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include "furvm/handle.hpp" // IWYU pragma: keep
|
#include "furvm/handle.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
enum class type_t : std::uint32_t {
|
enum class type_t : std::uint32_t {
|
||||||
|
|||||||
@@ -1,49 +1,127 @@
|
|||||||
#include "furvm/detail/serialization.hpp"
|
#include "furvm/detail/serialization.hpp"
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace furvm::detail {
|
namespace furvm::detail {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename T, std::size_t... I>
|
||||||
|
void serialize_integral_impl(std::ostream& os, std::make_unsigned_t<T> u_value, std::index_sequence<I...>) {
|
||||||
|
((os << static_cast<char>((u_value >> (I * 8)) & 0xFF)), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t... I>
|
||||||
|
void load_integral_impl(const char* bs, std::make_unsigned_t<T>& u_value, std::index_sequence<I...>) {
|
||||||
|
using UnsignedT = std::make_unsigned_t<T>;
|
||||||
|
((u_value |= (static_cast<UnsignedT>(static_cast<std::uint8_t>(bs[I])) << (I * 8))), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::ostream& serialize_integral(std::ostream& os, T value) {
|
||||||
|
static_assert(std::is_integral_v<T>, "Type must be an integral type.");
|
||||||
|
using UnsignedT = std::make_unsigned_t<T>;
|
||||||
|
|
||||||
|
serialize_integral_impl<T>(os, static_cast<UnsignedT>(value), std::make_index_sequence<sizeof(T)>{});
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::istream& load_integral(std::istream& is, T& value) {
|
||||||
|
static_assert(std::is_integral_v<T>, "Type must be an integral type.");
|
||||||
|
|
||||||
|
char bs[sizeof(T)];
|
||||||
|
if (!is.read(bs, sizeof(T))) {
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
using UnsignedT = std::make_unsigned_t<T>;
|
||||||
|
UnsignedT uVal = 0;
|
||||||
|
|
||||||
|
load_integral_impl<T>(bs, uVal, std::make_index_sequence<sizeof(T)>{});
|
||||||
|
|
||||||
|
value = static_cast<T>(uVal);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::int8_t value) {
|
std::ostream& serialize(std::ostream& os, std::int8_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF);
|
return serialize_integral(os, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::int16_t value) {
|
std::ostream& serialize(std::ostream& os, std::int16_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF);
|
return serialize_integral(os, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::int32_t value) {
|
std::ostream& serialize(std::ostream& os, std::int32_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF)
|
return serialize_integral(os, value);
|
||||||
<< (char)((value >> 24ULL) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::int64_t value) {
|
std::ostream& serialize(std::ostream& os, std::int64_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF)
|
return serialize_integral(os, value);
|
||||||
<< (char)((value >> 24ULL) & 0xFF) << (char)((value >> 32ULL) & 0xFF) << (char)((value >> 40ULL) & 0xFF)
|
|
||||||
<< (char)((value >> 48ULL) & 0xFF) << (char)((value >> 56ULL) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::uint8_t value) {
|
std::ostream& serialize(std::ostream& os, std::uint8_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF);
|
return serialize_integral(os, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::uint16_t value) {
|
std::ostream& serialize(std::ostream& os, std::uint16_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF);
|
return serialize_integral(os, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::uint32_t value) {
|
std::ostream& serialize(std::ostream& os, std::uint32_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF)
|
return serialize_integral(os, value);
|
||||||
<< (char)((value >> 24ULL) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, std::uint64_t value) {
|
std::ostream& serialize(std::ostream& os, std::uint64_t value) {
|
||||||
return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF)
|
return serialize_integral(os, value);
|
||||||
<< (char)((value >> 24ULL) & 0xFF) << (char)((value >> 32ULL) & 0xFF) << (char)((value >> 40ULL) & 0xFF)
|
|
||||||
<< (char)((value >> 48ULL) & 0xFF) << (char)((value >> 56ULL) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& serialize(std::ostream& os, const std::string& value) {
|
std::ostream& serialize(std::ostream& os, const std::string& value) {
|
||||||
return serialize(os, std::uint16_t(value.size())).write(value.data(), static_cast<std::streamsize>(value.size()));
|
return serialize(os, static_cast<std::uint16_t>(value.size()))
|
||||||
|
.write(value.data(), static_cast<std::streamsize>(value.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::int8_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::int16_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::int32_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::int64_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::uint8_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::uint16_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::uint32_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::uint64_t& value) {
|
||||||
|
return load_integral(is, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& load(std::istream& is, std::string& value) {
|
||||||
|
std::uint16_t length = 0;
|
||||||
|
load(is, length);
|
||||||
|
|
||||||
|
value.resize(length);
|
||||||
|
return is.read(value.data(), static_cast<std::streamsize>(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furvm::detail
|
} // namespace furvm::detail
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ void executor::push_frame(const mod_h& mod, function function) {
|
|||||||
} break;
|
} break;
|
||||||
case function_t::Native: {
|
case function_t::Native: {
|
||||||
m_frames.emplace((struct executor::frame){ mod, 0, m_stack.size(), std::move(args) });
|
m_frames.emplace((struct executor::frame){ mod, 0, m_stack.size(), std::move(args) });
|
||||||
modInst->get_native_function(function.name())(*this);
|
modInst->get_native_function(function.native())(*this);
|
||||||
m_frames.pop();
|
m_frames.pop();
|
||||||
} break;
|
} break;
|
||||||
default: throw std::runtime_error("unexpected function type");
|
default: throw std::runtime_error("unexpected function type");
|
||||||
|
|||||||
+18
-20
@@ -1,5 +1,6 @@
|
|||||||
#ifndef LIBFURVM
|
#ifndef LIBFURVM
|
||||||
|
|
||||||
|
#include "furvm/detail/serialization.hpp"
|
||||||
#include "furvm/furvm.hpp"
|
#include "furvm/furvm.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -7,33 +8,30 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
static constexpr std::array<furvm::byte, 9> s_bytecode = {
|
int main(int argc, char** argv) {
|
||||||
furvm::byte(furvm::instruction_t::PushB2I),
|
if (argc != 2) {
|
||||||
67,
|
std::cerr << "Usage: " << argv[0] << " <mod.fmod>\n";
|
||||||
furvm::byte(furvm::instruction_t::Duplicate),
|
return 1;
|
||||||
furvm::byte(furvm::instruction_t::Reference),
|
}
|
||||||
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::context>();
|
auto context = std::make_shared<furvm::context>();
|
||||||
|
|
||||||
furvm::mod_h furlangModule = context->emplace("furlang");
|
std::ifstream file(argv[1]);
|
||||||
furvm::function_h printFunc = furlangModule->emplace_function("print", 1, "print");
|
if (!file.is_open()) {
|
||||||
furlangModule->set_native_function("print",
|
std::cerr << "Failed to open " << argv[1] << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
furvm::mod_h mod = context->emplace("main", furvm::mod::load(file));
|
||||||
|
furvm::function_h func = mod->function_at("main");
|
||||||
|
|
||||||
|
mod->set_native_function("print",
|
||||||
[](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; });
|
[](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; });
|
||||||
|
|
||||||
furvm::mod_h mainModule = context->emplace("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);
|
furvm::executor_h executor = context->emplace_executor(context);
|
||||||
executor->push_frame(mainModule, *mainFunc);
|
executor->push_frame(mod, *func);
|
||||||
|
|
||||||
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
||||||
executor->step();
|
executor->step();
|
||||||
|
|||||||
+95
-4
@@ -4,19 +4,25 @@
|
|||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/type.hpp"
|
#include "furvm/type.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
std::ostream& mod::serialize(std::ostream& os) const {
|
std::ostream& mod::serialize(std::ostream& os) const {
|
||||||
os << MAGIC;
|
os.write(MAGIC, sizeof(MAGIC));
|
||||||
detail::serialize(os, std::uint32_t(0)); // version
|
detail::serialize(os, std::uint32_t(0)); // version
|
||||||
|
|
||||||
detail::serialize(os, function_id(m_functionMap.size()));
|
function_id funcCount = m_functions.cend() - m_functions.cbegin();
|
||||||
for (function_id id = 0; id < m_functions.cend() - m_functions.cbegin(); ++id) {
|
detail::serialize(os, funcCount);
|
||||||
|
for (function_id id = 0; id < funcCount; ++id) {
|
||||||
if (!m_functions.contains(id)) {
|
if (!m_functions.contains(id)) {
|
||||||
detail::serialize(os, "");
|
detail::serialize(os, "");
|
||||||
|
detail::serialize(os, 0);
|
||||||
detail::serialize(os, std::uint8_t(0xFF)); // null function
|
detail::serialize(os, std::uint8_t(0xFF)); // null function
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -24,12 +30,15 @@ std::ostream& mod::serialize(std::ostream& os) const {
|
|||||||
function_h func = m_functions.at(id);
|
function_h func = m_functions.at(id);
|
||||||
bool isPublic = m_publicFunctions.find(func->name()) != m_publicFunctions.end();
|
bool isPublic = m_publicFunctions.find(func->name()) != m_publicFunctions.end();
|
||||||
detail::serialize(os, isPublic ? func->name() : ""); // private functions have empty names
|
detail::serialize(os, isPublic ? func->name() : ""); // private functions have empty names
|
||||||
|
detail::serialize(os, func->param_count());
|
||||||
detail::serialize(os, std::uint8_t(func->type()));
|
detail::serialize(os, std::uint8_t(func->type()));
|
||||||
switch (func->type()) {
|
switch (func->type()) {
|
||||||
case function_t::Normal: {
|
case function_t::Normal: {
|
||||||
detail::serialize(os, func->position());
|
detail::serialize(os, func->position());
|
||||||
} break;
|
} break;
|
||||||
case function_t::Native: break;
|
case function_t::Native: {
|
||||||
|
detail::serialize(os, func->native());
|
||||||
|
} break;
|
||||||
case function_t::Import: {
|
case function_t::Import: {
|
||||||
detail::serialize(os, func->imp().mod);
|
detail::serialize(os, func->imp().mod);
|
||||||
detail::serialize(os, func->imp().function);
|
detail::serialize(os, func->imp().function);
|
||||||
@@ -60,4 +69,86 @@ std::ostream& mod::serialize(std::ostream& os) const {
|
|||||||
detail::serialize(os, std::uint64_t(m_bytecode.size()));
|
detail::serialize(os, std::uint64_t(m_bytecode.size()));
|
||||||
return os.write(reinterpret_cast<const char*>(m_bytecode.data()), static_cast<std::streamsize>(m_bytecode.size()));
|
return os.write(reinterpret_cast<const char*>(m_bytecode.data()), static_cast<std::streamsize>(m_bytecode.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod mod::load(std::istream& is) {
|
||||||
|
std::uint32_t magic = 0;
|
||||||
|
detail::load(is, magic);
|
||||||
|
std::uint32_t version = 0;
|
||||||
|
detail::load(is, version);
|
||||||
|
if (std::memcmp(&magic, MAGIC, sizeof(MAGIC)) != 0) throw std::runtime_error("invalid magic");
|
||||||
|
if (version != 0) throw std::runtime_error("unsupported version");
|
||||||
|
|
||||||
|
mod mod;
|
||||||
|
|
||||||
|
function_id functionCount = 0;
|
||||||
|
detail::load(is, functionCount);
|
||||||
|
for (function_id id = 0; id < functionCount; ++id) {
|
||||||
|
std::string name;
|
||||||
|
detail::load(is, name);
|
||||||
|
std::uint32_t paramCount = 0;
|
||||||
|
detail::load(is, paramCount);
|
||||||
|
std::uint8_t type = 0;
|
||||||
|
detail::load(is, type);
|
||||||
|
if (type == 0xFF) continue;
|
||||||
|
|
||||||
|
switch ((function_t)type) {
|
||||||
|
case function_t::Normal: {
|
||||||
|
decltype(std::declval<function>().position()) offset = 0;
|
||||||
|
detail::load(is, offset);
|
||||||
|
mod.emplace_function(id, std::move(name), paramCount, offset).dispatch();
|
||||||
|
} break;
|
||||||
|
case function_t::Native: {
|
||||||
|
std::string native;
|
||||||
|
detail::load(is, native);
|
||||||
|
mod.emplace_function(id, std::move(name), paramCount, std::move(native)).dispatch();
|
||||||
|
} break;
|
||||||
|
case function_t::Import: {
|
||||||
|
std::string modName;
|
||||||
|
detail::load(is, modName);
|
||||||
|
function_id function = 0;
|
||||||
|
detail::load(is, function);
|
||||||
|
mod.emplace_function(id, std::move(modName), function).dispatch();
|
||||||
|
} break;
|
||||||
|
default: throw std::runtime_error("unknown function type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type_id typeCount = 0;
|
||||||
|
detail::load(is, typeCount);
|
||||||
|
for (type_id id = 0; id < typeCount; ++id) {
|
||||||
|
std::uint8_t type = 0;
|
||||||
|
detail::load(is, type);
|
||||||
|
if (type == 0xFF) continue;
|
||||||
|
|
||||||
|
switch ((type_t)type) {
|
||||||
|
case type_t::Primitive: {
|
||||||
|
primitive_type primitive = 0;
|
||||||
|
detail::load(is, primitive);
|
||||||
|
mod.emplace_type(id, std::make_shared<class type>(primitive)).dispatch();
|
||||||
|
} break;
|
||||||
|
case type_t::Reference: throw std::runtime_error("reference type serialization is unimplemented");
|
||||||
|
case type_t::List: {
|
||||||
|
type_id typeId = 0;
|
||||||
|
detail::load(is, typeId);
|
||||||
|
mod.emplace_type(id, std::make_shared<class type>(mod.type_at(typeId))).dispatch();
|
||||||
|
} break;
|
||||||
|
case type_t::Import: {
|
||||||
|
std::string modName;
|
||||||
|
detail::load(is, modName);
|
||||||
|
type_id typeId = 0;
|
||||||
|
detail::load(is, typeId);
|
||||||
|
mod.emplace_type(id, std::make_shared<class type>(import_type{ std::move(modName), typeId })).dispatch();
|
||||||
|
} break;
|
||||||
|
default: throw std::runtime_error("unknown type type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t bytecodeLength = 0;
|
||||||
|
detail::load(is, bytecodeLength);
|
||||||
|
mod.bytecode().resize(bytecodeLength);
|
||||||
|
is.read(reinterpret_cast<char*>(mod.bytecode().data()), static_cast<std::streamsize>(bytecodeLength));
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
Reference in New Issue
Block a user