Compare commits
2 Commits
713aec199f
...
84b70077c1
| Author | SHA1 | Date | |
|---|---|---|---|
|
84b70077c1
|
|||
|
21e92dcb4b
|
@@ -9,7 +9,7 @@
|
|||||||
struct context {
|
struct context {
|
||||||
furvm::context_p context = std::make_shared<furvm::context>();
|
furvm::context_p context = std::make_shared<furvm::context>();
|
||||||
furvm::mod_h mod;
|
furvm::mod_h mod;
|
||||||
furvm::executor_h executor;
|
furvm::executor* executor = nullptr;
|
||||||
furvm::function_h mainFunction;
|
furvm::function_h mainFunction;
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|||||||
+2
-3
@@ -56,12 +56,11 @@ int main(int argc, char** argv) {
|
|||||||
std::cerr << "Failed to load module " << argv[1] << ": " << ex.what() << '\n';
|
std::cerr << "Failed to load module " << argv[1] << ": " << ex.what() << '\n';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ctx.executor = ctx.context->emplace_executor(ctx.context);
|
ctx.executor = &ctx.context->allocate_executor();
|
||||||
ctx.mainFunction = ctx.mod->function_at("main", furvm::function_sig{});
|
ctx.mainFunction = ctx.mod->function_at("main", furvm::function_sig{});
|
||||||
|
|
||||||
ctx.mod->set_native_function("println", [](furvm::executor& executor) {
|
ctx.mod->set_native_function("println", [](furvm::executor& executor) {
|
||||||
auto arg = executor.load_thing(0);
|
print_thing(executor.load_thing(0));
|
||||||
print_thing(*arg);
|
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
@@ -39,15 +40,10 @@ public:
|
|||||||
context(const context&) = delete;
|
context(const context&) = delete;
|
||||||
context& operator=(const context&) = delete;
|
context& operator=(const context&) = delete;
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief Emplaces an executor in the context.
|
|
||||||
*
|
|
||||||
* @param args Arguments forwarded to executor's constructor.
|
|
||||||
* @return A handle to the emplaced executor.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto emplace_executor(Args&&... args) {
|
auto& allocate_executor() {
|
||||||
return m_executors.emplace_back(std::forward<Args>(args)...);
|
executor executor(this);
|
||||||
|
return m_executors.emplace_back(std::move(executor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,7 +53,7 @@ public:
|
|||||||
* @return A handle to the executor.
|
* @return A handle to the executor.
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto executor_at(Args&&... args) {
|
auto& executor_at(Args&&... args) {
|
||||||
return m_executors.at(std::forward<Args>(args)...);
|
return m_executors.at(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,57 +64,12 @@ public:
|
|||||||
* @return A handle to the executor.
|
* @return A handle to the executor.
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto executor_at(Args&&... args) const {
|
const auto& executor_at(Args&&... args) const {
|
||||||
return m_executors.at(std::forward<Args>(args)...);
|
return m_executors.at(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const std::vector<executor>& executors() const { return m_executors; }
|
||||||
* @brief Erases an executor from the context.
|
|
||||||
*
|
|
||||||
* @param args Id of the executor.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
void erase_executor(Args&&... args) {
|
|
||||||
m_executors.erase(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
|
||||||
auto emplace_thing(Args&&... args) {
|
|
||||||
return m_things.emplace_back(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a thing from the context.
|
|
||||||
*
|
|
||||||
* @param args Id of the thing.
|
|
||||||
* @return A handle to the thing.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
auto thing_at(Args&&... args) {
|
|
||||||
return m_things.at(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a thing from the context.
|
|
||||||
*
|
|
||||||
* @param args Id of the thing.
|
|
||||||
* @return A handle to the thing.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
auto thing_at(Args&&... args) const {
|
|
||||||
return m_things.at(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Erases a thing from the context.
|
|
||||||
*
|
|
||||||
* @param args Id of the thing.
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
void erase_thing(Args&&... args) {
|
|
||||||
m_things.erase(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns context's thing allocator.
|
* @brief Returns context's thing allocator.
|
||||||
*
|
*
|
||||||
@@ -128,9 +79,8 @@ public:
|
|||||||
|
|
||||||
thing_type_store& tt_store() { return m_thingTypeStore; }
|
thing_type_store& tt_store() { return m_thingTypeStore; }
|
||||||
private:
|
private:
|
||||||
handle_container<mod_h> m_modules;
|
handle_container<mod_h> m_modules;
|
||||||
handle_container<thing_h> m_things;
|
std::vector<executor> m_executors;
|
||||||
handle_container<executor_h> m_executors;
|
|
||||||
|
|
||||||
furlang::arena m_thingArena;
|
furlang::arena m_thingArena;
|
||||||
thing_allocator<std::byte> m_thingAllocator;
|
thing_allocator<std::byte> m_thingAllocator;
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ static inline executor_flags operator~(executor_flags flags) {
|
|||||||
using executor_callback = std::function<void(executor&)>;
|
using executor_callback = std::function<void(executor&)>;
|
||||||
|
|
||||||
class executor {
|
class executor {
|
||||||
|
friend class context;
|
||||||
|
private:
|
||||||
|
executor(context* context)
|
||||||
|
: m_context(context) {}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Executor frame.
|
* @brief Executor frame.
|
||||||
@@ -44,17 +48,9 @@ public:
|
|||||||
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
|
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
|
||||||
|
|
||||||
thing_type* returnType; /**< Return type. */
|
thing_type* returnType; /**< Return type. */
|
||||||
std::vector<thing_h> variables; /**< Frame variables. */
|
std::vector<thing<>> variables; /**< Frame variables. */
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief Returns a new executor.
|
|
||||||
*
|
|
||||||
* @param context Context.
|
|
||||||
*/
|
|
||||||
executor(const context_p& context)
|
|
||||||
: m_context(context) {}
|
|
||||||
|
|
||||||
~executor() = default;
|
~executor() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,20 +105,10 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The frame.
|
* @return The frame.
|
||||||
*/
|
*/
|
||||||
frame frame() const;
|
frame top_frame() const;
|
||||||
|
|
||||||
const std::stack<struct frame>& frames() const { return m_frames; }
|
const std::stack<frame>& frames() const { return m_frames; }
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief Pushes a thing handle onto the stack.
|
|
||||||
*
|
|
||||||
* @param handle Thing handle.
|
|
||||||
*/
|
|
||||||
template <typename HandleFwd>
|
|
||||||
void push_thing(HandleFwd&& handle) {
|
|
||||||
m_stack.emplace(std::forward<HandleFwd>(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pushes a thing onto the stack.
|
* @brief Pushes a thing onto the stack.
|
||||||
*
|
*
|
||||||
@@ -131,21 +117,25 @@ public:
|
|||||||
* @param thing Thing.
|
* @param thing Thing.
|
||||||
* @return The pushed handle.
|
* @return The pushed handle.
|
||||||
*/
|
*/
|
||||||
thing_h push_thing(class thing<>&& thing);
|
thing<>& push_thing(thing<>&& thing);
|
||||||
|
|
||||||
|
thing<>& push_thing(const thing<>& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pops a thing from the stack.
|
* @brief Pops a thing from the stack.
|
||||||
*
|
*
|
||||||
* @return A handle to the popped thing.
|
* @return A handle to the popped thing.
|
||||||
*/
|
*/
|
||||||
thing_h pop_thing();
|
thing<> pop_thing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the top thing on the stack.
|
* @brief Returns the top thing on the stack.
|
||||||
*
|
*
|
||||||
* @return A handle to the top thing.
|
* @return A handle to the top thing.
|
||||||
*/
|
*/
|
||||||
thing_h thing() const;
|
thing<>& top_thing();
|
||||||
|
|
||||||
|
const thing<>& top_thing() const;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Stores a thing in a frame variable.
|
* @brief Stores a thing in a frame variable.
|
||||||
@@ -153,7 +143,7 @@ public:
|
|||||||
* @param variable Id of the variable in which the handle will be put.
|
* @param variable Id of the variable in which the handle will be put.
|
||||||
* @param thing Thing handle.
|
* @param thing Thing handle.
|
||||||
*/
|
*/
|
||||||
void store_thing(variable_t variable, const thing_h& thing);
|
void store_thing(variable_t variable, const thing<>& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stores a thing in a frame variable.
|
* @brief Stores a thing in a frame variable.
|
||||||
@@ -161,7 +151,7 @@ public:
|
|||||||
* @param variable Id of the variable in which the handle will be put.
|
* @param variable Id of the variable in which the handle will be put.
|
||||||
* @param thing Thing handle.
|
* @param thing Thing handle.
|
||||||
*/
|
*/
|
||||||
void store_thing(variable_t variable, thing_h&& thing);
|
void store_thing(variable_t variable, thing<>&& thing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a thing stored in a variable.
|
* @brief Returns a thing stored in a variable.
|
||||||
@@ -169,7 +159,9 @@ public:
|
|||||||
* @param variable Id of the variable from which the handle will be fetched.
|
* @param variable Id of the variable from which the handle will be fetched.
|
||||||
* @return A handle stored in the variable.
|
* @return A handle stored in the variable.
|
||||||
*/
|
*/
|
||||||
thing_h load_thing(variable_t variable) const;
|
thing<>& load_thing(variable_t variable);
|
||||||
|
|
||||||
|
const thing<>& load_thing(variable_t variable) const;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Executes next instruction.
|
* @brief Executes next instruction.
|
||||||
@@ -179,12 +171,14 @@ private:
|
|||||||
thing_type thing_type_impl(mod_h mod, mod_type type) const;
|
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;
|
thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const;
|
||||||
|
|
||||||
|
thing<> make_reference(const thing<>& thing) const;
|
||||||
private:
|
private:
|
||||||
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
|
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
|
||||||
context_p m_context;
|
context* m_context;
|
||||||
|
|
||||||
std::stack<struct frame> m_frames;
|
std::stack<frame> m_frames;
|
||||||
std::stack<thing_h> m_stack;
|
std::stack<thing<>> m_stack;
|
||||||
|
|
||||||
executor_callback m_newFrameCb = nullptr;
|
executor_callback m_newFrameCb = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -169,11 +169,6 @@ class thing;
|
|||||||
*/
|
*/
|
||||||
using thing_id = std::uint32_t;
|
using thing_id = std::uint32_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A handle to a thing.
|
|
||||||
*/
|
|
||||||
using thing_h = handle<thing<thing_allocator>, refcount_header<thing_id>>;
|
|
||||||
|
|
||||||
// executor.hpp
|
// executor.hpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -195,21 +190,11 @@ enum class executor_flags : std::uint32_t;
|
|||||||
*/
|
*/
|
||||||
class executor;
|
class executor;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An alias to a executor shared pointer.
|
|
||||||
*/
|
|
||||||
using executor_p = std::shared_ptr<executor>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Furvm executor's index.
|
* @brief Furvm executor's index.
|
||||||
*/
|
*/
|
||||||
using executor_id = std::uint32_t;
|
using executor_id = std::uint32_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A handle to an executor.
|
|
||||||
*/
|
|
||||||
using executor_h = handle<executor, refcount_header<executor_id>>;
|
|
||||||
|
|
||||||
// context.hpp
|
// context.hpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ struct thing_type {
|
|||||||
Array,
|
Array,
|
||||||
|
|
||||||
Count,
|
Count,
|
||||||
} type;
|
} type = Count;
|
||||||
union value {
|
union value {
|
||||||
std::nullptr_t null = nullptr;
|
std::nullptr_t null = nullptr;
|
||||||
thing_type* typeRef;
|
thing_type* typeRef;
|
||||||
@@ -202,6 +202,8 @@ public:
|
|||||||
std::byte* data;
|
std::byte* data;
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
|
thing() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a thing.
|
* @brief Constructs a thing.
|
||||||
*
|
*
|
||||||
@@ -239,6 +241,7 @@ public:
|
|||||||
thing& operator=(thing&& other) noexcept {
|
thing& operator=(thing&& other) noexcept {
|
||||||
if (this == &other) return *this;
|
if (this == &other) return *this;
|
||||||
m_type = other.m_type;
|
m_type = other.m_type;
|
||||||
|
m_size = other.m_size;
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
m_allocator = std::move(other.m_allocator);
|
m_allocator = std::move(other.m_allocator);
|
||||||
other.m_type.type = thing_type::Count;
|
other.m_type.type = thing_type::Count;
|
||||||
@@ -247,8 +250,32 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
thing(const thing&) = delete;
|
thing(const thing& other)
|
||||||
thing& operator=(const thing&) = delete;
|
: m_type(other.m_type), m_size(other.m_size), m_allocator(other.m_allocator) {
|
||||||
|
if (m_type.type == thing_type::Ref) {
|
||||||
|
m_data = other.m_data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_data = m_allocator.allocate(m_size);
|
||||||
|
other.copy(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
thing& operator=(const thing& other) {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
|
||||||
|
m_type = other.m_type;
|
||||||
|
m_size = other.m_size;
|
||||||
|
m_allocator = std::move(other.m_allocator);
|
||||||
|
|
||||||
|
if (m_type.type == thing_type::Ref) {
|
||||||
|
m_data = other.m_data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
m_data = m_allocator.allocate(m_size);
|
||||||
|
other.copy(*this);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a clone of the thing.
|
* @brief Returns a clone of the thing.
|
||||||
@@ -257,6 +284,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
thing clone() const {
|
thing clone() const {
|
||||||
thing res(m_type, m_allocator);
|
thing res(m_type, m_allocator);
|
||||||
|
copy(res);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void copy(thing<>& dst) const {
|
||||||
switch (m_type.type) {
|
switch (m_type.type) {
|
||||||
case thing_type::S8:
|
case thing_type::S8:
|
||||||
case thing_type::S16:
|
case thing_type::S16:
|
||||||
@@ -266,9 +297,9 @@ public:
|
|||||||
case thing_type::U16:
|
case thing_type::U16:
|
||||||
case thing_type::U32:
|
case thing_type::U32:
|
||||||
case thing_type::U64:
|
case thing_type::U64:
|
||||||
case thing_type::Ptr: std::memcpy(res.m_data, m_data, m_size); return std::move(res);
|
case thing_type::Ptr: std::memcpy(dst.m_data, m_data, m_size); return;
|
||||||
case thing_type::Array: copy_list(m_type, res.m_data, m_data); return std::move(res);
|
case thing_type::Array: copy_list(m_type, dst.m_data, m_data); return;
|
||||||
case thing_type::Ref: throw std::runtime_error("cannot clone references");
|
case thing_type::Ref: throw std::runtime_error("cannot copy references");
|
||||||
case thing_type::Count: break;
|
case thing_type::Count: break;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("unreachable");
|
throw std::runtime_error("unreachable");
|
||||||
@@ -460,17 +491,17 @@ public:
|
|||||||
thing at(thing_type::u64 index) const {
|
thing at(thing_type::u64 index) const {
|
||||||
if (!is(thing_type::Array)) throw bad_thing_access();
|
if (!is(thing_type::Array)) throw bad_thing_access();
|
||||||
|
|
||||||
std::size_t elementSize = compute_size_na(*m_type.value.array.type);
|
std::size_t elementSize = compute_size_na(*true_type().value.array.type);
|
||||||
if (m_type.value.array.size == 0) {
|
if (true_type().value.array.size == 0) {
|
||||||
auto& array = get<dynamic_array>();
|
auto& array = get<dynamic_array>();
|
||||||
if (index < 0 || index >= array.size) throw std::out_of_range("index out of range");
|
if (index < 0 || index >= array.size) throw std::out_of_range("index out of range");
|
||||||
thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator };
|
thing ref = { { thing_type::Ref, true_type().value.array.type }, m_allocator };
|
||||||
ref.m_data = array.data + (index * elementSize);
|
ref.m_data = array.data + (index * elementSize);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < 0 || index >= m_type.value.array.size) throw std::out_of_range("index out of range");
|
if (index < 0 || index >= true_type().value.array.size) throw std::out_of_range("index out of range");
|
||||||
thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator };
|
thing ref = { { thing_type::Ref, true_type().value.array.type }, m_allocator };
|
||||||
ref.m_data = m_data + (index * elementSize);
|
ref.m_data = m_data + (index * elementSize);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
@@ -727,8 +758,8 @@ private:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
thing_type m_type;
|
thing_type m_type;
|
||||||
std::size_t m_size;
|
std::size_t m_size = 0;
|
||||||
std::byte* m_data;
|
std::byte* m_data = nullptr;
|
||||||
|
|
||||||
allocator_type m_allocator;
|
allocator_type m_allocator;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class thing_allocator {
|
|||||||
public:
|
public:
|
||||||
using value_type = T; /**< Value type. */
|
using value_type = T; /**< Value type. */
|
||||||
public:
|
public:
|
||||||
|
thing_allocator() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a thing allocator.
|
* @brief Constructs a thing allocator.
|
||||||
*
|
*
|
||||||
@@ -101,7 +103,7 @@ public:
|
|||||||
return m_arena != other.m_arena || m_deadThings != other.m_deadThings;
|
return m_arena != other.m_arena || m_deadThings != other.m_deadThings;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
furlang::arena* m_arena;
|
furlang::arena* m_arena = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<dead_things> m_deadThings;
|
std::shared_ptr<dead_things> m_deadThings;
|
||||||
};
|
};
|
||||||
|
|||||||
+80
-57
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -45,6 +46,13 @@ thing_type* executor::mod_to_thing_type(const mod_h& mod, const mod_type& type)
|
|||||||
return m_context->tt_store().insert(thingType);
|
return m_context->tt_store().insert(thingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thing<> executor::make_reference(const thing<>& thing) const {
|
||||||
|
furvm::thing<> ref = { (struct thing_type){ thing_type::Ref, m_context->tt_store().insert(thing.type()) },
|
||||||
|
m_context->thing_alloc() };
|
||||||
|
ref.reference(thing);
|
||||||
|
return std::move(ref);
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@@ -53,11 +61,12 @@ void executor::push_frame(const mod_h& mod, function function) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto signature = function.signature();
|
auto signature = function.signature();
|
||||||
std::vector<thing_h> args;
|
std::vector<thing<>> args;
|
||||||
args.reserve(signature.params.size());
|
args.reserve(signature.params.size());
|
||||||
for (const auto& param : signature.params) {
|
for (const auto& param : signature.params) {
|
||||||
auto arg = pop_thing();
|
auto arg = pop_thing();
|
||||||
if (arg->type() != *mod_to_thing_type(mod, *param)) throw std::runtime_error("function argument type mismatch");
|
if (arg.true_type() != *mod_to_thing_type(mod, *param))
|
||||||
|
throw std::runtime_error("function argument type mismatch");
|
||||||
args.push_back(std::move(arg));
|
args.push_back(std::move(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,48 +94,65 @@ struct executor::frame executor::pop_frame() {
|
|||||||
if (m_frames.empty()) throw stack_underflow();
|
if (m_frames.empty()) throw stack_underflow();
|
||||||
struct executor::frame frame = m_frames.top();
|
struct executor::frame frame = m_frames.top();
|
||||||
m_frames.pop();
|
m_frames.pop();
|
||||||
thing_h returnValue;
|
std::optional<thing<>> returnValue;
|
||||||
if (frame.returnType != nullptr) returnValue = pop_thing();
|
if (frame.returnType != nullptr) {
|
||||||
|
returnValue = pop_thing();
|
||||||
|
if (returnValue->type() != *frame.returnType) throw std::runtime_error("function return type mismatch");
|
||||||
|
}
|
||||||
if (m_stack.size() != frame.stackBase) throw std::runtime_error("unexhausted stack");
|
if (m_stack.size() != frame.stackBase) throw std::runtime_error("unexhausted stack");
|
||||||
if (frame.returnType != nullptr) push_thing(std::move(returnValue));
|
if (returnValue.has_value()) push_thing(std::move(returnValue.value()));
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct executor::frame executor::frame() const {
|
struct executor::frame executor::top_frame() const {
|
||||||
return m_frames.top();
|
return m_frames.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_h executor::push_thing(::furvm::thing<>&& thing) {
|
thing<>& executor::push_thing(thing<>&& thing) {
|
||||||
return m_stack.emplace(m_context->emplace_thing(std::move(thing)));
|
return m_stack.emplace(std::move(thing));
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_h executor::pop_thing() {
|
thing<>& executor::push_thing(const thing<>& thing) {
|
||||||
|
return m_stack.emplace(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
thing<> 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_h top = std::move(m_stack.top());
|
auto top = std::move(m_stack.top());
|
||||||
m_stack.pop();
|
m_stack.pop();
|
||||||
return std::move(top);
|
return std::move(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_h executor::thing() const {
|
thing<>& executor::top_thing() {
|
||||||
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_h& thing) {
|
const thing<>& executor::top_thing() const {
|
||||||
|
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
||||||
|
return m_stack.top();
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::store_thing(variable_t variable, const thing<>& thing) {
|
||||||
auto& frame = m_frames.top();
|
auto& frame = m_frames.top();
|
||||||
if (frame.variables.size() <= variable) frame.variables.resize(variable + 1);
|
if (frame.variables.size() <= variable) frame.variables.resize(variable + 1);
|
||||||
frame.variables[variable] = thing;
|
frame.variables[variable] = thing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::store_thing(variable_t variable, thing_h&& thing) {
|
void executor::store_thing(variable_t variable, thing<>&& thing) {
|
||||||
auto& frame = m_frames.top();
|
auto& frame = m_frames.top();
|
||||||
if (frame.variables.size() <= variable) frame.variables.resize(variable + 1);
|
if (frame.variables.size() <= variable) frame.variables.resize(variable + 1);
|
||||||
frame.variables[variable] = std::move(thing);
|
frame.variables[variable] = std::move(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
thing_h executor::load_thing(variable_t variable) const {
|
thing<>& executor::load_thing(variable_t variable) {
|
||||||
|
auto& frame = m_frames.top();
|
||||||
|
return frame.variables[variable];
|
||||||
|
}
|
||||||
|
|
||||||
|
const thing<>& 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
void executor::step() {
|
void executor::step() {
|
||||||
@@ -139,27 +165,27 @@ void executor::step() {
|
|||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case instruction_t::NoOperation: break;
|
case instruction_t::NoOperation: break;
|
||||||
case instruction_t::PushS8: {
|
case instruction_t::PushS8: {
|
||||||
push_thing({ (struct thing_type){ thing_type::S8 }, m_context->thing_alloc() })->get<thing_type::s8>() =
|
push_thing({ (struct thing_type){ thing_type::S8 }, m_context->thing_alloc() }).get<thing_type::s8>() =
|
||||||
instr.arg.s8;
|
instr.arg.s8;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushU8: {
|
case instruction_t::PushU8: {
|
||||||
push_thing({ (struct thing_type){ thing_type::U8 }, m_context->thing_alloc() })->get<thing_type::u8>() =
|
push_thing({ (struct thing_type){ thing_type::U8 }, m_context->thing_alloc() }).get<thing_type::u8>() =
|
||||||
instr.arg.u8;
|
instr.arg.u8;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushS16: {
|
case instruction_t::PushS16: {
|
||||||
push_thing({ (struct thing_type){ thing_type::S16 }, m_context->thing_alloc() })->get<thing_type::s16>() =
|
push_thing({ (struct thing_type){ thing_type::S16 }, m_context->thing_alloc() }).get<thing_type::s16>() =
|
||||||
instr.arg.s16;
|
instr.arg.s16;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushU16: {
|
case instruction_t::PushU16: {
|
||||||
push_thing({ (struct thing_type){ thing_type::U16 }, m_context->thing_alloc() })->get<thing_type::u16>() =
|
push_thing({ (struct thing_type){ thing_type::U16 }, m_context->thing_alloc() }).get<thing_type::u16>() =
|
||||||
instr.arg.u16;
|
instr.arg.u16;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushS32: {
|
case instruction_t::PushS32: {
|
||||||
push_thing({ (struct thing_type){ thing_type::S32 }, m_context->thing_alloc() })->get<thing_type::s32>() =
|
push_thing({ (struct thing_type){ thing_type::S32 }, m_context->thing_alloc() }).get<thing_type::s32>() =
|
||||||
instr.arg.s8; // NOLINT
|
instr.arg.s8; // NOLINT
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushU32: {
|
case instruction_t::PushU32: {
|
||||||
push_thing({ (struct thing_type){ thing_type::U32 }, m_context->thing_alloc() })->get<thing_type::u32>() =
|
push_thing({ (struct thing_type){ thing_type::U32 }, m_context->thing_alloc() }).get<thing_type::u32>() =
|
||||||
static_cast<thing_type::u32>(instr.arg.u8);
|
static_cast<thing_type::u32>(instr.arg.u8);
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Array: {
|
case instruction_t::Array: {
|
||||||
@@ -167,30 +193,30 @@ void executor::step() {
|
|||||||
if (type.type != thing_type::Array || type.value.array.type == nullptr || type.value.array.type == &type)
|
if (type.type != thing_type::Array || type.value.array.type == nullptr || type.value.array.type == &type)
|
||||||
throw std::runtime_error("invalid array type");
|
throw std::runtime_error("invalid array type");
|
||||||
|
|
||||||
auto array = push_thing({ type, m_context->thing_alloc() });
|
auto& array = push_thing({ type, m_context->thing_alloc() });
|
||||||
|
|
||||||
if (type.value.array.size == 0) {
|
if (type.value.array.size == 0) {
|
||||||
auto sizeThing = pop_thing();
|
auto sizeThing = pop_thing();
|
||||||
std::int64_t size = sizeThing->integer();
|
std::int64_t size = sizeThing.integer();
|
||||||
array->resize(size);
|
array.resize(size);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Get: {
|
case instruction_t::Get: {
|
||||||
auto index = pop_thing();
|
auto index = pop_thing();
|
||||||
auto array = pop_thing();
|
auto array = pop_thing();
|
||||||
push_thing(array->at(index->integer()));
|
push_thing(array.at(index.integer()));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Set: {
|
case instruction_t::Set: {
|
||||||
auto element = pop_thing();
|
auto element = pop_thing();
|
||||||
auto index = pop_thing();
|
auto index = pop_thing();
|
||||||
auto array = pop_thing();
|
auto array = pop_thing();
|
||||||
array->at(index->integer()).assign(std::move(element->clone()));
|
array.at(index.integer()).assign(std::move(element));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Drop: {
|
case instruction_t::Drop: {
|
||||||
pop_thing();
|
pop_thing();
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Duplicate: {
|
case instruction_t::Duplicate: {
|
||||||
push_thing(thing());
|
push_thing(top_thing());
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Swap: {
|
case instruction_t::Swap: {
|
||||||
auto thing1 = pop_thing();
|
auto thing1 = pop_thing();
|
||||||
@@ -199,79 +225,76 @@ void executor::step() {
|
|||||||
push_thing(std::move(thing2));
|
push_thing(std::move(thing2));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Clone: {
|
case instruction_t::Clone: {
|
||||||
push_thing(std::move(thing()->clone()));
|
push_thing(top_thing());
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Reference: {
|
case instruction_t::Reference: {
|
||||||
auto thing = pop_thing();
|
push_thing(std::move(make_reference(pop_thing())));
|
||||||
push_thing({ (struct thing_type){ thing_type::Ref, m_context->tt_store().insert(thing->type()) },
|
|
||||||
m_context->thing_alloc() })
|
|
||||||
->reference(*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->add(*rhs));
|
push_thing(lhs.add(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->sub(*rhs));
|
push_thing(lhs.sub(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->mul(*rhs));
|
push_thing(lhs.mul(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->div(*rhs));
|
push_thing(lhs.div(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->mod(*rhs));
|
push_thing(lhs.mod(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->equals(*rhs));
|
push_thing(lhs.equals(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->not_equals(*rhs));
|
push_thing(lhs.not_equals(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->less_than(*rhs));
|
push_thing(lhs.less_than(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->greater_than(*rhs));
|
push_thing(lhs.greater_than(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->less_equals(*rhs));
|
push_thing(lhs.less_equals(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->greater_equals(*rhs));
|
push_thing(lhs.greater_equals(rhs));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Pointerof: {
|
case instruction_t::Pointerof: {
|
||||||
auto thing = pop_thing();
|
auto thing = pop_thing();
|
||||||
auto ptr = push_thing({ (struct thing_type){ thing_type::Ptr, m_context->tt_store().at(thing->type().id) },
|
push_thing({ (struct thing_type){ thing_type::Ptr, m_context->tt_store().at(thing.type().id) },
|
||||||
m_context->thing_alloc() });
|
m_context->thing_alloc() })
|
||||||
ptr->get<void*>() = thing->raw();
|
.get<void*>() = thing.raw();
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Sizeof: {
|
case instruction_t::Sizeof: {
|
||||||
auto thing = pop_thing();
|
auto thing = pop_thing();
|
||||||
auto size = push_thing({ (struct thing_type){ thing_type::U64 }, m_context->thing_alloc() });
|
auto& size = push_thing({ (struct thing_type){ thing_type::U64 }, m_context->thing_alloc() });
|
||||||
switch (thing->type().type) {
|
switch (thing.type().type) {
|
||||||
case thing_type::S8:
|
case thing_type::S8:
|
||||||
case thing_type::S16:
|
case thing_type::S16:
|
||||||
case thing_type::S32:
|
case thing_type::S32:
|
||||||
@@ -280,25 +303,25 @@ void executor::step() {
|
|||||||
case thing_type::U16:
|
case thing_type::U16:
|
||||||
case thing_type::U32:
|
case thing_type::U32:
|
||||||
case thing_type::U64:
|
case thing_type::U64:
|
||||||
size->get<thing_type::u64>() = static_cast<thing_type::u64>(thing_type::primitive_size(thing->type().type));
|
size.get<thing_type::u64>() = static_cast<thing_type::u64>(thing_type::primitive_size(thing.type().type));
|
||||||
break;
|
break;
|
||||||
case thing_type::Ptr: size->get<thing_type::u64>() = static_cast<thing_type::u64>(sizeof(void*)); break;
|
case thing_type::Ptr: size.get<thing_type::u64>() = static_cast<thing_type::u64>(sizeof(void*)); break;
|
||||||
case thing_type::Array:
|
case thing_type::Array:
|
||||||
/* TODO: Return actual memory size of the array
|
/* TODO: Return actual memory size of the array
|
||||||
* By the memory size I mean the length times sizeof single element.
|
* By the memory size I mean the length times sizeof single element.
|
||||||
*/
|
*/
|
||||||
size->get<thing_type::u64>() = thing->length();
|
size.get<thing_type::u64>() = thing.length();
|
||||||
break;
|
break;
|
||||||
default: throw std::runtime_error("unreachable");
|
default: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Lengthof: {
|
case instruction_t::Lengthof: {
|
||||||
auto thing = pop_thing();
|
auto thing = pop_thing();
|
||||||
auto length = push_thing({ (struct thing_type){ thing_type::U64 }, m_context->thing_alloc() });
|
push_thing({ (struct thing_type){ thing_type::U64 }, m_context->thing_alloc() }).get<thing_type::u64>() =
|
||||||
length->get<thing_type::u64>() = thing->length();
|
thing.length();
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Load: {
|
case instruction_t::Load: {
|
||||||
push_thing(load_thing(instr.arg.u16));
|
push_thing(make_reference(load_thing(instr.arg.u16)));
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Store: {
|
case instruction_t::Store: {
|
||||||
store_thing(instr.arg.u16, std::move(pop_thing()));
|
store_thing(instr.arg.u16, std::move(pop_thing()));
|
||||||
@@ -310,7 +333,7 @@ void executor::step() {
|
|||||||
frame.position += instr.arg.s8;
|
frame.position += instr.arg.s8;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::JumpNotZero: {
|
case instruction_t::JumpNotZero: {
|
||||||
if (pop_thing()->integer() != 0) frame.position += instr.arg.s8;
|
if (pop_thing().integer() != 0) frame.position += instr.arg.s8;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::Return: {
|
case instruction_t::Return: {
|
||||||
pop_frame();
|
pop_frame();
|
||||||
|
|||||||
+29
-1
@@ -1,5 +1,6 @@
|
|||||||
#include "furvm/function.hpp"
|
#include "furvm/function.hpp"
|
||||||
|
|
||||||
|
#include "furlang/utility/hash.hpp"
|
||||||
#include "furvm/furvm.hpp"
|
#include "furvm/furvm.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -100,8 +101,35 @@ function& function::operator=(const function& other) {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
struct mod_type_hash {
|
||||||
|
std::size_t operator()(const mod_type_h& type) const {
|
||||||
|
std::size_t hash = std::hash<decltype(type->type)>{}(type->type);
|
||||||
|
switch (type->type) {
|
||||||
|
case mod_type::S8:
|
||||||
|
case mod_type::S16:
|
||||||
|
case mod_type::S32:
|
||||||
|
case mod_type::S64:
|
||||||
|
case mod_type::U8:
|
||||||
|
case mod_type::U16:
|
||||||
|
case mod_type::U32:
|
||||||
|
case mod_type::U64: return hash;
|
||||||
|
case mod_type::Ptr:
|
||||||
|
case mod_type::Ref: return furlang::utility::hash_combine(hash, type->value.typeRef);
|
||||||
|
case mod_type::Array:
|
||||||
|
hash = furlang::utility::hash_combine(hash, type->value.array.size);
|
||||||
|
return furlang::utility::hash_combine(hash, type->value.array.typeId);
|
||||||
|
case mod_type::Import:
|
||||||
|
hash = furlang::utility::hash_combine(hash,
|
||||||
|
std::hash<decltype(type->value.imprt.modId)>{}(type->value.imprt.modId));
|
||||||
|
return furlang::utility::hash_combine(hash, type->value.imprt.typeId);
|
||||||
|
case mod_type::Count: break;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::size_t function_sig_hash::operator()(const function_sig& signature) const {
|
std::size_t function_sig_hash::operator()(const function_sig& signature) const {
|
||||||
return furlang::utility::vector_hash<mod_type_h, detail::handle_hash<mod_type_h>>{}(signature.params);
|
return furlang::utility::vector_hash<mod_type_h, mod_type_hash>{}(signature.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
+6
-7
@@ -10,7 +10,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
static void print_thing(const furvm::thing<furvm::thing_allocator>& thing) {
|
static void print_thing(const furvm::thing<>& thing) {
|
||||||
using namespace furvm;
|
using namespace furvm;
|
||||||
|
|
||||||
switch (thing.true_type().type) {
|
switch (thing.true_type().type) {
|
||||||
@@ -75,16 +75,15 @@ int main(int argc, char** argv) {
|
|||||||
mod->emplace_function(furvm::function_sig{ { u64Type }, u64Type }, "print").dispatch();
|
mod->emplace_function(furvm::function_sig{ { u64Type }, u64Type }, "print").dispatch();
|
||||||
#endif
|
#endif
|
||||||
mod->set_native_function("println", [](furvm::executor& executor) {
|
mod->set_native_function("println", [](furvm::executor& executor) {
|
||||||
auto arg = executor.load_thing(0);
|
print_thing(executor.load_thing(0));
|
||||||
print_thing(*arg);
|
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
furvm::executor_h executor = context->emplace_executor(context);
|
auto& executor = context->allocate_executor();
|
||||||
executor->push_frame(mod, *mainFunc);
|
executor.push_frame(mod, *mainFunc);
|
||||||
|
|
||||||
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
while ((executor.flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
||||||
executor->step();
|
executor.step();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -124,7 +124,12 @@ mod mod::load(std::istream& is) {
|
|||||||
case mod_type::Ptr: {
|
case mod_type::Ptr: {
|
||||||
mod_type_id typeId = 0;
|
mod_type_id typeId = 0;
|
||||||
detail::load(is, typeId);
|
detail::load(is, typeId);
|
||||||
mod.emplace_type(id, typeId).dispatch();
|
mod.emplace_type(id, mod_type::Ptr, typeId).dispatch();
|
||||||
|
} break;
|
||||||
|
case mod_type::Ref: {
|
||||||
|
mod_type_id typeId = 0;
|
||||||
|
detail::load(is, typeId);
|
||||||
|
mod.emplace_type(id, mod_type::Ref, typeId).dispatch();
|
||||||
} break;
|
} break;
|
||||||
case mod_type::Array: {
|
case mod_type::Array: {
|
||||||
mod_type_id typeId = 0;
|
mod_type_id typeId = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user