From 5188d57d19b97440307a6d48c7055fed353c42f8 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Tue, 7 Jun 2022 12:40:32 +0200 Subject: [PATCH] Util: Add JSON parser --- src/util/json/parser.cpp | 277 +++++++++++++++++++++++++++++++++++++++ src/util/json/parser.h | 46 +++++++ 2 files changed, 323 insertions(+) create mode 100644 src/util/json/parser.cpp create mode 100644 src/util/json/parser.h diff --git a/src/util/json/parser.cpp b/src/util/json/parser.cpp new file mode 100644 index 0000000..f42fa03 --- /dev/null +++ b/src/util/json/parser.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // size_t +#include // uint32_t +#include // printf +#include +#include // stod + +#include "util/json/array.h" +#include "util/json/lexer.h" +#include "util/json/object.h" +#include "util/json/parser.h" + +namespace Json { + +Parser::Parser(const std::string& input) + : m_input(input) +{ +} + +Parser::~Parser() +{ +} + +// ----------------------------------------- + +void Parser::parse() +{ + Lexer lexer(m_input); + lexer.analyze(); + m_tokens = lexer.tokens(); + + printf("---------\n"); + printf("Parsing:\n"); + + Value result; + + Token token; + while (m_index < m_tokens.size()) { + token = peek(); + + switch (token.type) { + case Token::Type::Literal: + if (token.symbol == "null") { + result = Value {}; + } + else if (token.symbol == "true") { + result = Value { true }; + } + else if (token.symbol == "false") { + result = Value { false }; + } + m_index++; + break; + case Token::Type::Number: + result = Value { std::stod(token.symbol) }; + m_index++; + break; + case Token::Type::String: + result = Value { token.symbol }; + m_index++; + break; + case Token::Type::BracketOpen: + result = getArray(); + break; + case Token::Type::BraceOpen: + result = getObject(); + break; + case Token::Type::Comma: + // Error! + // Multiple JSON root elements + break; + default: + // Error! + break; + } + + break; + } +} + +// ----------------------------------------- + +Token Parser::peek() +{ + return m_tokens[m_index]; +} + +Token Parser::consume() +{ + Token token = peek(); + m_index++; + return token; +} + +bool Parser::consumeSpecific(Token::Type type) +{ + if (peek().type != type) { + return false; + } + + m_index++; + return true; +} + +Value Parser::getArray() +{ + size_t index = m_index; + m_index++; + + Array array; + + Token token; + for (;;) { + token = consume(); + + switch (token.type) { + case Token::Type::Literal: + printf("Adding literal to array.. v:{%s}, t:{%d}\n", token.symbol.c_str(), (int)token.type); + if (token.symbol == "null") { + array.emplace(Value {}); + } + else if (token.symbol == "true") { + array.emplace(Value { true }); + } + else if (token.symbol == "false") { + array.emplace(Value { false }); + } + break; + case Token::Type::Number: + printf("Adding number to array.. v:{%s}, t:{%d} -> %f\n", token.symbol.c_str(), (int)token.type, std::stod(token.symbol)); + array.emplace(Value { std::stod(token.symbol) }); + break; + case Token::Type::String: + printf("Adding string to array.. v:{%s}, t:{%d}\n", token.symbol.c_str(), (int)token.type); + array.emplace(Value { token.symbol }); + break; + case Token::Type::BracketOpen: + m_index--; + array.emplace(Value { getArray() }); + break; + case Token::Type::BraceOpen: + m_index--; + array.emplace(Value { getObject() }); + break; + default: + // Error! + printf("Invalid JSON! array:1\n"); + break; + } + + // Find , or } + token = consume(); + if (token.type == Token::Type::Comma) { + continue; + } + else if (token.type == Token::Type::BracketClose) { + break; + } + else { + // Error! + printf("Invalid JSON! array:2\n"); + break; + } + } + + return Value { array }; +} + +Value Parser::getObject() +{ + size_t index = m_index; + m_index++; + + Object object; + + Token token; + std::string key; + std::map unique; + for (;;) { + // Find string key + token = consume(); + if (token.type != Token::Type::String) { + // Error! + printf("Invalid JSON! 1\n"); + break; + } + + // Check if key exists in hashmap + key = token.symbol; + if (unique.find(key) != unique.end()) { + // If exists, unique key fail! + // Error! + printf("Invalid JSON! 2\n"); + break; + } + // Add key to hashmap + unique.insert({ key, 0 }); + + // Find : + if (!consumeSpecific(Token::Type::Colon)) { + // Error! + printf("Invalid JSON! 3\n"); + break; + } + + // Find string/number/literal value + token = consume(); + if (token.type != Token::Type::String + && token.type != Token::Type::Number + && token.type != Token::Type::Literal + && token.type != Token::Type::BracketOpen + && token.type != Token::Type::BraceOpen) { + // Error! + printf("Invalid JSON! 4\n"); + break; + } + + // Add member to object + switch (token.type) { + case Token::Type::Literal: + printf("Adding literal to object.. k:{%s}, v:{%s}, t:{%d}\n", key.c_str(), token.symbol.c_str(), (int)token.type); + if (token.symbol == "null") { + object.emplace(key, Value {}); + } + else if (token.symbol == "true") { + object.emplace(key, Value { true }); + } + else if (token.symbol == "false") { + object.emplace(key, Value { false }); + } + break; + case Token::Type::Number: + printf("Adding number to object.. k:{%s}, v:{%s}, t:{%d} -> %f\n", key.c_str(), token.symbol.c_str(), (int)token.type, std::stod(token.symbol)); + object.emplace(key, Value { std::stod(token.symbol) }); + break; + case Token::Type::String: + printf("Adding string to object.. k:{%s}, v:{%s}, t:{%d}\n", key.c_str(), token.symbol.c_str(), (int)token.type); + object.emplace(key, Value { token.symbol }); + break; + case Token::Type::BracketOpen: + m_index--; + object.emplace(key, Value { getArray() }); + break; + case Token::Type::BraceOpen: + m_index--; + object.emplace(key, Value { getObject() }); + break; + default: + // Error! + printf("Invalid JSON! 5\n"); + break; + } + + // Find , or } + token = consume(); + if (token.type == Token::Type::Comma) { + continue; + } + else if (token.type == Token::Type::BraceClose) { + break; + } + else { + // Error! + printf("Invalid JSON! 6\n"); + break; + } + } + + return Value { object }; +} + +} // namespace Json diff --git a/src/util/json/parser.h b/src/util/json/parser.h new file mode 100644 index 0000000..763872e --- /dev/null +++ b/src/util/json/parser.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#ifndef JSON_PARSER_H +#define JSON_PARSER_H + +#include // size_t +#include +#include +#include +#include +#include + +#include "util/json/lexer.h" +#include "util/json/value.h" + +namespace Json { + +class Parser { +public: + Parser(const std::string& input); + virtual ~Parser(); + + void parse(); + +private: + Token peek(); + + Token consume(); + bool consumeSpecific(Token::Type type); + + Value getArray(); + Value getObject(); + + std::string m_input; + + std::vector m_tokens; + size_t m_index { 0 }; +}; + +} // namespace Json + +#endif // JSON_PARSER_H