diff --git a/runtime/json.cpp b/runtime/json.cpp index c72cc49..c677beb 100644 --- a/runtime/json.cpp +++ b/runtime/json.cpp @@ -1,7 +1,6 @@ #include "json.hpp" #include #include -#include #include #include #include @@ -153,18 +152,74 @@ auto Parser::parse_val() -> Res> case TokTyp::LBrace: { step(); ObjectFields fields; - while (curtyp() != TokTyp::RBrace) { } if (curtyp() != TokTyp::RBrace) { - return Err { - .pos = this->cur.val().pos, - .msg - = std::format("malformed object, expected '}', got '{}'", - tok_typ_to_string(this->cur.val().typ)), - }; + if (curtyp() != TokTyp::String) { + return unexpected_tok_err( + TokTyp::String, "malformed object"); + } + auto key = this->lexer.val(this->cur.val().val_id); + step(); + if (curtyp() != TokTyp::Comma) { + return unexpected_tok_err( + TokTyp::Comma, "malformed object"); + } + step(); + auto value = parse_val(); + if (value.ok()) { + return value.err(); + } + fields.insert_or_assign(key, std::move(value.val())); + while (curtyp() == TokTyp::Comma) { + step(); + if (curtyp() != TokTyp::String) { + return unexpected_tok_err( + TokTyp::String, "malformed object"); + } + auto key = this->lexer.val(this->cur.val().val_id); + step(); + if (curtyp() != TokTyp::Comma) { + return unexpected_tok_err( + TokTyp::Comma, "malformed object"); + } + step(); + auto value = parse_val(); + if (value.ok()) { + return value.err(); + } + fields.insert_or_assign(key, std::move(value.val())); + } } + if (curtyp() != TokTyp::RBrace) { + return unexpected_tok_err(TokTyp::RBrace, "malformed object"); + } + return Res>( + std::make_unique(std::move(fields))); + } + case TokTyp::LBracket: { + step(); + ArrayValues values; + if (curtyp() != TokTyp::RBrace) { + auto value = parse_val(); + if (value.ok()) { + return value.err(); + } + values.push_back(std::move(value.val())); + while (curtyp() == TokTyp::Comma) { + step(); + auto value = parse_val(); + if (value.ok()) { + return value.err(); + } + values.push_back(std::move(value.val())); + } + } + if (curtyp() != TokTyp::RBrace) { + return unexpected_tok_err(TokTyp::RBrace, "malformed object"); + } + return Res>( + std::make_unique(std::move(values))); } case TokTyp::RBrace: - case TokTyp::LBracket: case TokTyp::RBracket: case TokTyp::Comma: case TokTyp::Colon: @@ -175,4 +230,9 @@ auto Parser::parse_val() -> Res> }; break; } + return Err { + .pos = cur.pos, + .msg = std::format( + "internal error, could not parse '{}'", tok_typ_to_string(cur.typ)), + }; } diff --git a/runtime/json.hpp b/runtime/json.hpp index 0d39e52..1d543cb 100644 --- a/runtime/json.hpp +++ b/runtime/json.hpp @@ -2,11 +2,12 @@ #include #include +#include #include #include #include +#include #include -#include #include namespace sliger::json { @@ -292,6 +293,17 @@ public: 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(); @@ -305,12 +317,17 @@ private: Res cur; }; -struct Jsonable { - virtual ~Jsonable() = default; +struct Serializable { + virtual ~Serializable() = default; virtual auto to_json() const -> std::string = 0; }; -template auto from_json() -> T { T::from_json(); } +template + requires std::derived_from +auto from_json(std::string_view json_string) -> T +{ + return T::from_json(json_string); +} }