blob: ce7a243136232a991989c19ad9663924acc65170 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2002 2004 2006 Joel de Guzman
Copyright (c) 2004 Eric Niebler
http://spirit.sourceforge.net/
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_QUICKBOOK_PHRASE_HPP)
#define BOOST_SPIRIT_QUICKBOOK_PHRASE_HPP
#include "grammar.hpp"
#include "actions_class.hpp"
#include "utils.hpp"
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_chset.hpp>
#include <boost/spirit/include/classic_assign_actor.hpp>
#include <boost/spirit/include/classic_clear_actor.hpp>
#include <boost/spirit/include/classic_if.hpp>
#include <boost/spirit/include/classic_loops.hpp>
namespace quickbook
{
namespace cl = boost::spirit::classic;
template <typename Rule, typename Action>
inline void
simple_markup(
Rule& simple
, char mark
, Action const& action
, Rule const& close
)
{
simple =
mark >>
(
(
cl::graph_p // A single char. e.g. *c*
>> cl::eps_p(mark
>> (cl::space_p | cl::punct_p | cl::end_p))
// space_p, punct_p or end_p
) // must follow mark
|
( cl::graph_p >> // graph_p must follow mark
*(cl::anychar_p -
( (cl::graph_p >> mark) // Make sure that we don't go
| close // past a single block
)
) >> cl::graph_p // graph_p must precede mark
>> cl::eps_p(mark
>> (cl::space_p | cl::punct_p | cl::end_p))
// space_p, punct_p or end_p
) // must follow mark
) [action]
>> mark
;
}
template <typename Scanner>
struct phrase_grammar::definition
{
definition(phrase_grammar const& self);
cl::rule<Scanner>
space, blank, comment, phrase, phrase_markup, image,
simple_phrase_end, phrase_end, bold, italic, underline, teletype,
strikethrough, escape, url, common, funcref, classref,
memberref, enumref, macroref, headerref, conceptref, globalref,
anchor, link, hard_space, eol, inline_code, simple_format,
simple_bold, simple_italic, simple_underline,
simple_teletype, source_mode, template_,
quote, code_block, footnote, replaceable, macro,
dummy_block, cond_phrase, macro_identifier, template_args,
template_args_1_4, template_arg_1_4,
template_inner_arg_1_4, brackets_1_4,
template_args_1_5, template_arg_1_5,
template_inner_arg_1_5, brackets_1_5
;
cl::rule<Scanner> const&
start() const { return common; }
};
template <typename Scanner>
phrase_grammar::definition<Scanner>::definition(phrase_grammar const& self)
{
using detail::var;
quickbook::actions& actions = self.actions;
space =
*(cl::space_p | comment)
;
blank =
*(cl::blank_p | comment)
;
eol = blank >> cl::eol_p
;
phrase_end =
']' |
cl::if_p(var(self.no_eols))
[
eol >> eol // Make sure that we don't go
] // past a single block, except
; // when preformatted.
// Follows an alphanumeric identifier - ensures that it doesn't
// match an empty space in the middle of the identifier.
hard_space =
(cl::eps_p - (cl::alnum_p | '_')) >> space
;
comment =
"[/" >> *(dummy_block | (cl::anychar_p - ']')) >> ']'
;
dummy_block =
'[' >> *(dummy_block | (cl::anychar_p - ']')) >> ']'
;
common =
macro
| phrase_markup
| code_block
| inline_code
| simple_format
| escape
| comment
;
macro =
// must not be followed by alpha or underscore
cl::eps_p(actions.macro
>> (cl::eps_p - (cl::alpha_p | '_')))
>> actions.macro [actions.do_macro]
;
static const bool true_ = true;
static const bool false_ = false;
template_ =
(
cl::ch_p('`') [cl::assign_a(actions.template_escape,true_)]
|
cl::eps_p [cl::assign_a(actions.template_escape,false_)]
)
>>
( (
(cl::eps_p(cl::punct_p)
>> actions.templates.scope
) [cl::assign_a(actions.template_identifier)]
[cl::clear_a(actions.template_args)]
>> !template_args
) | (
(actions.templates.scope
>> cl::eps_p(hard_space)
) [cl::assign_a(actions.template_identifier)]
[cl::clear_a(actions.template_args)]
>> space
>> !template_args
) )
>> cl::eps_p(']')
;
template_args =
cl::if_p(qbk_since(105u)) [
template_args_1_5
].else_p [
template_args_1_4
]
;
template_args_1_4 = template_arg_1_4 >> *(".." >> template_arg_1_4);
template_arg_1_4 =
( cl::eps_p(*cl::blank_p >> cl::eol_p)
[cl::assign_a(actions.template_block, true_)]
| cl::eps_p [cl::assign_a(actions.template_block, false_)]
)
>> template_inner_arg_1_4 [actions.template_arg]
;
template_inner_arg_1_4 =
+(brackets_1_4 | (cl::anychar_p - (cl::str_p("..") | ']')))
;
brackets_1_4 =
'[' >> template_inner_arg_1_4 >> ']'
;
template_args_1_5 = template_arg_1_5 >> *(".." >> template_arg_1_5);
template_arg_1_5 =
( cl::eps_p(*cl::blank_p >> cl::eol_p)
[cl::assign_a(actions.template_block, true_)]
| cl::eps_p [cl::assign_a(actions.template_block, false_)]
)
>> (+(brackets_1_5 | ('\\' >> cl::anychar_p) | (cl::anychar_p - (cl::str_p("..") | '[' | ']'))))
[actions.template_arg]
;
template_inner_arg_1_5 =
+(brackets_1_5 | ('\\' >> cl::anychar_p) | (cl::anychar_p - (cl::str_p('[') | ']')))
;
brackets_1_5 =
'[' >> template_inner_arg_1_5 >> ']'
;
inline_code =
'`' >>
(
*(cl::anychar_p -
( '`'
| (eol >> eol) // Make sure that we don't go
) // past a single block
) >> cl::eps_p('`')
) [actions.inline_code]
>> '`'
;
code_block =
(
"```" >>
(
*(cl::anychar_p - "```")
>> cl::eps_p("```")
) [actions.code_block]
>> "```"
)
| (
"``" >>
(
*(cl::anychar_p - "``")
>> cl::eps_p("``")
) [actions.code_block]
>> "``"
)
;
simple_format =
simple_bold
| simple_italic
| simple_underline
| simple_teletype
;
simple_phrase_end = '[' | phrase_end;
simple_markup(simple_bold,
'*', actions.simple_bold, simple_phrase_end);
simple_markup(simple_italic,
'/', actions.simple_italic, simple_phrase_end);
simple_markup(simple_underline,
'_', actions.simple_underline, simple_phrase_end);
simple_markup(simple_teletype,
'=', actions.simple_teletype, simple_phrase_end);
phrase =
*( common
| comment
| (cl::anychar_p - phrase_end) [actions.plain_char]
)
;
phrase_markup =
'['
>> ( cond_phrase
| image
| url
| link
| anchor
| source_mode
| funcref
| classref
| memberref
| enumref
| macroref
| headerref
| conceptref
| globalref
| bold
| italic
| underline
| teletype
| strikethrough
| quote
| replaceable
| footnote
| template_ [actions.do_template]
| cl::str_p("br") [actions.break_]
)
>> ']'
;
escape =
cl::str_p("\\n") [actions.break_]
| cl::str_p("\\ ") // ignore an escaped space
| '\\' >> cl::punct_p [actions.raw_char]
| "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")]
[actions.escape_unicode]
| "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")]
[actions.escape_unicode]
| (
("'''" >> !eol) [actions.escape_pre]
>> *(cl::anychar_p - "'''") [actions.raw_char]
>> cl::str_p("'''") [actions.escape_post]
)
;
macro_identifier =
+(cl::anychar_p - (cl::space_p | ']'))
;
cond_phrase =
'?' >> blank
>> macro_identifier [actions.cond_phrase_pre]
>> (!phrase) [actions.cond_phrase_post]
;
image =
'$' >> blank [cl::clear_a(actions.attributes)]
>> cl::if_p(qbk_since(105u)) [
(+(
*cl::space_p
>> +(cl::anychar_p - (cl::space_p | phrase_end | '['))
)) [cl::assign_a(actions.image_fileref)]
>> hard_space
>> *(
'['
>> (*(cl::alnum_p | '_')) [cl::assign_a(actions.attribute_name)]
>> space
>> (*(cl::anychar_p - (phrase_end | '[')))
[actions.attribute]
>> ']'
>> space
)
].else_p [
(*(cl::anychar_p - phrase_end))
[cl::assign_a(actions.image_fileref)]
]
>> cl::eps_p(']') [actions.image]
;
url =
'@'
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.url_pre]
>> hard_space
>> phrase [actions.url_post]
;
link =
"link" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.link_pre]
>> hard_space
>> phrase [actions.link_post]
;
anchor =
"#"
>> blank
>> (*(cl::anychar_p - phrase_end)) [actions.anchor]
;
funcref =
"funcref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.funcref_pre]
>> hard_space
>> phrase [actions.funcref_post]
;
classref =
"classref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.classref_pre]
>> hard_space
>> phrase [actions.classref_post]
;
memberref =
"memberref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.memberref_pre]
>> hard_space
>> phrase [actions.memberref_post]
;
enumref =
"enumref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.enumref_pre]
>> hard_space
>> phrase [actions.enumref_post]
;
macroref =
"macroref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.macroref_pre]
>> hard_space
>> phrase [actions.macroref_post]
;
headerref =
"headerref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.headerref_pre]
>> hard_space
>> phrase [actions.headerref_post]
;
conceptref =
"conceptref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.conceptref_pre]
>> hard_space
>> phrase [actions.conceptref_post]
;
globalref =
"globalref" >> hard_space
>> (*(cl::anychar_p -
(']' | hard_space))) [actions.globalref_pre]
>> hard_space
>> phrase [actions.globalref_post]
;
bold =
cl::ch_p('*') [actions.bold_pre]
>> blank >> phrase [actions.bold_post]
;
italic =
cl::ch_p('\'') [actions.italic_pre]
>> blank >> phrase [actions.italic_post]
;
underline =
cl::ch_p('_') [actions.underline_pre]
>> blank >> phrase [actions.underline_post]
;
teletype =
cl::ch_p('^') [actions.teletype_pre]
>> blank >> phrase [actions.teletype_post]
;
strikethrough =
cl::ch_p('-') [actions.strikethrough_pre]
>> blank >> phrase [actions.strikethrough_post]
;
quote =
cl::ch_p('"') [actions.quote_pre]
>> blank >> phrase [actions.quote_post]
;
replaceable =
cl::ch_p('~') [actions.replaceable_pre]
>> blank >> phrase [actions.replaceable_post]
;
source_mode =
(
cl::str_p("c++")
| "python"
| "teletype"
) [cl::assign_a(actions.source_mode)]
;
footnote =
cl::str_p("footnote") [actions.footnote_pre]
>> blank >> phrase [actions.footnote_post]
;
}
}
#endif // BOOST_SPIRIT_QUICKBOOK_PHRASE_HPP