/*============================================================================= Copyright (c) 2002 2004 2006Joel 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) =============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include "grammars.hpp" #include "block.hpp" #include "template.hpp" #include "actions.hpp" #include "parse_utils.hpp" #include "code.hpp" BOOST_FUSION_ADAPT_STRUCT( quickbook::paragraph, (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::list_item, (quickbook::file_position, position) (std::string, indent) (char, mark) (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::title, (std::string, raw_markup) (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::begin_section, (boost::optional, id) (quickbook::title, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::end_section, (quickbook::file_position, position) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::heading, (int, level) (quickbook::title, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::def_macro, (std::string, macro_identifier) (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::define_template, (std::string, id) (std::vector, params) (quickbook::file_position, position) (std::string, body) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::variablelist, (std::string, title) (std::vector, entries) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::table, (boost::optional, id) (std::string, title) (std::vector, rows) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::xinclude, (std::string, path) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::import, (std::string, path) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::include, (boost::optional, id) (std::string, path) ) namespace quickbook { namespace qi = boost::spirit::qi; namespace ph = boost::phoenix; struct block_grammar::rules { rules(quickbook::actions& actions_); quickbook::actions& actions; bool no_eols; phrase_grammar common; qi::rule start_, blocks, block_markup; qi::rule begin_section; qi::rule end_section; qi::rule heading; qi::symbols heading_symbol; qi::rule paragraph_block, blockquote, preformatted; qi::symbols paragraph_blocks; qi::rule def_macro; qi::rule table; qi::rule table_row; qi::rule table_cell; qi::rule table_cell_body; qi::rule variablelist; qi::rule varlistentry; qi::rule varlistterm, varlistterm_body, varlistitem, varlistitem_body; qi::rule xinclude; qi::rule include; qi::rule import; qi::rule define_template; qi::rule template_body; qi::rule template_body_recurse; qi::rule code; qi::rule code_line; qi::rule list; qi::rule list_item; qi::rule list_item_content; qi::rule hr; qi::rule paragraph; qi::rule paragraph_content; qi::rule paragraph_end; qi::symbols<> paragraph_end_markups; qi::rule title_phrase; qi::rule inside_paragraph; qi::rule inside_paragraph2; qi::rule phrase_attr; qi::rule phrase_end; qi::rule comment, dummy_block; qi::rule()> element_id; qi::rule element_id_part; qi::rule macro_identifier; qi::rule template_id; qi::rule hard_space, space, blank, eol; qi::rule position; qi::rule error; }; block_grammar::block_grammar(quickbook::actions& actions_) : block_grammar::base_type(start, "block") , rules_pimpl(new rules(actions_)) , start(rules_pimpl->start_) {} block_grammar::~block_grammar() {} block_grammar::rules::rules(quickbook::actions& actions_) : actions(actions_), no_eols(true), common(actions, no_eols) { start_ = blocks >> blank ; blocks = +( block_markup | code [actions.process] | list [actions.process] | hr [actions.process] | comment >> *eol | paragraph [actions.process] | eol ) ; block_markup = '[' >> space >> ( begin_section | end_section | heading | paragraph_block | blockquote | preformatted | def_macro | table | variablelist | xinclude | include | import | define_template ) [actions.process] >> ( (space >> ']' >> +eol) | error ) ; begin_section = "section" >> hard_space >> element_id >> title_phrase ; end_section = position >> "endsect" >> qi::attr(nothing()) ; heading = heading_symbol >> hard_space >> title_phrase; heading_symbol.add ("h1", 1) ("h2", 2) ("h3", 3) ("h4", 4) ("h5", 5) ("h6", 6) ("heading", -1); paragraph_block = paragraph_blocks >> hard_space >> inside_paragraph ; paragraph_blocks.add ("blurb", formatted_type("blurb")) ("warning", formatted_type("warning")) ("caution", formatted_type("caution")) ("important", formatted_type("important")) ("note", formatted_type("note")) ("tip", formatted_type("tip")) ; blockquote = ':' >> blank >> qi::attr(formatted_type("blockquote")) >> inside_paragraph ; preformatted %= "pre" >> hard_space [ph::ref(no_eols) = false] >> -eol >> qi::attr(formatted_type("preformatted")) >> phrase_attr >> qi::eps [ph::ref(no_eols) = true] ; def_macro = "def" >> hard_space >> macro_identifier >> blank >> phrase_attr ; table = "table" >> (&(*qi::blank >> qi::eol) | hard_space) >> ((qi::eps(qbk_since(105u)) >> element_id) | qi::eps) >> (&(*qi::blank >> qi::eol) | space) >> *(qi::char_ - eol) >> +eol >> *table_row ; table_row = space >> '[' >> ( *table_cell >> ']' >> space | error >> qi::attr(quickbook::table_row()) ) ; table_cell = space >> '[' >> ( table_cell_body >> ']' >> space | error >> qi::attr(quickbook::table_cell()) ) ; table_cell_body = qi::attr(formatted_type("cell")) >> inside_paragraph ; variablelist = "variablelist" >> (&(*qi::blank >> qi::eol) | hard_space) >> *(qi::char_ - eol) >> +eol >> *varlistentry ; varlistentry = space >> '[' >> ( varlistterm >> +varlistitem >> ']' >> space | error >> qi::attr(quickbook::varlistentry()) ) ; varlistterm = space >> '[' >> ( varlistterm_body >> ']' >> space | error >> qi::attr(quickbook::formatted()) ) ; varlistterm_body = qi::attr(formatted_type("varlistterm")) >> phrase_attr ; varlistitem = space >> '[' >> ( varlistitem_body >> ']' >> space | error >> qi::attr(quickbook::formatted()) ) ; varlistitem_body = qi::attr(formatted_type("varlistitem")) >> inside_paragraph ; // TODO: Why do these use phrase_end? It doesn't make any sense. xinclude = "xinclude" >> hard_space >> *(qi::char_ - phrase_end) >> qi::attr(nothing()) ; include = "include" >> hard_space >> -( ':' >> *((qi::alnum | '_') - qi::space) >> space ) >> *(qi::char_ - phrase_end) ; import = "import" >> hard_space >> *(qi::char_ - phrase_end) >> qi::attr(nothing()) ; define_template = "template" >> hard_space >> template_id >> -( space >> '[' >> *(space >> template_id) >> space >> ']' ) >> position >> template_body ; template_body = qi::raw[template_body_recurse] ; template_body_recurse = *( ('[' >> template_body_recurse >> ']') | (qi::char_ - ']') ) >> space >> &qi::lit(']') ; // Blocks indicated by text layout (indentation, leading characters etc.) code = position >> qi::raw[ code_line >> *(*eol >> code_line) ] >> +eol >> qi::attr(true) ; code_line = qi::char_(" \t") >> *(qi::char_ - eol) >> eol ; list = &qi::char_("*#") >> +list_item ; list_item = position >> *qi::blank >> qi::char_("*#") >> qi::omit[*qi::blank] >> list_item_content ; list_item_content = qi::eps[actions.phrase_push] >> *( common | (qi::char_ - ( qi::eol >> *qi::blank >> &(qi::char_('*') | '#') | (eol >> eol) ) ) [actions.process] ) >> +eol >> qi::eps[actions.phrase_pop] ; hr = qi::omit[ "----" >> *(qi::char_ - eol) >> +eol ] >> qi::attr(quickbook::hr()) ; paragraph = paragraph_content >> qi::attr(nothing()); paragraph_content = qi::eps [actions.phrase_push] >> *( common | (qi::char_ - // Make sure we don't go past paragraph_end // a single block. ) [actions.process] ) >> qi::eps [actions.phrase_pop] >> (&qi::lit('[') | +eol) ; paragraph_end = '[' >> space >> paragraph_end_markups >> hard_space | eol >> eol ; paragraph_end_markups = "section", "endsect", "h1", "h2", "h3", "h4", "h5", "h6", "blurb", ":", "pre", "def", "table", "include", "xinclude", "variablelist", "import", "template", "warning", "caution", "important", "note", "tip", ":" ; // Block contents // Used when the title is used both to generate the title text and // possibly to generate an id (based on the raw source). title_phrase = qi::raw[ phrase_attr [ph::at_c<1>(qi::_val) = qi::_1] ] [ph::at_c<0>(qi::_val) = as_string(qi::_1)] ; inside_paragraph = qi::eps [actions.phrase_push] >> inside_paragraph2 [actions.process] >> *( eol >> eol >> inside_paragraph2 [actions.process] ) >> qi::eps [actions.phrase_pop] ; inside_paragraph2 = qi::attr(formatted_type("paragraph")) >> phrase_attr; phrase_attr = qi::eps [actions.phrase_push] >> *( common | comment | (qi::char_ - phrase_end) [actions.process] ) >> qi::eps [actions.phrase_pop] ; // Make sure that we don't go past a single block, except when // preformatted. phrase_end = ']' | qi::eps(ph::ref(no_eols)) >> eol >> eol ; comment = "[/" >> *(dummy_block | (qi::char_ - ']')) >> ']' ; dummy_block = '[' >> *(dummy_block | (qi::char_ - ']')) >> ']' ; // Identifiers element_id = ( ':' >> -(qi::eps(qbk_since(105u)) >> space) >> ( element_id_part | qi::omit[ qi::raw[qi::eps] [actions.element_id_warning] ] ) ) | qi::eps ; element_id_part = +(qi::alnum | qi::char_('_')); macro_identifier = +(qi::char_ - (qi::space | ']')) ; template_id = (qi::alpha | '_') >> *(qi::alnum | '_') | qi::repeat(1)[qi::punct - qi::char_("[]")] ; // Used after an identifier that must not be immediately // followed by an alpha-numeric character or underscore. hard_space = !(qi::alnum | '_') >> space ; space = *(qi::space | comment) ; blank = *(qi::blank | comment) ; eol = blank >> qi::eol ; position = qi::raw[qi::eps] [get_position]; error = qi::raw[qi::eps] [actions.error]; } }