#pragma once #include #include "Support/JSON.h" #include "Support/Ranges.h" #include "llvm/Support/Error.h" namespace clice { template void print(std::format_string fmt, Args&&... args) { llvm::outs() << std::vformat(fmt.get(), std::make_format_args(args...)); } template void println(std::format_string fmt, Args&&... args) { llvm::outs() << std::vformat(fmt.get(), std::make_format_args(args...)) << '\n'; } } // namespace clice template <> struct std::formatter : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(llvm::StringRef s, FormatContext& ctx) const { return Base::format(std::string_view(s.str()), ctx); } }; template struct std::formatter> : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(const llvm::SmallString& s, FormatContext& ctx) const { return Base::format(llvm::StringRef(s), ctx); } }; template <> struct std::formatter : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(const llvm::Error& e, FormatContext& ctx) const { llvm::SmallString<128> buffer; llvm::raw_svector_ostream os(buffer); os << e; return Base::format(buffer, ctx); } }; template <> struct std::formatter : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(const std::error_code& e, FormatContext& ctx) const { return Base::format(e.message(), ctx); } }; template <> struct std::formatter : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(const clice::json::Value& value, FormatContext& ctx) const { llvm::SmallString<128> buffer; llvm::raw_svector_ostream os{buffer}; os << value; return Base::format(buffer, ctx); } }; template struct std::formatter : std::formatter { using Base = std::formatter; template constexpr auto parse(ParseContext& ctx) { return Base::parse(ctx); } template auto format(const E& e, FormatContext& ctx) const { return Base::format(e.name(), ctx); } }; namespace clice { /// Dump object to string for debugging. Note that it is not efficient /// and should not be used except for debugging. template std::string dump(const Object& object) { if constexpr(std::is_fundamental_v) { return std::format("{}", object); } else if constexpr(std::is_same_v || std::is_same_v || std::is_same_v) { return std::format("\"{}\"", object); } else if constexpr(ranges::range) { constexpr bool is_sequence = sequence_range; std::string result = is_sequence ? "[" : "{"; if constexpr(map_range) { for(auto&& [key, value]: object) { result += std::format("\"{}\": {}, ", dump(key), dump(value)); } } else { for(auto&& value: object) { result += std::format("{}, ", dump(value)); } } if(!object.empty()) { result.pop_back(); result.pop_back(); } result += is_sequence ? "]" : "}"; return result; } else if constexpr(std::is_enum_v) { return std::format("\"{}\"", refl::enum_name(object)); } else if constexpr(refl::reflectable_enum) { return std::format("\"{}\"", object); } else if constexpr(refl::reflectable_struct) { std::string result = "{"; refl::foreach(object, [&](auto name, auto value) { result += std::format("\"{}\": {}, ", name, dump(value)); }); if(refl::member_count() != 0) { result.pop_back(); result.pop_back(); } result += "}"; return result; } else { static_assert(dependent_false, "Cannot dump object"); } } template std::string pretty_dump(const Object& object, std::size_t indent = 2) { std::string repr = dump(object); auto json = json::parse(repr); if(!json) { clice::println("{} {}", json.takeError(), repr); std::abort(); } llvm::SmallString<128> buffer = {std::format("{{0:{}}}", indent)}; return llvm::formatv(buffer.c_str(), *json); } } // namespace clice