From 00893b3cfc68f12c09e84643d255044a488b0eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 22 Jan 2013 05:56:12 +0100 Subject: Instance model (or at least something like it) --- .../property_tree/detail/json_parser_read.hpp | 333 +++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 hacks/boost/property_tree/detail/json_parser_read.hpp (limited to 'hacks/boost/property_tree') diff --git a/hacks/boost/property_tree/detail/json_parser_read.hpp b/hacks/boost/property_tree/detail/json_parser_read.hpp new file mode 100644 index 00000000..9a22e75b --- /dev/null +++ b/hacks/boost/property_tree/detail/json_parser_read.hpp @@ -0,0 +1,333 @@ +// ---------------------------------------------------------------------------- +// Copyright (C) 2002-2006 Marcin Kalicinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org +// ---------------------------------------------------------------------------- +#ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED +#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED + +//#define BOOST_SPIRIT_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace property_tree { namespace json_parser +{ + + /////////////////////////////////////////////////////////////////////// + // Json parser context + + template + struct context + { + + typedef typename Ptree::key_type::value_type Ch; + typedef std::basic_string Str; + typedef typename std::vector::iterator It; + + Str string; + Str name; + Ptree root; + std::vector stack; + + struct a_object_s + { + context &c; + a_object_s(context &c): c(c) { } + void operator()(Ch) const + { + if (c.stack.empty()) + c.stack.push_back(&c.root); + else + { + Ptree *parent = c.stack.back(); + Ptree *child = &parent->push_back(std::make_pair(c.name, Ptree()))->second; + c.stack.push_back(child); + c.name.clear(); + } + } + }; + + struct a_object_e + { + context &c; + a_object_e(context &c): c(c) { } + void operator()(Ch) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.pop_back(); + } + }; + + struct a_name + { + context &c; + a_name(context &c): c(c) { } + void operator()(It, It) const + { + c.name.swap(c.string); + c.string.clear(); + } + }; + + struct a_string_val + { + context &c; + a_string_val(context &c): c(c) { } + void operator()(It, It) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.back()->push_back(std::make_pair(c.name, Ptree(c.string))); + c.name.clear(); + c.string.clear(); + } + }; + + struct a_literal_val + { + context &c; + a_literal_val(context &c): c(c) { } + void operator()(It b, It e) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.back()->push_back(std::make_pair(c.name, + Ptree(Str(b, e)))); + c.name.clear(); + c.string.clear(); + } + }; + + struct a_char + { + context &c; + a_char(context &c): c(c) { } + void operator()(It b, It e) const + { + c.string += *b; + } + }; + + struct a_escape + { + context &c; + a_escape(context &c): c(c) { } + void operator()(Ch ch) const + { + switch (ch) + { + case Ch('\"'): c.string += Ch('\"'); break; + case Ch('\\'): c.string += Ch('\\'); break; + case Ch('/'): c.string += Ch('/'); break; + case Ch('b'): c.string += Ch('\b'); break; + case Ch('f'): c.string += Ch('\f'); break; + case Ch('n'): c.string += Ch('\n'); break; + case Ch('r'): c.string += Ch('\r'); break; + case Ch('t'): c.string += Ch('\t'); break; + default: BOOST_ASSERT(0); + } + } + }; + + struct a_unicode + { + context &c; + a_unicode(context &c): c(c) { } + void operator()(unsigned long u) const + { + //u = (std::min)(u, static_cast((std::numeric_limits::max)())); + c.string += Ch(u); + } + }; + + }; + + /////////////////////////////////////////////////////////////////////// + // Json grammar + + template + struct json_grammar : + public boost::spirit::classic::grammar > + { + + typedef context Context; + typedef typename Ptree::key_type::value_type Ch; + + mutable Context c; + + template + struct definition + { + + boost::spirit::classic::rule + root, object, member, array, item, value, string, number; + boost::spirit::classic::rule< + typename boost::spirit::classic::lexeme_scanner::type> + character, escape; + + definition(const json_grammar &self) + { + + using namespace boost::spirit::classic; + // There's a boost::assertion too, so another explicit using + // here: + using boost::spirit::classic::assertion; + + // Assertions + assertion expect_root("expected object or array"); + assertion expect_eoi("expected end of input"); + assertion expect_objclose("expected ',' or '}'"); + assertion expect_arrclose("expected ',' or ']'"); + assertion expect_name("expected object name"); + assertion expect_colon("expected ':'"); + assertion expect_value("expected value"); + assertion expect_escape("invalid escape sequence"); + + // JSON grammar rules + root + = expect_root(object | array) + >> expect_eoi(end_p) + ; + + object + = ch_p('{')[typename Context::a_object_s(self.c)] + >> (ch_p('}')[typename Context::a_object_e(self.c)] + | (list_p(member, ch_p(',')) + >> expect_objclose(ch_p('}')[typename Context::a_object_e(self.c)]) + ) + ) + ; + + member + = expect_name(string[typename Context::a_name(self.c)]) + >> expect_colon(ch_p(':')) + >> expect_value(value) + ; + + array + = ch_p('[')[typename Context::a_object_s(self.c)] + >> (ch_p(']')[typename Context::a_object_e(self.c)] + | (list_p(item, ch_p(',')) + >> expect_arrclose(ch_p(']')[typename Context::a_object_e(self.c)]) + ) + ) + ; + + item + = expect_value(value) + ; + + value + = string[typename Context::a_string_val(self.c)] + | (number | str_p("true") | "false" | "null")[typename Context::a_literal_val(self.c)] + | object + | array + ; + + number + = !ch_p("-") >> + (ch_p("0") | (range_p(Ch('1'), Ch('9')) >> *digit_p)) >> + !(ch_p(".") >> +digit_p) >> + !(chset_p(detail::widen("eE").c_str()) >> + !chset_p(detail::widen("-+").c_str()) >> + +digit_p) + ; + + string + = +(lexeme_d[confix_p('\"', *character, '\"')]) + ; + + character + = (anychar_p - "\\" - "\"") + [typename Context::a_char(self.c)] + | ch_p("\\") >> expect_escape(escape) + ; + + escape + = chset_p(detail::widen("\"\\/bfnrt").c_str()) + [typename Context::a_escape(self.c)] + | 'u' >> uint_parser() + [typename Context::a_unicode(self.c)] + ; + + // Debug + BOOST_SPIRIT_DEBUG_RULE(root); + BOOST_SPIRIT_DEBUG_RULE(object); + BOOST_SPIRIT_DEBUG_RULE(member); + BOOST_SPIRIT_DEBUG_RULE(array); + BOOST_SPIRIT_DEBUG_RULE(item); + BOOST_SPIRIT_DEBUG_RULE(value); + BOOST_SPIRIT_DEBUG_RULE(string); + BOOST_SPIRIT_DEBUG_RULE(number); + BOOST_SPIRIT_DEBUG_RULE(escape); + BOOST_SPIRIT_DEBUG_RULE(character); + + } + + const boost::spirit::classic::rule &start() const + { + return root; + } + + }; + + }; + + template + unsigned long count_lines(It begin, It end) + { + return static_cast(std::count(begin, end, Ch('\n')) + 1); + } + + template + void read_json_internal(std::basic_istream &stream, + Ptree &pt, + const std::string &filename) + { + + using namespace boost::spirit::classic; + typedef typename Ptree::key_type::value_type Ch; + typedef typename std::vector::iterator It; + + // Load data into vector + std::vector v(std::istreambuf_iterator(stream.rdbuf()), + std::istreambuf_iterator()); + if (!stream.good()) + BOOST_PROPERTY_TREE_THROW(json_parser_error("read error", filename, 0)); + + // Prepare grammar + json_grammar g; + + // Parse + try + { + parse_info pi = parse(v.begin(), v.end(), g, + space_p | comment_p("//") | comment_p("/*", "*/")); + if (!pi.hit || !pi.full) + BOOST_PROPERTY_TREE_THROW((parser_error(v.begin(), "syntax error"))); + } + catch (parser_error &e) + { + BOOST_PROPERTY_TREE_THROW(json_parser_error(e.descriptor, filename, count_lines(v.begin(), e.where))); + } + + // Swap grammar context root and pt + pt.swap(g.c.root); + + } + +} } } + +#endif + -- cgit v1.2.3