Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
575054b75a
|
|||
|
a7ab214ce3
|
|||
|
e087c11008
|
|||
|
2164ab0d97
|
|||
|
11b05b8c18
|
+1
-1
@@ -61,7 +61,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto context = std::make_shared<furvm::context>();
|
auto context = std::make_shared<furvm::context>();
|
||||||
auto furvmMod = context->emplace_module("main", furc::back::furvm_generator::generate(mod));
|
auto furvmMod = context->emplace("main", furc::back::furvm_generator::generate(mod));
|
||||||
|
|
||||||
std::ofstream file("./a.fmod", std::ios::binary);
|
std::ofstream file("./a.fmod", std::ios::binary);
|
||||||
furvmMod->serialize(file);
|
furvmMod->serialize(file);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
class context {
|
class context : public handle_container<mod_h> {
|
||||||
public:
|
public:
|
||||||
friend class executor;
|
friend class executor;
|
||||||
public:
|
public:
|
||||||
@@ -36,49 +36,6 @@ public:
|
|||||||
|
|
||||||
context(const context&) = delete;
|
context(const context&) = delete;
|
||||||
context& operator=(const context&) = delete;
|
context& operator=(const context&) = delete;
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Emplaces a module in the context.
|
|
||||||
*
|
|
||||||
* @param args Arguments forwarded to the module constructor.
|
|
||||||
* @return The emplaced module.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
auto emplace_module(Args&&... args) {
|
|
||||||
return m_modules.emplace(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a module from the context.
|
|
||||||
*
|
|
||||||
* @param args Module's id.
|
|
||||||
* @return A handle to the module.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
auto module_at(Args&&... args) {
|
|
||||||
return m_modules.at(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a module from the context.
|
|
||||||
*
|
|
||||||
* @param args Module's id.
|
|
||||||
* @return A handle to the module.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
auto module_at(Args&&... args) const {
|
|
||||||
return m_modules.at(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Erases a module from the context.
|
|
||||||
*
|
|
||||||
* @param args Module's id.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
void erase_module(Args&&... args) {
|
|
||||||
m_modules.erase(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Emplaces an executor in the context.
|
* @brief Emplaces an executor in the context.
|
||||||
|
|||||||
@@ -154,6 +154,10 @@ struct type;
|
|||||||
|
|
||||||
using type_p = std::shared_ptr<type>;
|
using type_p = std::shared_ptr<type>;
|
||||||
|
|
||||||
|
using type_id = std::uint32_t;
|
||||||
|
|
||||||
|
using type_h = handle<type_p, generic_header<type_id>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class bad_thing_access
|
* @class bad_thing_access
|
||||||
* @brief Bad thing access exception.
|
* @brief Bad thing access exception.
|
||||||
|
|||||||
@@ -180,8 +180,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The reference count.
|
* @return The reference count.
|
||||||
*/
|
*/
|
||||||
template <typename ReferenceCount = typename Header::refcount_type>
|
template <typename U = Header, typename = std::enable_if_t<detail::header_has_refcount_v<U>>>
|
||||||
ReferenceCount reference_count() const {
|
auto reference_count() const {
|
||||||
return m_value->first.reference_count();
|
return m_value->first.reference_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "furvm/function.hpp"
|
#include "furvm/function.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/handle.hpp"
|
#include "furvm/handle.hpp"
|
||||||
|
#include "furvm/type.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@@ -187,6 +188,49 @@ public:
|
|||||||
native_function get_native_function(NameFwd&& name) const {
|
native_function get_native_function(NameFwd&& name) const {
|
||||||
return m_nativeFunctions.at(std::forward<NameFwd>(name));
|
return m_nativeFunctions.at(std::forward<NameFwd>(name));
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Emplaces a type in the context.
|
||||||
|
*
|
||||||
|
* @param args Arguments forwarded to the type constructor.
|
||||||
|
* @return The emplaced type.
|
||||||
|
*/
|
||||||
|
template <typename... Args>
|
||||||
|
auto emplace_type(Args&&... args) {
|
||||||
|
return m_types.emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a type from the context.
|
||||||
|
*
|
||||||
|
* @param args type's id.
|
||||||
|
* @return A handle to the type.
|
||||||
|
*/
|
||||||
|
template <typename... Args>
|
||||||
|
auto type_at(Args&&... args) {
|
||||||
|
return m_types.at(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a type from the context.
|
||||||
|
*
|
||||||
|
* @param args type's id.
|
||||||
|
* @return A handle to the type.
|
||||||
|
*/
|
||||||
|
template <typename... Args>
|
||||||
|
auto type_at(Args&&... args) const {
|
||||||
|
return m_types.at(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erases a type from the context.
|
||||||
|
*
|
||||||
|
* @param args type's id.
|
||||||
|
*/
|
||||||
|
template <typename... Args>
|
||||||
|
void erase_type(Args&&... args) {
|
||||||
|
m_types.erase(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Prints the module in a bytecode form to an output stream.
|
* @brief Prints the module in a bytecode form to an output stream.
|
||||||
@@ -202,6 +246,8 @@ private:
|
|||||||
std::unordered_map<std::string, function_id> m_publicFunctions;
|
std::unordered_map<std::string, function_id> m_publicFunctions;
|
||||||
handle_container<function_h> m_functions;
|
handle_container<function_h> m_functions;
|
||||||
|
|
||||||
|
handle_container<type_h> m_types;
|
||||||
|
|
||||||
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+38
-137
@@ -4,141 +4,27 @@
|
|||||||
#include "furlang/arena.hpp"
|
#include "furlang/arena.hpp"
|
||||||
#include "furvm/exceptions.hpp"
|
#include "furvm/exceptions.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
#include "furvm/module.hpp"
|
||||||
|
#include "furvm/type.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
enum class type_t : std::uint32_t {
|
|
||||||
Primitive = 0,
|
|
||||||
Reference,
|
|
||||||
List,
|
|
||||||
};
|
|
||||||
|
|
||||||
using primitive_type = std::uint64_t;
|
|
||||||
using reference_type = std::shared_ptr<type>;
|
|
||||||
using list_type = std::shared_ptr<type>;
|
|
||||||
|
|
||||||
struct type {
|
|
||||||
type_t t;
|
|
||||||
union {
|
|
||||||
primitive_type primitive;
|
|
||||||
reference_type reference;
|
|
||||||
list_type list;
|
|
||||||
};
|
|
||||||
|
|
||||||
type(type_t type)
|
|
||||||
: t(type), primitive(0) {}
|
|
||||||
|
|
||||||
type(primitive_type primitive)
|
|
||||||
: t(type_t::Primitive), primitive(primitive) {}
|
|
||||||
|
|
||||||
type(const reference_type& reference)
|
|
||||||
: t(type_t::Reference), reference(reference) {}
|
|
||||||
|
|
||||||
static type make_list(const list_type& list) {
|
|
||||||
type type(type_t::List);
|
|
||||||
new (&type.list) list_type(list);
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
~type() {
|
|
||||||
switch (t) {
|
|
||||||
case type_t::Reference: reference.~reference_type(); break;
|
|
||||||
case type_t::List: list.~list_type(); break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type(type&& other) noexcept
|
|
||||||
: t(other.t) {
|
|
||||||
switch (t) {
|
|
||||||
case type_t::Primitive: primitive = other.primitive; break;
|
|
||||||
case type_t::Reference: reference = std::move(other.reference); break;
|
|
||||||
case type_t::List: list = std::move(other.list); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type& operator=(type&& other) noexcept {
|
|
||||||
if (this == &other) return *this;
|
|
||||||
t = other.t;
|
|
||||||
switch (t) {
|
|
||||||
case type_t::Primitive: primitive = other.primitive; break;
|
|
||||||
case type_t::Reference: reference = std::move(other.reference); break;
|
|
||||||
case type_t::List: list = std::move(other.list); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
type(const type& other)
|
|
||||||
: t(other.t) {
|
|
||||||
switch (t) {
|
|
||||||
case type_t::Primitive: primitive = other.primitive; break;
|
|
||||||
case type_t::Reference: reference = other.reference; break;
|
|
||||||
case type_t::List: list = other.list; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type& operator=(const type& other) {
|
|
||||||
if (this == &other) return *this;
|
|
||||||
t = other.t;
|
|
||||||
switch (t) {
|
|
||||||
case type_t::Primitive: primitive = other.primitive; break;
|
|
||||||
case type_t::Reference: reference = other.reference; break;
|
|
||||||
case type_t::List: list = other.list; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using byte_t = std::int8_t; /**< A 1-byte integer. */
|
|
||||||
using short_t = std::int16_t; /**< A 2-byte integer. */
|
|
||||||
using int_t = std::int32_t; /**< A 4-byte integer. */
|
|
||||||
using long_t = std::int64_t; /**< An 8-byte integer. */
|
|
||||||
|
|
||||||
using reference_t = std::byte*;
|
|
||||||
|
|
||||||
struct list_t {
|
|
||||||
long_t size;
|
|
||||||
std::byte* data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A 1-byte integer thing type.
|
|
||||||
*/
|
|
||||||
inline static type byteType = { sizeof(byte_t) }; // NOLINT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A 2-byte integer thing type.
|
|
||||||
*/
|
|
||||||
inline static type shortType = { sizeof(short_t) }; // NOLINT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A 4-byte integer thing type.
|
|
||||||
*/
|
|
||||||
inline static type intType = { sizeof(int_t) }; // NOLINT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An 8-byte integer thing type.
|
|
||||||
*/
|
|
||||||
inline static type longType = { sizeof(long_t) }; // NOLINT
|
|
||||||
|
|
||||||
template <template <typename> typename Allocator>
|
template <template <typename> typename Allocator>
|
||||||
class thing final {
|
class thing final {
|
||||||
friend class executor;
|
friend class executor;
|
||||||
public:
|
public:
|
||||||
using allocator_type = Allocator<std::byte>; /**< Allocator type. */
|
using allocator_type = Allocator<std::byte>; /**< Allocator type. */
|
||||||
|
|
||||||
|
using mod_container = std::shared_ptr<handle_container<mod_h>>;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a thing.
|
* @brief Constructs a thing.
|
||||||
@@ -146,8 +32,8 @@ public:
|
|||||||
* @param type Thing type.
|
* @param type Thing type.
|
||||||
* @param allocator Allocator for the thing's data.
|
* @param allocator Allocator for the thing's data.
|
||||||
*/
|
*/
|
||||||
thing(const type& type, const allocator_type& allocator = {})
|
thing(const type& type, const mod_container& modules = nullptr, const allocator_type& allocator = {})
|
||||||
: thing(std::make_shared<class type>(type), allocator) {}
|
: thing(std::make_shared<class type>(type), modules, allocator) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a thing.
|
* @brief Constructs a thing.
|
||||||
@@ -155,8 +41,8 @@ public:
|
|||||||
* @param type Thing type.
|
* @param type Thing type.
|
||||||
* @param allocator Allocator for the thing's data.
|
* @param allocator Allocator for the thing's data.
|
||||||
*/
|
*/
|
||||||
thing(const type_p& type, const allocator_type& allocator = {})
|
thing(const type_p& type, const mod_container& modules = nullptr, const allocator_type& allocator = {})
|
||||||
: m_type(type), m_size(compute_size(type)), m_allocator(allocator) {
|
: m_type(type), m_size(compute_size(resolve_type(type, modules))), m_modules(modules), m_allocator(allocator) {
|
||||||
// TODO: Account for alignment
|
// TODO: Account for alignment
|
||||||
m_data = m_allocator.allocate(m_size);
|
m_data = m_allocator.allocate(m_size);
|
||||||
std::memset(m_data, 0, m_size);
|
std::memset(m_data, 0, m_size);
|
||||||
@@ -176,6 +62,7 @@ public:
|
|||||||
: m_type(std::move(other.m_type)),
|
: m_type(std::move(other.m_type)),
|
||||||
m_data(other.m_data),
|
m_data(other.m_data),
|
||||||
m_size(other.m_size),
|
m_size(other.m_size),
|
||||||
|
m_modules(std::move(other.m_modules)),
|
||||||
m_allocator(std::move(other.m_allocator)) {
|
m_allocator(std::move(other.m_allocator)) {
|
||||||
other.m_type = {};
|
other.m_type = {};
|
||||||
other.m_data = nullptr;
|
other.m_data = nullptr;
|
||||||
@@ -189,6 +76,7 @@ public:
|
|||||||
if (this == &other) return *this;
|
if (this == &other) return *this;
|
||||||
m_type = other.m_type;
|
m_type = other.m_type;
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
|
m_modules = std::move(other.m_modules);
|
||||||
m_allocator = std::move(other.m_allocator);
|
m_allocator = std::move(other.m_allocator);
|
||||||
other.m_type = {};
|
other.m_type = {};
|
||||||
other.m_data = nullptr;
|
other.m_data = nullptr;
|
||||||
@@ -198,6 +86,8 @@ public:
|
|||||||
|
|
||||||
thing(const thing&) = delete;
|
thing(const thing&) = delete;
|
||||||
thing& operator=(const thing&) = delete;
|
thing& operator=(const thing&) = delete;
|
||||||
|
public:
|
||||||
|
void assign_mod_container(const mod_container& modules) { m_modules = modules; }
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a clone of the thing.
|
* @brief Returns a clone of the thing.
|
||||||
@@ -205,15 +95,16 @@ public:
|
|||||||
* @return A clone of this thing.
|
* @return A clone of this thing.
|
||||||
*/
|
*/
|
||||||
thing clone() const {
|
thing clone() const {
|
||||||
thing res(m_type, m_allocator);
|
thing res(resolve_type(m_type, m_modules), m_modules, m_allocator);
|
||||||
switch (m_type->t) {
|
switch (m_type->t) {
|
||||||
case type_t::Primitive:
|
case type_t::Primitive:
|
||||||
case type_t::Reference: {
|
case type_t::Reference: {
|
||||||
std::memcpy(res.m_data, m_data, m_size);
|
std::memcpy(res.m_data, m_data, m_size);
|
||||||
} break;
|
} break;
|
||||||
case type_t::List: {
|
case type_t::List: {
|
||||||
copy_list(m_type->list, res.get<list_t>(), get<list_t>());
|
copy_list(resolve_type(m_type->list, m_modules), res.get<list_t>(), get<list_t>());
|
||||||
} break;
|
} break;
|
||||||
|
case type_t::Import: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
@@ -246,7 +137,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T& get() {
|
T& get() {
|
||||||
std::size_t size = m_size > 0 ? m_size : compute_size_na(m_type);
|
std::size_t size = m_size > 0 ? m_size : compute_size_na(resolve_type(m_type, m_modules));
|
||||||
if (size != sizeof(T)) throw bad_thing_access();
|
if (size != sizeof(T)) throw bad_thing_access();
|
||||||
return *std::launder(reinterpret_cast<T*>(m_data));
|
return *std::launder(reinterpret_cast<T*>(m_data));
|
||||||
}
|
}
|
||||||
@@ -258,7 +149,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T& get() const {
|
const T& get() const {
|
||||||
std::size_t size = m_size > 0 ? m_size : compute_size_na(m_type);
|
std::size_t size = m_size > 0 ? m_size : compute_size_na(resolve_type(m_type, m_modules));
|
||||||
if (size != sizeof(T)) throw bad_thing_access();
|
if (size != sizeof(T)) throw bad_thing_access();
|
||||||
return *std::launder(reinterpret_cast<const T*>(m_data));
|
return *std::launder(reinterpret_cast<const T*>(m_data));
|
||||||
}
|
}
|
||||||
@@ -368,13 +259,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
thing reference() const {
|
thing reference() const {
|
||||||
thing res = { std::make_shared<class type>(m_type), m_allocator };
|
thing res = { std::make_shared<class type>(m_type), m_modules, m_allocator };
|
||||||
res.get<reference_t>() = m_data;
|
res.get<reference_t>() = m_data;
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing resolve() const {
|
thing resolve() const {
|
||||||
thing rsv = { m_type, m_data, m_allocator };
|
thing rsv = { resolve_type(m_type, m_modules), m_data, m_allocator };
|
||||||
while (rsv.type().t == type_t::Reference)
|
while (rsv.type().t == type_t::Reference)
|
||||||
rsv = { rsv.m_type->reference, rsv.get<reference_t>(), std::move(rsv.m_allocator) };
|
rsv = { rsv.m_type->reference, rsv.get<reference_t>(), std::move(rsv.m_allocator) };
|
||||||
return rsv;
|
return rsv;
|
||||||
@@ -384,8 +275,10 @@ public:
|
|||||||
if (m_type->t != type_t::List) throw bad_thing_access();
|
if (m_type->t != type_t::List) throw bad_thing_access();
|
||||||
auto& list = get<list_t>();
|
auto& list = get<list_t>();
|
||||||
if (newSize < 0 || newSize == list.size) return;
|
if (newSize < 0 || newSize == list.size) return;
|
||||||
std::byte* newData = new std::byte[compute_size_na(m_type->list) * newSize];
|
std::byte* newData = new std::byte[compute_size_na(resolve_type(m_type->list, m_modules)) * newSize];
|
||||||
std::memcpy(newData, list.data, compute_size_na(m_type->list) * std::min(list.size, newSize));
|
std::memcpy(newData,
|
||||||
|
list.data,
|
||||||
|
compute_size_na(resolve_type(m_type->list, m_modules)) * std::min(list.size, newSize));
|
||||||
list.size = newSize;
|
list.size = newSize;
|
||||||
delete[] list.data;
|
delete[] list.data;
|
||||||
list.data = newData;
|
list.data = newData;
|
||||||
@@ -395,10 +288,17 @@ public:
|
|||||||
if (m_type->t != type_t::List) throw bad_thing_access();
|
if (m_type->t != type_t::List) throw bad_thing_access();
|
||||||
auto& list = get<list_t>();
|
auto& list = get<list_t>();
|
||||||
if (index < 0 || index >= list.size) throw std::out_of_range("index out of range");
|
if (index < 0 || index >= list.size) throw std::out_of_range("index out of range");
|
||||||
thing res = { m_type->list, m_allocator };
|
thing res = { m_type->list, m_modules, m_allocator };
|
||||||
res.get<reference_t>() = list.data; // TODO: Account for padding, alignment and stuff
|
res.get<reference_t>() = list.data; // TODO: Account for padding, alignment and stuff
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
static type_p resolve_type(const type_p& initType, const mod_container& modules) {
|
||||||
|
type_p rsv = initType;
|
||||||
|
while (rsv->t == type_t::Import)
|
||||||
|
rsv = *modules->at(initType->imp.mod)->type_at(initType->imp.type);
|
||||||
|
return rsv;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
static void copy_list(const type_p& innerType, list_t& dst, const list_t& src) {
|
static void copy_list(const type_p& innerType, list_t& dst, const list_t& src) {
|
||||||
dst.size = src.size;
|
dst.size = src.size;
|
||||||
@@ -412,16 +312,15 @@ private:
|
|||||||
dst.data = new std::byte[size];
|
dst.data = new std::byte[size];
|
||||||
switch (innerType->t) {
|
switch (innerType->t) {
|
||||||
case type_t::Primitive:
|
case type_t::Primitive:
|
||||||
case type_t::Reference: {
|
case type_t::Reference: std::memcpy(dst.data, src.data, size); break;
|
||||||
std::memcpy(dst.data, src.data, size);
|
case type_t::List:
|
||||||
} break;
|
|
||||||
case type_t::List: {
|
|
||||||
for (std::size_t i = 0; i < size; ++i) {
|
for (std::size_t i = 0; i < size; ++i) {
|
||||||
copy_list(innerType->list,
|
copy_list(innerType->list,
|
||||||
*std::launder(reinterpret_cast<list_t*>(dst.data)),
|
*std::launder(reinterpret_cast<list_t*>(dst.data)),
|
||||||
*std::launder(reinterpret_cast<list_t*>(src.data)));
|
*std::launder(reinterpret_cast<list_t*>(src.data)));
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
case type_t::Import: throw std::runtime_error("unresolved type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -430,6 +329,7 @@ private:
|
|||||||
case type_t::Primitive: return type->primitive;
|
case type_t::Primitive: return type->primitive;
|
||||||
case type_t::Reference: return sizeof(reference_t);
|
case type_t::Reference: return sizeof(reference_t);
|
||||||
case type_t::List: return sizeof(list_t);
|
case type_t::List: return sizeof(list_t);
|
||||||
|
case type_t::Import: throw std::runtime_error("unresolved type");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("unreachable");
|
throw std::runtime_error("unreachable");
|
||||||
@@ -451,7 +351,7 @@ private:
|
|||||||
|
|
||||||
long_t result = op(lhsRsv.integer(), rhsRsv.integer());
|
long_t result = op(lhsRsv.integer(), rhsRsv.integer());
|
||||||
|
|
||||||
thing res({ size }, m_allocator);
|
thing res({ size }, m_modules, m_allocator);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case sizeof(byte_t): res.get<byte_t>() = result; break;
|
case sizeof(byte_t): res.get<byte_t>() = result; break;
|
||||||
case sizeof(short_t): res.get<short_t>() = result; break;
|
case sizeof(short_t): res.get<short_t>() = result; break;
|
||||||
@@ -469,6 +369,7 @@ private:
|
|||||||
std::size_t m_size;
|
std::size_t m_size;
|
||||||
std::byte* m_data;
|
std::byte* m_data;
|
||||||
|
|
||||||
|
mod_container m_modules;
|
||||||
allocator_type m_allocator;
|
allocator_type m_allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#ifndef FURVM_TYPE_HPP
|
||||||
|
#define FURVM_TYPE_HPP
|
||||||
|
|
||||||
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace furvm {
|
||||||
|
|
||||||
|
enum class type_t : std::uint32_t {
|
||||||
|
Primitive = 0,
|
||||||
|
Reference,
|
||||||
|
List,
|
||||||
|
|
||||||
|
Import,
|
||||||
|
};
|
||||||
|
|
||||||
|
using primitive_type = std::uint64_t;
|
||||||
|
using reference_type = std::shared_ptr<type>;
|
||||||
|
using list_type = std::shared_ptr<type>;
|
||||||
|
|
||||||
|
struct import_type {
|
||||||
|
mod_id mod;
|
||||||
|
type_id type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type {
|
||||||
|
type_t t;
|
||||||
|
union {
|
||||||
|
primitive_type primitive;
|
||||||
|
reference_type reference;
|
||||||
|
list_type list;
|
||||||
|
import_type imp;
|
||||||
|
};
|
||||||
|
|
||||||
|
type(type_t type)
|
||||||
|
: t(type), primitive(0) {}
|
||||||
|
|
||||||
|
type(primitive_type primitive)
|
||||||
|
: t(type_t::Primitive), primitive(primitive) {}
|
||||||
|
|
||||||
|
type(const reference_type& reference)
|
||||||
|
: t(type_t::Reference), reference(reference) {}
|
||||||
|
|
||||||
|
static type make_list(const list_type& list) {
|
||||||
|
type type(type_t::List);
|
||||||
|
new (&type.list) list_type(list);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
type(const import_type& imp)
|
||||||
|
: t(type_t::Import), imp(imp) {}
|
||||||
|
|
||||||
|
~type() {
|
||||||
|
switch (t) {
|
||||||
|
case type_t::Reference: reference.~reference_type(); break;
|
||||||
|
case type_t::List: list.~list_type(); break;
|
||||||
|
case type_t::Import: imp.~import_type(); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type(type&& other) noexcept
|
||||||
|
: t(other.t) {
|
||||||
|
switch (t) {
|
||||||
|
case type_t::Primitive: primitive = other.primitive; break;
|
||||||
|
case type_t::Reference: reference = std::move(other.reference); break;
|
||||||
|
case type_t::List: list = std::move(other.list); break;
|
||||||
|
case type_t::Import: imp = std::move(other.imp); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type& operator=(type&& other) noexcept {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
t = other.t;
|
||||||
|
switch (t) {
|
||||||
|
case type_t::Primitive: primitive = other.primitive; break;
|
||||||
|
case type_t::Reference: reference = std::move(other.reference); break;
|
||||||
|
case type_t::List: list = std::move(other.list); break;
|
||||||
|
case type_t::Import: imp = std::move(other.imp); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
type(const type& other)
|
||||||
|
: t(other.t) {
|
||||||
|
switch (t) {
|
||||||
|
case type_t::Primitive: primitive = other.primitive; break;
|
||||||
|
case type_t::Reference: reference = other.reference; break;
|
||||||
|
case type_t::List: list = other.list; break;
|
||||||
|
case type_t::Import: imp = other.imp; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type& operator=(const type& other) {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
t = other.t;
|
||||||
|
switch (t) {
|
||||||
|
case type_t::Primitive: primitive = other.primitive; break;
|
||||||
|
case type_t::Reference: reference = other.reference; break;
|
||||||
|
case type_t::List: list = other.list; break;
|
||||||
|
case type_t::Import: imp = other.imp; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using byte_t = std::int8_t; /**< A 1-byte integer. */
|
||||||
|
using short_t = std::int16_t; /**< A 2-byte integer. */
|
||||||
|
using int_t = std::int32_t; /**< A 4-byte integer. */
|
||||||
|
using long_t = std::int64_t; /**< An 8-byte integer. */
|
||||||
|
|
||||||
|
using reference_t = std::byte*;
|
||||||
|
|
||||||
|
struct list_t {
|
||||||
|
long_t size;
|
||||||
|
std::byte* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A 1-byte integer thing type.
|
||||||
|
*/
|
||||||
|
inline static type byteType = { sizeof(byte_t) }; // NOLINT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A 2-byte integer thing type.
|
||||||
|
*/
|
||||||
|
inline static type shortType = { sizeof(short_t) }; // NOLINT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A 4-byte integer thing type.
|
||||||
|
*/
|
||||||
|
inline static type intType = { sizeof(int_t) }; // NOLINT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An 8-byte integer thing type.
|
||||||
|
*/
|
||||||
|
inline static type longType = { sizeof(long_t) }; // NOLINT
|
||||||
|
|
||||||
|
} // namespace furvm
|
||||||
|
|
||||||
|
#endif // FURVM_TYPE_HPP
|
||||||
@@ -16,7 +16,7 @@ namespace furvm {
|
|||||||
void executor::push_frame(const mod_h& mod, function function) {
|
void executor::push_frame(const mod_h& mod, function function) {
|
||||||
mod_h modInst = mod;
|
mod_h modInst = mod;
|
||||||
while (function.type() == function_t::Import) {
|
while (function.type() == function_t::Import) {
|
||||||
modInst = m_context->module_at(function.imp().mod);
|
modInst = m_context->at(function.imp().mod);
|
||||||
function = *modInst->function_at(function.imp().function);
|
function = *modInst->function_at(function.imp().function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ void executor::step() {
|
|||||||
switch (instr) {
|
switch (instr) {
|
||||||
case instruction_t::NoOperation: break;
|
case instruction_t::NoOperation: break;
|
||||||
case instruction_t::PushB2I: {
|
case instruction_t::PushB2I: {
|
||||||
push_thing({ intType, m_context->thing_alloc() })->get<int_t>() = frame.mod->byte(frame.position++);
|
push_thing({ intType, m_context, m_context->thing_alloc() })->get<int_t>() = frame.mod->byte(frame.position++);
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Drop: {
|
case instruction_t::Drop: {
|
||||||
pop_thing();
|
pop_thing();
|
||||||
|
|||||||
+2
-2
@@ -23,12 +23,12 @@ static constexpr std::array<furvm::byte, 9> s_bytecode = {
|
|||||||
int main(void) {
|
int main(void) {
|
||||||
auto context = std::make_shared<furvm::context>();
|
auto context = std::make_shared<furvm::context>();
|
||||||
|
|
||||||
furvm::mod_h furlangModule = context->emplace_module("furlang");
|
furvm::mod_h furlangModule = context->emplace("furlang");
|
||||||
furvm::function_h printFunc = furlangModule->emplace_function("print", 1, "print");
|
furvm::function_h printFunc = furlangModule->emplace_function("print", 1, "print");
|
||||||
furlangModule->set_native_function("print",
|
furlangModule->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_module("main", s_bytecode.begin(), s_bytecode.end());
|
furvm::mod_h mainModule = context->emplace("main", s_bytecode.begin(), s_bytecode.end());
|
||||||
furvm::function_h mainFunc = mainModule->emplace_function("main", 0, 0);
|
furvm::function_h mainFunc = mainModule->emplace_function("main", 0, 0);
|
||||||
mainModule->emplace_function(furlangModule, printFunc).dispatch();
|
mainModule->emplace_function(furlangModule, printFunc).dispatch();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user