feat(furvm): add step function to executor
This commit is contained in:
@@ -9,6 +9,7 @@ namespace furvm {
|
|||||||
|
|
||||||
enum class executor_flags : std::uint32_t {
|
enum class executor_flags : std::uint32_t {
|
||||||
Suspended = (1 << 0), /**< Execution suspended. */
|
Suspended = (1 << 0), /**< Execution suspended. */
|
||||||
|
Done = (1 << 1), /**< Execution is finished. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) {
|
static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) {
|
||||||
@@ -132,6 +133,11 @@ public:
|
|||||||
* @return The thing.
|
* @return The thing.
|
||||||
*/
|
*/
|
||||||
thing_p thing() const;
|
thing_p thing() const;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Executes next instruction.
|
||||||
|
*/
|
||||||
|
void step();
|
||||||
private:
|
private:
|
||||||
executor_handle m_id;
|
executor_handle m_id;
|
||||||
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
|
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ using module_handle = std::uint32_t;
|
|||||||
*/
|
*/
|
||||||
enum class thing_t : std::uint8_t;
|
enum class thing_t : std::uint8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class bad_thing_access
|
||||||
|
* @brief Bad thing access exception.
|
||||||
|
*/
|
||||||
|
class bad_thing_access;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class thing
|
* @class thing
|
||||||
* @brief Furvm thing.
|
* @brief Furvm thing.
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ public:
|
|||||||
* @return The id.
|
* @return The id.
|
||||||
*/
|
*/
|
||||||
constexpr module_handle id() const { return m_id; }
|
constexpr module_handle id() const { return m_id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a byte from bytecode of this module.
|
||||||
|
*
|
||||||
|
* @param offset An offset of the byte.
|
||||||
|
* @return The byte.
|
||||||
|
*/
|
||||||
|
constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); }
|
||||||
private:
|
private:
|
||||||
module_handle m_id;
|
module_handle m_id;
|
||||||
bytecode_t m_bytecode;
|
bytecode_t m_bytecode;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
enum class thing_t : std::uint8_t {
|
enum class thing_t : std::uint8_t {
|
||||||
Int,
|
Int32,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,6 +17,39 @@ enum class thing_t : std::uint8_t {
|
|||||||
*/
|
*/
|
||||||
std::size_t thing_type_size(thing_t type);
|
std::size_t thing_type_size(thing_t type);
|
||||||
|
|
||||||
|
class bad_thing_access : public std::exception {
|
||||||
|
public:
|
||||||
|
bad_thing_access() = default;
|
||||||
|
~bad_thing_access() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
|
bad_thing_access(bad_thing_access&&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
|
bad_thing_access& operator=(bad_thing_access&&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
bad_thing_access(const bad_thing_access&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
bad_thing_access& operator=(const bad_thing_access&) = default;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns a C-style string describing the cause of the error.
|
||||||
|
*
|
||||||
|
* @return The cause of the error.
|
||||||
|
*/
|
||||||
|
const char* what() const noexcept override { return "bad thing access"; }
|
||||||
|
};
|
||||||
|
|
||||||
class thing {
|
class thing {
|
||||||
friend class executor;
|
friend class executor;
|
||||||
private:
|
private:
|
||||||
@@ -61,6 +94,20 @@ public:
|
|||||||
* @return Shared pointer to the new thing.
|
* @return Shared pointer to the new thing.
|
||||||
*/
|
*/
|
||||||
static thing_p create(const context_p& context, thing_t type);
|
static thing_p create(const context_p& context, thing_t type);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns an int32 value from this thing.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
std::int32_t& int32();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns an int32 value from this thing.
|
||||||
|
*
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
const std::int32_t& int32() const;
|
||||||
private:
|
private:
|
||||||
thing_handle m_id;
|
thing_handle m_id;
|
||||||
thing_t m_type;
|
thing_t m_type;
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "furvm/executor.hpp"
|
#include "furvm/executor.hpp"
|
||||||
|
|
||||||
#include "furvm/context.hpp" // IWYU pragma: keep
|
#include "furvm/context.hpp" // IWYU pragma: keep
|
||||||
|
#include "furvm/instruction.hpp"
|
||||||
|
#include "furvm/thing.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
@@ -47,4 +51,32 @@ thing_p executor::thing() const {
|
|||||||
return m_stack.top();
|
return m_stack.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void executor::step() {
|
||||||
|
if ((m_flags & executor_flags::Suspended) == executor_flags::Suspended) return;
|
||||||
|
|
||||||
|
struct frame& frame = m_frames.top();
|
||||||
|
|
||||||
|
instruction_t instr = static_cast<instruction_t>(frame.mod->byte(frame.position++));
|
||||||
|
switch (instr) {
|
||||||
|
case instruction_t::NoOperation: break;
|
||||||
|
case instruction_t::Return: {
|
||||||
|
pop_frame();
|
||||||
|
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
||||||
|
} break;
|
||||||
|
case instruction_t::PushB2I: {
|
||||||
|
auto thing = thing::create(m_context, thing_t::Int32);
|
||||||
|
thing->int32() = frame.mod->byte(frame.position++);
|
||||||
|
m_stack.push(std::move(thing));
|
||||||
|
} break;
|
||||||
|
case instruction_t::Drop: {
|
||||||
|
m_stack.pop();
|
||||||
|
} break;
|
||||||
|
case instruction_t::PushConstant:
|
||||||
|
case instruction_t::Duplicate:
|
||||||
|
case instruction_t::ReturnValue: {
|
||||||
|
throw std::runtime_error("unimplemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
@@ -22,6 +22,10 @@ int main(void) {
|
|||||||
auto executor = furvm::executor::create(context);
|
auto executor = furvm::executor::create(context);
|
||||||
executor->push_frame(mainModule, 0);
|
executor->push_frame(mainModule, 0);
|
||||||
|
|
||||||
|
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
||||||
|
executor->step();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -10,7 +10,7 @@ namespace furvm {
|
|||||||
|
|
||||||
std::size_t thing_type_size(thing_t type) {
|
std::size_t thing_type_size(thing_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case thing_t::Int: return 4;
|
case thing_t::Int32: return 4;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,16 @@ thing_p thing::create(const context_p& context, thing_t type) {
|
|||||||
return std::move(th);
|
return std::move(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::int32_t& thing::int32() {
|
||||||
|
if (m_type != thing_t::Int32) throw bad_thing_access();
|
||||||
|
return *static_cast<std::int32_t*>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::int32_t& thing::int32() const {
|
||||||
|
if (m_type != thing_t::Int32) throw bad_thing_access();
|
||||||
|
return *static_cast<std::int32_t*>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|
||||||
// NOLINTEND(cppcoreguidelines-no-malloc)
|
// NOLINTEND(cppcoreguidelines-no-malloc)
|
||||||
Reference in New Issue
Block a user