slige/runtime/json.hpp
2024-11-12 11:59:42 +01:00

170 lines
2.9 KiB
C++

#pragma once
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
namespace sliger::json {
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&
{
return static_cast<T&>(this);
}
};
struct Null final : public Value {
auto type() const -> Type override { return Type::Null; }
};
struct String final : public Value {
auto type() const -> Type override { return Type::String; }
std::string value;
};
struct Number final : public Value {
auto type() const -> Type override { return Type::Number; }
double value;
};
struct Bool final : public Value {
auto type() const -> Type override { return Type::Bool; }
bool value;
};
struct Array final : public Value {
auto type() const -> Type override { return Type::Array; }
std::vector<std::unique_ptr<Value>> values;
};
struct Object final : public Value {
auto type() const -> Type override { return Type::Object; }
};
struct Pos {
int line;
int col;
};
enum class TokTyp {
Error,
Eof,
String,
Float,
False,
True,
Null,
LBrace,
RBrace,
LBracket,
RBracket,
Comma,
Colon,
};
struct Tok {
Tok(TokTyp typ)
: typ(typ)
, val_id(0)
{
}
Tok(TokTyp typ, size_t val_id)
: typ(typ)
, val_id(val_id)
{
}
Tok(TokTyp typ, double float_val)
: typ(typ)
, float_val(float_val)
{
}
Tok(TokTyp typ, bool bool_val)
: typ(typ)
, bool_val(bool_val)
{
}
TokTyp typ;
union {
size_t val_id;
double float_val;
bool bool_val;
};
};
class Lexer {
public:
Lexer(std::string_view text)
: text(text)
{
}
auto next() -> Tok;
inline auto pos() const -> Pos { return { this->line, this->col }; }
private:
inline void step() { this->i += 1; }
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;
};
class Parser {
public:
Parser(std::string_view text)
: lexer(text)
, cur(lexer.next())
{
}
private:
Lexer lexer;
Tok cur;
};
struct Jsonable {
virtual ~Jsonable() = default;
virtual auto to_json() const -> std::string = 0;
};
template <typename T> auto from_json() -> T { T::from_json(); }
}