slige/runtime/json.hpp

358 lines
7.5 KiB
C++
Raw Normal View History

2024-11-12 10:59:42 +00:00
#pragma once
#include <concepts>
#include <cstddef>
#include <memory>
#include <optional>
#include <string>
2024-11-18 09:11:58 +00:00
#include <string_view>
2024-11-15 14:22:57 +00:00
#include <unordered_map>
2024-11-19 04:06:27 +00:00
#include <utility>
2024-11-12 10:59:42 +00:00
#include <vector>
namespace sliger::json {
2024-11-15 14:22:57 +00:00
struct Pos {
int line;
int col;
};
struct Err {
Pos pos;
std::string msg;
};
template <typename T> 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<T> maybe_value;
std::optional<Err> maybe_error;
};
template <> class Res<void> {
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<Err> maybe_error;
};
2024-11-12 10:59:42 +00:00
enum class Type {
Null,
String,
Number,
Bool,
Array,
Object,
};
struct Value {
virtual ~Value() = default;
virtual auto type() const -> Type = 0;
template <typename T>
requires std::derived_from<T, Value>
inline auto as() & -> T&
{
2024-11-27 12:28:45 +00:00
return static_cast<T&>(*this);
2024-11-12 10:59:42 +00:00
}
2024-12-13 15:11:16 +00:00
template <typename T>
requires std::derived_from<T, Value>
inline auto as() const& -> const T&
{
return static_cast<const T&>(*this);
}
2024-11-12 10:59:42 +00:00
};
struct Null final : public Value {
auto type() const -> Type override { return Type::Null; }
};
struct String final : public Value {
2024-11-15 14:22:57 +00:00
String(std::string value)
: value(std::move(value))
{
}
2024-11-12 10:59:42 +00:00
auto type() const -> Type override { return Type::String; }
std::string value;
};
struct Number final : public Value {
2024-11-15 14:22:57 +00:00
Number(double value)
: value(value)
{
}
2024-11-12 10:59:42 +00:00
auto type() const -> Type override { return Type::Number; }
double value;
};
struct Bool final : public Value {
2024-11-15 14:22:57 +00:00
Bool(bool value)
: value(value)
{
}
2024-11-12 10:59:42 +00:00
auto type() const -> Type override { return Type::Bool; }
bool value;
};
2024-11-15 14:22:57 +00:00
using ArrayValues = std::vector<std::unique_ptr<Value>>;
2024-11-12 10:59:42 +00:00
struct Array final : public Value {
2024-11-15 14:22:57 +00:00
Array(ArrayValues values)
: values(std::move(values))
{
}
2024-11-12 10:59:42 +00:00
auto type() const -> Type override { return Type::Array; }
2024-11-15 14:22:57 +00:00
ArrayValues values;
2024-11-12 10:59:42 +00:00
};
2024-11-15 14:22:57 +00:00
using ObjectFields = std::unordered_map<std::string, std::unique_ptr<Value>>;
2024-11-12 10:59:42 +00:00
struct Object final : public Value {
2024-11-15 14:22:57 +00:00
Object(ObjectFields fields)
: fields(std::move(fields))
{
}
2024-11-12 10:59:42 +00:00
auto type() const -> Type override { return Type::Object; }
2024-11-15 14:22:57 +00:00
ObjectFields fields;
2024-11-12 10:59:42 +00:00
};
enum class TokTyp {
Eof,
String,
Float,
False,
True,
Null,
LBrace,
RBrace,
LBracket,
RBracket,
Comma,
Colon,
};
2024-12-12 15:07:59 +00:00
auto tok_typ_to_string(TokTyp typ) -> std::string;
2024-11-15 14:22:57 +00:00
2024-11-12 10:59:42 +00:00
struct Tok {
2024-11-15 14:22:57 +00:00
Tok(TokTyp typ, Pos pos)
2024-11-12 10:59:42 +00:00
: typ(typ)
2024-11-15 14:22:57 +00:00
, pos(pos)
2024-11-12 10:59:42 +00:00
, val_id(0)
{
}
2024-11-15 14:22:57 +00:00
Tok(TokTyp typ, Pos pos, size_t val_id)
2024-11-12 10:59:42 +00:00
: typ(typ)
2024-11-15 14:22:57 +00:00
, pos(pos)
2024-11-12 10:59:42 +00:00
, val_id(val_id)
{
}
2024-11-15 14:22:57 +00:00
Tok(TokTyp typ, Pos pos, double float_val)
2024-11-12 10:59:42 +00:00
: typ(typ)
2024-11-15 14:22:57 +00:00
, pos(pos)
2024-11-12 10:59:42 +00:00
, float_val(float_val)
{
}
2024-11-15 14:22:57 +00:00
Tok(TokTyp typ, Pos pos, bool bool_val)
2024-11-12 10:59:42 +00:00
: typ(typ)
2024-11-15 14:22:57 +00:00
, pos(pos)
2024-11-12 10:59:42 +00:00
, bool_val(bool_val)
{
}
TokTyp typ;
2024-11-15 14:22:57 +00:00
Pos pos;
2024-11-12 10:59:42 +00:00
union {
size_t val_id;
double float_val;
bool bool_val;
};
};
class Lexer {
public:
Lexer(std::string_view text)
: text(text)
{
}
2024-11-15 14:22:57 +00:00
auto next() -> Res<Tok>;
2024-11-12 10:59:42 +00:00
inline auto pos() const -> Pos { return { this->line, this->col }; }
2024-11-15 14:22:57 +00:00
inline auto val(size_t val_id) const -> const std::string&
{
return this->strs_vals.at(val_id);
}
2024-11-12 10:59:42 +00:00
private:
2024-12-12 09:40:38 +00:00
inline void step()
{
if (this->cur() == '\n') {
this->col = 1;
this->line += 1;
} else {
this->col += 1;
}
this->i += 1;
}
2024-11-12 10:59:42 +00:00
2024-11-15 14:22:57 +00:00
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;
}
2024-11-12 10:59:42 +00:00
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;
2024-11-15 14:22:57 +00:00
std::unordered_map<std::string, size_t> strs_val_id_map;
std::vector<std::string> strs_vals;
2024-11-12 10:59:42 +00:00
};
class Parser {
public:
Parser(std::string_view text)
: lexer(text)
, cur(lexer.next())
{
}
2024-11-15 14:22:57 +00:00
auto parse_val() -> Res<std::unique_ptr<Value>>;
2024-11-12 10:59:42 +00:00
private:
2024-12-13 15:11:16 +00:00
auto unexpected_tok_err(TokTyp expected, std::string_view msg)
-> Res<std::unique_ptr<Value>>;
2024-11-18 09:11:58 +00:00
2024-11-15 14:22:57 +00:00
inline auto step() -> Res<void>
{
auto tok = this->lexer.next();
if (not tok.ok())
return tok.err();
2024-12-11 00:03:16 +00:00
this->cur = tok;
2024-11-15 14:22:57 +00:00
return {};
}
inline auto curtyp() const -> TokTyp { return this->cur.val().typ; }
2024-11-12 10:59:42 +00:00
Lexer lexer;
2024-11-15 14:22:57 +00:00
Res<Tok> cur;
2024-11-12 10:59:42 +00:00
};
2024-11-20 11:55:59 +00:00
inline auto parse_json(std::string_view value) -> Res<std::unique_ptr<Value>>
{
return Parser(value).parse_val();
}
2024-11-19 04:06:27 +00:00
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 <typename T, typename F>
auto add_comma_seperated(const T& values, F f)
{
2024-11-21 03:12:07 +00:00
auto first = true;
2024-11-19 04:06:27 +00:00
for (const auto& value : values) {
2024-11-21 03:12:07 +00:00
if (!first) {
add(",");
}
first = false;
2024-11-19 04:06:27 +00:00
f(*this, value);
}
}
inline auto done() -> std::string { return std::move(this->data); }
2024-11-12 10:59:42 +00:00
2024-11-19 04:06:27 +00:00
private:
std::string data;
};
struct ToAndFromJson {
virtual ~ToAndFromJson() = default;
virtual void to_json(Writer& writer) const = 0;
2024-11-12 10:59:42 +00:00
};
2024-11-19 04:06:27 +00:00
auto to_json(const std::derived_from<ToAndFromJson> auto& value) -> std::string
{
auto writer = Writer();
value.to_json(writer);
return writer.done();
}
2024-11-18 09:11:58 +00:00
template <typename T>
2024-11-19 04:06:27 +00:00
requires std::derived_from<T, ToAndFromJson>
2024-11-18 09:11:58 +00:00
auto from_json(std::string_view json_string) -> T
{
return T::from_json(json_string);
}
2024-11-12 10:59:42 +00:00
}