#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "cppjson.hpp"
using std::isdigit;
using std::logic_error;
using std::pair;
using std::string;
pair parseJSON(const string &input, string::size_type index);
pair parseJSONObject(const string &input, string::size_type index);
pair parseJSONArray(const string &input, string::size_type index);
pair parseStringLiteral(const string &input, string::size_type index);
pair parseJSONNumber(const string &input, string::size_type index);
string::size_type expectString(const string &input, string::size_type index, const string &keyword);
string::size_type skipWhitespaces(const string &input, string::size_type index);
inline bool isHexLiteral(const string &input, string::size_type index);
inline bool isOctalLiteral(const string &input, string::size_type index);
std::pair parseUTF16EscapedValue(const string &input, string::size_type index);
inline bool isLeadSurrogate(char16_t v);
inline bool isTrailSurrogate(char16_t v);
char32_t calculateCodepoint(char16_t leadSurroatge, char16_t trailSurrogate);
void writeAsUTF8CodeUnits(std::ostringstream &oss, char32_t codepoint);
void writeHexValueToBuffer(char buf[], const string &input, string::size_type index);
JSON parse(const string &str)
{
auto result = parseJSON(str, 0);
auto end = skipWhitespaces(str, result.second);
if (end != str.size())
throw SyntaxError();
return result.first;
}
pair parseJSON(const string &input, string::size_type index)
{
index = skipWhitespaces(input, index);
auto ch = input[index];
if (ch == '{')
return parseJSONObject(input, index);
else if (ch == '[')
return parseJSONArray(input, index);
else if (ch == '"')
{
auto result = parseStringLiteral(input, index);
return std::make_pair(JSON(result.first), result.second);
}
else if (isdigit(ch) || ch == '-')
return parseJSONNumber(input, index);
else if (ch == 't')
{
index = expectString(input, index, "true");
return std::make_pair(JSON(true), index);
}
else if (ch == 'f')
{
index = expectString(input, index, "false");
return std::make_pair(JSON(false), index);
}
else if (ch == 'n')
{
index = expectString(input, index, "null");
return std::make_pair(JSON(nullptr), index);
}
else
throw SyntaxError();
}
// The program looked ahead the next character first, and confirmed the what
// JSON value would be next, before it actually calls the function to parse a
// value, so the initial `index` value must points to the first character of
// a JSON value, hence we can simply skip it without checking.
pair parseJSONObject(const string &input, string::size_type index)
{
std::map result;
index = skipWhitespaces(input, index + 1);
if (index == input.size())
throw SyntaxError();
if (input[index] == '}')
return std::make_pair(JSON(result), index + 1);
while (true)
{
index = skipWhitespaces(input, index);
auto objectKey = parseStringLiteral(input, index);
index = skipWhitespaces(input, objectKey.second);
index = expectString(input, index, ":");
index = skipWhitespaces(input, index);
auto objectValue = parseJSON(input, index);
index = skipWhitespaces(input, objectValue.second);
if (input[index] == '}')
{
result[objectKey.first] = objectValue.first;
return std::make_pair(JSON(result), index + 1);
}
else if (input[index] == ',')
{
result[objectKey.first] = objectValue.first;
index++;
}
else
throw SyntaxError();
}
throw SyntaxError();
}
pair parseJSONArray(const string &input, string::size_type index)
{
std::vector result;
index = skipWhitespaces(input, index + 1);
if (index == input.size())
throw SyntaxError();
if (input[index] == ']')
return std::make_pair(JSON(result), index + 1);
while (true)
{
auto jsonVal = parseJSON(input, index);
index = skipWhitespaces(input, jsonVal.second);
if (index == input.size())
throw SyntaxError();
else if (input[index] == ']')
{
result.push_back(jsonVal.first);
return std::make_pair(JSON(result), index + 1);
}
else if (input[index] == ',')
{
result.push_back(jsonVal.first);
index = skipWhitespaces(input, index + 1);
}
else
throw SyntaxError();
}
}
pair parseStringLiteral(const string &input, string::size_type index)
{
// Skip the double-quote at the begining
index++;
string::size_type start = index;
std::ostringstream oss;
while (index != input.size())
{
if (input[index] == '\\')
{
if (index + 1 >= input.size())
throw SyntaxError();
oss