2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-19 04:22:13 +00:00

Json basic test passing

This commit is contained in:
Joel de Guzman
2011-11-09 17:56:03 +08:00
parent 662edc877d
commit e1316604bd
10 changed files with 440 additions and 21 deletions

100
test/json_test.cpp Normal file
View File

@@ -0,0 +1,100 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
*/
#include "../yaml/parser/flow_def.hpp"
#include "../yaml/parser/scalar_def.hpp"
#include <iostream>
#include <fstream>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
namespace
{
template <typename Char>
bool parse(
std::basic_istream<Char>& is,
omd::ast::value_t& result,
std::string const& source_file = "")
{
// no white space skipping in the stream!
is.unsetf(std::ios::skipws);
typedef
boost::spirit::basic_istream_iterator<Char>
stream_iterator_type;
stream_iterator_type sfirst(is);
stream_iterator_type slast;
typedef boost::spirit::line_pos_iterator<stream_iterator_type>
iterator_type;
iterator_type first(sfirst);
iterator_type last(slast);
omd::parser::flow<iterator_type> p(source_file);
omd::parser::white_space<iterator_type> ws;
using boost::spirit::qi::phrase_parse;
return phrase_parse(first, last, p, ws, result);
}
}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename = NULL;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
// Ignore the BOM marking the beginning of a UTF-8 file in Windows
char c = in.peek();
if (c == '\xef')
{
char s[3];
in >> s[0] >> s[1] >> s[2];
s[3] = '\0';
if (s != std::string("\xef\xbb\xbf"))
{
std::cerr << "Error: Unexpected characters from input file: "
<< filename << std::endl;
return 1;
}
}
using omd::ast::value_t;
namespace qi = boost::spirit::qi;
value_t result;
if (parse(in, result, filename))
{
std::cout << "success: ";
//~ println(std::cout, result);
std::cout << std::endl;
}
else
{
std::cout << "parse error" << std::endl;
}
return 0;
}

View File

@@ -1,4 +1,8 @@
#include "../yaml/parser/scalar_def.hpp"
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
*/
#include "../yaml/parser/scalar_def.hpp"
#include <boost/detail/lightweight_test.hpp>
namespace

View File

@@ -0,0 +1,14 @@
[
123.45,
true,
false,
0xFF,
077,
"this is a unicode \u20AC string",
"Τη γλώσσα μου έδωσαν ελληνική",
12345,
[
92,
["another string", "apple", "Sîne"]
]
]

View File

@@ -3,8 +3,8 @@
* consultomd.com
*
*/
#ifndef OMD_JSON_VALUE_HPP
#define OMD_JSON_VALUE_HPP
#ifndef OMD_AST_VALUE_HPP
#define OMD_AST_VALUE_HPP
#include <string>
#include <map>
@@ -20,14 +20,14 @@ namespace omd { namespace ast
typedef int int_t;
typedef bool bool_t;
struct null_t
{
// nulls always compare
bool operator==(const null_t&) const{ return true; }
bool operator!=(const null_t&) const{ return false; }
};
{};
// nulls always compare
inline bool operator==(null_t a, null_t b) { return true; }
inline bool operator!=(null_t a, null_t b) { return false; }
struct value_t;
typedef std::map<std::string, value_t> object_t;
typedef std::map<value_t, value_t> object_t;
typedef std::vector<value_t> array_t;
struct value_t
@@ -37,7 +37,8 @@ namespace omd { namespace ast
string_t,
double_t,
int_t,
object_t
object_t,
array_t
>
{
value_t(string_t const& val) : base_type(val) {}
@@ -45,12 +46,19 @@ namespace omd { namespace ast
value_t(int_t val) : base_type(val) {}
value_t(bool_t val) : base_type(val) {}
value_t(null_t val = null_t()) : base_type(val) {}
value_t(object_t const& val) : base_type(val) {}
value_t(array_t const& val) : base_type(val) {}
value_t(value_t const& rhs)
: base_type(rhs.get()) {}
};
bool operator==(value_t const& a, value_t const& b);
bool operator!=(value_t const& a, value_t const& b);
bool operator<(value_t const& a, value_t const& b);
// ---------------------------------------------------
}}
#include "detail/ast_impl.hpp"
#endif

108
yaml/detail/ast_impl.hpp Normal file
View File

@@ -0,0 +1,108 @@
/**
* Copyright (C) 2010, 2011 Michael Caisse, Object Modeling Designs
* consultomd.com
*
*/
#ifndef OMD_AST_VALUE_IMPL_HPP
#define OMD_AST_VALUE_IMPL_HPP
#include "../ast.hpp"
#include <algorithm>
namespace omd { namespace ast
{
namespace detail
{
struct value_equal
{
typedef bool result_type;
template <typename A, typename B>
bool operator()(A const& a, B const& b) const
{
BOOST_ASSERT(false); // this should not happen. We cannot compare different types
return false;
}
template <typename T>
bool operator()(T const& a, T const& b) const
{
return a == b;
}
bool operator()(object_t const& a, object_t const& b)
{
if (a.size() != b.size())
return false;
object_t::const_iterator ii = b.begin();
for (object_t::const_iterator i = a.begin(); i != a.end(); ++i)
{
if (*i != *ii++)
return false;
}
return true;
}
bool operator()(array_t const& a, array_t const& b)
{
if (a.size() != b.size())
return false;
array_t::const_iterator ii = b.begin();
for (array_t::const_iterator i = a.begin(); i != a.end(); ++i)
{
if (*i != *ii++)
return false;
}
return true;
}
};
}
inline bool operator==(value_t const& a, value_t const& b)
{
return boost::apply_visitor(detail::value_equal(), a.get(), b.get());
}
inline bool operator!=(value_t const& a, value_t const& b)
{
return !(a == b);
}
namespace detail
{
struct value_compare
{
typedef bool result_type;
template <typename A, typename B>
bool operator()(A const& a, B const& b) const
{
BOOST_ASSERT(false); // this should not happen. We cannot compare different types
return false;
}
template <typename T>
bool operator()(T const& a, T const& b) const
{
return a < b;
}
bool operator()(object_t const& a, object_t const& b)
{
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
bool operator()(array_t const& a, array_t const& b)
{
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
};
}
inline bool operator<(value_t const& a, value_t const& b)
{
return boost::apply_visitor(detail::value_compare(), a.get(), b.get());
}
}}
#endif

View File

@@ -0,0 +1,56 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
* Copyright (c) 2010 Joel de Guzman
*/
#if !defined(OMD_COMMON_ERROR_HANDLER_HPP)
#define OMD_COMMON_ERROR_HANDLER_HPP
#include <boost/spirit/home/support/info.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
#include <string>
#include <iostream>
namespace omd { namespace parser
{
template <typename Iterator>
struct error_handler
{
template <typename, typename, typename, typename>
struct result { typedef void type; };
std::string source_file;
error_handler(std::string const& source_file = "")
: source_file(source_file) {}
void operator()(
Iterator first, Iterator last,
Iterator err_pos, boost::spirit::info const& what) const
{
Iterator eol = err_pos;
int line = boost::spirit::get_line(err_pos);
if (source_file != "")
std::cerr << source_file;
if (line != -1)
std::cerr << '(' << line << ')';
std::cerr << " : Error! Expecting " << what;
std::cerr << " got:\"";
for (Iterator i = err_pos; i != last; ++i)
{
Iterator::value_type c = *i;
if (c == '\r' || c == '\n')
break;
std::cerr << c;
}
std::cerr << "\"" << std::endl;
}
};
}}
#endif

41
yaml/parser/flow.hpp Normal file
View File

@@ -0,0 +1,41 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
*/
#if !defined(OMD_PARSER_FLOW_HPP)
#define OMD_PARSER_FLOW_HPP
#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
#include <string>
#include "scalar.hpp"
namespace omd { namespace parser
{
template <typename Iterator>
struct white_space : qi::grammar<Iterator>
{
white_space();
qi::rule<Iterator> start;
};
template <typename Iterator>
struct flow : qi::grammar<Iterator, ast::value_t(), white_space<Iterator> >
{
flow(std::string const& source_file = "");
typedef std::pair<ast::value_t, ast::value_t> element_t;
typedef white_space<Iterator> white_space;
qi::rule<Iterator, ast::value_t(), white_space> value;
qi::rule<Iterator, ast::object_t(), white_space> object;
qi::rule< Iterator, element_t(), white_space > member_pair;
qi::rule<Iterator, ast::array_t(), white_space> array;
scalar<Iterator> scalar_value;
typedef omd::parser::error_handler<Iterator> error_handler_t;
boost::phoenix::function<error_handler_t> const error_handler;
};
}}
#endif

73
yaml/parser/flow_def.hpp Normal file
View File

@@ -0,0 +1,73 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
*/
#if !defined(OMD_PARSER_FLOW_DEF_HPP)
#define OMD_PARSER_FLOW_DEF_HPP
#include "flow.hpp"
#include <boost/fusion/adapted/std_pair.hpp>
namespace omd { namespace parser
{
template <typename Iterator>
white_space<Iterator>::white_space()
: white_space::base_type(start)
{
qi::char_type char_;
qi::eol_type eol;
qi::space_type space;
start =
space // tab/space/cr/lf
| '#' >> *(char_ - eol) >> eol // comments
;
}
template <typename Iterator>
flow<Iterator>::flow(std::string const& source_file)
: flow::base_type(value),
scalar_value(source_file),
error_handler(error_handler_t(source_file))
{
value =
scalar_value
| object
| array
;
object =
'{'
> -(member_pair % ',')
> '}'
;
member_pair =
scalar_value
>> ':'
>> value
;
array =
'['
> -(value % ',')
> ']'
;
BOOST_SPIRIT_DEBUG_NODES(
(value)
(object)
(member_pair)
(array)
);
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::on_error<qi::fail>(value, error_handler(_1, _2, _3, _4));
}
}}
#endif

View File

@@ -1,16 +1,20 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
* Copyright (c) 2010 Joel de Guzman
*/
#if !defined(OMD_PARSER_STRING)
#define OMD_PARSER_STRING
#if !defined(OMD_PARSER_SCALAR_HPP)
#define OMD_PARSER_SCALAR_HPP
#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
#include <string>
#include <boost/spirit/include/qi.hpp>
#include "../ast.hpp" // our AST
#include <boost/spirit/include/phoenix_function.hpp>
#include "../ast.hpp" // our AST
#include "error_handler.hpp" // Our Error Handler
namespace omd { namespace parser
{
@@ -32,13 +36,16 @@ namespace omd { namespace parser
template <typename Iterator>
struct scalar : qi::grammar<Iterator, ast::value_t()>
{
scalar();
scalar(std::string const& source_file = "");
qi::rule<Iterator, ast::value_t()> value;
unicode_string<Iterator> string_value;
qi::rule<Iterator, int()> integer_value;
qi::symbols<char, bool> bool_value;
qi::rule<Iterator, ast::null_t() > null_value;
typedef omd::parser::error_handler<Iterator> error_handler_t;
boost::phoenix::function<error_handler_t> const error_handler;
};
}}

View File

@@ -1,11 +1,13 @@
/**
* Copyright (C) 2010, 2011 Object Modeling Designs
* Copyright (c) 2010 Joel de Guzman
*/
#if !defined(OMD_COMMON_STRING_DEF)
#define OMD_COMMON_STRING_DEF
#if !defined(OMD_COMMON_SCALAR_DEF_HPP)
#define OMD_COMMON_SCALAR_DEF_HPP
#include "scalar.hpp"
#include <boost/cstdint.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
@@ -99,12 +101,12 @@ namespace omd { namespace parser
}
template <typename Iterator>
scalar<Iterator>::scalar()
: scalar::base_type(value)
scalar<Iterator>::scalar(std::string const& source_file)
: scalar::base_type(value),
error_handler(error_handler_t(source_file))
{
qi::_val_type _val;
qi::lit_type lit;
qi::lexeme_type lexeme;
qi::char_type char_;
qi::hex_type hex;
qi::oct_type oct;
@@ -123,8 +125,8 @@ namespace omd { namespace parser
;
integer_value =
lexeme[no_case["0x"] > hex]
| lexeme['0' >> oct]
no_case["0x"] > hex
| '0' >> oct
| int_
;
@@ -148,6 +150,12 @@ namespace omd { namespace parser
(bool_value)
(null_value)
);
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::on_error<qi::fail>(value, error_handler(_1, _2, _3, _4));
}
}}