summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--json.cpp131
-rw-r--r--json.h32
2 files changed, 163 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);
+}
diff --git a/json.h b/json.h
new file mode 100644
index 0000000..0e18911
--- /dev/null
+++ b/json.h
@@ -0,0 +1,32 @@
+#ifndef JSON_H
+#define JSON_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+
+#include <boost/variant.hpp>
+
+namespace JSON {
+ // TODO: Support null.
+ typedef boost::make_recursive_variant<
+ bool,
+ int,
+ float,
+ std::string,
+ std::vector<boost::recursive_variant_ >,
+ std::map<std::string, boost::recursive_variant_ >
+ >::type Value;
+
+ typedef std::vector<Value> Array;
+ typedef std::map<std::string, Value> Object;
+
+ //! Parse JSON string into value-tree.
+ bool parse(const std::string& s, Value& v);
+};
+
+//! Write JSON to stream.
+std::ostream& operator<<(std::ostream& s, const JSON::Value& v);
+
+#endif