Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
e9b38e95a2
|
|||
|
00bcc0e6a5
|
|||
|
e8ccaa6390
|
|||
|
c2b32c9604
|
+3
-2
@@ -28,7 +28,8 @@ Checks: >
|
|||||||
-cppcoreguidelines-macro-usage,
|
-cppcoreguidelines-macro-usage,
|
||||||
-cppcoreguidelines-owning-memory,
|
-cppcoreguidelines-owning-memory,
|
||||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access
|
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,
|
||||||
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay
|
||||||
|
|
||||||
WarningsAsErrors: "*"
|
WarningsAsErrors: "*"
|
||||||
|
|
||||||
@@ -95,4 +96,4 @@ CheckOptions:
|
|||||||
- key: readability-identifier-naming.EnumConstantCase
|
- key: readability-identifier-naming.EnumConstantCase
|
||||||
value: CamelCase
|
value: CamelCase
|
||||||
- key: readability-identifier-naming.ScopedEnumConstantCase
|
- key: readability-identifier-naming.ScopedEnumConstantCase
|
||||||
value: CamelCase
|
value: CamelCase
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
#define FURVM_CONTEXT_HPP
|
#define FURVM_CONTEXT_HPP
|
||||||
|
|
||||||
#include "furlang/arena.hpp"
|
#include "furlang/arena.hpp"
|
||||||
|
#include "furvm/executor.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/module.hpp"
|
#include "furvm/module.hpp"
|
||||||
|
#include "furvm/thing.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -40,12 +43,13 @@ public:
|
|||||||
* @brief Emplaces a new module in this context.
|
* @brief Emplaces a new module in this context.
|
||||||
*
|
*
|
||||||
* @param args Arguments to forward to module's constructor.
|
* @param args Arguments to forward to module's constructor.
|
||||||
* @return An index to the emplaced module.
|
* @return A handle to the module.
|
||||||
*/
|
*/
|
||||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<mod, Args...>>>
|
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<mod, Args...>>>
|
||||||
auto& emplace_module(Args&&... args) {
|
mod_h emplace_module(Args&&... args) {
|
||||||
mod_p mod = std::make_shared<class mod>(std::forward<Args>(args)...);
|
mod_p mod = std::make_shared<class mod>(std::forward<Args>(args)...);
|
||||||
return m_modules.emplace(mod->name(), std::move(mod)).first->second;
|
std::string name = mod->name();
|
||||||
|
return { name, m_modules[name] = std::move(mod) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,24 +93,51 @@ public:
|
|||||||
constexpr size_t module_count() const { return m_modules.size(); }
|
constexpr size_t module_count() const { return m_modules.size(); }
|
||||||
public:
|
public:
|
||||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<executor, Args...>>>
|
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<executor, Args...>>>
|
||||||
auto& emplace_executor(Args&&... args) {
|
executor_h emplace_executor(Args&&... args) {
|
||||||
executor_p executor = std::make_shared<class executor>(std::forward<Args>(args)...);
|
executor executor(std::forward<Args>(args)...);
|
||||||
return m_executors.emplace_back(std::move(executor));
|
executor_id id = m_executors.size();
|
||||||
|
m_executors.emplace_back(std::move(executor));
|
||||||
|
return { id, m_executors[id] };
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Removes unreferenced things from the thing list.
|
* @brief Removes unreferenced things from the thing list.
|
||||||
*/
|
*/
|
||||||
void collect();
|
void collect();
|
||||||
|
public:
|
||||||
|
thing_h emplace_thing(thing_t type) {
|
||||||
|
thing_id id = m_things.size();
|
||||||
|
if (!m_deadThings.empty()) {
|
||||||
|
id = m_deadThings.front();
|
||||||
|
m_deadThings.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = thing_type_size(type);
|
||||||
|
void* data = nullptr;
|
||||||
|
for (auto it = m_deadThingData.begin(); it != m_deadThingData.end(); ++it) {
|
||||||
|
thing_t curType{};
|
||||||
|
std::memcpy(&curType, static_cast<char*>(*it) - sizeof(curType), sizeof(curType));
|
||||||
|
if (thing_type_size(curType) != size) continue;
|
||||||
|
data = *it;
|
||||||
|
m_deadThingData.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data == nullptr) data = m_thingArena.allocate<char>(sizeof(thing_t) + size);
|
||||||
|
memcpy(data, &type, sizeof(type));
|
||||||
|
data = static_cast<char*>(data) + sizeof(type);
|
||||||
|
|
||||||
|
thing_p thing = std::make_shared<class thing>(type, data);
|
||||||
|
return { id, m_things.emplace_back(std::move(thing)) };
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, mod_p> m_modules;
|
std::unordered_map<std::string, mod_p> m_modules;
|
||||||
|
|
||||||
std::vector<thing_p> m_things;
|
std::vector<thing_p> m_things;
|
||||||
std::vector<executor_p> m_executors;
|
std::vector<executor> m_executors;
|
||||||
|
|
||||||
std::queue<thing_handle> m_deadThings;
|
std::queue<thing_id> m_deadThings;
|
||||||
std::vector<void*> m_deadThingData;
|
std::vector<void*> m_deadThingData;
|
||||||
furlang::arena m_thingArena;
|
furlang::arena m_thingArena;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ public:
|
|||||||
* Call frame.
|
* Call frame.
|
||||||
*/
|
*/
|
||||||
struct frame {
|
struct frame {
|
||||||
mod_p mod; /**< Shared pointer to a module with the bytecode. */
|
mod_h mod; /**< Shared pointer to a module with the bytecode. */
|
||||||
std::size_t position; /**< Cursor to a current instruction in the bytecode. */
|
std::size_t position; /**< Cursor to a current instruction in the bytecode. */
|
||||||
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
|
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
|
||||||
|
|
||||||
std::vector<thing_p> variables; /**< Frame variables. */
|
std::vector<thing_h> variables; /**< Frame variables. */
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -60,8 +60,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
executor& operator=(executor&&) noexcept = default;
|
executor& operator=(executor&&) noexcept = default;
|
||||||
|
|
||||||
executor(const executor&) = delete;
|
/**
|
||||||
executor& operator=(const executor&) = delete;
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
executor(const executor&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
executor& operator=(const executor&) = default;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns flags of this executor.
|
* @brief Returns flags of this executor.
|
||||||
@@ -76,7 +83,7 @@ public:
|
|||||||
* @param mod Module.
|
* @param mod Module.
|
||||||
* @param function Function handle.
|
* @param function Function handle.
|
||||||
*/
|
*/
|
||||||
void push_frame(const mod_p& mod, function_handle function);
|
void push_frame(const mod_h& mod, const function_h& function);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pops the top frame.
|
* @brief Pops the top frame.
|
||||||
@@ -97,28 +104,28 @@ public:
|
|||||||
*
|
*
|
||||||
* @param thing The thing to push.
|
* @param thing The thing to push.
|
||||||
*/
|
*/
|
||||||
void push_thing(const thing_p& thing);
|
void push_thing(const thing_h& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pushes a thing onto the stack.
|
* @brief Pushes a thing onto the stack.
|
||||||
*
|
*
|
||||||
* @param thing The thing to push.
|
* @param thing The thing to push.
|
||||||
*/
|
*/
|
||||||
void push_thing(thing_p&& thing);
|
void push_thing(thing_h&& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pops a thing from the stack.
|
* @brief Pops a thing from the stack.
|
||||||
*
|
*
|
||||||
* @return The popped thing.
|
* @return The popped thing.
|
||||||
*/
|
*/
|
||||||
thing_p pop_thing();
|
thing_h pop_thing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the top thing on the stack.
|
* @brief Returns the top thing on the stack.
|
||||||
*
|
*
|
||||||
* @return The thing.
|
* @return The thing.
|
||||||
*/
|
*/
|
||||||
thing_p thing() const;
|
thing_h thing() const;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Stores a thing in a variable.
|
* @brief Stores a thing in a variable.
|
||||||
@@ -126,7 +133,7 @@ public:
|
|||||||
* @param variable Variable to store the thing in.
|
* @param variable Variable to store the thing in.
|
||||||
* @param thing Thing to store.
|
* @param thing Thing to store.
|
||||||
*/
|
*/
|
||||||
void store_thing(variable_t variable, const thing_p& thing);
|
void store_thing(variable_t variable, const thing_h& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stores a thing in a variable.
|
* @brief Stores a thing in a variable.
|
||||||
@@ -134,7 +141,7 @@ public:
|
|||||||
* @param variable Variable to store the thing in.
|
* @param variable Variable to store the thing in.
|
||||||
* @param thing Thing to store.
|
* @param thing Thing to store.
|
||||||
*/
|
*/
|
||||||
void store_thing(variable_t variable, thing_p&& thing);
|
void store_thing(variable_t variable, thing_h&& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a thing stored in a variable.
|
* @brief Returns a thing stored in a variable.
|
||||||
@@ -142,7 +149,7 @@ public:
|
|||||||
* @param variable Variable where the thing is stored.
|
* @param variable Variable where the thing is stored.
|
||||||
* @return The thing stored in the variable.
|
* @return The thing stored in the variable.
|
||||||
*/
|
*/
|
||||||
thing_p load_thing(variable_t variable) const;
|
thing_h load_thing(variable_t variable) const;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Executes next instruction.
|
* @brief Executes next instruction.
|
||||||
@@ -153,7 +160,7 @@ private:
|
|||||||
context_p m_context;
|
context_p m_context;
|
||||||
|
|
||||||
std::stack<struct frame> m_frames;
|
std::stack<struct frame> m_frames;
|
||||||
std::stack<thing_p> m_stack;
|
std::stack<thing_h> m_stack;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ public:
|
|||||||
: m_name(name), m_type(function_t::Native), m_value(native) {}
|
: m_name(name), m_type(function_t::Native), m_value(native) {}
|
||||||
|
|
||||||
template <typename Name, typename ModuleName>
|
template <typename Name, typename ModuleName>
|
||||||
function(Name&& name, ModuleName&& moduleName, function_handle function)
|
function(Name&& name, ModuleName&& moduleName, function_id function)
|
||||||
: m_name(std::forward<Name>(name)),
|
: m_name(std::forward<Name>(name)),
|
||||||
m_type(function_t::Import),
|
m_type(function_t::Import),
|
||||||
m_value(std::forward<ModuleName>(moduleName), function) {}
|
m_value(std::forward<ModuleName>(moduleName), function) {}
|
||||||
|
|
||||||
template <typename ModuleName>
|
template <typename ModuleName>
|
||||||
function(const char* name, ModuleName&& moduleName, function_handle function)
|
function(const char* name, ModuleName&& moduleName, function_id function)
|
||||||
: m_name(name), m_type(function_t::Import), m_value(std::forward<ModuleName>(moduleName), function) {}
|
: m_name(name), m_type(function_t::Import), m_value(std::forward<ModuleName>(moduleName), function) {}
|
||||||
|
|
||||||
~function();
|
~function();
|
||||||
@@ -56,8 +56,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
function& operator=(function&&) noexcept;
|
function& operator=(function&&) noexcept;
|
||||||
|
|
||||||
function(const function&) = delete;
|
/**
|
||||||
function& operator=(const function&) = delete;
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
function(const function&);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
function& operator=(const function&);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a name of this function.
|
* @brief Returns a name of this function.
|
||||||
@@ -108,7 +115,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A handle to the module.
|
* @return A handle to the module.
|
||||||
*/
|
*/
|
||||||
function_handle imported_function() const {
|
function_id imported_function() const {
|
||||||
if (m_type != function_t::Import) throw std::runtime_error("function type mismatch");
|
if (m_type != function_t::Import) throw std::runtime_error("function type mismatch");
|
||||||
return m_value.imp.function;
|
return m_value.imp.function;
|
||||||
}
|
}
|
||||||
@@ -120,8 +127,8 @@ private:
|
|||||||
std::size_t position = 0;
|
std::size_t position = 0;
|
||||||
native_function native;
|
native_function native;
|
||||||
struct {
|
struct {
|
||||||
std::string moduleName;
|
std::string moduleName;
|
||||||
function_handle function;
|
function_id function;
|
||||||
} imp;
|
} imp;
|
||||||
|
|
||||||
value() = default;
|
value() = default;
|
||||||
@@ -133,7 +140,7 @@ private:
|
|||||||
: native(native) {}
|
: native(native) {}
|
||||||
|
|
||||||
template <typename Name>
|
template <typename Name>
|
||||||
value(Name&& moduleName, function_handle function)
|
value(Name&& moduleName, function_id function)
|
||||||
: imp({ std::forward<Name>(moduleName), function }) {}
|
: imp({ std::forward<Name>(moduleName), function }) {}
|
||||||
|
|
||||||
~value() {}
|
~value() {}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#ifndef FURVM_FWD_HPP
|
#ifndef FURVM_FWD_HPP
|
||||||
#define FURVM_FWD_HPP
|
#define FURVM_FWD_HPP
|
||||||
|
|
||||||
|
#include "furvm/handle.hpp"
|
||||||
|
|
||||||
#include <cstddef> // IWYU pragma: export
|
#include <cstddef> // IWYU pragma: export
|
||||||
#include <cstdint> // IWYU pragma: export
|
#include <cstdint> // IWYU pragma: export
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Furlang's virtual machine.
|
* @brief Furlang's virtual machine.
|
||||||
@@ -81,7 +84,12 @@ using function_p = std::shared_ptr<function>;
|
|||||||
/**
|
/**
|
||||||
* @brief Furvm function's index.
|
* @brief Furvm function's index.
|
||||||
*/
|
*/
|
||||||
using function_handle = std::uint16_t;
|
using function_id = std::uint16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A handle to a furvm function.
|
||||||
|
*/
|
||||||
|
using function_h = handle<function_id, function>;
|
||||||
|
|
||||||
// module.hpp
|
// module.hpp
|
||||||
|
|
||||||
@@ -98,6 +106,16 @@ class mod;
|
|||||||
*/
|
*/
|
||||||
using mod_p = std::shared_ptr<mod>;
|
using mod_p = std::shared_ptr<mod>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An alias for a module's identifier.
|
||||||
|
*/
|
||||||
|
using mod_id = std::string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A handle to a furvm module.
|
||||||
|
*/
|
||||||
|
using mod_h = handle<mod_id, mod_p>;
|
||||||
|
|
||||||
// thing.hpp
|
// thing.hpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +146,12 @@ using thing_p = std::shared_ptr<thing>;
|
|||||||
/**
|
/**
|
||||||
* @brief Furvm thing's index.
|
* @brief Furvm thing's index.
|
||||||
*/
|
*/
|
||||||
using thing_handle = std::uint32_t;
|
using thing_id = std::uint32_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A handle to a furvm's thing.
|
||||||
|
*/
|
||||||
|
using thing_h = handle<thing_id, thing_p>;
|
||||||
|
|
||||||
// executor.hpp
|
// executor.hpp
|
||||||
|
|
||||||
@@ -159,7 +182,12 @@ using executor_p = std::shared_ptr<executor>;
|
|||||||
/**
|
/**
|
||||||
* @brief Furvm executor's index.
|
* @brief Furvm executor's index.
|
||||||
*/
|
*/
|
||||||
using executor_handle = std::uint32_t;
|
using executor_id = std::uint32_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A handle to a furvm's executor.
|
||||||
|
*/
|
||||||
|
using executor_h = handle<executor_id, executor>;
|
||||||
|
|
||||||
// context.hpp
|
// context.hpp
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#ifndef FURVM_HANDLE_HPP
|
||||||
|
#define FURVM_HANDLE_HPP
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace furvm {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename Id, typename = void>
|
||||||
|
struct dead_id {
|
||||||
|
static constexpr Id value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Id>
|
||||||
|
struct dead_id<Id, std::enable_if_t<std::is_integral_v<Id>>> {
|
||||||
|
static constexpr Id value = std::numeric_limits<Id>::max();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename Id, typename T>
|
||||||
|
class handle {
|
||||||
|
public:
|
||||||
|
using id_type = Id;
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns a new handle.
|
||||||
|
*
|
||||||
|
* @param id Id of the handle.
|
||||||
|
* @param value Value of the handle.
|
||||||
|
*/
|
||||||
|
template <typename IdF, typename Value>
|
||||||
|
handle(IdF&& id, Value&& value)
|
||||||
|
: m_id(std::forward<IdF>(id)), m_value(std::forward<Value>(value)) {}
|
||||||
|
|
||||||
|
handle()
|
||||||
|
: m_id(detail::dead_id<Id>::value), m_value() {}
|
||||||
|
public:
|
||||||
|
handle& operator=(value_type&& value) noexcept {
|
||||||
|
m_value = std::move(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle& operator=(const value_type& value) noexcept {
|
||||||
|
m_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns the handle's id.
|
||||||
|
*
|
||||||
|
* @return The id.
|
||||||
|
*/
|
||||||
|
constexpr Id id() const { return m_id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the handle's pointer.
|
||||||
|
*
|
||||||
|
* @return The pointer.
|
||||||
|
*/
|
||||||
|
reference value() { return m_value; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the handle's pointer.
|
||||||
|
*
|
||||||
|
* @return The pointer.
|
||||||
|
*/
|
||||||
|
const_reference value() const { return m_value; }
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns the handle's id.
|
||||||
|
*
|
||||||
|
* @return The id.
|
||||||
|
*/
|
||||||
|
explicit operator Id() const { return m_id; }
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns a reference to the handle's value.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
reference operator*() { return m_value; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a reference to the handle's value.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
const_reference operator*() const { return m_value; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a pointer to the handle's value.
|
||||||
|
*
|
||||||
|
* @return The value pointer.
|
||||||
|
*/
|
||||||
|
pointer operator->() { return &m_value; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a pointer to the handle's value.
|
||||||
|
*
|
||||||
|
* @return The value pointer.
|
||||||
|
*/
|
||||||
|
const_pointer operator->() const { return &m_value; }
|
||||||
|
private:
|
||||||
|
id_type m_id;
|
||||||
|
value_type m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace furvm
|
||||||
|
|
||||||
|
#endif // FURVM_HANDLE_HPP
|
||||||
@@ -4,8 +4,6 @@
|
|||||||
#include "furvm/function.hpp"
|
#include "furvm/function.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -93,8 +91,9 @@ public:
|
|||||||
* @return The function.
|
* @return The function.
|
||||||
*/
|
*/
|
||||||
template <typename Name>
|
template <typename Name>
|
||||||
constexpr const function_p& function_at(Name&& name) const {
|
function_h function_at(Name&& name) const {
|
||||||
return m_functions.at(std::forward<Name>(name));
|
if (auto it = m_functionMap.find(std::forward<Name>(name)); it != m_functionMap.end()) return it->second;
|
||||||
|
throw std::runtime_error("invalid function");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,34 +102,23 @@ public:
|
|||||||
* @param id Id of the function.
|
* @param id Id of the function.
|
||||||
* @return The function.
|
* @return The function.
|
||||||
*/
|
*/
|
||||||
constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); }
|
function_h function_at(function_id id) const { return { id, 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>
|
template <typename... Args>
|
||||||
function_handle emplace_function(Args&&... args) {
|
function_h emplace_function(Args&&... args) {
|
||||||
function_p function = std::make_shared<class function>(std::forward<Args>(args)...);
|
function function(std::forward<Args>(args)...);
|
||||||
m_functionMap.emplace(function->name(), function);
|
std::string name = function.name();
|
||||||
function_handle id = m_functions.size();
|
function_id id = m_functions.size();
|
||||||
m_functions.emplace_back(std::move(function));
|
function_h handle = { id, m_functions.emplace_back(std::move(function)) };
|
||||||
return id;
|
m_functionMap.emplace(std::move(name), handle);
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
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::unordered_map<std::string, function_h> m_functionMap;
|
||||||
std::vector<function_p> m_functions;
|
std::vector<function> m_functions;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
+21
-107
@@ -1,7 +1,6 @@
|
|||||||
#ifndef FURVM_THING_HPP
|
#ifndef FURVM_THING_HPP
|
||||||
#define FURVM_THING_HPP
|
#define FURVM_THING_HPP
|
||||||
|
|
||||||
#include "furvm/context.hpp" // IWYU pragma: keep
|
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
@@ -56,9 +55,11 @@ class thing final {
|
|||||||
public:
|
public:
|
||||||
using nref_t = std::size_t; /**< Type of reference count. */
|
using nref_t = std::size_t; /**< Type of reference count. */
|
||||||
|
|
||||||
static constexpr thing_handle GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */
|
static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */
|
||||||
public:
|
public:
|
||||||
thing(const context_p& context, thing_t type);
|
thing(thing_t type);
|
||||||
|
|
||||||
|
thing(thing_t type, void* data);
|
||||||
|
|
||||||
~thing();
|
~thing();
|
||||||
|
|
||||||
@@ -74,104 +75,6 @@ public:
|
|||||||
|
|
||||||
thing(const thing&) = delete;
|
thing(const thing&) = delete;
|
||||||
thing& operator=(const thing&) = delete;
|
thing& operator=(const thing&) = delete;
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Adds two things together.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator+(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Subtracts two things together.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator-(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Multiplies two things together.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator*(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Divides two things together.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator/(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Modulos two things together.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator%(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares two things for equality.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator==(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares two things for equality.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator!=(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
/**
|
|
||||||
* @brief Compares if the left thing is less than the right thing.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator<(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares if the left thing is greater than the right thing.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator>(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares if the left thing is less than or equal to the right thing.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator<=(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares if the left thing is greater than or equal to the right thing.
|
|
||||||
*
|
|
||||||
* @param lhs Left-hand-side thing.
|
|
||||||
* @param rhs Right-hand-side thing.
|
|
||||||
* @return Shared pointer to result thing.
|
|
||||||
*/
|
|
||||||
friend thing_p operator>=(const thing_p& lhs, const thing_p& rhs);
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a clone of the thing.
|
* @brief Returns a clone of the thing.
|
||||||
@@ -179,7 +82,7 @@ public:
|
|||||||
* @param thing Thing to clone.
|
* @param thing Thing to clone.
|
||||||
* @return Shared pointer to a clone of the thing.
|
* @return Shared pointer to a clone of the thing.
|
||||||
*/
|
*/
|
||||||
static thing_p clone(const thing_p& thing);
|
static thing_h clone(const context_p& context, const thing_h& thing);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns an int32 value from this thing.
|
* @brief Returns an int32 value from this thing.
|
||||||
@@ -194,6 +97,18 @@ public:
|
|||||||
* @return The value.
|
* @return The value.
|
||||||
*/
|
*/
|
||||||
const std::int32_t& int32() const;
|
const std::int32_t& int32() const;
|
||||||
|
public:
|
||||||
|
thing_h add(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h sub(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h mul(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h div(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h mod(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h equals(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h not_equals(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h less_than(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h greater_than(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h less_equals(const context_p& context, const thing_h& rhs) const;
|
||||||
|
thing_h greater_equals(const context_p& context, const thing_h& rhs) const;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Increments reference count of this thing by one.
|
* @brief Increments reference count of this thing by one.
|
||||||
@@ -212,11 +127,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
constexpr nref_t reference_count() const { return m_refCount; }
|
constexpr nref_t reference_count() const { return m_refCount; }
|
||||||
private:
|
private:
|
||||||
context_p m_context;
|
thing_t m_type;
|
||||||
thing_t m_type;
|
bool m_ownData = true;
|
||||||
|
nref_t m_refCount = 0;
|
||||||
nref_t m_refCount = 0;
|
void* m_data = nullptr;
|
||||||
void* m_data = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ void context::collect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
+50
-51
@@ -8,15 +8,13 @@
|
|||||||
#include "furvm/thing.hpp"
|
#include "furvm/thing.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
void executor::push_frame(const mod_p& mod, function_handle function) {
|
void executor::push_frame(const mod_h& mod, const function_h& function) {
|
||||||
const auto& func = mod->function_at(function);
|
if (function->type() != function_t::Normal) throw std::runtime_error("unexpected function type");
|
||||||
if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type");
|
m_frames.emplace((struct executor::frame){ mod, function->position(), m_stack.size() });
|
||||||
m_frames.emplace((struct executor::frame){ mod, func->position(), m_stack.size() });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct executor::frame executor::pop_frame() {
|
struct executor::frame executor::pop_frame() {
|
||||||
@@ -30,50 +28,50 @@ struct executor::frame executor::frame() const {
|
|||||||
return m_frames.top();
|
return m_frames.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::push_thing(const thing_p& thing) {
|
void executor::push_thing(const thing_h& thing) {
|
||||||
thing->add_reference();
|
(*thing)->add_reference();
|
||||||
m_stack.push(thing);
|
m_stack.push(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::push_thing(thing_p&& thing) {
|
void executor::push_thing(thing_h&& thing) {
|
||||||
thing->add_reference();
|
(*thing)->add_reference();
|
||||||
m_stack.push(std::move(thing));
|
m_stack.push(std::move(thing));
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_p executor::pop_thing() {
|
thing_h executor::pop_thing() {
|
||||||
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
||||||
thing_p top = std::move(m_stack.top());
|
thing_h top = std::move(m_stack.top());
|
||||||
m_stack.pop();
|
m_stack.pop();
|
||||||
top->remove_reference();
|
(*top)->remove_reference();
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_p executor::thing() const {
|
thing_h executor::thing() const {
|
||||||
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
||||||
return m_stack.top();
|
return m_stack.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::store_thing(variable_t variable, const thing_p& thing) {
|
void executor::store_thing(variable_t variable, const thing_h& thing) {
|
||||||
auto& frame = m_frames.top();
|
auto& frame = m_frames.top();
|
||||||
frame.variables.resize(variable + 1);
|
frame.variables.resize(variable + 1);
|
||||||
if (frame.variables[variable] != nullptr) {
|
if (*frame.variables[variable] != nullptr) {
|
||||||
frame.variables[variable]->remove_reference();
|
(*frame.variables[variable])->remove_reference();
|
||||||
}
|
}
|
||||||
frame.variables[variable] = thing;
|
frame.variables[variable] = thing;
|
||||||
thing->add_reference();
|
(*thing)->add_reference();
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::store_thing(variable_t variable, thing_p&& thing) {
|
void executor::store_thing(variable_t variable, thing_h&& thing) {
|
||||||
auto& frame = m_frames.top();
|
auto& frame = m_frames.top();
|
||||||
frame.variables.resize(variable + 1);
|
frame.variables.resize(variable + 1);
|
||||||
if (frame.variables[variable] != nullptr) {
|
if ((*frame.variables[variable]) != nullptr) {
|
||||||
frame.variables[variable]->remove_reference();
|
(*frame.variables[variable])->remove_reference();
|
||||||
}
|
}
|
||||||
thing->add_reference();
|
(*thing)->add_reference();
|
||||||
frame.variables[variable] = std::move(thing);
|
frame.variables[variable] = std::move(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_p executor::load_thing(variable_t variable) const {
|
thing_h executor::load_thing(variable_t variable) const {
|
||||||
const auto& frame = m_frames.top();
|
const auto& frame = m_frames.top();
|
||||||
return frame.variables[variable];
|
return frame.variables[variable];
|
||||||
}
|
}
|
||||||
@@ -83,12 +81,12 @@ void executor::step() {
|
|||||||
|
|
||||||
struct frame& frame = m_frames.top();
|
struct frame& frame = m_frames.top();
|
||||||
|
|
||||||
instruction_t instr = static_cast<instruction_t>(frame.mod->byte(frame.position++));
|
instruction_t instr = static_cast<instruction_t>((*frame.mod)->byte(frame.position++));
|
||||||
switch (instr) {
|
switch (instr) {
|
||||||
case instruction_t::NoOperation: break;
|
case instruction_t::NoOperation: break;
|
||||||
case instruction_t::PushB2I: {
|
case instruction_t::PushB2I: {
|
||||||
auto thing = std::make_shared<class thing>(m_context, thing_t::Int32);
|
auto thing = m_context->emplace_thing(thing_t::Int32);
|
||||||
thing->int32() = frame.mod->byte(frame.position++);
|
(*thing)->int32() = (*frame.mod)->byte(frame.position++);
|
||||||
push_thing(std::move(thing));
|
push_thing(std::move(thing));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Drop: {
|
case instruction_t::Drop: {
|
||||||
@@ -98,97 +96,98 @@ void executor::step() {
|
|||||||
push_thing(thing());
|
push_thing(thing());
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Clone: {
|
case instruction_t::Clone: {
|
||||||
push_thing(std::move(thing::clone(thing())));
|
push_thing(std::move(thing::clone(m_context, thing())));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Add: {
|
case instruction_t::Add: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs + rhs);
|
push_thing((*lhs)->add(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Sub: {
|
case instruction_t::Sub: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs - rhs);
|
push_thing((*lhs)->sub(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Mul: {
|
case instruction_t::Mul: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs * rhs);
|
push_thing((*lhs)->mul(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Div: {
|
case instruction_t::Div: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs / rhs);
|
push_thing((*lhs)->div(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Mod: {
|
case instruction_t::Mod: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs % rhs);
|
push_thing((*lhs)->mod(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Equals: {
|
case instruction_t::Equals: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs == rhs);
|
push_thing((*lhs)->equals(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::NotEquals: {
|
case instruction_t::NotEquals: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs != rhs);
|
push_thing((*lhs)->not_equals(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::LessThan: {
|
case instruction_t::LessThan: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs < rhs);
|
push_thing((*lhs)->less_than(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::GreaterThan: {
|
case instruction_t::GreaterThan: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs > rhs);
|
push_thing((*lhs)->greater_than(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::LessEqual: {
|
case instruction_t::LessEqual: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs <= rhs);
|
push_thing((*lhs)->less_equals(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::GreaterEqual: {
|
case instruction_t::GreaterEqual: {
|
||||||
auto rhs = pop_thing();
|
auto rhs = pop_thing();
|
||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs >= rhs);
|
push_thing((*lhs)->greater_equals(m_context, rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Load: {
|
case instruction_t::Load: {
|
||||||
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
variable_t variable = static_cast<std::uint16_t>((*frame.mod)->byte(frame.position)) |
|
||||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
(static_cast<std::uint16_t>((*frame.mod)->byte(frame.position + 1)) << 8);
|
||||||
frame.position += 2;
|
frame.position += 2;
|
||||||
push_thing(load_thing(variable));
|
push_thing(load_thing(variable));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Store: {
|
case instruction_t::Store: {
|
||||||
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
variable_t variable = static_cast<std::uint16_t>((*frame.mod)->byte(frame.position)) |
|
||||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
(static_cast<std::uint16_t>((*frame.mod)->byte(frame.position + 1)) << 8);
|
||||||
frame.position += 2;
|
frame.position += 2;
|
||||||
store_thing(variable, std::move(pop_thing()));
|
store_thing(variable, std::move(pop_thing()));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Call: {
|
case instruction_t::Call: {
|
||||||
function_handle funcId = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
function_id funcId = static_cast<std::uint16_t>((*frame.mod)->byte(frame.position)) |
|
||||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
(static_cast<std::uint16_t>((*frame.mod)->byte(frame.position + 1)) << 8);
|
||||||
frame.position += 2;
|
frame.position += 2;
|
||||||
|
|
||||||
const function_p& function = frame.mod->function_at(funcId);
|
const function_h& function = (*frame.mod)->function_at(funcId);
|
||||||
switch (function->type()) {
|
switch (function->type()) {
|
||||||
case function_t::Normal: push_frame(frame.mod, funcId); break;
|
case function_t::Normal: push_frame(frame.mod, function); 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(frame.mod, function->imported_function());
|
// push_frame(frame.mod, function->imported_function());
|
||||||
|
throw std::runtime_error("unimplemented");
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Jump: {
|
case instruction_t::Jump: {
|
||||||
frame.position += frame.mod->byte(frame.position++);
|
frame.position += (*frame.mod)->byte(frame.position++);
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::JumpNotZero: {
|
case instruction_t::JumpNotZero: {
|
||||||
byte offset = frame.mod->byte(frame.position++);
|
byte offset = (*frame.mod)->byte(frame.position++);
|
||||||
auto cond = pop_thing();
|
auto cond = pop_thing();
|
||||||
if (cond->int32() != 0) frame.position += offset;
|
if ((*cond)->int32() != 0) frame.position += offset;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Return: {
|
case instruction_t::Return: {
|
||||||
pop_frame();
|
pop_frame();
|
||||||
|
|||||||
@@ -54,4 +54,41 @@ function& function::operator=(function&& other) noexcept {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function::function(const function& other)
|
||||||
|
: m_name(other.m_name), m_type(other.m_type) {
|
||||||
|
switch (m_type) {
|
||||||
|
case function_t::Normal: {
|
||||||
|
m_value.position = other.m_value.position;
|
||||||
|
} break;
|
||||||
|
case function_t::Native: {
|
||||||
|
new (&m_value.native) native_function(other.m_value.native);
|
||||||
|
} break;
|
||||||
|
case function_t::Import: {
|
||||||
|
m_value.imp.moduleName = other.m_value.imp.moduleName;
|
||||||
|
m_value.imp.function = other.m_value.imp.function;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function& function::operator=(const function& other) {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
|
||||||
|
m_name = other.m_name;
|
||||||
|
m_type = other.m_type;
|
||||||
|
switch (m_type) {
|
||||||
|
case function_t::Normal: {
|
||||||
|
m_value.position = other.m_value.position;
|
||||||
|
} break;
|
||||||
|
case function_t::Native: {
|
||||||
|
new (&m_value.native) native_function(other.m_value.native);
|
||||||
|
} break;
|
||||||
|
case function_t::Import: {
|
||||||
|
m_value.imp.moduleName = other.m_value.imp.moduleName;
|
||||||
|
m_value.imp.function = other.m_value.imp.function;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
+5
-4
@@ -3,6 +3,7 @@
|
|||||||
#include "furvm/context.hpp"
|
#include "furvm/context.hpp"
|
||||||
#include "furvm/executor.hpp"
|
#include "furvm/executor.hpp"
|
||||||
#include "furvm/function.hpp"
|
#include "furvm/function.hpp"
|
||||||
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/instruction.hpp"
|
#include "furvm/instruction.hpp"
|
||||||
#include "furvm/serializer.hpp"
|
#include "furvm/serializer.hpp"
|
||||||
#include "furvm/thing.hpp"
|
#include "furvm/thing.hpp"
|
||||||
@@ -24,11 +25,11 @@ static constexpr std::array<furvm::byte, 8> s_bytecode = {
|
|||||||
int main(void) {
|
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());
|
furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end());
|
||||||
mainModule->emplace_function("main", 0);
|
furvm::function_h mainFunc = (*mainModule)->emplace_function("main", 0);
|
||||||
|
|
||||||
auto executor = context->emplace_executor(context);
|
furvm::executor_h executor = context->emplace_executor(context);
|
||||||
executor->push_frame(mainModule, 0);
|
executor->push_frame(mainModule, mainFunc);
|
||||||
|
|
||||||
static constexpr std::size_t FPC = 3; // Frames per collection
|
static constexpr std::size_t FPC = 3; // Frames per collection
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,7 @@
|
|||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/module.hpp" // IWYU pragma: keep
|
#include "furvm/module.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstring>
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <optional>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@@ -75,8 +72,8 @@ 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 (function_handle id = 0; id < static_cast<function_handle>(mod->m_functions.size()); ++id) {
|
for (function_id id = 0; id < static_cast<function_id>(mod->m_functions.size()); ++id) {
|
||||||
const auto& func = mod->m_functions[id];
|
const auto& func = mod->function_at(id);
|
||||||
write_u16(os, 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()) {
|
||||||
|
|||||||
+145
-153
@@ -17,23 +17,10 @@ std::size_t thing_type_size(thing_t type) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
thing::thing(const context_p& context, thing_t type)
|
thing::thing(thing_t type)
|
||||||
: m_context(context), m_type(type) {
|
: m_type(type) {
|
||||||
std::size_t size = thing_type_size(type);
|
std::size_t size = thing_type_size(type);
|
||||||
std::byte* data = nullptr;
|
byte* data = new byte[size];
|
||||||
if (!m_context->m_deadThingData.empty()) {
|
|
||||||
thing_t itType{};
|
|
||||||
for (auto it = m_context->m_deadThingData.rbegin(); it != m_context->m_deadThingData.rend(); ++it) {
|
|
||||||
std::memcpy(&itType, static_cast<std::byte*>(*it) - sizeof(itType), sizeof(itType));
|
|
||||||
if (size == thing_type_size(itType)) {
|
|
||||||
data = static_cast<std::byte*>(*it);
|
|
||||||
m_context->m_deadThingData.erase(std::next(it).base());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data == nullptr) data = m_context->m_thingArena.allocate<std::byte>(sizeof(type) + size);
|
|
||||||
|
|
||||||
if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing");
|
if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing");
|
||||||
std::memcpy(data, &type, sizeof(type));
|
std::memcpy(data, &type, sizeof(type));
|
||||||
m_data = data + sizeof(type);
|
m_data = data + sizeof(type);
|
||||||
@@ -45,6 +32,20 @@ thing::thing(const context_p& context, thing_t type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thing::thing(thing_t type, void* data)
|
||||||
|
: m_type(type), m_ownData(false) {
|
||||||
|
std::size_t size = thing_type_size(type);
|
||||||
|
if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing");
|
||||||
|
std::memcpy(data, &type, sizeof(type));
|
||||||
|
m_data = static_cast<char*>(data) + sizeof(type);
|
||||||
|
|
||||||
|
switch (m_type) {
|
||||||
|
// Primitives are zero-initialized.
|
||||||
|
default:
|
||||||
|
case thing_t::Int32: std::memset(m_data, 0, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thing::~thing() {
|
thing::~thing() {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
// Primitives are not destructed.
|
// Primitives are not destructed.
|
||||||
@@ -52,19 +53,19 @@ thing::~thing() {
|
|||||||
case thing_t::Int32: break;
|
case thing_t::Int32: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context->m_deadThingData.push_back(m_data);
|
if (m_ownData) delete[] static_cast<char*>(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing::thing(thing&& other) noexcept
|
thing::thing(thing&& other) noexcept
|
||||||
: m_context(std::move(other.m_context)), m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) {
|
: m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) {
|
||||||
other.m_type = {};
|
other.m_type = {};
|
||||||
|
other.m_ownData = false;
|
||||||
other.m_refCount = {};
|
other.m_refCount = {};
|
||||||
other.m_data = nullptr;
|
other.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
thing& thing::operator=(thing&& other) noexcept {
|
thing& thing::operator=(thing&& other) noexcept {
|
||||||
if (this == &other) return *this;
|
if (this == &other) return *this;
|
||||||
m_context = std::move(other.m_context);
|
|
||||||
m_type = other.m_type;
|
m_type = other.m_type;
|
||||||
m_refCount = other.m_refCount;
|
m_refCount = other.m_refCount;
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
@@ -79,145 +80,15 @@ static constexpr std::uint16_t thing_type_pair(thing_t lhs, thing_t rhs) {
|
|||||||
return (static_cast<std::uint16_t>(lhs) << 8) | static_cast<std::uint16_t>(rhs);
|
return (static_cast<std::uint16_t>(lhs) << 8) | static_cast<std::uint16_t>(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_p operator+(const thing_p& lhs, const thing_p& rhs) {
|
thing_h thing::clone(const context_p& context, const thing_h& thing) {
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
auto th = context->emplace_thing((*thing)->m_type);
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
switch ((*thing)->m_type) {
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = lhs->int32() + rhs->int32();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator-(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = lhs->int32() - rhs->int32();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator*(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = lhs->int32() * rhs->int32();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator/(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = lhs->int32() / rhs->int32();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator%(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = lhs->int32() % rhs->int32();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator==(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() == rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator!=(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() != rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator<(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() < rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator>(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() > rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator<=(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() <= rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p operator>=(const thing_p& lhs, const thing_p& rhs) {
|
|
||||||
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
|
|
||||||
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
|
||||||
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
|
|
||||||
res->int32() = static_cast<std::int32_t>(lhs->int32() >= rhs->int32());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default: throw std::runtime_error("unexpected operator");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thing_p thing::clone(const thing_p& thing) {
|
|
||||||
thing_handle id = thing->m_context->m_things.size();
|
|
||||||
if (!thing->m_context->m_deadThings.empty()) {
|
|
||||||
id = thing->m_context->m_deadThings.front();
|
|
||||||
thing->m_context->m_deadThings.pop();
|
|
||||||
id += 1 << GENERATION_SIZE;
|
|
||||||
}
|
|
||||||
thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1);
|
|
||||||
|
|
||||||
auto th = std::make_shared<class thing>(thing->m_context, thing->m_type);
|
|
||||||
switch (thing->m_type) {
|
|
||||||
// Primitives
|
// Primitives
|
||||||
default: {
|
default: {
|
||||||
memcpy(th->m_data, thing->m_data, thing_type_size(thing->m_type));
|
memcpy((*th)->m_data, (*thing)->m_data, thing_type_size((*thing)->m_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thing->m_context->m_things.emplace(thing->m_context->m_things.begin() + idx, th);
|
|
||||||
return std::move(th);
|
return std::move(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +102,127 @@ const std::int32_t& thing::int32() const {
|
|||||||
return *static_cast<std::int32_t*>(m_data);
|
return *static_cast<std::int32_t*>(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thing_h thing::add(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = int32() + (*rhs)->int32();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::sub(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = int32() - (*rhs)->int32();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::mul(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = int32() * (*rhs)->int32();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::div(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = int32() / (*rhs)->int32();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::mod(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = int32() % (*rhs)->int32();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::equals(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() == (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::not_equals(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() != (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::less_than(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() < (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::greater_than(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() > (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::less_equals(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() <= (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thing_h thing::greater_equals(const context_p& context, const thing_h& rhs) const {
|
||||||
|
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
|
||||||
|
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
|
||||||
|
thing_h res = context->emplace_thing(thing_t::Int32);
|
||||||
|
(*res)->int32() = static_cast<std::int32_t>(int32() >= (*rhs)->int32());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|
||||||
// NOLINTEND(cppcoreguidelines-no-malloc)
|
// NOLINTEND(cppcoreguidelines-no-malloc)
|
||||||
|
|||||||
Reference in New Issue
Block a user