summaryrefslogtreecommitdiff
path: root/json.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'json.cpp')
-rw-r--r--json.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/json.cpp b/json.cpp
new file mode 100644
index 0000000..0277cce
--- /dev/null
+++ b/json.cpp
@@ -0,0 +1,131 @@
+#include "json.h"
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+
+namespace qi = boost::spirit::qi;
+
+using namespace JSON;
+
+bool JSON::parse(const std::string& s, Value& v) {
+ typedef std::string::const_iterator Iterator;
+
+ qi::rule<Iterator, bool()> bool_p = qi::lit("false")[qi::_val = false] | qi::lit("true")[qi::_val = true];
+
+ qi::rule<Iterator, boost::variant<int, float>()> number_p = (qi::int_ >> !(qi::lit('.') | 'e' | 'E')) | qi::float_;
+
+ qi::rule<Iterator, char()> char_p = (qi::char_ - '\"' - '\\') | '\\' >> (
+ qi::char_('\"') |
+ qi::char_('\\') |
+ qi::char_('/') |
+ 'b' >> qi::attr('\b') |
+ 'f' >> qi::attr('\f') |
+ 'n' >> qi::attr('\n') |
+ 'r' >> qi::attr('\r') |
+ 't' >> qi::attr('\t')
+ );
+
+ qi::rule<Iterator, std::string()> string_p = '\"' >> *(char_p) >> '\"';
+
+ qi::rule<Iterator, Value()> value_p;
+
+ qi::rule<Iterator, Array()> array_p = '[' >> -(value_p % ',') >> ']';
+
+ qi::rule<Iterator, std::pair<std::string, Value>()> key_value_p = string_p >> ":" >> value_p;
+ qi::rule<Iterator, Object()> object_p = '{' >> -(key_value_p % ',') >> '}';
+
+ value_p = qi::omit[*qi::space] >> (bool_p | number_p | string_p | array_p | object_p) >> qi::omit[*qi::space];
+
+ return qi::parse(s.begin(), s.end(), value_p, v);
+}
+
+struct generate : public boost::static_visitor<std::ostream&> {
+ std::ostream& stream;
+ generate(std::ostream& s) : stream(s) {}
+
+ std::ostream& operator()(const bool& x) const {
+ return stream << (x ? "true" : "false");
+ }
+
+ std::ostream& operator()(const int& x) const {
+ return stream << x;
+ }
+
+ std::ostream& operator()(const float& x) const {
+ return stream << x;
+ }
+
+ std::ostream& operator()(const std::string& x) const {
+ stream << '\"';
+ for(std::string::const_iterator it = x.begin(); it != x.end(); it++) {
+ switch(*it) {
+ case '\"':
+ case '\\':
+ case '/':
+ stream << '\\' << *it;
+ break;
+
+ case '\b':
+ stream << "\\b";
+ break;
+
+ case '\f':
+ stream << "\\f";
+ break;
+
+ case '\n':
+ stream << "\\n";
+ break;
+
+ case '\r':
+ stream << "\\r";
+ break;
+
+ case '\t':
+ stream << "\\t";
+ break;
+
+ default:
+ stream << *it;
+ }
+ }
+ return stream << '\"';
+ }
+
+ std::ostream& operator()(const Array& x) const {
+ stream << "[";
+ for(Array::const_iterator it = x.begin();;) {
+ boost::apply_visitor(generate(stream), *it);
+
+ if(++it == x.end()) {
+ break;
+ }
+
+ stream << ", ";
+ }
+ return stream << "]";
+ }
+
+ std::ostream& operator()(const Object& x) const {
+ stream << "{";
+ for(Object::const_iterator it = x.begin();;) {
+ (*this)(it->first);
+
+ stream << ": ";
+
+ boost::apply_visitor(generate(stream), it->second);
+
+ if(++it == x.end()) {
+ break;
+ }
+
+ stream << ", ";
+ }
+ return stream << "}";
+ }
+};
+
+std::ostream& operator<<(std::ostream& s, const Value& v) {
+ return boost::apply_visitor(generate(s), v);
+}