fix doc example typo
[boost.git] / boost / property_tree / detail / json_parser_read.hpp
blob9c01d8b1e20cf5d216af04715f9c9d31e154dede
1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED
11 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED
13 //#define BOOST_SPIRIT_DEBUG
15 #include <boost/property_tree/ptree.hpp>
16 #include <boost/property_tree/detail/ptree_utils.hpp>
17 #include <boost/property_tree/detail/json_parser_error.hpp>
18 #include <boost/spirit.hpp>
19 #include <boost/limits.hpp>
20 #include <string>
21 #include <locale>
22 #include <istream>
23 #include <vector>
24 #include <algorithm>
26 namespace boost { namespace property_tree { namespace json_parser
29 ///////////////////////////////////////////////////////////////////////
30 // Json parser context
32 template<class Ptree>
33 struct context
36 typedef typename Ptree::key_type::value_type Ch;
37 typedef std::basic_string<Ch> Str;
38 typedef typename std::vector<Ch>::iterator It;
40 Str string;
41 Str name;
42 Ptree root;
43 std::vector<Ptree *> stack;
45 struct a_object_s
47 context &c;
48 a_object_s(context &c): c(c) { }
49 void operator()(Ch) const
51 if (c.stack.empty())
52 c.stack.push_back(&c.root);
53 else
55 Ptree *parent = c.stack.back();
56 Ptree *child = &parent->push_back(std::make_pair(c.name, Ptree()))->second;
57 c.stack.push_back(child);
58 c.name.clear();
63 struct a_object_e
65 context &c;
66 a_object_e(context &c): c(c) { }
67 void operator()(Ch) const
69 BOOST_ASSERT(c.stack.size() >= 1);
70 c.stack.pop_back();
74 struct a_name
76 context &c;
77 a_name(context &c): c(c) { }
78 void operator()(It, It) const
80 c.name.swap(c.string);
81 c.string.clear();
85 struct a_string_val
87 context &c;
88 a_string_val(context &c): c(c) { }
89 void operator()(It, It) const
91 BOOST_ASSERT(c.stack.size() >= 1);
92 c.stack.back()->push_back(std::make_pair(c.name, Ptree(c.string)));
93 c.name.clear();
94 c.string.clear();
98 struct a_literal_val
100 context &c;
101 a_literal_val(context &c): c(c) { }
102 void operator()(It b, It e) const
104 BOOST_ASSERT(c.stack.size() >= 1);
105 c.stack.back()->push_back(std::make_pair(c.name, Str(b, e)));
106 c.name.clear();
107 c.string.clear();
111 struct a_char
113 context &c;
114 a_char(context &c): c(c) { }
115 void operator()(It b, It e) const
117 c.string += *b;
121 struct a_escape
123 context &c;
124 a_escape(context &c): c(c) { }
125 void operator()(Ch ch) const
127 switch (ch)
129 case Ch('\"'): c.string += Ch('\"'); break;
130 case Ch('\\'): c.string += Ch('\\'); break;
131 case Ch('0'): c.string += Ch('\0'); break;
132 case Ch('b'): c.string += Ch('\b'); break;
133 case Ch('f'): c.string += Ch('\f'); break;
134 case Ch('n'): c.string += Ch('\n'); break;
135 case Ch('r'): c.string += Ch('\r'); break;
136 case Ch('t'): c.string += Ch('\t'); break;
137 default: BOOST_ASSERT(0);
142 struct a_unicode
144 context &c;
145 a_unicode(context &c): c(c) { }
146 void operator()(unsigned long u) const
148 u = (std::min)(u, static_cast<unsigned long>((std::numeric_limits<Ch>::max)()));
149 c.string += Ch(u);
155 ///////////////////////////////////////////////////////////////////////
156 // Json grammar
158 template<class Ptree>
159 struct json_grammar: public boost::spirit::grammar<json_grammar<Ptree> >
162 typedef context<Ptree> Context;
163 typedef typename Ptree::key_type::value_type Ch;
165 mutable Context c;
167 template<class Scanner>
168 struct definition
171 boost::spirit::rule<Scanner> root, object, member, array, item, value, string, number;
172 boost::spirit::rule<typename boost::spirit::lexeme_scanner<Scanner>::type> character, escape;
174 definition(const json_grammar &self)
177 using namespace boost::spirit;
179 // Assertions
180 assertion<std::string> expect_object("expected object");
181 assertion<std::string> expect_eoi("expected end of input");
182 assertion<std::string> expect_objclose("expected ',' or '}'");
183 assertion<std::string> expect_arrclose("expected ',' or ']'");
184 assertion<std::string> expect_name("expected object name");
185 assertion<std::string> expect_colon("expected ':'");
186 assertion<std::string> expect_value("expected value");
187 assertion<std::string> expect_escape("invalid escape sequence");
189 // JSON grammar rules
190 root
191 = expect_object(object)
192 >> expect_eoi(end_p)
195 object
196 = ch_p('{')[typename Context::a_object_s(self.c)]
197 >> (ch_p('}')[typename Context::a_object_e(self.c)]
198 | (list_p(member, ch_p(','))
199 >> expect_objclose(ch_p('}')[typename Context::a_object_e(self.c)])
204 member
205 = expect_name(string[typename Context::a_name(self.c)])
206 >> expect_colon(ch_p(':'))
207 >> expect_value(value)
210 array
211 = ch_p('[')[typename Context::a_object_s(self.c)]
212 >> (ch_p(']')[typename Context::a_object_e(self.c)]
213 | (list_p(item, ch_p(','))
214 >> expect_arrclose(ch_p(']')[typename Context::a_object_e(self.c)])
219 item
220 = expect_value(value)
223 value
224 = string[typename Context::a_string_val(self.c)]
225 | (number | str_p("true") | "false" | "null")[typename Context::a_literal_val(self.c)]
226 | object
227 | array
230 number
231 = strict_real_p
232 | int_p
235 string
236 = +(lexeme_d[confix_p('\"', *character, '\"')])
239 character
240 = (anychar_p - "\\" - "\"")[typename Context::a_char(self.c)]
241 | ch_p("\\") >> expect_escape(escape)
244 escape
245 = chset_p(detail::widen<Ch>("\"\\0bfnrt").c_str())[typename Context::a_escape(self.c)]
246 | 'u' >> uint_parser<unsigned long, 16, 4, 4>()[typename Context::a_unicode(self.c)]
249 // Debug
250 BOOST_SPIRIT_DEBUG_RULE(root);
251 BOOST_SPIRIT_DEBUG_RULE(object);
252 BOOST_SPIRIT_DEBUG_RULE(member);
253 BOOST_SPIRIT_DEBUG_RULE(array);
254 BOOST_SPIRIT_DEBUG_RULE(item);
255 BOOST_SPIRIT_DEBUG_RULE(value);
256 BOOST_SPIRIT_DEBUG_RULE(string);
257 BOOST_SPIRIT_DEBUG_RULE(number);
258 BOOST_SPIRIT_DEBUG_RULE(escape);
259 BOOST_SPIRIT_DEBUG_RULE(character);
263 const boost::spirit::rule<Scanner> &start() const
265 return root;
272 template<class It, class Ch>
273 unsigned long count_lines(It begin, It end)
275 return static_cast<unsigned long>(std::count(begin, end, Ch('\n')) + 1);
278 template<class Ptree>
279 void read_json_internal(std::basic_istream<typename Ptree::key_type::value_type> &stream,
280 Ptree &pt,
281 const std::string &filename)
284 using namespace boost::spirit;
285 typedef typename Ptree::key_type::value_type Ch;
286 typedef typename std::vector<Ch>::iterator It;
288 // Load data into vector
289 std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
290 std::istreambuf_iterator<Ch>());
291 if (!stream.good())
292 BOOST_PROPERTY_TREE_THROW(json_parser_error("read error", filename, 0));
294 // Prepare grammar
295 json_grammar<Ptree> g;
297 // Parse
300 parse_info<It> pi = parse(v.begin(), v.end(), g,
301 space_p | comment_p("//") | comment_p("/*", "*/"));
302 if (!pi.hit || !pi.full)
303 BOOST_PROPERTY_TREE_THROW((parser_error<std::string, It>(v.begin(), "syntax error")));
305 catch (parser_error<std::string, It> &e)
307 BOOST_PROPERTY_TREE_THROW(json_parser_error(e.descriptor, filename, count_lines<It, Ch>(v.begin(), e.where)));
310 // Swap grammar context root and pt
311 pt.swap(g.c.root);
315 } } }
317 #endif