Riyyi
3 years ago
2 changed files with 323 additions and 0 deletions
@ -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
|
@ -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…
Reference in new issue