$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r75446 - in branches/quickbook-dev/tools/quickbook: doc src test
From: dnljms_at_[hidden]
Date: 2011-11-10 13:17:05
Author: danieljames
Date: 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
New Revision: 75446
URL: http://svn.boost.org/trac/boost/changeset/75446
Log:
Quickbook: Parse lists with paragraphs.
Quite a big change. I moved the list logic into the grammar so that it's
easier to tell how to parse different blocks. Also reworked some of the
block vs. phrase stuff - it's a lot cleaner now which helped implement
this.  It generates terrible markup at the moment, but at least the
parser is in place.
Added:
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold
      - copied, changed from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook
      - copied, changed from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook
Text files modified: 
   branches/quickbook-dev/tools/quickbook/doc/1_6.qbk                  |    33 +++                                     
   branches/quickbook-dev/tools/quickbook/src/actions.cpp              |    97 ++-------                               
   branches/quickbook-dev/tools/quickbook/src/actions.hpp              |    15 +                                       
   branches/quickbook-dev/tools/quickbook/src/actions_class.cpp        |     1                                         
   branches/quickbook-dev/tools/quickbook/src/actions_class.hpp        |     6                                         
   branches/quickbook-dev/tools/quickbook/src/block_tags.hpp           |     2                                         
   branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp         |    31 +-                                      
   branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp         |   390 +++++++++++++++++++++++++++++++-------- 
   branches/quickbook-dev/tools/quickbook/src/quickbook.cpp            |    10                                         
   branches/quickbook-dev/tools/quickbook/test/Jamfile.v2              |     1                                         
   branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold      |   123 ++++++++++++                            
   branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook |    33 +++                                     
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold      |   161 ++++++++++++++++                        
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook |    49 ++++                                    
   14 files changed, 772 insertions(+), 180 deletions(-)
Modified: branches/quickbook-dev/tools/quickbook/doc/1_6.qbk
==============================================================================
--- branches/quickbook-dev/tools/quickbook/doc/1_6.qbk	(original)
+++ branches/quickbook-dev/tools/quickbook/doc/1_6.qbk	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -200,4 +200,37 @@
 
 [endsect]
 
+[section:listparagraphs Pargraphs in lists]
+
+I'm still refining this, but paragraphs can now be used in lists:
+
+[pre
+* Para 1
+
+  Para 2
+  * Nested Para 1
+
+    Nested Para 2
+
+        Code block
+  Para 3
+]
+
+generates:
+
+* Para 1
+
+  Para 2
+  * Nested Para 1
+
+    Nested Para 2
+
+        Code block
+  Para 3
+
+/TODO/: Improve code generation.
+/TODO/: Allow block elements in list items.
+
+[endsect]
+
 [endsect] [/1_6]
\ No newline at end of file
Modified: branches/quickbook-dev/tools/quickbook/src/actions.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.cpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -67,7 +67,6 @@
         }
     }
 
-    void list_action(quickbook::actions&, value);
     void explicit_list_action(quickbook::actions&, value);
     void header_action(quickbook::actions&, value);
     void begin_section_action(quickbook::actions&, value);
@@ -99,8 +98,6 @@
         
         switch(v.get_tag())
         {
-        case block_tags::list:
-            return list_action(actions, v);
         case block_tags::ordered_list:
         case block_tags::itemized_list:
             return explicit_list_action(actions, v);
@@ -314,6 +311,14 @@
         }
     }
 
+    void list_item_action::operator()() const
+    {
+        std::string str;
+        actions.phrase.swap(str);
+        actions.out << str;
+        write_anchors(actions, actions.out);
+    }
+
     void phrase_end_action::operator()() const
     {
         write_anchors(actions, actions.phrase);
@@ -486,76 +491,30 @@
         }
     }
 
-    void list_action(quickbook::actions& actions, value list)
+    void actions::start_list(char mark)
     {
-        write_anchors(actions, actions.out);
-
-        typedef std::pair<char, int> mark_type;
-        std::stack<mark_type> list_marks;
-        int list_indent = -1;
-
-        BOOST_FOREACH(value_consumer values, list)
-        {
-            int new_indent = indent_length(
-                    values.consume(general_tags::list_indent).get_quickbook());
-            value mark_value = values.consume(general_tags::list_mark);
-            std::string content = values.consume().get_boostbook();
-            values.finish();
-
-            char mark = *mark_value.get_quickbook().begin();
-            assert(mark == '*' || mark == '#');
-
-            if(list_indent == -1) {
-                assert(new_indent == 0);
-            }
-
-            if(new_indent > list_indent)
-            {
-                list_indent = new_indent;
-                list_marks.push(mark_type(mark, list_indent));
-
-                actions.out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
-            }
-            else if (new_indent < list_indent)
-            {
-                BOOST_ASSERT(!list_marks.empty());
-                list_indent = new_indent;
+        write_anchors(*this, out);
+        assert(mark == '*' || mark == '#');
+        out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
+    }
 
-                while (!list_marks.empty() && (list_indent < list_marks.top().second))
-                {
-                    char mark = list_marks.top().first;
-                    list_marks.pop();
-                    actions.out << "</simpara></listitem>";
-                    actions.out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
-                }
-                actions.out << "</simpara></listitem>";
-            }
-            else
-            {
-                actions.out << "</simpara></listitem>";
-            }
+    void actions::end_list(char mark)
+    {
+        write_anchors(*this, out);
+        assert(mark == '*' || mark == '#');
+        out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
+    }
 
-            if (mark != list_marks.top().first) // new_indent == list_indent
-            {
-                detail::outerr(mark_value.get_file(), mark_value.get_position())
-                    << "Illegal change of list style.\n";
-                detail::outwarn(mark_value.get_file(), mark_value.get_position())
-                    << "Ignoring change of list style" << std::endl;
-                ++actions.error_count;
-            }
-            
-            actions.out << "<listitem><simpara>";
-            actions.out << content;
-        }
+    void actions::start_list_item()
+    {
+        out << "<listitem><simpara>";
+        write_anchors(*this, out);
+    }
 
-        assert(!list_marks.empty());
-        while (!list_marks.empty())
-        {
-            char mark = list_marks.top().first;
-            list_marks.pop();
-            actions.out << "</simpara></listitem>";
-            actions.out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
-        }
+    void actions::end_list_item()
+    {
+        write_anchors(*this, out);
+        out << "</simpara></listitem>";
     }
 
     void explicit_list_action(quickbook::actions& actions, value list)
Modified: branches/quickbook-dev/tools/quickbook/src/actions.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.hpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -131,6 +131,21 @@
         quickbook::actions& actions;
     };
 
+    struct list_item_action
+    {
+        //  implicit paragraphs
+        //  doesn't output the paragraph if it's only whitespace.
+
+        list_item_action(
+            quickbook::actions& actions)
+        : actions(actions) {}
+
+        void operator()() const;
+        void operator()(parse_iterator, parse_iterator) const { (*this)(); }
+
+        quickbook::actions& actions;
+    };
+
     struct phrase_end_action
     {
         phrase_end_action(quickbook::actions& actions) :
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.cpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -59,6 +59,7 @@
         , code_block(phrase, phrase, *this)
         , inline_code(phrase, *this)
         , paragraph(*this)
+        , list_item(*this)
         , phrase_end(*this)
         , raw_char(phrase)
         , plain_char(phrase, *this)
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.hpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -77,6 +77,11 @@
     // actions
     ///////////////////////////////////////////////////////////////////////////
 
+        void start_list(char mark);
+        void end_list(char mark);
+        void start_list_item();
+        void end_list_item();
+
         scoped_parser<to_value_scoped_action>
                                 to_value;
         scoped_parser<cond_phrase_push>
@@ -91,6 +96,7 @@
         code_action             code_block;
         inline_code_action      inline_code;
         paragraph_action        paragraph;
+        list_item_action        list_item;
         phrase_end_action       phrase_end;
         raw_char_action         raw_char;
         plain_char_action       plain_char;
Modified: branches/quickbook-dev/tools/quickbook/src/block_tags.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/block_tags.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/block_tags.hpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -23,7 +23,7 @@
         (variable_list)(table)
         (xinclude)(import)(include)
         (paragraph)
-        (list)(ordered_list)(itemized_list)
+        (ordered_list)(itemized_list)
         (hr)
     )
 
Modified: branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -22,26 +22,21 @@
 
     struct element_info
     {
-        enum context {
-            in_block = 1,
-            in_phrase = 2,
-            in_conditional = 4,
-            in_nested_block = 8,
-            // This is a magic value to indicate an element that
-            // might be a block or might be a phrase. It isn't
-            // perfect, if a contextual_block appears at the
-            // beginning of a paragraph it might interpreted as
-            // a block when is should be a phrase.
-            contextual_block = 16
-        };
-
         enum type_enum {
             nothing = 0,
-            block = in_block,
-            conditional_or_block = block | in_conditional,
-            nested_block = conditional_or_block | in_nested_block,
-            phrase = nested_block | in_phrase,
-            maybe_block = phrase | contextual_block
+            block = 1,
+            conditional_or_block = 2,
+            nested_block = 4,
+            phrase = 8,
+            maybe_block = 16
+        };
+
+        enum context {
+            in_phrase = phrase | maybe_block,
+            in_conditional = in_phrase | conditional_or_block,
+            in_nested_block = in_conditional | nested_block,
+            only_block = block | conditional_or_block | nested_block,
+            only_contextual_block = block | conditional_or_block | nested_block | maybe_block
         };
 
         element_info()
Modified: branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -16,6 +16,7 @@
 #include "phrase_tags.hpp"
 #include "parsers.hpp"
 #include "scoped.hpp"
+#include "input_path.hpp"
 #include <boost/spirit/include/classic_core.hpp>
 #include <boost/spirit/include/classic_chset.hpp>
 #include <boost/spirit/include/classic_if.hpp>
@@ -23,16 +24,65 @@
 #include <boost/spirit/include/classic_attribute.hpp>
 #include <boost/spirit/include/classic_lazy.hpp>
 #include <boost/spirit/include/phoenix1_primitives.hpp>
+#include <boost/range/algorithm/find_first_of.hpp>
+#include <boost/range/as_literal.hpp>
+
+#include <iostream>
 
 namespace quickbook
 {
     namespace cl = boost::spirit::classic;
 
+    struct list_stack_item {
+        bool root;
+        unsigned int indent;
+        unsigned int indent2;
+        char mark;
+
+        list_stack_item() :
+            root(true), indent(0), indent2(0), mark('\0') {}
+
+        list_stack_item(char mark, unsigned int indent, unsigned int indent2) :
+            root(false), indent(indent), indent2(indent2), mark(mark)
+        {}
+
+    };
+
+    struct block_types {
+        enum values {
+            none, code, list, paragraph
+        };
+    };
+
+    template <typename T>
+    struct member_action
+    {
+        typedef void(T::*member_function)(parse_iterator, parse_iterator);
+
+        T& l;
+        member_function mf;
+
+        member_action(T& l, member_function mf) : l(l), mf(mf) {}
+
+        void operator()(parse_iterator first, parse_iterator last) const {
+            (l.*mf)(first, last);
+        }
+    };
+
     struct main_grammar_local
     {
         ////////////////////////////////////////////////////////////////////////
         // Local actions
 
+        void start_blocks_impl(parse_iterator first, parse_iterator last);
+        void end_blocks_impl(parse_iterator first, parse_iterator last);
+        void check_indentation_impl(parse_iterator first, parse_iterator last);
+        void check_code_block_impl(parse_iterator first, parse_iterator last);
+        void plain_block(string_iterator first, string_iterator last);
+        void list_block(string_iterator first, string_iterator mark_pos,
+                string_iterator last);
+        void clear_stack();
+
         struct process_element_impl : scoped_action_base {
             process_element_impl(main_grammar_local& l)
                 : l(l) {}
@@ -45,16 +95,10 @@
 
                 info_ = l.info;
 
-                if (!(info_.type & element_info::in_phrase))
+                if (info_.type != element_info::phrase &&
+                        info_.type != element_info::maybe_block)
                     l.actions_.paragraph();
 
-                if ((info_.type & element_info::contextual_block) &&
-                        l.top_level.parse_blocks())
-                {
-                    info_.type = element_info::type_enum(
-                        info_.type & ~element_info::in_phrase);
-                }
-
                 l.actions_.values.builder.reset();
                 
                 return true;
@@ -76,32 +120,25 @@
             main_grammar_local& l;
             element_info info_;
         };
-        
-        struct is_block_type
-        {
-            typedef bool result_type;
-            template <typename Arg1 = void>
-            struct result { typedef bool type; };
-        
-            is_block_type(main_grammar_local& l)
-                : l_(l)
-            {}
 
-            bool operator()() const
-            {
-                return l_.element_type && !(l_.element_type & element_info::in_phrase);
+        struct in_list_impl {
+            main_grammar_local& l;
+
+            in_list_impl(main_grammar_local& l) :
+                l(l) {}
+
+            bool operator()() const {
+                return !l.list_stack.top().root;
             }
-            
-            main_grammar_local& l_;
         };
 
         ////////////////////////////////////////////////////////////////////////
         // Local members
 
         cl::rule<scanner>
-                        blocks, paragraph_separator,
+                        top_level, indent_check,
+                        paragraph_separator,
                         code, code_line, blank_line, hr,
-                        list, list_item,
                         inline_code,
                         template_,
                         code_block, macro,
@@ -121,10 +158,9 @@
             member1 mark;
         };
 
-        struct block_parse_closure
-            : cl::closure<block_parse_closure, bool>
+        struct block_item_closure : cl::closure<block_item_closure, bool>
         {
-            member1 parse_blocks;
+            member1 still_in_block;
         };
 
         struct context_closure : cl::closure<context_closure, element_info::context>
@@ -135,24 +171,39 @@
         cl::rule<scanner, simple_markup_closure::context_t> simple_markup;
         cl::rule<scanner> simple_markup_end;
 
-        cl::rule<scanner, block_parse_closure::context_t> top_level;
+        cl::rule<scanner, block_item_closure::context_t> paragraph;
+        cl::rule<scanner, context_closure::context_t> paragraph_item;
+        cl::rule<scanner, block_item_closure::context_t> list;
+        cl::rule<scanner, context_closure::context_t> list_item;
         cl::rule<scanner, context_closure::context_t> common;
         cl::rule<scanner, context_closure::context_t> element;
 
+        std::stack<list_stack_item> list_stack;
+        unsigned int list_indent;
+        block_types::values block_type;
+
         element_info info;
         element_info::type_enum element_type;
 
         quickbook::actions& actions_;
+        member_action<main_grammar_local> check_indentation;
+        member_action<main_grammar_local> check_code_block;
+        member_action<main_grammar_local> start_blocks;
+        member_action<main_grammar_local> end_blocks;
+        in_list_impl in_list;
         scoped_parser<process_element_impl> process_element;
-        is_block_type is_block;
 
         ////////////////////////////////////////////////////////////////////////
         // Local constructor
 
         main_grammar_local(quickbook::actions& actions)
             : actions_(actions)
+            , check_indentation(*this, &main_grammar_local::check_indentation_impl)
+            , check_code_block(*this, &main_grammar_local::check_indentation_impl)
+            , start_blocks(*this, &main_grammar_local::start_blocks_impl)
+            , end_blocks(*this, &main_grammar_local::end_blocks_impl)
+            , in_list(*this)
             , process_element(*this)
-            , is_block(*this)
             {}
     };
 
@@ -219,47 +270,85 @@
             ]
             ;
         // Top level blocks
-        block_start = local.top_level;
+        block_start =
+                (*eol)                          [local.start_blocks]
+            >>  (*local.top_level)              [local.end_blocks]
+            ;
 
         local.top_level =
-                cl::eps_p                       [local.top_level.parse_blocks = true]
-            >>  *(  cl::eps_p(local.top_level.parse_blocks)
-                >>  local.blocks
-                |   local.element(element_info::in_block)
-                                                [local.top_level.parse_blocks = false]
-                >>  !(cl::eps_p(local.is_block) >> +eol)
-                                                [local.top_level.parse_blocks = true]
-                |   local.paragraph_separator   [local.top_level.parse_blocks = true]
-                |   local.common(element_info::in_phrase)
-                                                [local.top_level.parse_blocks = false]
+                cl::eps_p(local.indent_check)
+            >>  (   cl::eps_p(ph::var(local.block_type) == block_types::code)
+                >>  local.code
+                |   cl::eps_p(ph::var(local.block_type) == block_types::list)
+                >>  local.list
+                |   cl::eps_p(ph::var(local.block_type) == block_types::paragraph)
+                >>  (   local.hr
+                    |   local.paragraph
+                    )
+                )
+            >>  *eol
+            ;
+
+        local.indent_check =
+            (   *cl::blank_p
+            >>  !(  (cl::ch_p('*') | '#')
+                >> *cl::blank_p)
+            )                                   [local.check_indentation]
+            ;
+
+        local.paragraph =
+                cl::eps_p                       [local.paragraph.still_in_block = true]
+            >>  local.paragraph_item(element_info::only_contextual_block)
+            >>  *(  cl::eps_p(local.paragraph.still_in_block)
+                >>  local.paragraph_item(element_info::only_block)
                 )
             >>  cl::eps_p                       [actions.paragraph]
             ;
 
+        local.paragraph_item =
+                local.element(local.paragraph_item.context)
+            >>  !eol                            [local.paragraph.still_in_block = false]
+            |   local.paragraph_separator       [local.paragraph.still_in_block = false]
+            |   local.common(element_info::in_phrase)
+            ;
+
+        local.list =
+                *cl::blank_p
+            >>  (cl::ch_p('*') | '#')
+            >>  *cl::blank_p                    [local.list.still_in_block = true]
+            >>  *(  cl::eps_p(local.list.still_in_block)
+                >>  local.list_item
+                )
+            >>  cl::eps_p                       [actions.list_item]
+            ;
+
+        local.list_item =
+                cl::eps_p(local.paragraph_separator) [local.list.still_in_block = false]
+            |   local.common(element_info::in_phrase)
+            ;
+
+        local.paragraph_separator =
+                cl::eol_p
+            >>  cl::eps_p
+                (   *cl::blank_p
+                >>  (   cl::eol_p
+                    |   cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#')
+                    )
+                )
+            >>  *eol
+            ;
+
         // Blocks contains within an element, e.g. a table cell or a footnote.
         inside_paragraph =
             actions.values.save()
             [   *(  local.paragraph_separator   [actions.paragraph]
+                >>  *eol
                 |   ~cl::eps_p(']')
                 >>  local.common(element_info::in_nested_block)
                 )
             ]                                   [actions.paragraph]
             ;
 
-        local.blocks =
-           +(   local.code
-            |   local.list
-            |   local.hr
-            |   +eol
-            )
-            ;
-
-        local.paragraph_separator
-            =   cl::eol_p
-            >> *cl::blank_p
-            >>  cl::eol_p                       [actions.paragraph]
-            ;
-
         local.hr =
                 cl::str_p("----")
             >>  actions.values.list(block_tags::hr)
@@ -297,39 +386,18 @@
             ;
 
         local.code_line =
-            cl::blank_p >> *(cl::anychar_p - cl::eol_p) >> (cl::eol_p | cl::end_p)
+            (   *cl::blank_p
+            >>  ~cl::eps_p(cl::eol_p)
+            )                                   [local.check_code_block]
+        >>  cl::eps_p(ph::var(local.block_type) == block_types::code)
+        >>  *(cl::anychar_p - cl::eol_p)
+        >>  (cl::eol_p | cl::end_p)
             ;
 
         local.blank_line =
             *cl::blank_p >> cl::eol_p
             ;
 
-        local.list =
-                cl::eps_p(cl::ch_p('*') | '#')
-            >>  actions.values.list(block_tags::list)
-                [   +actions.values.list()
-                    [   (*cl::blank_p)      [actions.values.entry(ph::arg1, ph::arg2, general_tags::list_indent)]
-                    >>  (cl::ch_p('*') | '#')
-                                            [actions.values.entry(ph::arg1, ph::arg2, general_tags::list_mark)]
-                    >>  *cl::blank_p
-                    >>  actions.to_value() [ local.list_item ]
-                    ]
-                ]                           [actions.element]
-            ;
-
-        local.list_item =
-            actions.values.save()
-            [
-                *(  ~cl::eps_p
-                    (   cl::eol_p >> *cl::blank_p
-                    >>  (cl::ch_p('*') | '#' | cl::eol_p)
-                    )
-                >>  local.common(element_info::in_phrase)
-                )
-            ]
-            >> (+eol | cl::end_p)
-            ;
-
         local.common =
                 local.macro
             |   local.element(local.common.context)
@@ -621,4 +689,160 @@
             >>  +(cl::anychar_p - (cl::space_p | ']'))
             ;
     }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Indentation Handling
+
+    template <typename Iterator>
+    int indent_length(Iterator first, Iterator end)
+    {
+        int length = 0;
+        for(; first != end; ++first)
+        {
+            if (*first == '\t') {
+                // hardcoded tab to 4 for now
+                length = length + 4 - (length % 4);
+            }
+            else {
+                ++length;
+            }
+        }
+
+        return length;
+    }
+
+    void main_grammar_local::start_blocks_impl(parse_iterator, parse_iterator)
+    {
+        list_stack.push(list_stack_item());
+    }
+
+    void main_grammar_local::end_blocks_impl(parse_iterator, parse_iterator)
+    {
+        clear_stack();
+        list_stack.pop();
+    }
+
+    void main_grammar_local::check_indentation_impl(parse_iterator first_, parse_iterator last_)
+    {
+        string_iterator first = first_.base();
+        string_iterator last = last_.base();
+        string_iterator mark_pos = boost::find_first_of(
+            boost::make_iterator_range(first, last),
+            boost::as_literal("#*"));
+
+        if (mark_pos == last) {
+            plain_block(first, last);
+        }
+        else {
+            list_block(first, mark_pos, last);
+        }
+    }
+
+    void main_grammar_local::check_code_block_impl(parse_iterator first, parse_iterator last)
+    {
+        unsigned int new_indent = indent_length(first.base(), last.base());
+
+        block_type = (new_indent > list_stack.top().indent2) ?
+             block_types::code : block_types::none;
+    }
+
+    void main_grammar_local::plain_block(string_iterator first, string_iterator last)
+    {
+        if (qbk_version_n >= 106u) {
+            unsigned int new_indent = indent_length(first, last);
+
+            if (new_indent > list_stack.top().indent2) {
+                block_type = block_types::code;
+            }
+            else {
+                while (!list_stack.top().root && new_indent < list_stack.top().indent)
+                {
+                    actions_.end_list_item();
+                    actions_.end_list(list_stack.top().mark);
+                    list_stack.pop();
+                    list_indent = list_stack.top().indent;
+                }
+
+                if (!list_stack.top().root && new_indent == list_stack.top().indent)
+                {
+                    list_stack_item save = list_stack.top();
+                    list_stack.pop();
+                    if (new_indent == list_stack.top().indent) {
+                        actions_.end_list_item();
+                        actions_.end_list(save.mark);
+                        list_indent = list_stack.top().indent;
+                    }
+                    else {
+                        list_stack.push(save);
+                    }
+                }
+
+                block_type = block_types::paragraph;
+            }
+        }
+        else {
+            clear_stack();
+
+            if (last == first)
+                block_type = block_types::paragraph;
+            else
+                block_type = block_types::code;
+        }
+    }
+
+    void main_grammar_local::list_block(string_iterator first, string_iterator mark_pos,
+            string_iterator last)
+    {
+        unsigned int new_indent = indent_length(first, mark_pos);
+        unsigned int new_indent2 = indent_length(first, last);
+        char mark = *mark_pos;
+
+        if (list_stack.top().root && new_indent > 0) {
+            block_type = block_types::code;
+            return;
+        }
+
+        if (list_stack.top().root || new_indent > list_indent) {
+            list_stack.push(list_stack_item(mark, new_indent, new_indent2));
+            actions_.start_list(mark);
+        }
+        else if (new_indent == list_indent) {
+            actions_.end_list_item();
+        }
+        else {
+            // This should never reach root, since the first list
+            // has indentation 0.
+            while(!list_stack.top().root && new_indent < list_stack.top().indent)
+            {
+                actions_.end_list_item();
+                actions_.end_list(list_stack.top().mark);
+                list_stack.pop();
+            }
+
+            actions_.end_list_item();
+        }
+
+        list_indent = new_indent;
+
+        if (mark != list_stack.top().mark)
+        {
+            detail::outerr(actions_.current_file, first)
+                << "Illegal change of list style.\n";
+            detail::outwarn(actions_.current_file, first)
+                << "Ignoring change of list style." << std::endl;
+            ++actions_.error_count;
+        }
+
+        actions_.start_list_item();
+        block_type = block_types::list;
+    }
+
+    void main_grammar_local::clear_stack()
+    {
+        while (!list_stack.top().root) {
+            actions_.end_list_item();
+            actions_.end_list(list_stack.top().mark);
+            list_stack.pop();
+        }
+    }
 }
Modified: branches/quickbook-dev/tools/quickbook/src/quickbook.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/quickbook.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/quickbook.cpp	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -98,10 +98,8 @@
             pre(actor.out, actor, include_doc_id, docinfo_type);
 
             info = cl::parse(info.hit ? info.stop : first, last, actor.grammar().block);
-            if (info.full)
-            {
-                post(actor.out, actor, docinfo_type);
-            }
+
+            post(actor.out, actor, docinfo_type);
         }
 
         if (!info.full)
@@ -148,10 +146,10 @@
             result = 1;
         }
 
-        std::string stage2 = ids.replace_placeholders(buffer.str());
-
         if (result == 0)
         {
+            std::string stage2 = ids.replace_placeholders(buffer.str());
+
             fs::ofstream fileout(fileout_);
 
             if (pretty_print)
Modified: branches/quickbook-dev/tools/quickbook/test/Jamfile.v2
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/Jamfile.v2	(original)
+++ branches/quickbook-dev/tools/quickbook/test/Jamfile.v2	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -60,6 +60,7 @@
     [ quickbook-test link-1_1 ]
     [ quickbook-test link-1_6 ]
     [ quickbook-test list_test-1_5 ]
+    [ quickbook-test list_test-1_6 ]
     [ quickbook-test macro-1_5 ]
     [ quickbook-test macro-1_6 ]
     [ quickbook-error-test mismatched_brackets-1_1-fail ]
Modified: branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold	(original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -211,6 +211,77 @@
     </listitem>
   </orderedlist>
   <para>
+    Inconsistent Indentation:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+        <itemizedlist>
+          <listitem>
+            <simpara>
+              B1
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B2
+              <itemizedlist>
+                <listitem>
+                  <simpara>
+                    C1
+                  </simpara>
+                </listitem>
+                <listitem>
+                  <simpara>
+                    C2
+                  </simpara>
+                </listitem>
+              </itemizedlist>
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B3
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B4
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B5
+              <itemizedlist>
+                <listitem>
+                  <simpara>
+                    C3
+                  </simpara>
+                </listitem>
+              </itemizedlist>
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B6
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A2
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A3
+      </simpara>
+    </listitem>
+  </itemizedlist>
+  <para>
     Markup in list:
   </para>
   <itemizedlist>
@@ -239,6 +310,58 @@
       </simpara>
     </listitem>
   </itemizedlist>
+  <para>
+    Don't end list with comment 1:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A2
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A3
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A4
+      </simpara>
+    </listitem>
+  </itemizedlist>
+  <para>
+    Don't end list with comment 2:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+        <itemizedlist>
+          <listitem>
+            <simpara>
+              B1
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B2
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B3
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </simpara>
+    </listitem>
+  </itemizedlist>
   <section id="list_test.list_immediately_following_markup">
     <title><link linkend="list_test.list_immediately_following_markup">List immediately
     following markup</link></title>
Modified: branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook	(original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -52,6 +52,21 @@
 # G
 # H
 
+Inconsistent Indentation:
+
+* A1
+  * B1
+  * B2
+    * C1
+    * C2
+   * B3
+   * B4
+  * B5
+   * C3
+  * B6
+ * A2
+* A3
+
 Markup in list:
 
 *   *Bold*
@@ -59,6 +74,24 @@
 *   ["Quoted]
 *   [footnote Footnote]
 
+Don't end list with comment 1:
+
+* A1
+* A2
+
+[/ End list?]
+* A3
+* A4
+
+Don't end list with comment 2:
+
+* A1
+  * B1
+
+[/ End list?]
+  * B2
+  * B3
+
 [section List immediately following markup]
 * One
 * Two
Copied: branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold (from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold)
==============================================================================
--- /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold	(original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -211,6 +211,77 @@
     </listitem>
   </orderedlist>
   <para>
+    Inconsistent Indentation:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+        <itemizedlist>
+          <listitem>
+            <simpara>
+              B1
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B2
+              <itemizedlist>
+                <listitem>
+                  <simpara>
+                    C1
+                  </simpara>
+                </listitem>
+                <listitem>
+                  <simpara>
+                    C2
+                  </simpara>
+                </listitem>
+              </itemizedlist>
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B3
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B4
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B5
+              <itemizedlist>
+                <listitem>
+                  <simpara>
+                    C3
+                  </simpara>
+                </listitem>
+              </itemizedlist>
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B6
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A2
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A3
+      </simpara>
+    </listitem>
+  </itemizedlist>
+  <para>
     Markup in list:
   </para>
   <itemizedlist>
@@ -239,8 +310,60 @@
       </simpara>
     </listitem>
   </itemizedlist>
-  <section id="list_test.list_immediately_following_markup">
-    <title><link linkend="list_test.list_immediately_following_markup">List immediately
+  <para>
+    Don't end list with comment 1:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A2
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A3
+      </simpara>
+    </listitem>
+    <listitem>
+      <simpara>
+        A4
+      </simpara>
+    </listitem>
+  </itemizedlist>
+  <para>
+    Don't end list with comment 2:
+  </para>
+  <itemizedlist>
+    <listitem>
+      <simpara>
+        A1
+        <itemizedlist>
+          <listitem>
+            <simpara>
+              B1
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B2
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              B3
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </simpara>
+    </listitem>
+  </itemizedlist>
+  <section id="list_test.list_immediately_following_marku">
+    <title><link linkend="list_test.list_immediately_following_marku">List immediately
     following markup</link></title>
     <itemizedlist>
       <listitem>
@@ -260,4 +383,38 @@
       </listitem>
     </itemizedlist>
   </section>
+  <section id="list_test.paragraphs_in_list_items">
+    <title><link linkend="list_test.paragraphs_in_list_items">Paragraphs in list
+    items</link></title>
+    <itemizedlist>
+      <listitem>
+        <simpara>
+          One
+          <para>
+            Two
+          </para>
+        </simpara>
+      </listitem>
+      <listitem>
+        <simpara>
+          Three
+          <itemizedlist>
+            <listitem>
+              <simpara>
+                Four
+                <para>
+                  Five
+                </para>
+              </simpara>
+            </listitem>
+          </itemizedlist>
+        </simpara>
+      </listitem>
+      <listitem>
+        <simpara>
+          Six
+        </simpara>
+      </listitem>
+    </itemizedlist>
+  </section>
 </article>
Copied: branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook (from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook)
==============================================================================
--- /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook	(original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook	2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -1,5 +1,5 @@
 [article List Test
-[quickbook 1.5]
+[quickbook 1.6]
 ]
 
 Simple list:
@@ -52,6 +52,21 @@
 # G
 # H
 
+Inconsistent Indentation:
+
+* A1
+  * B1
+  * B2
+    * C1
+    * C2
+   * B3
+   * B4
+  * B5
+   * C3
+  * B6
+ * A2
+* A3
+
 Markup in list:
 
 *   *Bold*
@@ -59,9 +74,41 @@
 *   ["Quoted]
 *   [footnote Footnote]
 
+Don't end list with comment 1:
+
+* A1
+* A2
+
+[/ End list?]
+* A3
+* A4
+
+Don't end list with comment 2:
+
+* A1
+  * B1
+
+[/ End list?]
+  * B2
+  * B3
+
 [section List immediately following markup]
 * One
 * Two
 * Three
 
 [endsect]
+
+[section Paragraphs in list items]
+
+* One
+
+  Two
+
+* Three
+  * Four
+
+    Five
+* Six
+
+[endsect]
\ No newline at end of file