2024-11-08 11:22:42 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cstdint>
|
2024-11-20 13:46:19 +00:00
|
|
|
#include <cstdlib>
|
2024-11-08 11:22:42 +00:00
|
|
|
#include <string>
|
2024-11-19 04:06:27 +00:00
|
|
|
#include <utility>
|
2024-11-08 11:22:42 +00:00
|
|
|
#include <variant>
|
|
|
|
|
|
|
|
namespace sliger {
|
|
|
|
|
2024-12-11 11:36:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-11-08 11:22:42 +00:00
|
|
|
enum class ValueType {
|
|
|
|
Null,
|
|
|
|
Int,
|
|
|
|
Bool,
|
|
|
|
String,
|
|
|
|
Ptr,
|
|
|
|
};
|
|
|
|
|
2024-11-19 04:06:27 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2024-11-08 11:22:42 +00:00
|
|
|
class Values;
|
|
|
|
|
|
|
|
struct Null { };
|
|
|
|
struct Int {
|
2024-11-11 14:31:54 +00:00
|
|
|
int32_t value;
|
2024-11-08 11:22:42 +00:00
|
|
|
};
|
|
|
|
struct Bool {
|
|
|
|
bool value;
|
|
|
|
};
|
|
|
|
struct String {
|
|
|
|
std::string value;
|
2024-12-13 15:03:01 +00:00
|
|
|
inline auto at(int32_t index) -> int32_t {
|
|
|
|
if (index >= static_cast<int32_t>(this->value.length()) || index < 0) {
|
|
|
|
std::cout << std::format("index not in range, expected to be in range (0..{}), got: {}", this->value.length()-1, index);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return this->value.at(index);
|
|
|
|
}
|
2024-11-08 11:22:42 +00:00
|
|
|
};
|
|
|
|
struct Ptr {
|
|
|
|
uint32_t value;
|
|
|
|
};
|
|
|
|
|
2024-11-20 13:46:19 +00:00
|
|
|
// 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
|
|
|
|
|
2024-11-08 11:22:42 +00:00
|
|
|
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; };
|
|
|
|
|
2024-11-20 13:46:19 +00:00
|
|
|
template <ValueType VT> inline auto as() -> ValueTypeToType<VT>::Type&
|
2024-11-19 04:06:27 +00:00
|
|
|
{
|
|
|
|
try {
|
2024-11-20 13:46:19 +00:00
|
|
|
return std::get<typename ValueTypeToType<VT>::Type>(value);
|
2024-11-19 04:06:27 +00:00
|
|
|
} catch (const std::bad_variant_access& ex) {
|
2024-12-13 15:11:16 +00:00
|
|
|
print_tried_to_unwrap_error_message(VT);
|
2024-11-20 13:46:19 +00:00
|
|
|
std::exit(1);
|
2024-11-19 04:06:27 +00:00
|
|
|
}
|
|
|
|
}
|
2024-11-08 11:22:42 +00:00
|
|
|
|
2024-11-20 13:46:19 +00:00
|
|
|
template <ValueType VT>
|
|
|
|
inline auto as() const -> const ValueTypeToType<VT>::Type&
|
2024-11-19 04:06:27 +00:00
|
|
|
{
|
|
|
|
try {
|
2024-11-20 13:46:19 +00:00
|
|
|
return std::get<typename ValueTypeToType<VT>::Type>(value);
|
2024-11-19 04:06:27 +00:00
|
|
|
} catch (const std::bad_variant_access& ex) {
|
2024-12-13 15:11:16 +00:00
|
|
|
print_tried_to_unwrap_error_message(VT);
|
2024-11-20 13:46:19 +00:00
|
|
|
std::exit(1);
|
2024-11-19 04:06:27 +00:00
|
|
|
}
|
|
|
|
}
|
2024-11-08 11:22:42 +00:00
|
|
|
|
2024-11-20 13:46:19 +00:00
|
|
|
// 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>(); }
|
2024-11-08 11:22:42 +00:00
|
|
|
|
2024-11-20 13:46:19 +00:00
|
|
|
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
|
2024-11-19 04:06:27 +00:00
|
|
|
|
2024-12-13 15:11:16 +00:00
|
|
|
auto to_string() const -> std::string;
|
|
|
|
auto to_repr_string() const -> std::string;
|
2024-11-08 11:22:42 +00:00
|
|
|
|
|
|
|
private:
|
2024-12-13 15:11:16 +00:00
|
|
|
void print_tried_to_unwrap_error_message(ValueType vt) const;
|
|
|
|
|
2024-11-08 11:22:42 +00:00
|
|
|
ValueType m_type;
|
|
|
|
std::variant<Null, Int, Bool, String, Ptr> value;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|