1 /*=============================================================================
2     Copyright (c) 2002 2004 2006 Joel de Guzman
3     Copyright (c) 2004 Eric Niebler
4     http://spirit.sourceforge.net/
5 
6     Use, modification and distribution is subject to the Boost Software
7     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8     http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 
11 #include <boost/spirit/include/classic_assign_actor.hpp>
12 #include <boost/spirit/include/classic_clear_actor.hpp>
13 #include <boost/spirit/include/classic_core.hpp>
14 #include <boost/spirit/include/classic_if.hpp>
15 #include <boost/spirit/include/phoenix1_casts.hpp>
16 #include <boost/spirit/include/phoenix1_primitives.hpp>
17 #include "actions.hpp"
18 #include "for.hpp"
19 #include "grammar_impl.hpp"
20 #include "phrase_tags.hpp"
21 #include "state.hpp"
22 #include "utils.hpp"
23 
24 namespace quickbook
25 {
26     namespace cl = boost::spirit::classic;
27 
28     struct phrase_element_grammar_local
29     {
30         cl::rule<scanner> image, anchor, link, empty, cond_phrase, inner_phrase,
31             role, source_mode;
32     };
33 
init_phrase_elements()34     void quickbook_grammar::impl::init_phrase_elements()
35     {
36         phrase_element_grammar_local& local =
37             cleanup_.add(new phrase_element_grammar_local);
38 
39         error_action error(state);
40         raw_char_action raw_char(state);
41         scoped_parser<cond_phrase_push> scoped_cond_phrase(state);
42         scoped_parser<to_value_scoped_action> to_value(state);
43 
44         // clang-format off
45 
46         elements.add
47             ("?", element_info(element_info::phrase, &local.cond_phrase))
48             ;
49 
50         local.cond_phrase =
51                 ( !(qbk_ver(107u) >> "!") )     [state.values.entry(ph::arg1, ph::arg2)]
52             >>  blank
53             >>  macro_identifier                [state.values.entry(ph::arg1, ph::arg2)]
54             >>  scoped_cond_phrase() [extended_phrase]
55             ;
56 
57         elements.add
58             ("$", element_info(element_info::phrase, &local.image, phrase_tags::image))
59             ;
60 
61         // Note that the attribute values here are encoded in plain text not
62         // boostbook.
63         local.image =
64                 qbk_ver(105u)
65             >>  blank
66             >>  (   qbk_ver(0, 106u)
67                 >>  (+(
68                         *cl::space_p
69                     >>  +(cl::anychar_p - (cl::space_p | phrase_end | '['))
70                     ))                  [state.values.entry(ph::arg1, ph::arg2)]
71                 |   qbk_ver(106u)
72                 >>  to_value()
73                     [   +(  raw_escape
74                         |   (+cl::space_p >> ~cl::eps_p(phrase_end | '['))
75                                         [raw_char]
76                         |   (cl::anychar_p - (cl::space_p | phrase_end | '['))
77                                         [raw_char]
78                         )
79                     ]
80                 )
81             >>  hard_space
82             >>  *state.values.list()
83                 [   '['
84                 >>  (*(cl::alnum_p | '_'))
85                                         [state.values.entry(ph::arg1, ph::arg2)]
86                 >>  space
87                 >>  (   qbk_ver(0, 106u)
88                     >>  (*(cl::anychar_p - (phrase_end | '[')))
89                                         [state.values.entry(ph::arg1, ph::arg2)]
90                     |   qbk_ver(106u)
91                     >>  to_value()
92                         [   *(  raw_escape
93                             |   (cl::anychar_p - (phrase_end | '['))
94                                                         [raw_char]
95                             )
96                         ]
97                     )
98                 >>  ']'
99                 >>  space
100                 ]
101             >>  cl::eps_p(']')
102             |   qbk_ver(0, 105u)
103             >>  blank
104             >>  (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)]
105             >>  cl::eps_p(']')
106             ;
107 
108         elements.add
109             ("@", element_info(element_info::phrase, &local.link, phrase_tags::url))
110             ("link", element_info(element_info::phrase, &local.link, phrase_tags::link))
111             ("funcref", element_info(element_info::phrase, &local.link, phrase_tags::funcref))
112             ("classref", element_info(element_info::phrase, &local.link, phrase_tags::classref))
113             ("memberref", element_info(element_info::phrase, &local.link, phrase_tags::memberref))
114             ("enumref", element_info(element_info::phrase, &local.link, phrase_tags::enumref))
115             ("macroref", element_info(element_info::phrase, &local.link, phrase_tags::macroref))
116             ("headerref", element_info(element_info::phrase, &local.link, phrase_tags::headerref))
117             ("conceptref", element_info(element_info::phrase, &local.link, phrase_tags::conceptref))
118             ("globalref", element_info(element_info::phrase, &local.link, phrase_tags::globalref))
119             ;
120 
121         local.link =
122                 space
123             >>  (   qbk_ver(0, 106u)
124                 >>  (*(cl::anychar_p - (']' | space)))
125                                                 [state.values.entry(ph::arg1, ph::arg2)]
126                 |   qbk_ver(106u, 107u)
127                 >>  to_value()
128                     [   *(  raw_escape
129                         |   (cl::anychar_p - (cl::ch_p('[') | ']' | space))
130                                                 [raw_char]
131                         )
132                     ]
133                     >>  !(  ~cl::eps_p(comment)
134                         >>  cl::eps_p('[')      [error("Open bracket in link value.")]
135                         )
136                 |   qbk_ver(107u)
137                 >>  to_value() [attribute_value_1_7]
138                 )
139             >>  hard_space
140             >>  local.inner_phrase
141             ;
142 
143         elements.add
144             ("#", element_info(element_info::maybe_block, &local.anchor, phrase_tags::anchor))
145             ;
146 
147         local.anchor =
148                 blank
149             >>  (   qbk_ver(0, 106u)
150                 >>  (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)]
151                 |   qbk_ver(106u, 107u)
152                 >>  to_value()
153                     [   *(  raw_escape
154                         |   (cl::anychar_p - phrase_end)
155                                                     [raw_char]
156                         )
157                     ]
158                 |   qbk_ver(107u)
159                 >>  to_value() [attribute_value_1_7]
160                 )
161             ;
162 
163         elements.add
164             ("*", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::bold))
165             ("'", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::italic))
166             ("_", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::underline))
167             ("^", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::teletype))
168             ("-", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::strikethrough))
169             ("\"", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::quote))
170             ("~", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::replaceable))
171             ("footnote", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::footnote))
172             ;
173 
174         elements.add("!", element_info(element_info::maybe_block, &local.source_mode, code_tags::next_source_mode, 107u))
175             ;
176 
177         local.source_mode =
178                 cl::eps_p                           [state.values.entry(ph::arg1, ph::arg2)]
179             >>  source_modes                        [state.values.entry(ph::arg1)];
180 
181         QUICKBOOK_FOR(int tag, source_mode_tags::tags()) {
182             source_modes.add(source_mode_tags::name(tag), tag);
183             elements.add(source_mode_tags::name(tag),
184                 element_info(element_info::phrase, &local.empty, tag));
185         }
186 
187         elements.add
188             ("role", element_info(element_info::phrase, &local.role, phrase_tags::role, 106u))
189             ;
190 
191         local.role
192             =   space
193             >>  (   qbk_ver(0, 107u)
194                 >>  (+(cl::alnum_p | '_'))          [state.values.entry(ph::arg1, ph::arg2)]
195                 |   qbk_ver(107u)
196                 >>  to_value() [attribute_value_1_7]
197                 )
198             >>  hard_space
199             >>  local.inner_phrase
200             ;
201 
202         local.empty = cl::eps_p;
203 
204         local.inner_phrase =
205                 blank
206             >>  to_value() [ paragraph_phrase ]
207             ;
208 
209         // clang-format on
210     }
211 }
212