View on GitHub
jbson
C++11/1y BSON library
expression_parser.hpp
1 // Copyright Christian Manning 2014.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef JBSON_EXPRESSION_PARSER_HPP
7 #define JBSON_EXPRESSION_PARSER_HPP
8 
9 #include "detail/config.hpp"
10 
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
17 
18 #ifdef BOOST_SPIRIT_DEBUG_OUT
19 #undef BOOST_SPIRIT_DEBUG_OUT
20 #endif
21 #define BOOST_SPIRIT_DEBUG_OUT ::std::clog
22 
23 namespace jbson {
24 namespace detail {
25 namespace expression {
26 
27 namespace ast {
28 
29 struct nil {};
30 struct unary;
31 struct expression;
32 
33 struct variable {
34  // variable() = default;
35  // variable(std::string const& name) : name(name) {}
36  std::string name;
37 };
38 
39 typedef boost::variant<nil, bool, int64_t, std::string, variable, boost::recursive_wrapper<unary>,
40  boost::recursive_wrapper<expression>> operand;
41 
42 enum class optoken {
43  plus,
44  minus,
45  times,
46  divide,
47  positive,
48  negative,
49  op_not,
50  equal,
51  not_equal,
52  less,
53  less_equal,
54  greater,
55  greater_equal,
56  op_and,
57  op_or
58 };
59 
60 struct unary {
61  optoken operator_;
62  operand operand_;
63 };
64 
65 struct operation {
66  optoken operator_;
67  operand operand_;
68 };
69 
70 struct expression {
71  operand first;
72  std::list<operation> rest;
73 };
74 
75 inline std::ostream& operator<<(std::ostream& out, optoken tk) {
76  out << (int)tk;
77  return out;
78 }
79 inline std::ostream& operator<<(std::ostream& out, nil) {
80  out << "nil";
81  return out;
82 }
83 inline std::ostream& operator<<(std::ostream& out, variable const& var) {
84  out << var.name;
85  return out;
86 }
87 
88 } // namespace ast
89 
90 template <typename Iterator> struct error_handler {
91  template <typename, typename, typename> struct result {
92  typedef void type;
93  };
94 
95  error_handler(Iterator first, Iterator last) : first(first), last(last) {}
96 
97  template <typename Message, typename What>
98  void operator()(Message const& message, What const& what, Iterator err_pos) const {
99  int line;
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)
105  std::clog << ' ';
106  std::clog << '^' << std::endl;
107  } else {
108  std::clog << "Unexpected end of file. ";
109  std::clog << message << what << " line " << line << std::endl;
110  }
111  }
112 
113  Iterator get_pos(Iterator err_pos, int& line) const {
114  line = 1;
115  Iterator i = first;
116  Iterator line_start = first;
117  while(i != err_pos) {
118  bool eol = false;
119  if(i != err_pos && *i == '\r') // CR
120  {
121  eol = true;
122  line_start = ++i;
123  }
124  if(i != err_pos && *i == '\n') // LF
125  {
126  eol = true;
127  line_start = ++i;
128  }
129  if(eol)
130  ++line;
131  else
132  ++i;
133  }
134  return line_start;
135  }
136 
137  std::string get_line(Iterator err_pos) const {
138  Iterator i = err_pos;
139  // position i to the next EOL
140  while(i != last && (*i != '\r' && *i != '\n'))
141  ++i;
142  return std::string(err_pos, i);
143  }
144 
145  Iterator first;
146  Iterator last;
147  std::vector<Iterator> iters;
148 };
149 
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;
160 
161  explicit parser(error_handler<Iterator>& error_handle) : parser::base_type(expr) {
162  namespace qi = boost::spirit::qi;
163  qi::_3_type _3;
164  qi::_4_type _4;
165 
166  qi::char_type char_;
167  qi::any_int_parser<int64_t> int_;
168  qi::raw_type raw;
169  qi::lexeme_type lexeme;
170  qi::alpha_type alpha;
171  qi::alnum_type alnum;
172  qi::bool_type bool_;
173 
174  using qi::on_error;
175  using qi::on_success;
176  using qi::fail;
177  using boost::phoenix::function;
178 
179  typedef function<error_handler<Iterator>> error_handler_function;
180 
181  // Tokens
182  equality_op.add("==", ast::optoken::equal)("!=", ast::optoken::not_equal);
183 
184  relational_op.add("<", ast::optoken::less)("<=", ast::optoken::less_equal)(">", ast::optoken::greater)(
185  ">=", ast::optoken::greater_equal);
186 
187  logical_op.add("&&", ast::optoken::op_and)("||", ast::optoken::op_or);
188 
189  additive_op.add("+", ast::optoken::plus)("-", ast::optoken::minus);
190 
191  multiplicative_op.add("*", ast::optoken::times)("/", ast::optoken::divide);
192 
193  unary_op.add("+", ast::optoken::positive)("-", ast::optoken::negative)("!", ast::optoken::op_not);
194 
195  keywords.add("true")("false");
196 
197  // Main expression grammar
198  expr = equality_expr.alias();
199 
200  equality_expr = relational_expr >> *(equality_op > relational_expr);
201 
202  relational_expr = logical_expr >> *(relational_op > logical_expr);
203 
204  logical_expr = additive_expr >> *(logical_op > additive_expr);
205 
206  additive_expr = multiplicative_expr >> *(additive_op > multiplicative_expr);
207 
208  multiplicative_expr = unary_expr >> *(multiplicative_op > unary_expr);
209 
210  unary_expr = primary_expr | (unary_op > primary_expr);
211 
212  primary_expr = int_ | quoted_string | identifier | bool_ | '(' > expr > ')';
213 
214  quoted_string = lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['\'' >> +(char_ - '\'') >> '\''];
215 
216  identifier = !keywords >> raw[lexeme[(alpha | '_' | '@' | '.') >> *(alnum | '_' | '@' | '.')]];
217 
219  // Debugging and error handling and reporting support.
220  BOOST_SPIRIT_DEBUG_NODES((expr)(equality_expr)(relational_expr)(logical_expr)(additive_expr)(
221  multiplicative_expr)(unary_expr)(primary_expr)(identifier)(quoted_string));
222 
224  // Error handling: on error in expr, call error_handler.
225  on_error<fail>(expr, error_handler_function(error_handle)("Error! Expecting ", _4, _3));
226  }
227 };
228 
229 } // namespace expression
230 } // namespace detail
231 } // namespace jbson
232 
233 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::unary,
234  (jbson::detail::expression::ast::optoken, operator_)(jbson::detail::expression::ast::operand,
235  operand_))
236 
237 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::variable, (std::string, name))
238 
239 BOOST_FUSION_ADAPT_STRUCT(jbson::detail::expression::ast::operation,
240  (jbson::detail::expression::ast::optoken, operator_)(jbson::detail::expression::ast::operand,
241  operand_))
242 
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))
246 
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.
Definition: element.hpp:896