]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/quickbook/src/code_snippet.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / quickbook / src / code_snippet.cpp
CommitLineData
7c673cae
FG
1/*=============================================================================
2 Copyright (c) 2006 Joel de Guzman
3 http://spirit.sourceforge.net/
4
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8=============================================================================*/
9
10#include <boost/spirit/include/classic_core.hpp>
11#include <boost/spirit/include/classic_actor.hpp>
12#include <boost/spirit/include/classic_confix.hpp>
13#include <boost/shared_ptr.hpp>
14#include <boost/bind.hpp>
15#include "block_tags.hpp"
16#include "template_stack.hpp"
17#include "actions.hpp"
18#include "state.hpp"
19#include "values.hpp"
20#include "files.hpp"
b32b8144 21#include "stream.hpp"
7c673cae
FG
22
23namespace quickbook
24{
25 namespace cl = boost::spirit::classic;
26
27 struct code_snippet_actions
28 {
b32b8144
FG
29 code_snippet_actions(std::vector<template_symbol>& storage_,
30 file_ptr source_file_,
31 char const* source_type_)
32 : last_code_pos(source_file_->source().begin())
7c673cae
FG
33 , in_code(false)
34 , snippet_stack()
b32b8144
FG
35 , storage(storage_)
36 , source_file(source_file_)
37 , source_type(source_type_)
7c673cae
FG
38 , error_count(0)
39 {
40 source_file->is_code_snippets = true;
41 content.start(source_file);
42 }
43
44 void mark(string_iterator first, string_iterator last);
45 void pass_thru(string_iterator first, string_iterator last);
46 void escaped_comment(string_iterator first, string_iterator last);
47 void start_snippet(string_iterator first, string_iterator last);
48 void start_snippet_impl(std::string const&, string_iterator);
49 void end_snippet(string_iterator first, string_iterator last);
50 void end_snippet_impl(string_iterator);
51 void end_file(string_iterator, string_iterator);
52
53 void append_code(string_iterator first, string_iterator last);
54 void close_code();
55
56 struct snippet_data
57 {
b32b8144
FG
58 snippet_data(std::string const& id_)
59 : id(id_)
7c673cae
FG
60 , start_code(false)
61 {}
62
63 std::string id;
64 bool start_code;
65 string_iterator source_pos;
b32b8144 66 mapped_file_builder::pos_type start_pos;
7c673cae
FG
67 boost::shared_ptr<snippet_data> next;
68 };
69
70 void push_snippet_data(std::string const& id,
71 string_iterator pos)
72 {
73 boost::shared_ptr<snippet_data> new_snippet(new snippet_data(id));
74 new_snippet->next = snippet_stack;
75 snippet_stack = new_snippet;
76 snippet_stack->start_code = in_code;
77 snippet_stack->source_pos = pos;
78 snippet_stack->start_pos = content.get_pos();
79 }
80
81 boost::shared_ptr<snippet_data> pop_snippet_data()
82 {
83 boost::shared_ptr<snippet_data> snippet(snippet_stack);
84 snippet_stack = snippet->next;
85 snippet->next.reset();
86 return snippet;
87 }
88
89 mapped_file_builder content;
b32b8144
FG
90 string_iterator mark_begin, mark_end;
91 string_iterator last_code_pos;
7c673cae
FG
92 bool in_code;
93 boost::shared_ptr<snippet_data> snippet_stack;
94 std::vector<template_symbol>& storage;
95 file_ptr source_file;
96 char const* const source_type;
97 int error_count;
98 };
99
100 struct python_code_snippet_grammar
101 : cl::grammar<python_code_snippet_grammar>
102 {
103 typedef code_snippet_actions actions_type;
104
b32b8144
FG
105 python_code_snippet_grammar(actions_type & actions_)
106 : actions(actions_)
7c673cae
FG
107 {}
108
109 template <typename Scanner>
110 struct definition
111 {
112 typedef code_snippet_actions actions_type;
113
114 definition(python_code_snippet_grammar const& self)
115 {
116
b32b8144 117 start_ = (*code_elements) [boost::bind(&actions_type::end_file, &self.actions, _1, _2)]
7c673cae
FG
118 ;
119
120 identifier =
121 (cl::alpha_p | '_') >> *(cl::alnum_p | '_')
122 ;
123
124 code_elements =
b32b8144
FG
125 start_snippet [boost::bind(&actions_type::start_snippet, &self.actions, _1, _2)]
126 | end_snippet [boost::bind(&actions_type::end_snippet, &self.actions, _1, _2)]
127 | escaped_comment [boost::bind(&actions_type::escaped_comment, &self.actions, _1, _2)]
128 | pass_thru_comment [boost::bind(&actions_type::pass_thru, &self.actions, _1, _2)]
129 | ignore [boost::bind(&actions_type::append_code, &self.actions, _1, _2)]
7c673cae
FG
130 | cl::anychar_p
131 ;
132
133 start_snippet =
134 *cl::blank_p
135 >> !(cl::eol_p >> *cl::blank_p)
136 >> "#["
137 >> *cl::blank_p
b32b8144 138 >> identifier [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
139 >> *(cl::anychar_p - cl::eol_p)
140 ;
141
142 end_snippet =
143 *cl::blank_p
144 >> !(cl::eol_p >> *cl::blank_p)
145 >> "#]"
146 >> *(cl::anychar_p - cl::eol_p)
147 ;
148
149 ignore
150 = cl::confix_p(
151 *cl::blank_p >> "#<-",
152 *cl::anychar_p,
153 "#->" >> *cl::blank_p >> (cl::eol_p | cl::end_p)
154 )
155 | cl::confix_p(
156 "\"\"\"<-\"\"\"",
157 *cl::anychar_p,
158 "\"\"\"->\"\"\""
159 )
160 | cl::confix_p(
161 "\"\"\"<-",
162 *cl::anychar_p,
163 "->\"\"\""
164 )
165 ;
166
167 escaped_comment =
168 cl::confix_p(
169 *cl::space_p >> "#`",
b32b8144 170 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
171 (cl::eol_p | cl::end_p)
172 )
173 | cl::confix_p(
174 *cl::space_p >> "\"\"\"`",
b32b8144 175 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
176 "\"\"\""
177 )
178 ;
179
180 // Note: Unlike escaped_comment and ignore, this doesn't
181 // swallow preceeding whitespace.
182 pass_thru_comment
183 = "#=" >> (cl::eps_p - '=')
184 >> ( *(cl::anychar_p - cl::eol_p)
185 >> (cl::eol_p | cl::end_p)
b32b8144 186 ) [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
187 | cl::confix_p(
188 "\"\"\"=" >> (cl::eps_p - '='),
b32b8144 189 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
190 "\"\"\""
191 )
192 ;
193 }
194
195 cl::rule<Scanner>
196 start_, identifier, code_elements, start_snippet, end_snippet,
197 escaped_comment, pass_thru_comment, ignore;
198
199 cl::rule<Scanner> const&
200 start() const { return start_; }
201 };
202
203 actions_type& actions;
204 };
205
206 struct cpp_code_snippet_grammar
207 : cl::grammar<cpp_code_snippet_grammar>
208 {
209 typedef code_snippet_actions actions_type;
210
b32b8144
FG
211 cpp_code_snippet_grammar(actions_type & actions_)
212 : actions(actions_)
7c673cae
FG
213 {}
214
215 template <typename Scanner>
216 struct definition
217 {
218 definition(cpp_code_snippet_grammar const& self)
219 {
b32b8144 220 start_ = (*code_elements) [boost::bind(&actions_type::end_file, &self.actions, _1, _2)]
7c673cae
FG
221 ;
222
223 identifier =
224 (cl::alpha_p | '_') >> *(cl::alnum_p | '_')
225 ;
226
227 code_elements =
b32b8144
FG
228 start_snippet [boost::bind(&actions_type::start_snippet, &self.actions, _1, _2)]
229 | end_snippet [boost::bind(&actions_type::end_snippet, &self.actions, _1, _2)]
230 | escaped_comment [boost::bind(&actions_type::escaped_comment, &self.actions, _1, _2)]
231 | ignore [boost::bind(&actions_type::append_code, &self.actions, _1, _2)]
232 | pass_thru_comment [boost::bind(&actions_type::pass_thru, &self.actions, _1, _2)]
7c673cae
FG
233 | cl::anychar_p
234 ;
235
236 start_snippet =
237 *cl::blank_p
238 >> !(cl::eol_p >> *cl::blank_p)
239 >> "//["
240 >> *cl::blank_p
b32b8144 241 >> identifier [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
242 >> *(cl::anychar_p - cl::eol_p)
243 |
244 *cl::blank_p
245 >> cl::eol_p
246 >> *cl::blank_p
247 >> "/*["
248 >> *cl::space_p
b32b8144 249 >> identifier [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
250 >> *cl::space_p
251 >> "*/"
252 >> *cl::blank_p
253 >> cl::eps_p(cl::eol_p)
254 |
255 "/*["
256 >> *cl::space_p
b32b8144 257 >> identifier [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
258 >> *cl::space_p
259 >> "*/"
260 ;
261
262 end_snippet =
263 *cl::blank_p
264 >> !(cl::eol_p >> *cl::blank_p)
265 >> "//]"
266 >> *(cl::anychar_p - cl::eol_p)
267 |
268 *cl::blank_p
269 >> cl::eol_p
270 >> *cl::blank_p
271 >> "/*]*/"
272 >> *cl::blank_p
273 >> cl::eps_p(cl::eol_p)
274 |
275 "/*[*/"
276 ;
277
278 ignore
279 = cl::confix_p(
280 *cl::blank_p >> "//<-",
281 *cl::anychar_p,
282 "//->"
283 )
284 >> *cl::blank_p
285 >> cl::eol_p
286 | cl::confix_p(
287 "/*<-*/",
288 *cl::anychar_p,
289 "/*->*/"
290 )
291 | cl::confix_p(
292 "/*<-",
293 *cl::anychar_p,
294 "->*/"
295 )
296 ;
297
298 escaped_comment
299 = cl::confix_p(
300 *cl::space_p >> "//`",
b32b8144 301 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
302 (cl::eol_p | cl::end_p)
303 )
304 | cl::confix_p(
305 *cl::space_p >> "/*`",
b32b8144 306 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
307 "*/"
308 )
309 ;
310
311 // Note: Unlike escaped_comment and ignore, this doesn't
312 // swallow preceeding whitespace.
313 pass_thru_comment
314 = "//=" >> (cl::eps_p - '=')
315 >> ( *(cl::anychar_p - cl::eol_p)
316 >> (cl::eol_p | cl::end_p)
b32b8144 317 ) [boost::bind(&actions_type::mark, &self.actions, _1, _2)]
7c673cae
FG
318 | cl::confix_p(
319 "/*=" >> (cl::eps_p - '='),
b32b8144 320 (*cl::anychar_p) [boost::bind(&actions_type::mark, &self.actions, _1, _2)],
7c673cae
FG
321 "*/"
322 )
323 ;
324 }
325
326 cl::rule<Scanner>
327 start_, identifier, code_elements, start_snippet, end_snippet,
328 escaped_comment, pass_thru_comment, ignore;
329
330 cl::rule<Scanner> const&
331 start() const { return start_; }
332 };
333
334 actions_type& actions;
335 };
336
337 int load_snippets(
338 fs::path const& filename
339 , std::vector<template_symbol>& storage // snippets are stored in a
340 // vector of template_symbols
341 , std::string const& extension
342 , value::tag_type load_type)
343 {
344 assert(load_type == block_tags::include ||
345 load_type == block_tags::import);
346
b32b8144 347 bool is_python = extension == ".py" || extension == ".jam";
7c673cae
FG
348 code_snippet_actions a(storage, load(filename, qbk_version_n), is_python ? "[python]" : "[c++]");
349
350 string_iterator first(a.source_file->source().begin());
351 string_iterator last(a.source_file->source().end());
352
353 cl::parse_info<string_iterator> info;
354
355 if(is_python) {
356 info = boost::spirit::classic::parse(first, last, python_code_snippet_grammar(a));
357 }
358 else {
359 info = boost::spirit::classic::parse(first, last, cpp_code_snippet_grammar(a));
360 }
361
362 assert(info.full);
363 return a.error_count;
364 }
365
366 void code_snippet_actions::append_code(string_iterator first, string_iterator last)
367 {
368 assert(last_code_pos <= first);
369
370 if(snippet_stack) {
371 if (last_code_pos != first) {
372 if (!in_code)
373 {
374 content.add_at_pos("\n\n", last_code_pos);
375 content.add_at_pos(source_type, last_code_pos);
376 content.add_at_pos("```\n", last_code_pos);
377
378 in_code = true;
379 }
380
b32b8144 381 content.add(quickbook::string_view(last_code_pos, first - last_code_pos));
7c673cae
FG
382 }
383 }
384
385 last_code_pos = last;
386 }
387
388 void code_snippet_actions::close_code()
389 {
390 if (!snippet_stack) return;
391
392 if (in_code)
393 {
394 content.add_at_pos("\n```\n\n", last_code_pos);
395 in_code = false;
396 }
397 }
398
399 void code_snippet_actions::mark(string_iterator first, string_iterator last)
400 {
401 mark_begin = first;
402 mark_end = last;
403 }
404
405 void code_snippet_actions::pass_thru(string_iterator first, string_iterator last)
406 {
407 if(!snippet_stack) return;
408 append_code(first, last);
409
410 if (!in_code)
411 {
412 content.add_at_pos("\n\n", first);
413 content.add_at_pos(source_type, first);
414 content.add_at_pos("```\n", first);
415 in_code = true;
416 }
417
b32b8144 418 content.add(quickbook::string_view(mark_begin, mark_end - mark_begin));
7c673cae
FG
419 }
420
421 void code_snippet_actions::escaped_comment(string_iterator first, string_iterator last)
422 {
423 append_code(first, last);
424 close_code();
425
426 if (mark_begin != mark_end)
427 {
428 if (!snippet_stack)
429 {
430 start_snippet_impl("!", first);
431 }
432
433 snippet_data& snippet = *snippet_stack;
434
435 content.add_at_pos("\n", mark_begin);
b32b8144 436 content.unindent_and_add(quickbook::string_view(mark_begin, mark_end - mark_begin));
7c673cae
FG
437
438 if (snippet.id == "!")
439 {
440 end_snippet_impl(last);
441 }
442 }
443 }
444
445 void code_snippet_actions::start_snippet(string_iterator first, string_iterator last)
446 {
447 append_code(first, last);
448 start_snippet_impl(std::string(mark_begin, mark_end), first);
449 }
450
451 void code_snippet_actions::end_snippet(string_iterator first, string_iterator last)
452 {
453 append_code(first, last);
454
455 if(!snippet_stack) {
456 if (qbk_version_n >= 106u) {
457 detail::outerr(source_file, first)
458 << "Mismatched end snippet."
459 << std::endl;
460 ++error_count;
461 }
462 else {
463 detail::outwarn(source_file, first)
464 << "Mismatched end snippet."
465 << std::endl;
466 }
467 return;
468 }
469
470 end_snippet_impl(first);
471 }
472
473 void code_snippet_actions::end_file(string_iterator, string_iterator pos)
474 {
475 append_code(pos, pos);
476 close_code();
477
478 while (snippet_stack) {
479 if (qbk_version_n >= 106u) {
480 detail::outerr(source_file->path)
481 << "Unclosed snippet '"
482 << snippet_stack->id
483 << "'"
484 << std::endl;
485 ++error_count;
486 }
487 else {
488 detail::outwarn(source_file->path)
489 << "Unclosed snippet '"
490 << snippet_stack->id
491 << "'"
492 << std::endl;
493 }
494
495 end_snippet_impl(pos);
496 }
497 }
498
499 void code_snippet_actions::start_snippet_impl(std::string const& id,
500 string_iterator position)
501 {
502 push_snippet_data(id, position);
503 }
504
505 void code_snippet_actions::end_snippet_impl(string_iterator position)
506 {
507 assert(snippet_stack);
508
509 boost::shared_ptr<snippet_data> snippet = pop_snippet_data();
510
511 mapped_file_builder f;
512 f.start(source_file);
513 if (snippet->start_code) {
514 f.add_at_pos("\n\n", snippet->source_pos);
515 f.add_at_pos(source_type, snippet->source_pos);
516 f.add_at_pos("```\n", snippet->source_pos);
517 }
518 f.add(content, snippet->start_pos, content.get_pos());
519 if (in_code) {
520 f.add_at_pos("\n```\n\n", position);
521 }
522
523 std::vector<std::string> params;
524
525 file_ptr body = f.release();
526
527 storage.push_back(template_symbol(snippet->id, params,
528 qbk_value(body, body->source().begin(), body->source().end(),
529 template_tags::snippet)));
530 }
531}