#include "json.hpp" #include #include #include #include #include using namespace sliger::json; auto ident_tok_typs = std::unordered_map { { "null", TokTyp::Null }, { "false", TokTyp::False }, { "true", TokTyp::True }, }; auto id_start_chars = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; auto id_tail_chars = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "1234567890-"; auto Lexer::next() -> Res { auto pos = this->pos(); if (done()) { return Tok(TokTyp::Eof, pos); } if (test('"')) { step(); auto value = std::string(); while (!done() and !test('"')) { if (cur() == '\\') { step(); if (done()) break; value.push_back([&] { char ch = cur(); switch (ch) { case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case '0': return '\0'; default: return ch; } }()); } else { value.push_back(cur()); } step(); } if (!test('"')) { return Err { .pos = pos, .msg = std::format("malformed string, expected '\"', got '{}' token", this->cur()), }; } step(); return Tok(TokTyp::String, pos, intern_str(value)); } auto step_n_ret = [&](auto tok) { step(); return tok; }; switch (cur()) { case '0': return step_n_ret(Tok(TokTyp::Float, pos, 0.0)); case '{': return step_n_ret(Tok(TokTyp::LBrace, pos)); case '}': return step_n_ret(Tok(TokTyp::RBrace, pos)); case '[': return step_n_ret(Tok(TokTyp::LBracket, pos)); case ']': return step_n_ret(Tok(TokTyp::RBracket, pos)); case ',': return step_n_ret(Tok(TokTyp::Comma, pos)); case ':': return step_n_ret(Tok(TokTyp::Colon, pos)); } if (test_in(id_start_chars)) { auto value = std::string(); while (test_in(id_tail_chars)) { value.push_back(cur()); step(); } if (ident_tok_typs.find(value) == ident_tok_typs.end()) { return Err { .pos = pos, .msg = std::format("unknown identifier \"{}\"", value), }; } return Tok(ident_tok_typs.at(value), pos); } if (test_in("123456789")) { auto value_str = std::string(); while (test_in("1234567890")) { value_str.push_back(cur()); step(); } auto value = std::atof(value_str.c_str()); return Tok(TokTyp::Float, pos, value); } auto ch = cur(); step(); return Err { .pos = pos, .msg = std::format("unknown character '{}'", ch), }; } auto Parser::parse_val() -> Res> { if (not this->cur.ok()) return this->cur.err(); auto cur = this->cur.val(); switch (cur.typ) { case TokTyp::Eof: return Err { .pos = cur.pos, .msg = "expected value, got eof", }; case TokTyp::String: { auto value = this->lexer.val(cur.val_id); step(); return Res>(std::make_unique(value)); } case TokTyp::Float: { auto value = cur.float_val; step(); return Res>(std::make_unique(value)); } case TokTyp::False: { step(); return Res>(std::make_unique(false)); } case TokTyp::True: { step(); return Res>(std::make_unique(true)); } case TokTyp::Null: { step(); return Res>(std::make_unique()); } case TokTyp::LBrace: { step(); ObjectFields fields; if (curtyp() != TokTyp::RBrace) { 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::Colon) { return unexpected_tok_err( TokTyp::Colon, "malformed object"); } step(); auto value = parse_val(); if (not 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::Colon) { return unexpected_tok_err( TokTyp::Colon, "malformed object"); } step(); auto value = parse_val(); if (not 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"); } step(); return Res>( std::make_unique(std::move(fields))); } case TokTyp::LBracket: { step(); ArrayValues values; if (curtyp() != TokTyp::RBracket) { auto value = parse_val(); if (not value.ok()) { return value.err(); } values.push_back(std::move(value.val())); while (curtyp() == TokTyp::Comma) { step(); auto value = parse_val(); if (not value.ok()) { return value.err(); } values.push_back(std::move(value.val())); } } if (curtyp() != TokTyp::RBracket) { return unexpected_tok_err(TokTyp::RBracket, "malformed array"); } step(); return Res>( std::make_unique(std::move(values))); } case TokTyp::RBrace: case TokTyp::RBracket: case TokTyp::Comma: case TokTyp::Colon: return Err { .pos = cur.pos, .msg = std::format("expected value, got '{}' token", tok_typ_to_string(cur.typ)), }; break; } return Err { .pos = cur.pos, .msg = std::format( "internal error, could not parse '{}'", tok_typ_to_string(cur.typ)), }; }