From a644c0a630d734120d40c1b19b0de8dccf2e8039 Mon Sep 17 00:00:00 2001 From: SimonFJ20 Date: Tue, 12 Nov 2024 11:59:42 +0100 Subject: [PATCH] add json --- runtime/json.cpp | 106 +++++++++++++++++++++++++++++ runtime/json.hpp | 169 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 runtime/json.cpp create mode 100644 runtime/json.hpp diff --git a/runtime/json.cpp b/runtime/json.cpp new file mode 100644 index 0000000..901b573 --- /dev/null +++ b/runtime/json.cpp @@ -0,0 +1,106 @@ +#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() -> 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; +} diff --git a/runtime/json.hpp b/runtime/json.hpp new file mode 100644 index 0000000..af472cf --- /dev/null +++ b/runtime/json.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace sliger::json { + +enum class Type { + Null, + String, + Number, + Bool, + Array, + Object, +}; + +struct Value { + virtual ~Value() = default; + virtual auto type() const -> Type = 0; + + template + requires std::derived_from + inline auto as() & -> T& + { + return static_cast(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> 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 auto from_json() -> T { T::from_json(); } + +}