mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 23:06:32 +00:00
183 lines
4.8 KiB
C++
183 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <format>
|
|
#include <iostream>
|
|
#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;
|
|
};
|
|
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) {
|
|
std::cerr << std::format("error: tried to unwrap {} as {}\n",
|
|
value_type_to_string(this->m_type), value_type_to_string(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) {
|
|
std::cerr << std::format("error: tried to unwrap {} as {}\n",
|
|
value_type_to_string(this->m_type), value_type_to_string(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
|
|
|
|
inline auto to_string() const -> std::string
|
|
{
|
|
switch (this->m_type) {
|
|
case ValueType::Null:
|
|
return "null";
|
|
case ValueType::Int:
|
|
return std::to_string(as_int().value);
|
|
case ValueType::Bool:
|
|
return as_bool().value ? "true" : "false";
|
|
case ValueType::String:
|
|
return std::format("\"{}\"", escape_string(as_string().value));
|
|
case ValueType::Ptr:
|
|
return std::to_string(as_ptr().value);
|
|
}
|
|
std::unreachable();
|
|
}
|
|
|
|
inline auto to_repr_string() const -> std::string
|
|
{
|
|
return std::format(
|
|
"{}({:.4s})", value_type_to_string(this->m_type), to_string());
|
|
}
|
|
|
|
private:
|
|
ValueType m_type;
|
|
std::variant<Null, Int, Bool, String, Ptr> value;
|
|
};
|
|
|
|
}
|