Initial commit

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
Slendi 2024-06-18 04:01:33 +03:00
commit abb6ce433e
No known key found for this signature in database
5 changed files with 533 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
json.exe
json

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
Copyright (C) 2023 Slendi
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>

456
json.cpp Normal file
View File

@ -0,0 +1,456 @@
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "json.hpp"
#include <stdarg.h>
using namespace std;
char buffer[512];
char *format(char const *base, ...) {
va_list lst;
va_start(lst, base);
vsnprintf(buffer, sizeof buffer, base, lst);
va_end(lst);
return buffer;
}
enum TokenType {
TOK_OPEN_OBJ = 0,
TOK_CLOSE_OBJ,
TOK_OPEN_ARR,
TOK_CLOSE_ARR,
TOK_ASSIGNMENT,
TOK_COMMA,
TOK_STRING,
TOK_NUMBER,
TOK_EOF
};
char const *TName(TokenType tok) {
switch (tok) {
case TOK_OPEN_OBJ:
return "{";
case TOK_CLOSE_OBJ:
return "}";
case TOK_OPEN_ARR:
return "[";
case TOK_CLOSE_ARR:
return "]";
case TOK_ASSIGNMENT:
return ":";
case TOK_COMMA:
return ",";
case TOK_STRING:
return "STRING!!!";
case TOK_NUMBER:
return "NUMBER FUUAAAAA";
case TOK_EOF:
return "EOF";
}
return "How the fuck did we even get here";
}
union TokenValue {
long double d;
char *s;
};
struct Token {
TokenType type;
TokenValue v;
char const *Name(void) { return TName(type); }
void PrettyPrint(void) {
cout << Name() << ' ';
if (type == TOK_STRING)
printf("%s", v.s);
if (type == TOK_NUMBER)
cout << v.d;
cout << endl;
}
};
struct Tokeniser {
istream *f = nullptr;
void Init(istream *stream) { f = stream; }
Token Next(void);
Token ParseIdent(string &str, bool &in_string);
} TS;
const std::string WHITESPACE = " \n\r\t\f\v";
std::string ltrim(const std::string &s) {
size_t start = s.find_first_not_of(WHITESPACE);
return (start == std::string::npos) ? "" : s.substr(start);
}
std::string rtrim(const std::string &s) {
size_t end = s.find_last_not_of(WHITESPACE);
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
}
std::string trim(const std::string &s) { return rtrim(ltrim(s)); }
Token Tokeniser::ParseIdent(string &str, bool &in_string) {
Token res{.type = TOK_NUMBER};
str = trim(str);
for (size_t i = 0; i < str.length(); i++) {
if (!isdigit(str[i]) && str[i] != '.' && str[i] != '\r' && str[i] != '\n') {
res.type = TOK_STRING;
break;
}
}
if (res.type == TOK_NUMBER) {
res.v.d = stold(str.c_str());
} else {
char *amogus = (char *)calloc(1, str.length() + 1);
if ((str.front() == '"' || str.front() == '\'') &&
(str.back() == '"' || str.back() == '\'')) {
memcpy(amogus, str.c_str() + 1, str.length() - 2);
amogus[str.length() - 1] = 0;
} else {
memcpy(amogus, str.c_str(), str.length());
}
res.v.s = amogus;
}
return res;
}
Token Tokeniser::Next(void) {
char ch;
string ident = "";
bool string_mode = false;
bool in_string = false;
while (f->get(ch)) {
static char const *chars = "{}[]:,";
static unsigned char chars_len = strlen(chars);
if (ch == '\r' || ch == '\n') {
if (string_mode == false)
continue;
}
if (ch == '"' || ch == '\'') {
in_string = !in_string;
string_mode = !string_mode;
}
if (!in_string)
for (unsigned char i = 0; i < chars_len; i++) {
if (ch == chars[i] || ch == ' ') {
if (string_mode && ident.length() > 0) {
auto a = ParseIdent(ident, in_string);
string_mode = false;
ident = "";
f->unget();
return a;
}
if (ch == ' ')
continue;
return Token{.type = (TokenType)i};
} else {
string_mode = true;
}
}
if (string_mode)
ident.push_back(ch);
}
return Token{.type = TOK_EOF};
}
void JSONNode::Free(void) {
switch (type) {
case JSON_STRING:
if (v.s)
delete v.s;
break;
case JSON_LIST:
if (v.list) {
for (auto i : *v.list)
i.Free();
delete v.list;
}
break;
case JSON_OBJECT:
if (v.object) {
for (auto i : *v.object) {
if (i.name)
delete i.name;
i.node.Free();
}
delete v.object;
}
break;
default:
break;
}
}
long double &JSONNode::Number(void) {
if (type != JSON_NUMBER)
throw runtime_error("JSON node is not a number.");
return v.ld;
}
long double JSONNode::Number(long double def) {
if (type != JSON_NUMBER)
return def;
return v.ld;
}
char *&JSONNode::String(void) {
if (type != JSON_STRING)
throw runtime_error("JSON node is not a string.");
return v.s;
}
char *JSONNode::String(char *def) {
if (type != JSON_STRING)
return def;
return v.s;
}
vector<JSONNode> *&JSONNode::List(void) {
if (type != JSON_LIST)
throw runtime_error("JSON node is not a list.");
return v.list;
}
vector<JSONKeyValue> *&JSONNode::Object(void) {
if (type != JSON_OBJECT)
throw runtime_error("JSON node is not a object.");
return v.object;
}
string const JSONNode::Name(void) {
switch (type) {
case JSON_UNKNOWN:
return "Unknown";
case JSON_OBJECT:
return "Object";
case JSON_LIST:
return "List";
case JSON_KEY:
return "Key";
case JSON_NUMBER:
return "Number";
case JSON_STRING:
return "String";
}
return "Unknown node";
}
JSONNode UNKNOWN{.type = JSON_UNKNOWN};
void JSONKeyValue::PrettyPrint(string indent, bool last) {
printf("%s", indent.c_str());
if (last) {
printf("\\-");
indent += " ";
} else {
printf("|-");
indent += "| ";
}
printf(" %s\n", name);
node.PrettyPrint(indent, false);
}
JSONNode &JSONNode::operator[](string key) {
for (size_t i = 0; i < v.object->size(); i++) {
JSONKeyValue &kv = v.object->at(i);
if (strcmp(kv.name, key.c_str()) == 0) {
return kv.node;
}
}
return UNKNOWN;
}
JSONNode &JSONNode::operator[](size_t index) { return v.list->at(index); }
void JSONNode::PrettyPrint(string indent = "", bool last = true) {
printf("%s", indent.c_str());
if (last) {
printf("\\-");
indent += " ";
} else {
printf("|-");
indent += "| ";
}
printf(" {%s}", Name().c_str());
printf("\r\e[40C");
if (type == JSON_NUMBER)
cout << v.ld;
if (type == JSON_STRING)
cout << v.s;
printf("\n");
if (type == JSON_OBJECT) {
for (size_t i = 0; i < v.object->size(); i++)
v.object->at(i).PrettyPrint(indent, i == v.list->size() - 1);
}
if (type == JSON_LIST) {
for (size_t i = 0; i < v.list->size(); i++)
v.list->at(i).PrettyPrint(indent, i == v.list->size() - 1);
}
}
struct ParserState {
Token tok;
Token Next(void) {
tok = TS.Next();
return tok;
}
bool Accept(TokenType other) {
if (tok.type == other) {
Next();
return true;
}
return false;
}
bool Expect(TokenType other) {
bool flag = false;
if (Accept(other))
flag = true;
else {
throw runtime_error(
format("Expected token: {}, got {}.", tok.Name(), TName(other)));
}
return flag;
}
JSONNode ParseObject(void);
JSONNode ParseArray(void);
JSONNode ParseValue(void);
JSONNode Parse(void);
} PS;
JSONNode ParserState::ParseObject(void) {
JSONNode node = {.type = JSON_OBJECT,
.v = {.object = new vector<JSONKeyValue>}};
if (Accept(TOK_CLOSE_OBJ))
return node;
while (1) {
JSONKeyValue pair;
if (tok.type != TOK_STRING) {
throw runtime_error("Expected key.");
}
pair.name = tok.v.s;
Next();
Expect(TOK_ASSIGNMENT);
pair.node = ParseValue();
node.v.object->push_back(pair);
Accept(TOK_COMMA);
if (tok.type == TOK_CLOSE_OBJ)
break;
}
Expect(TOK_CLOSE_OBJ);
return node;
}
JSONNode ParserState::ParseArray(void) {
JSONNode node = {.type = JSON_LIST, .v = {.list = new vector<JSONNode>}};
if (Accept(TOK_CLOSE_ARR))
return node;
while (1) {
node.v.list->push_back(ParseValue());
Accept(TOK_COMMA);
if (tok.type == TOK_CLOSE_ARR)
break;
}
Expect(TOK_CLOSE_ARR);
return node;
}
JSONNode ParserState::ParseValue(void) {
TokenValue value = tok.v;
if (Accept(TOK_OPEN_OBJ)) {
JSONNode node = ParseObject();
return node;
} else if (Accept(TOK_OPEN_ARR)) {
JSONNode node = ParseArray();
return node;
} else if (Accept(TOK_NUMBER)) {
JSONNode node = {
.type = JSON_NUMBER,
.v = {.ld = value.d},
};
return node;
} else if (Accept(TOK_STRING)) {
JSONNode node = {
.type = JSON_STRING,
.v = {.s = value.s},
};
return node;
} else if (Accept(TOK_EOF)) {
return JSONNode{
.type = JSON_UNKNOWN,
};
} else {
throw runtime_error(format("Invalid value: %s", tok.Name()));
}
}
JSONNode ParserState::Parse(void) {
JSONNode root{JSON_UNKNOWN, {0}};
Next();
if (tok.type == TOK_EOF) {
throw runtime_error("Empty file");
}
root = ParseValue();
return root;
}
JSONNode JSONParseFile(char *file) {
ifstream f(file);
TS.Init(&f);
return PS.Parse();
}
JSONNode JSONParseString(std::string string) {
istringstream f(string);
TS.Init(&f);
return PS.Parse();
}

51
json.hpp Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include <vector>
#include <string>
enum JSONNodeType {
JSON_UNKNOWN = -1,
JSON_OBJECT,
JSON_LIST,
JSON_KEY,
JSON_NUMBER,
JSON_STRING,
};
struct JSONKeyValue;
struct JSONNode {
JSONNodeType type;
union {
long double ld;
char *s;
std::vector<JSONNode> *list;
std::vector<JSONKeyValue> *object;
} v;
JSONNode &operator[](std::string key);
JSONNode &operator[](size_t index);
void Free(void);
long double &Number(void);
long double Number(long double def);
char *&String(void);
char *String(char *def);
std::vector<JSONNode> *&List(void);
std::vector<JSONKeyValue> *&Object(void);
std::string const Name(void);
void PrettyPrint(std::string indent, bool last);
};
struct JSONKeyValue {
char *name;
JSONNode node;
void PrettyPrint(std::string indent, bool last);
};
JSONNode JSONParseFile(char *file);
JSONNode JSONParseString(std::string string);

16
main.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "json.hpp"
#include <iostream>
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cout << "No JSON specified" << std::endl;
}
JSONNode root = JSONParseFile(argv[1]);
root.PrettyPrint("", true);
root.Free();
return 0;
}