6 #ifndef JBSON_EXPRESSION_PARSER_HPP
7 #define JBSON_EXPRESSION_PARSER_HPP
9 #include "detail/config.hpp"
11 JBSON_PUSH_DISABLE_DOCUMENTATION_WARNING
12 #include <boost/variant/recursive_variant.hpp>
13 #include <boost/fusion/include/adapt_struct.hpp>
14 #include <boost/spirit/home/qi.hpp>
15 #include <boost/optional.hpp>
16 JBSON_CLANG_POP_WARNINGS
18 #ifdef BOOST_SPIRIT_DEBUG_OUT
19 #undef BOOST_SPIRIT_DEBUG_OUT
21 #define BOOST_SPIRIT_DEBUG_OUT ::std::clog
25 namespace expression {
39 typedef boost::variant<nil, bool, int64_t, std::string, variable, boost::recursive_wrapper<unary>,
40 boost::recursive_wrapper<expression>> operand;
72 std::list<operation> rest;
75 inline std::ostream&
operator<<(std::ostream& out, optoken tk) {
79 inline std::ostream&
operator<<(std::ostream& out, nil) {
83 inline std::ostream&
operator<<(std::ostream& out, variable
const& var) {
90 template <
typename Iterator>
struct error_handler {
91 template <
typename,
typename,
typename>
struct result {
95 error_handler(Iterator first, Iterator last) : first(first), last(last) {}
97 template <
typename Message,
typename What>
98 void operator()(Message
const& message, What
const& what, Iterator err_pos)
const {
100 Iterator line_start = get_pos(err_pos, line);
101 if(err_pos != last) {
102 std::clog << message << what <<
" line " << line <<
':' << std::endl;
103 std::clog << get_line(line_start) << std::endl;
104 for(; line_start != err_pos; ++line_start)
106 std::clog <<
'^' << std::endl;
108 std::clog <<
"Unexpected end of file. ";
109 std::clog << message << what <<
" line " << line << std::endl;
113 Iterator get_pos(Iterator err_pos,
int& line)
const {
116 Iterator line_start = first;
117 while(i != err_pos) {
119 if(i != err_pos && *i ==
'\r')
124 if(i != err_pos && *i ==
'\n')
137 std::string get_line(Iterator err_pos)
const {
138 Iterator i = err_pos;
140 while(i != last && (*i !=
'\r' && *i !=
'\n'))
142 return std::string(err_pos, i);
147 std::vector<Iterator> iters;
150 template <
typename Iterator>
151 struct parser : boost::spirit::qi::grammar<Iterator, ast::expression(), boost::spirit::ascii::space_type> {
152 boost::spirit::qi::rule<Iterator, ast::expression(), boost::spirit::ascii::space_type> expr, equality_expr,
153 relational_expr, logical_expr, additive_expr, multiplicative_expr;
154 boost::spirit::qi::rule<Iterator, ast::operand(), boost::spirit::ascii::space_type> unary_expr, primary_expr;
155 boost::spirit::qi::rule<Iterator, ast::variable(), boost::spirit::ascii::space_type> identifier;
156 boost::spirit::qi::rule<Iterator, std::string(), boost::spirit::ascii::space_type> quoted_string;
157 boost::spirit::qi::symbols<char, ast::optoken> equality_op, relational_op, logical_op, additive_op,
158 multiplicative_op, unary_op;
159 boost::spirit::qi::symbols<char> keywords;
161 explicit parser(error_handler<Iterator>& error_handle) : parser::base_type(expr) {
162 namespace qi = boost::spirit::qi;
167 qi::any_int_parser<int64_t> int_;
169 qi::lexeme_type lexeme;
170 qi::alpha_type alpha;
171 qi::alnum_type alnum;
175 using qi::on_success;
177 using boost::phoenix::function;
179 typedef function<error_handler<Iterator>> error_handler_function;
182 equality_op.add(
"==", ast::optoken::equal)(
"!=", ast::optoken::not_equal);
184 relational_op.add(
"<", ast::optoken::less)(
"<=", ast::optoken::less_equal)(
">", ast::optoken::greater)(
185 ">=", ast::optoken::greater_equal);
187 logical_op.add(
"&&", ast::optoken::op_and)(
"||", ast::optoken::op_or);
189 additive_op.add(
"+", ast::optoken::plus)(
"-", ast::optoken::minus);
191 multiplicative_op.add(
"*", ast::optoken::times)(
"/", ast::optoken::divide);
193 unary_op.add(
"+", ast::optoken::positive)(
"-", ast::optoken::negative)(
"!", ast::optoken::op_not);
195 keywords.add(
"true")(
"false");
198 expr = equality_expr.alias();
200 equality_expr = relational_expr >> *(equality_op > relational_expr);
202 relational_expr = logical_expr >> *(relational_op > logical_expr);
204 logical_expr = additive_expr >> *(logical_op > additive_expr);
206 additive_expr = multiplicative_expr >> *(additive_op > multiplicative_expr);
208 multiplicative_expr = unary_expr >> *(multiplicative_op > unary_expr);
210 unary_expr = primary_expr | (unary_op > primary_expr);
212 primary_expr = int_ | quoted_string | identifier | bool_ |
'(' > expr >
')';
214 quoted_string = lexeme[
'"' >> +(char_ -
'"') >>
'"'] | lexeme[
'\'' >> +(char_ -
'\'') >>
'\''];
216 identifier = !keywords >> raw[lexeme[(alpha |
'_' |
'@' |
'.') >> *(alnum |
'_' |
'@' |
'.')]];
220 BOOST_SPIRIT_DEBUG_NODES((expr)(equality_expr)(relational_expr)(logical_expr)(additive_expr)(
221 multiplicative_expr)(unary_expr)(primary_expr)(identifier)(quoted_string));
225 on_error<fail>(expr, error_handler_function(error_handle)(
"Error! Expecting ", _4, _3));
233 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::unary,
234 (jbson::detail::expression::ast::optoken, operator_)(jbson::detail::expression::ast::operand,
237 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::variable, (std::
string, name))
239 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::operation,
240 (jbson::detail::expression::ast::optoken, operator_)(jbson::detail::expression::ast::operand,
243 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::expression,
244 (jbson::detail::expression::ast::operand,
245 first)(std::list<jbson::detail::expression::ast::operation>, rest))
247 #endif // JBSON_EXPRESSION_PARSER_HPP
std::basic_ostream< CharT, TraitsT > & operator<<(std::basic_ostream< CharT, TraitsT > &os, element_type e)
Stream operator for getting a string representation of an element_type.