refactor: improve thing types
Change thing_t enumeration to thing_type structure. Closes: #30
This commit is contained in:
+2
-8
@@ -67,14 +67,8 @@ int main(void) {
|
||||
furvmMod->serialize(file);
|
||||
file.close();
|
||||
|
||||
furvmMod->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;
|
||||
}
|
||||
});
|
||||
furvmMod->set_native_function("print",
|
||||
[](furvm::executor& executor) { std::cout << executor.load_thing(0)->get<furvm::int_t>() << '\n'; });
|
||||
|
||||
furvm::executor_h executor = context->emplace_executor(context);
|
||||
executor->push_frame(furvmMod, *furvmMod->function_at("main"));
|
||||
|
||||
@@ -141,10 +141,27 @@ using mod_h = handle<mod, refcount_header<mod_id>>;
|
||||
// thing.hpp
|
||||
|
||||
/**
|
||||
* @enum thing_t
|
||||
* @enum thing_type_t
|
||||
* @brief Type of the thing's type.
|
||||
*/
|
||||
enum class thing_type_t : std::uint32_t;
|
||||
|
||||
/**
|
||||
* @struct thing_type
|
||||
* @brief Thing type.
|
||||
*/
|
||||
enum class thing_t : std::uint8_t;
|
||||
struct thing_type;
|
||||
|
||||
/**
|
||||
* @brief Thing type's identifier.
|
||||
*/
|
||||
using thing_type_id = std::uint32_t;
|
||||
|
||||
// TODO: Use generic header
|
||||
/**
|
||||
* @brief A handle to a thing type.
|
||||
*/
|
||||
using thing_type_h = handle<thing_type, refcount_header<thing_type_id>>;
|
||||
|
||||
/**
|
||||
* @class bad_thing_access
|
||||
|
||||
@@ -5,31 +5,34 @@
|
||||
#include "furvm/exceptions.hpp"
|
||||
#include "furvm/fwd.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace furvm {
|
||||
|
||||
enum class thing_t : std::uint8_t {
|
||||
Int32,
|
||||
enum class thing_type_t : std::uint32_t {
|
||||
Primitive = 0,
|
||||
};
|
||||
|
||||
struct thing_type {
|
||||
thing_type_t type;
|
||||
std::uint64_t value;
|
||||
};
|
||||
|
||||
using int_t = std::int32_t; /**< A 4-byte integer. */
|
||||
|
||||
/**
|
||||
* @brief Returns how many bytes a thing would take up.
|
||||
*
|
||||
* @param type Type of the thing.
|
||||
* @return The byte count.
|
||||
* @brief A 4-byte integer thing type.
|
||||
*/
|
||||
static inline std::size_t thing_type_size(thing_t type) {
|
||||
switch (type) {
|
||||
case thing_t::Int32: return sizeof(std::int32_t);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
static constexpr thing_type IntType = { thing_type_t::Primitive, sizeof(int_t) };
|
||||
|
||||
template <template <typename> typename Allocator>
|
||||
class thing final {
|
||||
@@ -40,28 +43,37 @@ public:
|
||||
/**
|
||||
* @brief Constructs a thing.
|
||||
*
|
||||
* @param type Type of the thing.
|
||||
* @param type Thing type.
|
||||
* @param allocator Allocator for the thing's data.
|
||||
*/
|
||||
thing(thing_t type, const allocator_type& allocator = {})
|
||||
thing(const thing_type& type, const allocator_type& allocator = {})
|
||||
: m_type(type), m_allocator(allocator) {
|
||||
m_data = m_allocator.allocate(thing_type_size(type));
|
||||
switch (type.type) {
|
||||
case thing_type_t::Primitive: {
|
||||
m_size = type.value;
|
||||
} break;
|
||||
}
|
||||
|
||||
m_size = (m_size + 3) & ~3; // NOTE: Align to 4 bytes
|
||||
// TODO: Account for alignment
|
||||
m_data = m_allocator.allocate(m_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructs a thing.
|
||||
*/
|
||||
~thing() {
|
||||
if (m_data != nullptr) m_allocator.deallocate(m_data, thing_type_size(thing_t::Int32));
|
||||
if (m_data != nullptr) m_allocator.deallocate(m_data, m_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*/
|
||||
thing(thing&& other) noexcept
|
||||
: m_type(other.m_type), m_data(other.m_data), m_allocator(std::move(other.m_allocator)) {
|
||||
: m_type(other.m_type), m_data(other.m_data), m_size(other.m_size), m_allocator(std::move(other.m_allocator)) {
|
||||
other.m_type = {};
|
||||
other.m_data = nullptr;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +86,7 @@ public:
|
||||
m_allocator = std::move(other.m_allocator);
|
||||
other.m_type = {};
|
||||
other.m_data = nullptr;
|
||||
other.m_size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -86,10 +99,10 @@ public:
|
||||
* @return A clone of this thing.
|
||||
*/
|
||||
thing clone() const {
|
||||
class thing res(m_type, m_allocator);
|
||||
switch (m_type) {
|
||||
default: {
|
||||
std::memcpy(res.m_data, m_data, thing_type_size(m_type));
|
||||
thing res(m_type, m_allocator);
|
||||
switch (m_type.type) {
|
||||
case thing_type_t::Primitive: {
|
||||
std::memcpy(res.m_data, m_data, m_size);
|
||||
} break;
|
||||
}
|
||||
return std::move(res);
|
||||
@@ -103,23 +116,39 @@ public:
|
||||
constexpr auto type() const { return m_type; }
|
||||
public:
|
||||
/**
|
||||
* @brief Returns the thing's int32 value.
|
||||
* @brief Returns a raw data pointer.
|
||||
*
|
||||
* @return The data pointer.
|
||||
*/
|
||||
void* raw() { return m_data; }
|
||||
|
||||
/**
|
||||
* @brief Returns a raw data pointer.
|
||||
*
|
||||
* @return The data pointer.
|
||||
*/
|
||||
const void* raw() const { return m_data; }
|
||||
public:
|
||||
/**
|
||||
* @brief Returns the thing's value.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
std::int32_t& int32() {
|
||||
if (m_type != thing_t::Int32) throw bad_thing_access();
|
||||
return *reinterpret_cast<std::int32_t*>(m_data);
|
||||
template <typename T>
|
||||
T& get() {
|
||||
if (m_type.type == thing_type_t::Primitive && m_type.value != sizeof(T)) throw bad_thing_access();
|
||||
return *std::launder(reinterpret_cast<T*>(m_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the thing's int32 value.
|
||||
* @brief Returns the thing's value.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
const std::int32_t& int32() const {
|
||||
if (m_type != thing_t::Int32) throw bad_thing_access();
|
||||
return *reinterpret_cast<std::int32_t*>(m_data);
|
||||
template <typename T>
|
||||
const T& get() const {
|
||||
if (m_type.type == thing_type_t::Primitive && m_type.value != sizeof(T)) throw bad_thing_access();
|
||||
return *std::launder(reinterpret_cast<const T*>(m_data));
|
||||
}
|
||||
public:
|
||||
/**
|
||||
@@ -128,11 +157,7 @@ public:
|
||||
* @param rhs Thing to sum with this thing (right-hand-side).
|
||||
* @return The sum.
|
||||
*/
|
||||
thing add(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() + rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing add(const thing& rhs) const { return binary_op(rhs, std::plus<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Returns a difference of two things.
|
||||
@@ -140,11 +165,7 @@ public:
|
||||
* @param rhs Thing to subtract from this thing (right-hand-side).
|
||||
* @return The sum.
|
||||
*/
|
||||
thing sub(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() - rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing sub(const thing& rhs) const { return binary_op(rhs, std::minus<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Returns a product of two things.
|
||||
@@ -152,11 +173,7 @@ public:
|
||||
* @param rhs Thing to multiply with this thing (right-hand-side).
|
||||
* @return The product.
|
||||
*/
|
||||
thing mul(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() * rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing mul(const thing& rhs) const { return binary_op(rhs, std::multiplies<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Returns a quotient of two things.
|
||||
@@ -164,11 +181,7 @@ public:
|
||||
* @param rhs Thing to divide this thing by (right-hand-side).
|
||||
* @return The quotient.
|
||||
*/
|
||||
thing div(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() / rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing div(const thing& rhs) const { return binary_op(rhs, std::divides<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Returns a remainder of two things.
|
||||
@@ -176,11 +189,7 @@ public:
|
||||
* @param rhs Thing to divide this thing by (right-hand-side).
|
||||
* @return The remainder.
|
||||
*/
|
||||
thing mod(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() % rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing mod(const thing& rhs) const { return binary_op(rhs, std::modulus<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares two things for equality.
|
||||
@@ -188,11 +197,7 @@ public:
|
||||
* @param rhs Thing to compare this thing with (right-hand-side).
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing equals(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() == rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing equals(const thing& rhs) const { return binary_op(rhs, std::equal_to<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares two things for inequality.
|
||||
@@ -200,11 +205,7 @@ public:
|
||||
* @param rhs Thing to compare this thing with (right-hand-side).
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing not_equals(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() != rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing not_equals(const thing& rhs) const { return binary_op(rhs, std::not_equal_to<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares if this thing is less than an another thing.
|
||||
@@ -212,11 +213,7 @@ public:
|
||||
* @param rhs The another thing.
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing less_than(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() < rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing less_than(const thing& rhs) const { return binary_op(rhs, std::less<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares if this thing is greater than an another thing.
|
||||
@@ -224,11 +221,7 @@ public:
|
||||
* @param rhs The another thing.
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing greater_than(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() > rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing greater_than(const thing& rhs) const { return binary_op(rhs, std::greater<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares if this thing is less than or equal to an another thing.
|
||||
@@ -236,11 +229,7 @@ public:
|
||||
* @param rhs The another thing.
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing less_equals(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() <= rhs.int32();
|
||||
return res;
|
||||
}
|
||||
thing less_equals(const thing& rhs) const { return binary_op(rhs, std::less_equal<>{}); }
|
||||
|
||||
/**
|
||||
* @brief Compares if this thing is greater than or equal to an another thing.
|
||||
@@ -248,14 +237,36 @@ public:
|
||||
* @param rhs The another thing.
|
||||
* @return A boolean result of the comparison in a thing form.
|
||||
*/
|
||||
thing greater_equals(const thing& rhs) const {
|
||||
thing res(m_type, m_allocator);
|
||||
res.int32() = int32() >= rhs.int32();
|
||||
return res;
|
||||
thing greater_equals(const thing& rhs) const { return binary_op(rhs, std::greater_equal<>{}); }
|
||||
private:
|
||||
// TODO: Change to `to_long` after introducing long type.
|
||||
int_t to_int() const {
|
||||
if (m_type.type != thing_type_t::Primitive) throw bad_thing_access();
|
||||
switch (m_type.value) {
|
||||
case sizeof(int_t): return get<int_t>();
|
||||
default: throw std::runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Op>
|
||||
thing binary_op(const thing& rhs, const Op& op) const {
|
||||
if (type().type == thing_type_t::Primitive && rhs.type().type == thing_type_t::Primitive) {
|
||||
std::size_t size = std::max(type().value, rhs.type().value);
|
||||
|
||||
thing res(thing_type{ thing_type_t::Primitive, size }, m_allocator);
|
||||
switch (size) {
|
||||
case sizeof(int_t): res.get<int_t>() = op(to_int(), rhs.to_int()); break;
|
||||
default: throw std::runtime_error("unreachable");
|
||||
}
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
throw std::runtime_error("unexpected operation");
|
||||
}
|
||||
private:
|
||||
thing_t m_type{};
|
||||
std::byte* m_data;
|
||||
thing_type m_type;
|
||||
std::size_t m_size;
|
||||
std::byte* m_data;
|
||||
|
||||
allocator_type m_allocator;
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ void executor::step() {
|
||||
switch (instr) {
|
||||
case instruction_t::NoOperation: break;
|
||||
case instruction_t::PushB2I: {
|
||||
push_thing({ thing_t::Int32, m_context->thing_alloc() })->int32() = frame.mod->byte(frame.position++);
|
||||
push_thing({ IntType, m_context->thing_alloc() })->get<int_t>() = frame.mod->byte(frame.position++);
|
||||
} break;
|
||||
case instruction_t::Drop: {
|
||||
pop_thing();
|
||||
@@ -181,7 +181,7 @@ void executor::step() {
|
||||
case instruction_t::JumpNotZero: {
|
||||
byte offset = frame.mod->byte(frame.position++);
|
||||
auto cond = pop_thing();
|
||||
if (cond->int32() != 0) frame.position += (std::int8_t)offset;
|
||||
if (cond->get<int_t>() != 0) frame.position += (std::int8_t)offset;
|
||||
} break;
|
||||
case instruction_t::Return: {
|
||||
pop_frame();
|
||||
|
||||
+2
-8
@@ -24,14 +24,8 @@ int main(void) {
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
furlangModule->set_native_function("print",
|
||||
[](furvm::executor& executor) { std::cout << executor.load_thing(0)->get<furvm::int_t>() << '\n'; });
|
||||
|
||||
furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end());
|
||||
furvm::function_h mainFunc = mainModule->emplace_function("main", 0, 0);
|
||||
|
||||
Reference in New Issue
Block a user