@@ -1,74 +1,29 @@
|
|||||||
#ifndef FURVM_CONSTANT_HPP
|
#ifndef FURVM_CONSTANT_HPP
|
||||||
#define FURVM_CONSTANT_HPP
|
#define FURVM_CONSTANT_HPP
|
||||||
|
|
||||||
#include "furvm/exceptions.hpp"
|
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
enum class constant_t : std::uint8_t {
|
// TODO: Array constants
|
||||||
String, /**< String constant. */
|
struct constant {
|
||||||
|
enum type_e {
|
||||||
|
S32 = 0,
|
||||||
|
U32,
|
||||||
|
S64,
|
||||||
|
U64,
|
||||||
|
String,
|
||||||
|
} type = S32;
|
||||||
|
union {
|
||||||
|
std::int32_t s32;
|
||||||
|
std::uint32_t u32;
|
||||||
|
std::int64_t s64;
|
||||||
|
std::uint64_t u64;
|
||||||
|
std::string_view string;
|
||||||
};
|
};
|
||||||
|
|
||||||
class constant {
|
|
||||||
public:
|
|
||||||
using string_type = std::string_view; /**< String constant type. */
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Construct a new string constant.
|
|
||||||
*
|
|
||||||
* @param string String.
|
|
||||||
*/
|
|
||||||
constant(string_type string)
|
|
||||||
: m_type(constant_t::String), m_value(string) {}
|
|
||||||
|
|
||||||
~constant() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Move constructor.
|
|
||||||
*/
|
|
||||||
constant(constant&&) = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Move constructor.
|
|
||||||
*/
|
|
||||||
constant& operator=(constant&&) = default;
|
|
||||||
|
|
||||||
constant(const constant&) = delete;
|
|
||||||
constant& operator=(const constant&) = delete;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Returns this constant's type.
|
|
||||||
* @see constant_t
|
|
||||||
*
|
|
||||||
* @return The constant type.
|
|
||||||
*/
|
|
||||||
constexpr constant_t type() const { return m_type; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns this constant's string value.
|
|
||||||
* @throws bad_constant_access if this constant's type is not constant_t::String.
|
|
||||||
*
|
|
||||||
* @return The string value.
|
|
||||||
*/
|
|
||||||
constexpr string_type string() const {
|
|
||||||
require_type(constant_t::String);
|
|
||||||
return m_value.string;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void require_type(constant_t type) const {
|
|
||||||
if (m_type != type) throw bad_constant_access();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
constant_t m_type{};
|
|
||||||
union value {
|
|
||||||
string_type string;
|
|
||||||
|
|
||||||
value(string_type sv)
|
|
||||||
: string(sv) {}
|
|
||||||
} m_value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "furlang/utility/hash.hpp"
|
#include "furlang/utility/hash.hpp"
|
||||||
#include "furlang/view.hpp"
|
#include "furlang/view.hpp"
|
||||||
|
#include "furvm/constant.hpp"
|
||||||
#include "furvm/function.hpp"
|
#include "furvm/function.hpp"
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/handle.hpp"
|
#include "furvm/handle.hpp"
|
||||||
@@ -10,8 +11,6 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <limits>
|
|
||||||
#include <optional>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -384,6 +383,13 @@ public:
|
|||||||
if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot");
|
if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot");
|
||||||
return m_globalVariables[var];
|
return m_globalVariables[var];
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<constant, Args...>>>
|
||||||
|
void emplace_constant(Args&&... args) {
|
||||||
|
m_constants.emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
const constant& constant_at(constant_index index) const { return m_constants.at(index); }
|
||||||
public:
|
public:
|
||||||
template <typename Fwd, typename = std::enable_if_t<std::is_constructible_v<breakpoint, Fwd>>>
|
template <typename Fwd, typename = std::enable_if_t<std::is_constructible_v<breakpoint, Fwd>>>
|
||||||
void set_breakpoint(bytecode_pos pos, Fwd&& breakpoint) {
|
void set_breakpoint(bytecode_pos pos, Fwd&& breakpoint) {
|
||||||
@@ -423,6 +429,8 @@ private:
|
|||||||
|
|
||||||
std::vector<thing<>> m_globalVariables;
|
std::vector<thing<>> m_globalVariables;
|
||||||
|
|
||||||
|
std::vector<constant> m_constants;
|
||||||
|
|
||||||
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
||||||
|
|
||||||
std::unordered_map<bytecode_pos, breakpoint> m_breakpoints;
|
std::unordered_map<bytecode_pos, breakpoint> m_breakpoints;
|
||||||
|
|||||||
+19
-1
@@ -222,6 +222,25 @@ void executor::step() {
|
|||||||
push_thing({ (struct thing_type){ thing_type::U32 } }).get<thing_type::u32>() =
|
push_thing({ (struct thing_type){ thing_type::U32 } }).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::PushConstant: {
|
||||||
|
auto constant = frame.mod->constant_at(instr.arg.u16);
|
||||||
|
switch (constant.type) {
|
||||||
|
case constant::S32:
|
||||||
|
push_thing({ (struct thing_type){ thing_type::S32 } }).get<thing_type::s32>() = constant.s32; // NOLINT
|
||||||
|
break;
|
||||||
|
case constant::U32:
|
||||||
|
push_thing({ (struct thing_type){ thing_type::U32 } }).get<thing_type::u32>() = constant.u32; // NOLINT
|
||||||
|
break;
|
||||||
|
case constant::S64:
|
||||||
|
push_thing({ (struct thing_type){ thing_type::S64 } }).get<thing_type::s64>() = constant.s64; // NOLINT
|
||||||
|
break;
|
||||||
|
case constant::U64:
|
||||||
|
push_thing({ (struct thing_type){ thing_type::U64 } }).get<thing_type::u64>() = constant.u64; // NOLINT
|
||||||
|
break;
|
||||||
|
case constant::String: throw std::runtime_error("unimplemented");
|
||||||
|
default: throw std::runtime_error("invalid constant");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case instruction_t::Array: {
|
case instruction_t::Array: {
|
||||||
const auto& type = *mod_to_thing_type(frame.mod, *frame.mod->type_at(instr.arg.u32));
|
const auto& type = *mod_to_thing_type(frame.mod, *frame.mod->type_at(instr.arg.u32));
|
||||||
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)
|
||||||
@@ -377,7 +396,6 @@ void executor::step() {
|
|||||||
pop_frame();
|
pop_frame();
|
||||||
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::PushConstant: throw std::runtime_error("unimplemented");
|
|
||||||
default: throw std::runtime_error("unknown instruction");
|
default: throw std::runtime_error("unknown instruction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const std::size_t instruction_argument::s_sizes[instruction_argument::Count] = {
|
|||||||
// U32
|
// U32
|
||||||
1,
|
1,
|
||||||
// Constant:
|
// Constant:
|
||||||
4,
|
2,
|
||||||
// Type:
|
// Type:
|
||||||
4,
|
4,
|
||||||
// Variable:
|
// Variable:
|
||||||
|
|||||||
@@ -16,6 +16,19 @@ std::ostream& mod::serialize(std::ostream& os) const {
|
|||||||
os.write(MAGIC, sizeof(MAGIC));
|
os.write(MAGIC, sizeof(MAGIC));
|
||||||
detail::serialize(os, std::uint32_t(0)); // version
|
detail::serialize(os, std::uint32_t(0)); // version
|
||||||
|
|
||||||
|
detail::serialize(os, static_cast<constant_index>(m_constants.size()));
|
||||||
|
for (const auto& constant : m_constants) {
|
||||||
|
detail::serialize(os, constant.type);
|
||||||
|
switch (constant.type) {
|
||||||
|
case constant::S32:
|
||||||
|
case constant::U32: detail::serialize(os, constant.u32); break;
|
||||||
|
case constant::S64:
|
||||||
|
case constant::U64: detail::serialize(os, constant.u64); break;
|
||||||
|
case constant::String: throw std::runtime_error("unimplemented");
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod_type_id typeCount = mod_type_id(m_types.cend() - m_types.cbegin());
|
mod_type_id typeCount = mod_type_id(m_types.cend() - m_types.cbegin());
|
||||||
detail::serialize(os, typeCount);
|
detail::serialize(os, typeCount);
|
||||||
for (mod_type_id id = 0; id < typeCount; ++id) {
|
for (mod_type_id id = 0; id < typeCount; ++id) {
|
||||||
@@ -104,6 +117,22 @@ mod mod::load(std::istream& is) {
|
|||||||
|
|
||||||
mod mod;
|
mod mod;
|
||||||
|
|
||||||
|
constant_index constantCount = 0;
|
||||||
|
detail::load(is, constantCount);
|
||||||
|
mod.m_constants.reserve(constantCount);
|
||||||
|
for (; constantCount != 0; --constantCount) {
|
||||||
|
constant constant{};
|
||||||
|
detail::load(is, reinterpret_cast<std::uint32_t&>(constant.type));
|
||||||
|
switch (constant.type) {
|
||||||
|
case constant::S32:
|
||||||
|
case constant::U32: detail::load(is, constant.u32); break;
|
||||||
|
case constant::S64:
|
||||||
|
case constant::U64: detail::load(is, constant.u64); break;
|
||||||
|
case constant::String: throw std::runtime_error("unimplemented");
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod_type_id typeCount = 0;
|
mod_type_id typeCount = 0;
|
||||||
detail::load(is, typeCount);
|
detail::load(is, typeCount);
|
||||||
for (mod_type_id id = 0; id < typeCount; ++id) {
|
for (mod_type_id id = 0; id < typeCount; ++id) {
|
||||||
|
|||||||
Reference in New Issue
Block a user