Browse Source

Util: Add JSON parser

master
Riyyi 3 years ago
parent
commit
5188d57d19
  1. 277
      src/util/json/parser.cpp
  2. 46
      src/util/json/parser.h

277
src/util/json/parser.cpp

@ -0,0 +1,277 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <cstdio> // printf
#include <map>
#include <string> // 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<std::string, uint32_t> 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

46
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 <cstddef> // size_t
#include <map>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <vector>
#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<Token> m_tokens;
size_t m_index { 0 };
};
} // namespace Json
#endif // JSON_PARSER_H
Loading…
Cancel
Save