$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r59324 - branches/quickbook-1.5-spirit2
From: daniel_james_at_[hidden]
Date: 2010-01-27 17:07:24
Author: danieljames
Date: 2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
New Revision: 59324
URL: http://svn.boost.org/trac/boost/changeset/59324
Log:
Move most of the template implementation into template.[ch]pp
Added:
   branches/quickbook-1.5-spirit2/template.cpp   (contents, props changed)
      - copied, changed from r59323, /branches/quickbook-1.5-spirit2/phrase_template.cpp
   branches/quickbook-1.5-spirit2/template.hpp   (contents, props changed)
Removed:
   branches/quickbook-1.5-spirit2/phrase_template.cpp
   branches/quickbook-1.5-spirit2/template_stack.cpp
   branches/quickbook-1.5-spirit2/template_stack.hpp
Text files modified: 
   branches/quickbook-1.5-spirit2/Jamfile.v2             |     3                                         
   branches/quickbook-1.5-spirit2/actions_class.cpp      |     1                                         
   branches/quickbook-1.5-spirit2/actions_class.hpp      |     3                                         
   branches/quickbook-1.5-spirit2/block.hpp              |    11 -                                       
   branches/quickbook-1.5-spirit2/block_actions.cpp      |    33 +----                                   
   branches/quickbook-1.5-spirit2/code_snippet.cpp       |     7                                         
   branches/quickbook-1.5-spirit2/code_snippet_types.hpp |     6                                         
   branches/quickbook-1.5-spirit2/fwd.hpp                |     8 +                                       
   branches/quickbook-1.5-spirit2/parse_types.hpp        |     1                                         
   branches/quickbook-1.5-spirit2/phrase.cpp             |    16 +-                                      
   branches/quickbook-1.5-spirit2/phrase.hpp             |    10                                         
   branches/quickbook-1.5-spirit2/template.cpp           |   217 +++++++++++++++++++++++++++++++-------- 
   12 files changed, 206 insertions(+), 110 deletions(-)
Modified: branches/quickbook-1.5-spirit2/Jamfile.v2
==============================================================================
--- branches/quickbook-1.5-spirit2/Jamfile.v2	(original)
+++ branches/quickbook-1.5-spirit2/Jamfile.v2	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -26,12 +26,11 @@
     input_path.cpp
     post_process.cpp
     collector.cpp
-    template_stack.cpp
+    template.cpp
     markups.cpp
     phrase.cpp
     phrase_actions.cpp
     phrase_image.cpp
-    phrase_template.cpp
     block.cpp
     block_actions.cpp
     block_list.cpp
Modified: branches/quickbook-1.5-spirit2/actions_class.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/actions_class.cpp	(original)
+++ branches/quickbook-1.5-spirit2/actions_class.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -37,7 +37,6 @@
         , source_mode("c++")
 
     // temporary or global state
-        , template_info()
         , template_depth(0)
         , templates()
         , error_count(0)
Modified: branches/quickbook-1.5-spirit2/actions_class.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/actions_class.hpp	(original)
+++ branches/quickbook-1.5-spirit2/actions_class.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -15,7 +15,7 @@
 #include "fwd.hpp"
 #include "actions.hpp"
 #include "collector.hpp"
-#include "template_stack.hpp"
+#include "template.hpp"
 
 namespace quickbook
 {
@@ -61,7 +61,6 @@
         std::stack<state_tuple> state_stack;
 
     // temporary or global state
-        string_list             template_info;
         int                     template_depth;
         template_stack          templates;
         int                     error_count;
Modified: branches/quickbook-1.5-spirit2/block.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/block.hpp	(original)
+++ branches/quickbook-1.5-spirit2/block.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -62,14 +62,6 @@
         title content;
     };
 
-    struct define_template
-    {
-        std::string id;
-        std::vector<std::string> params;
-        quickbook::file_position position;
-        std::string body;
-    };
-
     struct def_macro
     {
         std::string macro_identifier;
@@ -119,7 +111,6 @@
     void process(quickbook::actions&, end_section const&);
     void process(quickbook::actions&, heading const&);
     void process(quickbook::actions&, def_macro const&);
-    void process(quickbook::actions&, define_template const&);
     void process(quickbook::actions&, variablelist const&);
     void process(quickbook::actions&, table const&);
     void process(quickbook::actions&, xinclude const&);
@@ -127,4 +118,4 @@
     void process(quickbook::actions&, include const&);
 }
 
-#endif
\ No newline at end of file
+#endif
Modified: branches/quickbook-1.5-spirit2/block_actions.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/block_actions.cpp	(original)
+++ branches/quickbook-1.5-spirit2/block_actions.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -182,20 +182,11 @@
 
     void process(quickbook::actions& actions, define_template const& x)
     {
-        if (actions.templates.find_top_scope(x.id))
-        {
+        if(!actions.templates.add(x)) {
             detail::outerr(x.position.file, x.position.line)
-                << "Template Redefinition: " << actions.template_info[0] << std::endl;
+                << "Template Redefinition: " << x.id << std::endl;
             ++actions.error_count;
         }
-
-        std::vector<std::string> info;
-        info.reserve(x.params.size() + 2);
-        info.push_back(x.id);
-        info.insert(info.end(), x.params.begin(), x.params.end());
-        info.push_back(x.body);
-
-        actions.templates.add(x.id, template_symbol(info, x.position));
     }
 
     void process(quickbook::actions& actions, variablelist const& x)
@@ -300,8 +291,8 @@
     {
         int load_snippets(
             std::string const& file
-          , std::vector<template_symbol>& storage   // snippets are stored in a
-                                                    // vector of template_symbols
+          , std::vector<define_template>& storage   // for storing snippets are stored in a
+                                                    // vector of define_templates
           , std::string const& extension
           , std::string const& doc_id)
         {
@@ -442,24 +433,18 @@
     {
         fs::path path = include_search(actions.filename.branch_path(), x.path);
         std::string ext = fs::extension(path);
-        std::vector<template_symbol> storage;
+        std::vector<define_template> storage;
         actions.error_count +=
             load_snippets(path.string(), storage, ext, actions.doc_id);
 
-        BOOST_FOREACH(template_symbol const& ts, storage)
+        BOOST_FOREACH(define_template const& definition, storage)
         {
-            std::string tname = boost::get<0>(ts)[0];
-            if (actions.templates.find_top_scope(tname))
+            if (!actions.templates.add(definition))
             {
-                file_position const pos = boost::get<1>(ts);
-                detail::outerr(pos.file, pos.line)
-                    << "Template Redefinition: " << tname << std::endl;
+                detail::outerr(definition.position.file, definition.position.line)
+                    << "Template Redefinition: " << definition.id << std::endl;
                 ++actions.error_count;
             }
-            else
-            {
-                actions.templates.add(tname, ts);
-            }
         }
     }
 }
\ No newline at end of file
Modified: branches/quickbook-1.5-spirit2/code_snippet.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/code_snippet.cpp	(original)
+++ branches/quickbook-1.5-spirit2/code_snippet.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -102,10 +102,9 @@
             }
         }
 
-        std::vector<std::string> tinfo;
-        tinfo.push_back(x.identifier);
-        tinfo.push_back(actions.snippet);
-        actions.storage.push_back(template_symbol(tinfo, x.position));
+        std::vector<std::string> empty_params;
+        actions.storage.push_back(define_template(
+            x.identifier, empty_params, actions.snippet, x.position));
 
         callout_id += actions.callouts.size();
         actions.callouts.clear();
Modified: branches/quickbook-1.5-spirit2/code_snippet_types.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/code_snippet_types.hpp	(original)
+++ branches/quickbook-1.5-spirit2/code_snippet_types.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -17,8 +17,6 @@
 #include <boost/fusion/include/adapt_struct.hpp>
 #include <boost/spirit/include/support_unused.hpp>
 #include "fwd.hpp"
-// TODO: Convert template_symbol into a struct so it can be forward declared.
-#include "template_stack.hpp"
 
 namespace quickbook
 {
@@ -67,7 +65,7 @@
 
     struct code_snippet_actions
     {
-        code_snippet_actions(std::vector<template_symbol>& storage,
+        code_snippet_actions(std::vector<define_template>& storage,
                                  std::string const& doc_id,
                                  char const* source_type)
             : process(*this)
@@ -104,7 +102,7 @@
         std::string code;
         std::string snippet;
         std::vector<std::string> callouts;
-        std::vector<template_symbol>& storage;
+        std::vector<define_template>& storage;
         std::string const doc_id;
         char const* const source_type;
     };
Modified: branches/quickbook-1.5-spirit2/fwd.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/fwd.hpp	(original)
+++ branches/quickbook-1.5-spirit2/fwd.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -22,10 +22,16 @@
 
     struct collector;
     struct string_stream;
-    
+ 
     typedef boost::spirit::classic::position_iterator<
         std::string::const_iterator> iterator;
     typedef boost::spirit::classic::file_position file_position;
+
+    // templates
+
+    struct call_template;
+    struct define_template;
+    struct template_symbol;
 }
 
 #endif
\ No newline at end of file
Modified: branches/quickbook-1.5-spirit2/parse_types.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/parse_types.hpp	(original)
+++ branches/quickbook-1.5-spirit2/parse_types.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -16,7 +16,6 @@
 
 namespace quickbook
 {
-
     struct markup {
         markup()
             : pre(""), post("") {}
Modified: branches/quickbook-1.5-spirit2/phrase.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/phrase.cpp	(original)
+++ branches/quickbook-1.5-spirit2/phrase.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -25,9 +25,6 @@
 #include "markups.hpp"
 #include "quickbook.hpp"
 #include "parse_utils.hpp"
-/*
-#include "utils.hpp"
-*/
 
 BOOST_FUSION_ADAPT_STRUCT(
     quickbook::anchor,
@@ -54,7 +51,6 @@
     (char const*, dummy)
 )
 
-
 BOOST_FUSION_ADAPT_STRUCT(
     quickbook::image,
     (quickbook::file_position, position)
@@ -69,11 +65,11 @@
 )
 
 BOOST_FUSION_ADAPT_STRUCT(
-    quickbook::template_,
+    quickbook::call_template,
     (quickbook::file_position, position)
     (bool, escape)
-    (quickbook::template_symbol, symbol)
-    (std::vector<std::string>, params)
+    (quickbook::template_symbol const*, symbol)
+    (std::vector<std::string>, args)
 )
 
 namespace quickbook
@@ -100,7 +96,7 @@
 
         qi::rule<iterator, file_position()> position;
 
-        qi::rule<iterator, quickbook::template_()> template_;
+        qi::rule<iterator, quickbook::call_template()> call_template;
         qi::rule<iterator, std::string()> template_arg_1_4, template_arg_1_5;
         qi::rule<iterator, std::vector<std::string>() > template_args;
 
@@ -193,7 +189,7 @@
 
         // Template call
 
-        template_ =
+        call_template =
                 position
             >>  (   '`' >> qi::attr(true)
                 |   qi::attr(false)
@@ -306,7 +302,7 @@
                 |   source_mode
                 |   formatted
                 |   footnote
-                |   template_
+                |   call_template
                 |   break_
                 )
             >>  ']'
Modified: branches/quickbook-1.5-spirit2/phrase.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/phrase.hpp	(original)
+++ branches/quickbook-1.5-spirit2/phrase.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -10,11 +10,11 @@
 #if !defined(BOOST_SPIRIT_QUICKBOOK_PHRASE_HPP)
 #define BOOST_SPIRIT_QUICKBOOK_PHRASE_HPP
 
+#include <vector>
 #include <string>
 #include <map>
 #include "fwd.hpp"
 #include "parse_types.hpp"
-#include "template_stack.hpp"
 
 namespace quickbook
 {
@@ -25,11 +25,11 @@
         std::string mode;
     };
     
-    struct template_ {
+    struct call_template {
         file_position position;
         bool escape;
-        template_symbol symbol;
-        std::vector<std::string> params;
+        template_symbol const* symbol;
+        std::vector<std::string> args;
     };
 
     struct anchor {
@@ -68,7 +68,7 @@
 
     void process(quickbook::actions&, source_mode const&);
     void process(quickbook::actions&, macro const&);
-    void process(quickbook::actions&, template_ const&);
+    void process(quickbook::actions&, call_template const&);
     void process(quickbook::actions&, anchor const&);
     void process(quickbook::actions&, link const&);
     void process(quickbook::actions&, simple_markup const&);
Deleted: branches/quickbook-1.5-spirit2/phrase_template.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/phrase_template.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
+++ (empty file)
@@ -1,301 +0,0 @@
-/*=============================================================================
-    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)
-=============================================================================*/
-
-#include "phrase.hpp"
-#include "grammars.hpp"
-#include "actions_class.hpp"
-#include "quickbook.hpp"
-#include "utils.hpp"
-
-namespace quickbook
-{    
-    namespace
-    {
-        std::string::size_type find_bracket_end(std::string const& str, std::string::size_type pos)
-        {
-            unsigned int depth = 1;
-
-            while(depth > 0) {
-                pos = str.find_first_of("[]\\", pos);
-                if(pos == std::string::npos) return pos;
-
-                if(str[pos] == '\\')
-                {
-                    pos += 2;
-                }
-                else
-                {
-                    depth += (str[pos] == '[') ? 1 : -1;
-                    ++pos;
-                }
-            }
-
-            return pos;
-        }
-
-        std::string::size_type find_first_seperator(std::string const& str)
-        {
-            if(qbk_version_n < 105) {
-                return str.find_first_of(" \t\r\n");
-            }
-            else {
-                std::string::size_type pos = 0;
-
-                while(true)
-                {
-                    pos = str.find_first_of(" \t\r\n\\[", pos);
-                    if(pos == std::string::npos) return pos;
-
-                    switch(str[pos])
-                    {
-                    case '[':
-                        pos = find_bracket_end(str, pos + 1);
-                        break;
-                    case '\\':
-                        pos += 2;
-                        break;
-                    default:
-                        return pos;
-                    }
-                }
-            }
-        }
-    
-        bool break_arguments(
-            std::vector<std::string>& params
-          , std::vector<std::string> const& template_
-          , file_position const& pos
-        )
-        {
-            // Quickbook 1.4-: If there aren't enough parameters seperated by
-            //                 '..' then seperate the last parameter using
-            //                 whitespace.
-            // Quickbook 1.5+: If '..' isn't used to seperate the parameters
-            //                 then use whitespace to separate them
-            //                 (2 = template name + argument).
-
-            if (qbk_version_n < 105 || params.size() == 1)
-            {
-                // template_.size() - 2 because template_ also includes the name and body.
-                while (params.size() < template_.size() - 2 )
-                {
-                    // Try to break the last argument at the first space found
-                    // and push it into the back of params. Do this
-                    // recursively until we have all the expected number of
-                    // arguments, or if there are no more spaces left.
-
-                    std::string& str = params.back();
-                    std::string::size_type l_pos = find_first_seperator(str);
-                    if (l_pos == std::string::npos)
-                        break;
-                    std::string first(str.begin(), str.begin()+l_pos);
-                    std::string::size_type r_pos = str.find_first_not_of(" \t\r\n", l_pos);
-                    if (r_pos == std::string::npos)
-                        break;
-                    std::string second(str.begin()+r_pos, str.end());
-                    str = first;
-                    params.push_back(second);
-                }
-            }
-
-            if (params.size() != template_.size() - 2)
-            {
-                detail::outerr(pos.file, pos.line)
-                    << "Invalid number of arguments passed. Expecting: "
-                    << template_.size()-2
-                    << " argument(s), got: "
-                    << params.size()
-                    << " argument(s) instead."
-                    << std::endl;
-                return false;
-            }
-            return true;
-        }
-
-        std::pair<bool, std::vector<std::string>::const_iterator>
-        get_arguments(
-            std::vector<std::string>& params
-          , std::vector<std::string> const& template_
-          , template_scope const& scope
-          , file_position const& pos
-          , quickbook::actions& actions
-        )
-        {
-            std::vector<std::string>::const_iterator arg = params.begin();
-            std::vector<std::string>::const_iterator tpl = template_.begin()+1;
-
-            // Store each of the argument passed in as local templates:
-            while (arg != params.end())
-            {
-                std::vector<std::string> tinfo;
-                tinfo.push_back(*tpl);
-                tinfo.push_back(*arg);
-                template_symbol template_(tinfo, pos, &scope);
-
-                if (actions.templates.find_top_scope(*tpl))
-                {
-                    detail::outerr(pos.file,pos.line)
-                        << "Duplicate Symbol Found" << std::endl;
-                    ++actions.error_count;
-                    return std::make_pair(false, tpl);
-                }
-                else
-                {
-                    actions.templates.add(*tpl, template_);
-                }
-                ++arg; ++tpl;
-            }
-            return std::make_pair(true, tpl);
-        }
-
-        bool parse_template(
-            std::string& body
-          , std::string& result
-          , file_position const& template_pos
-          , bool template_escape
-          , quickbook::actions& actions
-        )
-        {
-            // How do we know if we are to parse the template as a block or
-            // a phrase? We apply a simple heuristic: if the body starts with
-            // a newline, then we regard it as a block, otherwise, we parse
-            // it as a phrase.
-
-            std::string::const_iterator iter = body.begin();
-            while (iter != body.end() && ((*iter == ' ') || (*iter == '\t')))
-                ++iter; // skip spaces and tabs
-            bool is_block = (iter != body.end()) && ((*iter == '\r') || (*iter == '\n'));
-            bool r = false;
-
-            if (template_escape)
-            {
-                //  escape the body of the template
-                //  we just copy out the literal body
-                result = body;
-                r = true;
-            }
-            else if (!is_block)
-            {
-                simple_phrase_grammar phrase_p(actions);
-
-                //  do a phrase level parse
-                iterator first(body.begin(), body.end(), actions.filename.native_file_string().c_str());
-                first.set_position(template_pos);
-                iterator last(body.end(), body.end());
-                r = boost::spirit::qi::parse(first, last, phrase_p) && first == last;
-                actions.phrase.swap(result);
-            }
-            else
-            {
-                block_grammar block_p(actions);
-
-                //  do a block level parse
-                //  ensure that we have enough trailing newlines to eliminate
-                //  the need to check for end of file in the grammar.
-                body.push_back('\n');
-                body.push_back('\n');
-                while (iter != body.end() && ((*iter == '\r') || (*iter == '\n')))
-                    ++iter; // skip initial newlines
-                iterator first(iter, body.end(), actions.filename.native_file_string().c_str());
-                first.set_position(template_pos);
-                iterator last(body.end(), body.end());
-                r = boost::spirit::qi::parse(first, last, block_p) && first == last;
-                actions.phrase.swap(result);
-            }
-            return r;
-        }
-    }
-
-    void process(quickbook::actions& actions, template_ const& x)
-    {
-        ++actions.template_depth;
-        if (actions.template_depth > actions.max_template_depth)
-        {
-            detail::outerr(x.position.file,x.position.line)
-                << "Infinite loop detected" << std::endl;
-            --actions.template_depth;
-            ++actions.error_count;
-            return;
-        }
-
-        // The template arguments should have the scope that the template was
-        // called from, not the template's own scope.
-        //
-        // Note that for quickbook 1.4- this value is just ignored when the
-        // arguments are expanded.
-        template_scope const& call_scope = actions.templates.top_scope();
-
-        std::string result;
-        actions.push(); // scope the actions' states
-        {
-            // Quickbook 1.4-: When expanding the tempalte continue to use the
-            //                 current scope (the dynamic scope).
-            // Quickbook 1.5+: Use the scope the template was defined in
-            //                 (the static scope).
-            if (qbk_version_n >= 105)
-                actions.templates.set_parent_scope(*boost::get<2>(x.symbol));
-
-            std::vector<std::string> template_ = boost::get<0>(x.symbol);
-            file_position template_pos = boost::get<1>(x.symbol);
-
-            std::vector<std::string> params = x.params;
-    
-            ///////////////////////////////////
-            // Break the arguments
-            if (!break_arguments(params, template_, x.position))
-            {
-                actions.pop(); // restore the actions' states
-                --actions.template_depth;
-                ++actions.error_count;
-                return;
-            }
-
-            ///////////////////////////////////
-            // Prepare the arguments as local templates
-            bool get_arg_result;
-            std::vector<std::string>::const_iterator tpl;
-            boost::tie(get_arg_result, tpl) =
-                get_arguments(params, template_,
-                    call_scope, x.position, actions);
-
-            if (!get_arg_result)
-            {
-                actions.pop(); // restore the actions' states
-                --actions.template_depth;
-                return;
-            }
-
-            ///////////////////////////////////
-            // parse the template body:
-            std::string body;
-            body.assign(tpl->begin(), tpl->end());
-            body.reserve(body.size()+2); // reserve 2 more
-
-            if (!parse_template(body, result, template_pos, x.escape, actions))
-            {
-                detail::outerr(x.position.file,x.position.line)
-                    //<< "Expanding template:" << template_info[0] << std::endl
-                    << std::endl
-                    << "------------------begin------------------" << std::endl
-                    << body
-                    << "------------------end--------------------" << std::endl
-                    << std::endl;
-                actions.pop(); // restore the actions' states
-                --actions.template_depth;
-                ++actions.error_count;
-                return;
-            }
-        }
-
-        actions.pop(); // restore the actions' states
-        actions.phrase << result; // print it!!!
-        --actions.template_depth;
-    }
-}
\ No newline at end of file
Copied: branches/quickbook-1.5-spirit2/template.cpp (from r59323, /branches/quickbook-1.5-spirit2/phrase_template.cpp)
==============================================================================
--- /branches/quickbook-1.5-spirit2/phrase_template.cpp	(original)
+++ branches/quickbook-1.5-spirit2/template.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -1,6 +1,5 @@
 /*=============================================================================
     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
@@ -8,14 +7,149 @@
     http://www.boost.org/LICENSE_1_0.txt)
 =============================================================================*/
 
+#include <boost/spirit/include/qi_symbols.hpp>
+#include "template.hpp"
 #include "phrase.hpp"
 #include "grammars.hpp"
 #include "actions_class.hpp"
 #include "quickbook.hpp"
 #include "utils.hpp"
 
+#ifdef BOOST_MSVC
+#pragma warning(disable : 4355)
+#endif
+
 namespace quickbook
-{    
+{
+    struct template_symbol
+    {
+        template_symbol(
+                std::string const& identifier,
+                std::vector<std::string> const& params,
+                std::string const& body,
+                file_position const& position,
+                template_scope const* parent)
+           : identifier(identifier)
+           , params(params)
+           , body(body)
+           , position(position)
+           , parent(parent) {}
+    
+        std::string identifier;
+        std::vector<std::string> params;
+        std::string body;
+        file_position position;
+        template_scope const* parent;
+    };
+
+    typedef boost::spirit::qi::symbols<char, template_symbol> template_symbols;    
+
+    // template scope
+    //
+    // 1.4-: parent_scope is the previous scope on the stack
+    //       (the template's dynamic parent).
+    // 1.5+: parent_scope is the template's lexical parent.
+    //
+    // This means that a search along the parent_scope chain will follow the
+    // correct lookup chain for that version of quickboook.
+    //
+    // symbols contains the templates defined in this scope.
+    
+    struct template_scope
+    {
+        template_scope() : parent_scope() {}
+        template_scope const* parent_scope;
+        template_symbols symbols;
+    };
+
+    template_stack::template_stack()
+        : scope(template_stack::parser(*this))
+        , scopes()
+    {
+        scopes.push_front(template_scope());
+    }
+    
+    template_stack::~template_stack() {}
+    
+    template_symbol const* template_stack::prefix_find(iterator& first, iterator const& last) const
+    {
+        // search all scopes for the longest matching symbol.
+        iterator found = first;
+        template_symbol const* result = 0;
+        for (template_scope const* i = &*scopes.begin(); i; i = i->parent_scope)
+        {
+            iterator iter = first;
+            template_symbol const* symbol = i->symbols.prefix_find(iter, last);
+            if(symbol && iter.base() > found.base())
+            {
+                found = iter;
+                result = symbol;
+            }
+        }
+        first = found;
+        return result;
+    }
+
+    template_symbol const* template_stack::find(std::string const& symbol) const
+    {
+        for (template_scope const* i = &*scopes.begin(); i; i = i->parent_scope)
+        {
+            if (template_symbol const* ts = i->symbols.find(symbol.c_str()))
+                return ts;
+        }
+        return 0;
+    }
+
+    template_symbol const* template_stack::find_top_scope(std::string const& symbol) const
+    {
+        return scopes.front().symbols.find(symbol.c_str());
+    }
+
+    template_scope const& template_stack::top_scope() const
+    {
+        BOOST_ASSERT(!scopes.empty());
+        return scopes.front();
+    }
+        
+    bool template_stack::add(
+            define_template const& definition,
+            template_scope const* parent)
+    {
+        BOOST_ASSERT(!scopes.empty());
+
+        if (this->find_top_scope(definition.id)) {
+            return false;
+        }
+
+        template_symbol ts(
+            definition.id,
+            definition.params,
+            definition.body,
+            definition.position,
+            parent ? parent : &top_scope());
+
+        scopes.front().symbols.add(ts.identifier.c_str(), ts);
+        
+        return true;
+    }
+
+    void template_stack::push()
+    {
+        template_scope const& old_front = scopes.front();
+        scopes.push_front(template_scope());
+        set_parent_scope(old_front);
+    }
+
+    void template_stack::pop()
+    {
+        scopes.pop_front();
+    }
+
+    void template_stack::set_parent_scope(template_scope const& parent)
+    {
+        scopes.front().parent_scope = &parent;
+    }
+
     namespace
     {
         std::string::size_type find_bracket_end(std::string const& str, std::string::size_type pos)
@@ -69,8 +203,8 @@
         }
     
         bool break_arguments(
-            std::vector<std::string>& params
-          , std::vector<std::string> const& template_
+            std::vector<std::string>& args
+          , std::vector<std::string> const& params
           , file_position const& pos
         )
         {
@@ -81,17 +215,16 @@
             //                 then use whitespace to separate them
             //                 (2 = template name + argument).
 
-            if (qbk_version_n < 105 || params.size() == 1)
+            if (qbk_version_n < 105 || args.size() == 1)
             {
-                // template_.size() - 2 because template_ also includes the name and body.
-                while (params.size() < template_.size() - 2 )
+                while (args.size() < params.size() )
                 {
                     // Try to break the last argument at the first space found
-                    // and push it into the back of params. Do this
+                    // and push it into the back of args. Do this
                     // recursively until we have all the expected number of
                     // arguments, or if there are no more spaces left.
 
-                    std::string& str = params.back();
+                    std::string& str = args.back();
                     std::string::size_type l_pos = find_first_seperator(str);
                     if (l_pos == std::string::npos)
                         break;
@@ -101,17 +234,17 @@
                         break;
                     std::string second(str.begin()+r_pos, str.end());
                     str = first;
-                    params.push_back(second);
+                    args.push_back(second);
                 }
             }
 
-            if (params.size() != template_.size() - 2)
+            if (args.size() != params.size())
             {
                 detail::outerr(pos.file, pos.line)
                     << "Invalid number of arguments passed. Expecting: "
-                    << template_.size()-2
-                    << " argument(s), got: "
                     << params.size()
+                    << " argument(s), got: "
+                    << args.size()
                     << " argument(s) instead."
                     << std::endl;
                 return false;
@@ -121,42 +254,37 @@
 
         std::pair<bool, std::vector<std::string>::const_iterator>
         get_arguments(
-            std::vector<std::string>& params
-          , std::vector<std::string> const& template_
+            std::vector<std::string>& args
+          , std::vector<std::string> const& params
           , template_scope const& scope
           , file_position const& pos
           , quickbook::actions& actions
         )
         {
-            std::vector<std::string>::const_iterator arg = params.begin();
-            std::vector<std::string>::const_iterator tpl = template_.begin()+1;
+            std::vector<std::string>::const_iterator arg = args.begin();
+            std::vector<std::string>::const_iterator tpl = params.begin();
 
             // Store each of the argument passed in as local templates:
-            while (arg != params.end())
+            while (arg != args.end())
             {
-                std::vector<std::string> tinfo;
-                tinfo.push_back(*tpl);
-                tinfo.push_back(*arg);
-                template_symbol template_(tinfo, pos, &scope);
+                std::vector<std::string> empty_params;
 
-                if (actions.templates.find_top_scope(*tpl))
+                if (!actions.templates.add(
+                        define_template(*tpl, empty_params, *arg, pos),
+                        &scope))
                 {
                     detail::outerr(pos.file,pos.line)
                         << "Duplicate Symbol Found" << std::endl;
                     ++actions.error_count;
                     return std::make_pair(false, tpl);
                 }
-                else
-                {
-                    actions.templates.add(*tpl, template_);
-                }
                 ++arg; ++tpl;
             }
             return std::make_pair(true, tpl);
         }
 
         bool parse_template(
-            std::string& body
+            std::string body
           , std::string& result
           , file_position const& template_pos
           , bool template_escape
@@ -167,6 +295,8 @@
             // a phrase? We apply a simple heuristic: if the body starts with
             // a newline, then we regard it as a block, otherwise, we parse
             // it as a phrase.
+            
+            body.reserve(body.size() + 2);
 
             std::string::const_iterator iter = body.begin();
             while (iter != body.end() && ((*iter == ' ') || (*iter == '\t')))
@@ -199,8 +329,7 @@
                 //  do a block level parse
                 //  ensure that we have enough trailing newlines to eliminate
                 //  the need to check for end of file in the grammar.
-                body.push_back('\n');
-                body.push_back('\n');
+                body += "\n\n";
                 while (iter != body.end() && ((*iter == '\r') || (*iter == '\n')))
                     ++iter; // skip initial newlines
                 iterator first(iter, body.end(), actions.filename.native_file_string().c_str());
@@ -213,12 +342,12 @@
         }
     }
 
-    void process(quickbook::actions& actions, template_ const& x)
+    void process(quickbook::actions& actions, call_template const& x)
     {
         ++actions.template_depth;
         if (actions.template_depth > actions.max_template_depth)
         {
-            detail::outerr(x.position.file,x.position.line)
+            detail::outerr(x.position.file, x.position.line)
                 << "Infinite loop detected" << std::endl;
             --actions.template_depth;
             ++actions.error_count;
@@ -240,16 +369,13 @@
             // Quickbook 1.5+: Use the scope the template was defined in
             //                 (the static scope).
             if (qbk_version_n >= 105)
-                actions.templates.set_parent_scope(*boost::get<2>(x.symbol));
+                actions.templates.set_parent_scope(*x.symbol->parent);
 
-            std::vector<std::string> template_ = boost::get<0>(x.symbol);
-            file_position template_pos = boost::get<1>(x.symbol);
-
-            std::vector<std::string> params = x.params;
+            std::vector<std::string> args = x.args;
     
             ///////////////////////////////////
             // Break the arguments
-            if (!break_arguments(params, template_, x.position))
+            if (!break_arguments(args, x.symbol->params, x.position))
             {
                 actions.pop(); // restore the actions' states
                 --actions.template_depth;
@@ -262,7 +388,7 @@
             bool get_arg_result;
             std::vector<std::string>::const_iterator tpl;
             boost::tie(get_arg_result, tpl) =
-                get_arguments(params, template_,
+                get_arguments(args, x.symbol->params,
                     call_scope, x.position, actions);
 
             if (!get_arg_result)
@@ -274,17 +400,14 @@
 
             ///////////////////////////////////
             // parse the template body:
-            std::string body;
-            body.assign(tpl->begin(), tpl->end());
-            body.reserve(body.size()+2); // reserve 2 more
 
-            if (!parse_template(body, result, template_pos, x.escape, actions))
+            if (!parse_template(x.symbol->body, result, x.symbol->position, x.escape, actions))
             {
                 detail::outerr(x.position.file,x.position.line)
-                    //<< "Expanding template:" << template_info[0] << std::endl
+                    //<< "Expanding template:" << x.symbol->identifier << std::endl
                     << std::endl
                     << "------------------begin------------------" << std::endl
-                    << body
+                    << x.symbol->body
                     << "------------------end--------------------" << std::endl
                     << std::endl;
                 actions.pop(); // restore the actions' states
@@ -298,4 +421,6 @@
         actions.phrase << result; // print it!!!
         --actions.template_depth;
     }
-}
\ No newline at end of file
+}
+
+
Added: branches/quickbook-1.5-spirit2/template.hpp
==============================================================================
--- (empty file)
+++ branches/quickbook-1.5-spirit2/template.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
@@ -0,0 +1,102 @@
+/*=============================================================================
+    Copyright (c) 2002 2004 2006 Joel de Guzman
+    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_TEMPLATE_STACK_HPP)
+#define BOOST_SPIRIT_QUICKBOOK_TEMPLATE_STACK_HPP
+
+#include <string>
+#include <deque>
+#include <vector>
+#include <boost/spirit/include/qi_parse.hpp>
+#include <boost/spirit/home/qi/detail/assign_to.hpp>
+#include "fwd.hpp"
+
+namespace quickbook
+{
+    namespace qi = boost::spirit::qi;
+
+    struct define_template
+    {
+        define_template() {}    
+
+        define_template(
+            std::string id,
+            std::vector<std::string> params,
+            std::string body,
+            quickbook::file_position position)
+        :
+            id(id), params(params), body(body), position(position)
+        {}
+
+        std::string id;
+        std::vector<std::string> params;
+        std::string body;
+        quickbook::file_position position;
+    };
+
+    void process(quickbook::actions&, define_template const&);
+
+    struct template_scope;
+    struct template_symbol;
+
+    struct template_stack
+    {
+        typedef std::deque<template_scope> deque;
+
+        struct parser : boost::spirit::qi::primitive_parser<parser>
+        {
+            template <typename Ctx, typename Itr>
+            struct attribute {
+                typedef template_symbol const* type;
+            };
+        
+            parser(template_stack& ts)
+                : ts(ts) {}
+
+            template <typename Context, typename Skipper, typename Attribute>
+            bool parse(iterator& first, iterator const& last
+              , Context& context, Skipper const& skipper, Attribute& attr) const
+            {
+                boost::spirit::qi::skip_over(first, last, skipper);
+                template_symbol const* symbol = ts.prefix_find(first, last);
+                if(symbol) boost::spirit::traits::assign_to(symbol, attr);
+                return symbol;
+            }
+
+            template_stack& ts;
+        };
+
+        template_stack();
+        ~template_stack();
+        template_symbol const* prefix_find(iterator& first, iterator const& last) const;
+        template_symbol const* find(std::string const& symbol) const;
+        template_symbol const* find_top_scope(std::string const& symbol) const;
+        template_scope const& top_scope() const;
+        // Add the given template symbol to the current scope.
+        // If a parent scope isn't supplied, uses the current scope.
+        bool add(define_template const&, template_scope const* parent = 0);
+        void push();
+        void pop();
+
+        // Set the current scope's parent.
+        void set_parent_scope(template_scope const&);
+
+        parser scope;
+
+    private:
+
+        friend struct parser;
+        deque scopes;
+        
+        template_stack(template_stack const&);
+        template_stack& operator=(template_stack const&);        
+    };
+}
+
+#endif // BOOST_SPIRIT_QUICKBOOK_TEMPLATE_STACK_HPP
+
Deleted: branches/quickbook-1.5-spirit2/template_stack.cpp
==============================================================================
--- branches/quickbook-1.5-spirit2/template_stack.cpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
+++ (empty file)
@@ -1,78 +0,0 @@
-/*=============================================================================
-    Copyright (c) 2002 2004 2006 Joel de Guzman
-    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 "template_stack.hpp"
-
-#ifdef BOOST_MSVC
-#pragma warning(disable : 4355)
-#endif
-
-namespace quickbook
-{
-    template_stack::template_stack()
-        : scope(template_stack::parser(*this))
-        , scopes()
-    {
-        scopes.push_front(template_scope());
-    }
-    
-    template_symbol const* template_stack::find(std::string const& symbol) const
-    {
-        for (template_scope const* i = &*scopes.begin(); i; i = i->parent_scope)
-        {
-            if (template_symbol const* ts = i->symbols.find(symbol.c_str()))
-                return ts;
-        }
-        return 0;
-    }
-
-    template_symbol const* template_stack::find_top_scope(std::string const& symbol) const
-    {
-        return scopes.front().symbols.find(symbol.c_str());
-    }
-
-    template_symbols const& template_stack::top() const
-    {
-        BOOST_ASSERT(!scopes.empty());
-        return scopes.front().symbols;
-    }
-
-    template_scope const& template_stack::top_scope() const
-    {
-        BOOST_ASSERT(!scopes.empty());
-        return scopes.front();
-    }
-    
-    // TODO: Should symbols defined by '[import]' use the current scope?
-    void template_stack::add(std::string const& symbol, template_symbol const& ts)
-    {
-        BOOST_ASSERT(!scopes.empty());
-        scopes.front().symbols.add(symbol.c_str(),
-            boost::get<2>(ts) ? ts :
-            template_symbol(boost::get<0>(ts), boost::get<1>(ts), &top_scope()));
-    }    
-    
-    void template_stack::push()
-    {
-        template_scope const& old_front = scopes.front();
-        scopes.push_front(template_scope());
-        set_parent_scope(old_front);
-    }
-
-    void template_stack::pop()
-    {
-        scopes.pop_front();
-    }
-
-    void template_stack::set_parent_scope(template_scope const& parent)
-    {
-        scopes.front().parent_scope = &parent;
-    }
-}
-
-
Deleted: branches/quickbook-1.5-spirit2/template_stack.hpp
==============================================================================
--- branches/quickbook-1.5-spirit2/template_stack.hpp	2010-01-27 17:07:22 EST (Wed, 27 Jan 2010)
+++ (empty file)
@@ -1,131 +0,0 @@
-/*=============================================================================
-    Copyright (c) 2002 2004 2006 Joel de Guzman
-    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_TEMPLATE_STACK_HPP)
-#define BOOST_SPIRIT_QUICKBOOK_TEMPLATE_STACK_HPP
-
-#include <string>
-#include <deque>
-#include <vector>
-#include <boost/tuple/tuple.hpp>
-#include <boost/spirit/include/qi_symbols.hpp>
-#include <boost/spirit/include/qi_parse.hpp>
-#include <boost/next_prior.hpp>
-#include "fwd.hpp"
-
-namespace quickbook
-{
-    struct template_scope;
-
-    //  template symbols with N arguments are stored as follows:
-    //
-    //  vector<std::string>
-    //        0: template name
-    //        1: template param name[0]
-    //        2: template param name[1]
-    //      ...
-    //        N: template param name[N-1]
-    //      N+1: template body
-    //  file position
-    //  template scope (only used for 1.5+, 1.4- uses the dynamic scope)
-
-    typedef boost::tuple<
-            std::vector<std::string>
-          , file_position
-          , template_scope const*>
-    template_symbol;
-
-    typedef boost::spirit::qi::symbols<char, template_symbol> template_symbols;
-    
-    // template scope
-    //
-    // 1.4-: parent_scope is the previous scope on the stack
-    //       (the template's dynamic parent).
-    // 1.5+: parent_scope is the template's lexical parent.
-    //
-    // This means that a search along the parent_scope chain will follow the
-    // correct lookup chain for that version of quickboook.
-    //
-    // symbols contains the templates defined in this scope.
-    
-    struct template_scope
-    {
-        template_scope() : parent_scope() {}
-        template_scope const* parent_scope;
-        template_symbols symbols;
-    };
-
-    struct template_stack
-    {
-        typedef std::deque<template_scope> deque;
-
-        struct parser : boost::spirit::qi::primitive_parser<parser>
-        {
-            template <typename Ctx, typename Itr>
-            struct attribute {
-                typedef template_symbol type;
-            };
-        
-            parser(template_stack& ts)
-                : ts(ts) {}
-
-            template <typename Iterator, typename Context, typename Skipper, typename Attribute>
-            bool parse(Iterator& first, Iterator const& last
-              , Context& context, Skipper const& skipper, Attribute& attr) const
-            {
-                boost::spirit::qi::skip_over(first, last, skipper);
-            
-                // TODO: Is this right?
-                template_symbol result_attr;
-
-                // search all scopes for the longest matching symbol.
-                Iterator f = first;
-                std::ptrdiff_t len = -1;
-                for (template_scope const* i = &*ts.scopes.begin(); i; i = i->parent_scope)
-                {                    
-                    // TODO: Implement this without calling 'base'.
-                    if(i->symbols.parse(first, last, context, skipper, result_attr) && first.base() - f.base() > len)
-                    {
-                        boost::spirit::traits::assign_to(result_attr, attr);
-                        len = first.base() - f.base();
-                    }
-                    first = f;
-                }
-                if (len >= 0)
-                    first = boost::next(f, len);
-                return len > 0;
-            }
-
-            template_stack& ts;
-        };
-
-        template_stack();
-        template_symbol const* find(std::string const& symbol) const;
-        template_symbol const* find_top_scope(std::string const& symbol) const;
-        template_symbols const& top() const;
-        template_scope const& top_scope() const;
-        // Add the given template symbol to the current scope.
-        // If it doesn't have a scope, sets the symbol's scope to the current scope.
-        void add(std::string const& symbol, template_symbol const& ts);
-        void push();
-        void pop();
-
-        // Set the current scope's parent.
-        void set_parent_scope(template_scope const&);
-
-        parser scope;
-
-    private:
-
-        friend struct parser;
-        deque scopes;
-    };
-}
-
-#endif // BOOST_SPIRIT_QUICKBOOK_TEMPLATE_STACK_HPP
-