47#include "../include/JsonParser.h"
63 void skipWhitespace(std::istream& stream)
65 while (!stream.eof() && std::isspace(stream.peek())) {
70 void matchCharacter(std::istream& stream, std::istream::int_type expected)
72 auto actual = stream.get();
74 if (actual != expected) {
75 std::ostringstream what;
76 what <<
"Expected '" <<
static_cast<char>(expected) <<
"' but found '" <<
static_cast<char>(actual) <<
"' (0x" << std::hex << actual <<
")";
77 throw std::runtime_error(what.str());
81 void matchText(std::istream& stream, std::string
const& text)
83 for (
auto ch : text) {
84 matchCharacter(stream, ch);
89 static std::shared_ptr<Value> readValue(std::istream& stream);
93 Value(Node::Type type) : type(type) {}
103 String(std::istream& stream) :
Value(Node::Type::string)
105 matchCharacter(stream,
'"');
106 auto ch = stream.get();
110 throw std::logic_error(
"JSON parser: string escaping not implemented");
112 value.push_back(
static_cast<char>(ch));
122 Number(std::istream& stream) :
Value(Node::Type::number)
132 Object(std::istream& stream) :
Value(Node::Type::object)
134 matchCharacter(stream,
'{');
135 skipWhitespace(stream);
137 while (stream.peek() !=
'}') {
138 if (!value.empty()) {
139 matchCharacter(stream,
',');
140 skipWhitespace(stream);
143 auto key =
String(stream);
144 skipWhitespace(stream);
145 matchCharacter(stream,
':');
146 skipWhitespace(stream);
147 value[key.value] = readValue(stream);
148 skipWhitespace(stream);
154 std::map<std::string, std::shared_ptr<Value>> value;
159 Array(std::istream& stream) :
Value(Node::Type::array)
161 matchCharacter(stream,
'[');
162 skipWhitespace(stream);
164 if (stream.peek() !=
']') {
165 value.push_back(readValue(stream));
166 skipWhitespace(stream);
168 while (stream.peek() ==
',') {
170 value.push_back(readValue(stream));
171 skipWhitespace(stream);
175 matchCharacter(stream,
']');
178 std::vector<std::shared_ptr<Value>> value;
184 Bool(std::istream& stream) :
Value(Node::Type::boolean)
186 value = stream.peek() ==
't';
187 matchText(stream, value ?
"true" :
"false");
199 matchText(stream,
"null");
206 stream.exceptions(std::ios::badbit | std::ios::failbit);
207 auto value = readValue(stream);
208 skipWhitespace(stream);
211 auto ch = stream.get();
212 std::ostringstream what;
213 what <<
"Stray character " <<
static_cast<char>(ch) <<
" (0x" << std::ios::hex << ch <<
")";
214 throw std::runtime_error(what.str());
219 catch (std::runtime_error& e) {
220 throw std::runtime_error(std::string(
"JSON parser: ") + e.what());
222 catch (std::exception& e) {
223 throw std::logic_error(std::string(
"JSON parser bug: ") + e.what());
227 void Node::setOverrides(
Node overrides)
229 assert(type() == Type::object && overrides.
type() == Type::object);
230 m_overrides = std::dynamic_pointer_cast<Object>(overrides.m_value);
235 return m_value->type;
242 return{ m_overrides->value.at(key) };
244 catch (std::out_of_range&) {}
247 return{
dynamic_cast<Object&
>(*m_value).value.at(key) };
249 catch (std::out_of_range&) {
250 return{ std::make_shared<Null>() };
252 catch (std::bad_cast&) {
253 std::ostringstream what;
254 what <<
"JSON parser: Querying optional key '" << key <<
"', but node is not an object";
255 throw std::runtime_error(what.str());
264 std::ostringstream stream;
265 stream <<
"JSON parser: Parameter " << key <<
" is required but missing";
266 throw std::runtime_error(stream.str());
271 if (
type() != Type::array) {
272 throw std::runtime_error(
"JSON parser: Expected an array");
274 return{
dynamic_cast<Array&
>(*m_value).value.at(index) };
281 return dynamic_cast<Array&
>(*m_value).value.size();
283 return dynamic_cast<Object&
>(*m_value).value.size();
285 throw std::runtime_error(
"JSON parser: Expected an array or object");
292 if (
type() != Type::number) {
293 throw std::runtime_error(
"JSON parser: Expected a number");
295 return dynamic_cast<Number&
>(*m_value).value;
300 return static_cast<float>(
asDouble());
306 auto rounded =
static_cast<int>(std::lround(value));
307 auto error = value - rounded;
309 throw std::runtime_error(
"JSON parser: Expected an integer value");
316 if (
type() != Type::string) {
317 throw std::runtime_error(
"JSON parser: Expected a string");
319 return dynamic_cast<String&
>(*m_value).value;
324 if (
type() != Type::boolean) {
325 throw std::runtime_error(
"JSON parser: Expected a boolean");
327 return dynamic_cast<Bool&
>(*m_value).value;
330 Node::operator bool()
const
346 Node::Node(std::shared_ptr<Value> value)
350 static std::shared_ptr<Value> readValue(std::istream& stream)
352 skipWhitespace(stream);
353 auto ch = stream.peek();
356 case '{':
return std::make_shared<Object>(stream);
357 case '[':
return std::make_shared<Array>(stream);
358 case '"':
return std::make_shared<String>(stream);
359 case 't':
return std::make_shared<Bool>(stream);
360 case 'f':
return std::make_shared<Bool>(stream);
361 case 'n':
return std::make_shared<Null>(stream);
365 if (ch ==
'-' || std::isdigit(ch)) {
366 return std::make_shared<Number>(stream);
369 std::ostringstream what;
370 what <<
"Invalid character " <<
static_cast<char>(ch) <<
" (0x" << std::ios::hex << ch <<
")";
371 throw std::runtime_error(what.str());
Node optional(std::string const &key) const
std::string const & asString() const
Node require(std::string const &key) const
Node at(std::size_t index) const
static Node readFrom(std::istream &)