2
* Copyright (C) 2013 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include <boost/config/warning_disable.hpp>
23
#include <boost/fusion/include/adapt_struct.hpp>
24
#include <boost/spirit/include/phoenix_object.hpp>
25
#include <boost/spirit/include/phoenix_operator.hpp>
26
#include <boost/spirit/include/qi.hpp>
28
#include "xpathquerypart.h"
30
// this allows spirit to lazily construct these two structs...
31
BOOST_FUSION_ADAPT_STRUCT(
32
xpathselect::XPathQueryPart,
33
(std::string, node_name_)
34
(boost::optional<xpathselect::XPathQueryParam>, parameter)
37
BOOST_FUSION_ADAPT_STRUCT(
38
xpathselect::XPathQueryParam,
39
(std::string, param_name)
40
(std::string, param_value)
47
namespace qi = boost::spirit::qi;
48
namespace phoenix = boost::phoenix;
50
// This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few
51
// days, then the beauty of boost::spirit creeps into your brain. To help future programmers,
52
// I've heavily commented this.
54
// The first template parameter to this grammar defines the type of iterator the grammer will operate
55
// on - it must adhere to std::forward_iterator. The second template parameter is the type
56
// that this grammar will produce (in this case: a list of XPathQueryPart objects).
57
template <typename Iterator>
58
struct xpath_grammar : qi::grammar<Iterator, QueryList()>
60
xpath_grammar() : xpath_grammar::base_type(node_sequence) // node_sequence is the start rule.
62
using namespace qi::labels;
64
// node names can either be a text string (no spaces), or a wildcard.
65
node_name = ( +qi::char_("a-zA-Z0-9_\\-") | qi::char_('*') );
66
// a search node is '//' as long as it's not followed by '/' or '*' or end of input.
67
search_node = "//" >> !(qi::lit("*") || "/" || qi::eoi)[qi::_val = XPathQueryPart()];
68
// a normal separator is a '/' as long as it's followed by something other than another '/'
69
normal_sep = '/' >> !qi::lit('/');
70
separator = normal_sep || search_node; // nodes can be separated by normal_sep or search_node.
72
// parameter name and values can contain text (no spaces)
73
param_name = +qi::char_("a-zA-Z0-9_\\-");
74
param_value = +qi::char_("a-zA-Z0-9_\\-");
75
// parameter specification is simple: name=value
76
param %= param_name >> '=' >> param_value;
78
// a node consists of a node name, followed by an *optional* parameter inside '[' and ']'.
79
node %= node_name >> -('[' >> param >> ']');
80
// this is the money shot: a node sequence is one or more of a separator, followed by an
82
node_sequence %= +(separator >> -node);
85
// define DEBUG in order to have boost::spirit spit out useful debug information:
87
// this gives english names to all the grammar rules:
88
node_name.name("node_name");
89
search_node.name("search_node");
90
normal_sep.name("normal_separator");
91
separator.name("separator");
92
param_name.name("param_name");
93
param_value.name("param_value");
94
param.name("parameter");
96
node_sequence.name("node_sequence");
98
// set up error logging:
99
qi::on_error<qi::fail>(
102
<< phoenix::val("Error! Expecting ")
103
<< qi::_4 // what failed?
104
<< phoenix::val(" here: \"")
105
<< phoenix::construct<std::string>(qi::_3, qi::_2) // iterators to error-pos, end
106
<< phoenix::val("\"")
109
// specify which rules we want debug info about (all of them):
110
qi::debug(node_name);
111
qi::debug(search_node);
112
qi::debug(normal_sep);
113
qi::debug(separator);
114
qi::debug(param_name);
115
qi::debug(param_value);
118
qi::debug(node_sequence);
121
// declare all the rules. The second template parameter is the type they produce.
122
qi::rule<Iterator, std::string()> node_name;
123
qi::rule<Iterator, XPathQueryPart()> search_node;
124
qi::rule<Iterator> normal_sep;
125
qi::rule<Iterator, xpathselect::QueryList()> separator;
127
qi::rule<Iterator, std::string()> param_name;
128
qi::rule<Iterator, std::string()> param_value;
129
qi::rule<Iterator, XPathQueryParam()> param;
131
qi::rule<Iterator, XPathQueryPart()> node;
132
qi::rule<Iterator, xpathselect::QueryList()> node_sequence;