#ifndef FURVM_EXECUTOR_HPP #define FURVM_EXECUTOR_HPP #include "furvm/fwd.hpp" #include "furvm/module.hpp" // IWYU pragma: keep #include "furvm/stack.hpp" #include "furvm/thing.hpp" // IWYU pragma: keep #include #include #include namespace furvm { enum class executor_flags : std::uint32_t { Suspended = (1 << 0), /**< Execution suspended. */ Done = (1 << 1), /**< Execution is finished. */ JustHit = (1 << 16), /**< Executor just hit a breakpoint. */ }; static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) { return executor_flags(static_cast(lhs) | static_cast(rhs)); } static inline executor_flags operator&(executor_flags lhs, executor_flags rhs) { return executor_flags(static_cast(lhs) & static_cast(rhs)); } static inline executor_flags operator~(executor_flags flags) { return executor_flags(~static_cast(flags)); } class executor { friend class context; private: executor(context* context) : m_context(context) {} public: static constexpr executor_flags STATE_FLAGS = executor_flags::JustHit; using new_frame_callback = std::function; using stack_thing = thing; public: /** * @brief Executor frame. * * Call frame. */ struct frame { mod_h mod; /**< Handle to the frame's module. */ std::size_t position; /**< Cursor to a current instruction in the bytecode. */ std::size_t stackBase; /**< Snapshot of the stack size before this frame. */ thing_type* returnType; /**< Return type. */ std::vector variables; /**< Frame variables. */ }; public: ~executor() = default; /** * @brief Move constructor. */ executor(executor&&) noexcept = default; /** * @brief Move constructor. */ executor& operator=(executor&&) noexcept = default; /** * @brief Copy constructor. */ executor(const executor&) = default; /** * @brief Copy constructor. */ executor& operator=(const executor&) = default; public: template void set_new_frame_callback(CallbackFwd&& callback) { m_newFrameCb = std::forward(callback); } public: /** * @brief Returns flags of this executor. * * @return The flags. */ executor_flags flags() const { return m_flags; } bool done() const { return (m_flags & executor_flags::Done) == executor_flags::Done; } bool suspended() const { return (m_flags & executor_flags::Suspended) == executor_flags::Suspended; } void unsuspend() { m_flags = m_flags & ~executor_flags::Suspended; } void clear_flags() { m_flags = m_flags & STATE_FLAGS; m_flags = m_frames.empty() ? executor_flags::Done : furvm::executor_flags{ 0 }; } public: /** * @brief Pushes a new frame. * * @param mod Handle to the frame's module. * @param function Frame's function. */ void push_frame(const mod_h& mod, function function); /** * @brief Pops the top frame. * * @return The popped frame. */ frame pop_frame(); /** * @brief Returns the top frame. * * @return The frame. */ frame top_frame() const; const std::stack& frames() const { return m_frames; } public: /** * @brief Pushes a thing onto the stack. * * Registers a new thing and pushes its handle onto the stack. * * @param thing Thing. * @return The pushed handle. */ stack_thing& push_thing(stack_thing&& thing); stack_thing& push_thing(const stack_thing& thing); /** * @brief Pops a thing from the stack. * * @return A handle to the popped thing. */ stack_thing pop_thing(); /** * @brief Returns the top thing on the stack. * * @return A handle to the top thing. */ stack_thing& top_thing(); const stack_thing& top_thing() const; const std::vector& stack() const { return m_stack; } public: /** * @brief Stores a thing in a frame variable. * * @param variable Id of the variable in which the handle will be put. * @param thing Thing handle. */ void store_thing(variable_t variable, const stack_thing& thing); /** * @brief Stores a thing in a frame variable. * * @param variable Id of the variable in which the handle will be put. * @param thing Thing handle. */ void store_thing(variable_t variable, stack_thing&& thing); /** * @brief Returns a thing stored in a variable. * * @param variable Id of the variable from which the handle will be fetched. * @return A handle stored in the variable. */ stack_thing& load_thing(variable_t variable); const stack_thing& load_thing(variable_t variable) const; public: /** * @brief Executes next instruction. */ void step(); private: thing_type thing_type_impl(mod_h mod, mod_type type) const; thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const; private: static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs); private: executor_flags m_flags = executor_flags::Done; context* m_context; furvm::stack m_stackStorage; std::stack m_frames; std::vector m_stack; new_frame_callback m_newFrameCb = nullptr; }; } // namespace furvm #endif // FURVM_EXECUTOR_HPP