#pragma once #include #include #include #include #include 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 struct ValueTypeToType { }; template <> struct ValueTypeToType { using Type = Null; }; template <> struct ValueTypeToType { using Type = Int; }; template <> struct ValueTypeToType { using Type = Bool; }; template <> struct ValueTypeToType { using Type = String; }; template <> struct ValueTypeToType { 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 inline auto as() -> ValueTypeToType::Type& { try { return std::get::Type>(value); } catch (const std::bad_variant_access& ex) { print_tried_to_unwrap_error_message(VT); std::exit(1); } } template inline auto as() const -> const ValueTypeToType::Type& { try { return std::get::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(); } inline auto as_int() -> Int& { return as(); } inline auto as_bool() -> Bool& { return as(); } inline auto as_string() -> String& { return as(); } inline auto as_ptr() -> Ptr& { return as(); } inline auto as_null() const -> const Null& { return as(); } inline auto as_int() const -> const Int& { return as(); } inline auto as_bool() const -> const Bool& { return as(); } inline auto as_string() const -> const String& { return as(); } inline auto as_ptr() const -> const Ptr& { return as(); } // 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 value; }; }