#pragma once #include #include #include #include #include #include #include #include #include #include namespace sliger::json { struct Pos { int line; int col; }; struct Err { Pos pos; std::string msg; }; template class Res { public: Res(T value) : maybe_value(std::move(value)) , maybe_error() { } Res(Err error) : maybe_value() , maybe_error(std::move(error)) { } inline auto ok() const -> bool { return this->maybe_value.has_value(); } inline auto val() const& -> const T& { return this->maybe_value.value(); } inline auto val() & -> T& { return this->maybe_value.value(); } inline auto val() && -> T&& { return std::move(this->maybe_value.value()); } inline auto err() const& -> const Err& { return this->maybe_error.value(); } inline auto err() & -> Err& { return this->maybe_error.value(); } inline auto err() && -> Err&& { return std::move(this->maybe_error.value()); } private: std::optional maybe_value; std::optional maybe_error; }; template <> class Res { public: Res() : maybe_error() { } Res(Err error) : maybe_error(std::move(error)) { } inline auto ok() const -> bool { return not this->maybe_error.has_value(); } inline auto err() const& -> const Err& { return this->maybe_error.value(); } inline auto err() & -> Err& { return this->maybe_error.value(); } inline auto err() && -> Err&& { return std::move(this->maybe_error.value()); } private: std::optional maybe_error; }; enum class Type { Null, String, Number, Bool, Array, Object, }; struct Value { virtual ~Value() = default; virtual auto type() const -> Type = 0; template requires std::derived_from inline auto as() & -> T& { return static_cast(this); } }; struct Null final : public Value { auto type() const -> Type override { return Type::Null; } }; struct String final : public Value { String(std::string value) : value(std::move(value)) { } auto type() const -> Type override { return Type::String; } std::string value; }; struct Number final : public Value { Number(double value) : value(value) { } auto type() const -> Type override { return Type::Number; } double value; }; struct Bool final : public Value { Bool(bool value) : value(value) { } auto type() const -> Type override { return Type::Bool; } bool value; }; using ArrayValues = std::vector>; struct Array final : public Value { Array(ArrayValues values) : values(std::move(values)) { } auto type() const -> Type override { return Type::Array; } ArrayValues values; }; using ObjectFields = std::unordered_map>; struct Object final : public Value { Object(ObjectFields fields) : fields(std::move(fields)) { } auto type() const -> Type override { return Type::Object; } ObjectFields fields; }; enum class TokTyp { Eof, String, Float, False, True, Null, LBrace, RBrace, LBracket, RBracket, Comma, Colon, }; inline auto tok_typ_to_string(TokTyp typ) -> std::string { switch (typ) { case TokTyp::Eof: return "Eof"; case TokTyp::String: return "String"; case TokTyp::Float: return "Float"; case TokTyp::False: return "False"; case TokTyp::True: return "True"; case TokTyp::Null: return "Null"; case TokTyp::LBrace: return "LBrace"; case TokTyp::RBrace: return "RBrace"; case TokTyp::LBracket: return "LBracket"; case TokTyp::RBracket: return "RBracket"; case TokTyp::Comma: return "Comma"; case TokTyp::Colon: return "Colon"; } std::unreachable(); } struct Tok { Tok(TokTyp typ, Pos pos) : typ(typ) , pos(pos) , val_id(0) { } Tok(TokTyp typ, Pos pos, size_t val_id) : typ(typ) , pos(pos) , val_id(val_id) { } Tok(TokTyp typ, Pos pos, double float_val) : typ(typ) , pos(pos) , float_val(float_val) { } Tok(TokTyp typ, Pos pos, bool bool_val) : typ(typ) , pos(pos) , bool_val(bool_val) { } TokTyp typ; Pos pos; union { size_t val_id; double float_val; bool bool_val; }; }; class Lexer { public: Lexer(std::string_view text) : text(text) { } auto next() -> Res; inline auto pos() const -> Pos { return { this->line, this->col }; } inline auto val(size_t val_id) const -> const std::string& { return this->strs_vals.at(val_id); } private: inline void step() { this->i += 1; } inline auto intern_str(std::string val) -> size_t { if (this->strs_val_id_map.contains(val)) return strs_val_id_map.at(val); auto id = this->strs_vals.size(); this->strs_vals.push_back(val); this->strs_val_id_map.insert_or_assign(val, id); return id; } inline auto test_in(std::string_view chs) const -> bool { for (auto ch : chs) if (test(ch)) return true; return false; } inline auto test(char ch) const -> bool { return !done() && cur() == ch; } inline auto done() const -> bool { return this->i >= this->text.size(); } inline auto cur() const -> char { return this->text.at(this->i); } std::string_view text; size_t i = 0; int line = 1; int col = 1; std::unordered_map strs_val_id_map; std::vector strs_vals; }; class Parser { public: Parser(std::string_view text) : lexer(text) , cur(lexer.next()) { } auto parse_val() -> Res>; private: inline auto unexpected_tok_err( TokTyp expected, std::string_view msg) -> Res> { return Err { .pos = this->cur.val().pos, .msg = std::format("{}, expected '{}', got '{}'", msg, tok_typ_to_string(expected), tok_typ_to_string(this->cur.val().typ)), }; } inline auto step() -> Res { auto tok = this->lexer.next(); if (not tok.ok()) return tok.err(); return {}; } inline auto curtyp() const -> TokTyp { return this->cur.val().typ; } Lexer lexer; Res cur; }; class Writer { public: inline auto operator<<(auto value) -> Writer& { this->add(value); return *this; } inline void add(const char* value) { this->data.append(value); } inline void add(std::string_view value) { this->data.append(value); } inline void add(const std::string& value) { this->data.append(value); } inline void add(auto value) { this->data.push_back(value); } template auto add_comma_seperated(const T& values, F f) { for (const auto& value : values) { f(*this, value); } } inline auto done() -> std::string { return std::move(this->data); } private: std::string data; }; struct ToAndFromJson { virtual ~ToAndFromJson() = default; virtual void to_json(Writer& writer) const = 0; }; auto to_json(const std::derived_from auto& value) -> std::string { auto writer = Writer(); value.to_json(writer); return writer.done(); } template requires std::derived_from auto from_json(std::string_view json_string) -> T { return T::from_json(json_string); } }