slige/runtime/value.hpp
2024-12-13 16:16:11 +01:00

163 lines
4.0 KiB
C++

#pragma once
#include <cstdint>
#include <cstdlib>
#include <string>
#include <utility>
#include <variant>
namespace sliger {
inline auto escape_string(std::string str) -> std::string
{
auto result = std::string();
for (auto ch : str) {
switch (ch) {
case '\n':
result += "\\n";
break;
case '\t':
result += "\\t";
break;
case '\0':
result += "\\0";
break;
case '\\':
result += "\\\\";
break;
default:
result += ch;
}
}
return result;
}
enum class ValueType {
Null,
Int,
Bool,
String,
Ptr,
};
inline auto value_type_to_string(ValueType type) -> std::string
{
switch (type) {
case ValueType::Null:
return "Null";
case ValueType::Int:
return "Int";
case ValueType::Bool:
return "Bool";
case ValueType::String:
return "String";
case ValueType::Ptr:
return "Ptr";
}
std::unreachable();
}
class Values;
struct Null { };
struct Int {
int32_t value;
};
struct Bool {
bool value;
};
struct String {
std::string value;
auto at(int32_t index) -> int32_t;
};
struct Ptr {
uint32_t value;
};
// clang-format off
template <ValueType op> struct ValueTypeToType { };
template <> struct ValueTypeToType<ValueType::Null> { using Type = Null; };
template <> struct ValueTypeToType<ValueType::Int> { using Type = Int; };
template <> struct ValueTypeToType<ValueType::Bool> { using Type = Bool; };
template <> struct ValueTypeToType<ValueType::String> { using Type = String; };
template <> struct ValueTypeToType<ValueType::Ptr> { using Type = Ptr; };
// clang-format on
class Value {
public:
Value(Null&& value)
: m_type(ValueType::Null)
, value(value)
{
}
Value(Int&& value)
: m_type(ValueType::Int)
, value(value)
{
}
Value(Bool&& value)
: m_type(ValueType::Bool)
, value(value)
{
}
Value(String&& value)
: m_type(ValueType::String)
, value(value)
{
}
Value(Ptr&& value)
: m_type(ValueType::Ptr)
, value(value)
{
}
inline auto type() const -> ValueType { return m_type; };
template <ValueType VT> inline auto as() -> ValueTypeToType<VT>::Type&
{
try {
return std::get<typename ValueTypeToType<VT>::Type>(value);
} catch (const std::bad_variant_access& ex) {
print_tried_to_unwrap_error_message(VT);
std::exit(1);
}
}
template <ValueType VT>
inline auto as() const -> const ValueTypeToType<VT>::Type&
{
try {
return std::get<typename ValueTypeToType<VT>::Type>(value);
} catch (const std::bad_variant_access& ex) {
print_tried_to_unwrap_error_message(VT);
std::exit(1);
}
}
// clang-format off
inline auto as_null() -> Null& { return as<ValueType::Null>(); }
inline auto as_int() -> Int& { return as<ValueType::Int>(); }
inline auto as_bool() -> Bool& { return as<ValueType::Bool>(); }
inline auto as_string() -> String& { return as<ValueType::String>(); }
inline auto as_ptr() -> Ptr& { return as<ValueType::Ptr>(); }
inline auto as_null() const -> const Null& { return as<ValueType::Null>(); }
inline auto as_int() const -> const Int& { return as<ValueType::Int>(); }
inline auto as_bool() const -> const Bool& { return as<ValueType::Bool>(); }
inline auto as_string() const -> const String& { return as<ValueType::String>(); }
inline auto as_ptr() const -> const Ptr& { return as<ValueType::Ptr>(); }
// clang-format on
auto to_string() const -> std::string;
auto to_repr_string() const -> std::string;
private:
void print_tried_to_unwrap_error_message(ValueType vt) const;
ValueType m_type;
std::variant<Null, Int, Bool, String, Ptr> value;
};
}