mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 19:36:32 +00:00
170 lines
2.9 KiB
C++
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(); }
|
||
|
|
||
|
}
|