This commit is contained in:
SimonFJ20 2024-11-12 11:59:42 +01:00
parent fc65c193c3
commit a644c0a630
2 changed files with 275 additions and 0 deletions

106
runtime/json.cpp Normal file
View File

@ -0,0 +1,106 @@
#include "json.hpp"
#include <cstdlib>
#include <format>
#include <iostream>
#include <string>
#include <unordered_map>
using namespace sliger::json;
auto ident_tok_typs = std::unordered_map<std::string, TokTyp> {
{ "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() -> Tok
{
if (done()) {
return TokTyp::Eof;
}
auto pos = this->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();
}
}
auto step_n_ret = [&](auto tok) {
step();
return tok;
};
switch (cur()) {
case '0':
return step_n_ret(Tok(TokTyp::Float, 0.0));
case '{':
return step_n_ret(TokTyp::LBrace);
case '}':
return step_n_ret(TokTyp::RBrace);
case '[':
return step_n_ret(TokTyp::LBracket);
case ']':
return step_n_ret(TokTyp::RBracket);
case ',':
return step_n_ret(TokTyp::Comma);
case ':':
return step_n_ret(TokTyp::Colon);
}
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()) {
std::cerr << std::format("sliger::json::Lexer error: unknown "
"identifier \"{}\" at {}:{}",
value, pos.col, pos.line);
return TokTyp::Error;
}
return ident_tok_typs.at(value);
}
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, value);
}
std::cerr << std::format(
"sliger::json::Lexer error: unknown character '{}' at {}:{}", cur(),
this->line, this->col);
step();
return TokTyp::Error;
}

169
runtime/json.hpp Normal file
View File

@ -0,0 +1,169 @@
#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(); }
}