$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r55908 - in trunk/tools/quickbook: detail doc test
From: daniel_james_at_[hidden]
Date: 2009-08-31 07:36:48
Author: danieljames
Date: 2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
New Revision: 55908
URL: http://svn.boost.org/trac/boost/changeset/55908
Log:
Implement static/lexical scoping for 1.5. Refs #2034.
Added:
   trunk/tools/quickbook/test/fail-template-lookup1.quickbook   (contents, props changed)
   trunk/tools/quickbook/test/templates_1_5.gold   (contents, props changed)
   trunk/tools/quickbook/test/templates_1_5.quickbook   (contents, props changed)
Text files modified: 
   trunk/tools/quickbook/detail/actions.cpp           |    28 ++++++++++++++++++++++++----            
   trunk/tools/quickbook/detail/template_stack.cpp    |    22 +++++++++++++++++++---                  
   trunk/tools/quickbook/detail/template_stack.hpp    |    30 +++++++++++++++++++++++++-----          
   trunk/tools/quickbook/doc/quickbook.qbk            |     1 +                                       
   trunk/tools/quickbook/test/Jamfile.v2              |     2 ++                                      
   trunk/tools/quickbook/test/templates_1_4.quickbook |     2 +-                                      
   6 files changed, 72 insertions(+), 13 deletions(-)
Modified: trunk/tools/quickbook/detail/actions.cpp
==============================================================================
--- trunk/tools/quickbook/detail/actions.cpp	(original)
+++ trunk/tools/quickbook/detail/actions.cpp	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -512,7 +512,7 @@
         actions.template_info.push_back(std::string(first, last));
         actions.templates.add(
             actions.template_info[0]
-          , boost::make_tuple(actions.template_info, first.get_position()));
+          , template_symbol(actions.template_info, first.get_position()));
         actions.template_info.clear();
     }
 
@@ -565,6 +565,7 @@
         get_arguments(
             std::vector<std::string>& template_info
           , std::vector<std::string> const& template_
+          , template_scope const& scope
           , boost::spirit::classic::file_position const& pos
           , quickbook::actions& actions
         )
@@ -578,7 +579,7 @@
                 std::vector<std::string> tinfo;
                 tinfo.push_back(*tpl);
                 tinfo.push_back(*arg);
-                template_symbol template_(tinfo, pos);
+                template_symbol template_(tinfo, pos, &scope);
 
                 if (actions.templates.find_top_scope(*tpl))
                 {
@@ -665,6 +666,17 @@
             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();
+
+        template_symbol const* symbol =
+            actions.templates.find(actions.template_info[0]);
+        BOOST_ASSERT(symbol);
+            
         std::string result;
         actions.push(); // scope the actions' states
         {
@@ -672,6 +684,13 @@
                 actions.templates.find(actions.template_info[0]);
             BOOST_ASSERT(symbol);
 
+            // 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>(*symbol));
+
             std::vector<std::string> template_ = boost::get<0>(*symbol);
             boost::spirit::classic::file_position template_pos = boost::get<1>(*symbol);
 
@@ -693,7 +712,8 @@
             bool get_arg_result;
             std::vector<std::string>::const_iterator tpl;
             boost::tie(get_arg_result, tpl) =
-                get_arguments(template_info, template_, pos, actions);
+                get_arguments(template_info, template_,
+                    call_scope, pos, actions);
 
             if (!get_arg_result)
             {
@@ -1069,7 +1089,7 @@
         std::vector<std::string> tinfo;
         tinfo.push_back(id);
         tinfo.push_back(snippet);
-        storage.push_back(boost::make_tuple(tinfo, first.get_position()));
+        storage.push_back(template_symbol(tinfo, first.get_position()));
 
         callout_id += callouts.size();
         callouts.clear();
Modified: trunk/tools/quickbook/detail/template_stack.cpp
==============================================================================
--- trunk/tools/quickbook/detail/template_stack.cpp	(original)
+++ trunk/tools/quickbook/detail/template_stack.cpp	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -23,7 +23,7 @@
     
     template_symbol* template_stack::find(std::string const& symbol) const
     {
-        for (deque::const_iterator i = scopes.begin(); i != scopes.end(); ++i)
+        for (template_scope const* i = &*scopes.begin(); i; i = i->parent_scope)
         {
             if (template_symbol* ts = boost::spirit::classic::find(i->symbols, symbol.c_str()))
                 return ts;
@@ -41,22 +41,38 @@
         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());
-        boost::spirit::classic::add(scopes.front().symbols, symbol.c_str(), ts);
-    }
+        boost::spirit::classic::add(scopes.front().symbols, 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;
+    }
 }
 
 
Modified: trunk/tools/quickbook/detail/template_stack.hpp
==============================================================================
--- trunk/tools/quickbook/detail/template_stack.hpp	(original)
+++ trunk/tools/quickbook/detail/template_stack.hpp	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -21,6 +21,8 @@
 
 namespace quickbook
 {
+    struct template_scope;
+
     //  template symbols with N arguments are stored as follows:
     //
     //  vector<std::string>
@@ -28,21 +30,34 @@
     //        1: template param name[0]
     //        2: template param name[1]
     //      ...
-    //      template param name[N]
-    //      template body
     //        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>
-          , boost::spirit::classic::file_position>
+          , boost::spirit::classic::file_position
+          , template_scope const*>
     template_symbol;
 
     typedef boost::spirit::classic::symbols<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;
     };
 
@@ -64,8 +79,7 @@
                 // search all scopes for the longest matching symbol.
                 typename Scanner::iterator_t f = scan.first;
                 std::ptrdiff_t len = -1;
-                for (template_stack::deque::const_iterator i = ts.scopes.begin();
-                    i != ts.scopes.end(); ++i)
+                for (template_scope const* i = &*ts.scopes.begin(); i; i = i->parent_scope)
                 {
                     boost::spirit::classic::match<> m = i->symbols.parse(scan);
                     if (m.length() > len)
@@ -84,10 +98,16 @@
         template_symbol* find(std::string const& symbol) const;
         template_symbol* 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&);
+
         boost::spirit::classic::functor_parser<parser> scope;
 
     private:
Modified: trunk/tools/quickbook/doc/quickbook.qbk
==============================================================================
--- trunk/tools/quickbook/doc/quickbook.qbk	(original)
+++ trunk/tools/quickbook/doc/quickbook.qbk	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -176,6 +176,7 @@
 * Improved handling of unmatched escape in code blocks.
 * Support for python snippets.
 * `teletype` source mode.
+* Use static scoping in templates, should be a lot more intuitive.
 
 [endsect]
 
Modified: trunk/tools/quickbook/test/Jamfile.v2
==============================================================================
--- trunk/tools/quickbook/test/Jamfile.v2	(original)
+++ trunk/tools/quickbook/test/Jamfile.v2	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -22,6 +22,7 @@
     [ quickbook-test escape ]
     [ quickbook-test templates ]
     [ quickbook-test templates_1_4 ]
+    [ quickbook-test templates_1_5 ]
     [ quickbook-test xinclude ]
     [ quickbook-test import ]
     [ quickbook-fail-test fail-include ]
@@ -33,6 +34,7 @@
     [ quickbook-fail-test fail-post-process ]
     [ quickbook-fail-test fail-parse-error1 ]
     [ quickbook-fail-test fail-parse-error2 ]
+    [ quickbook-fail-test fail-template-lookup1 ]
     ;
 
 
Added: trunk/tools/quickbook/test/fail-template-lookup1.quickbook
==============================================================================
--- (empty file)
+++ trunk/tools/quickbook/test/fail-template-lookup1.quickbook	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -0,0 +1,7 @@
+[article Fail Template Lookup 1
+    [quickbook 1.5]
+]
+
+[template test1[] [a]]
+[template test2[a] [test1]]
+[test2 1]
\ No newline at end of file
Modified: trunk/tools/quickbook/test/templates_1_4.quickbook
==============================================================================
--- trunk/tools/quickbook/test/templates_1_4.quickbook	(original)
+++ trunk/tools/quickbook/test/templates_1_4.quickbook	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -13,4 +13,4 @@
 
 [template y new]
 [template foo3[a y] [a]]
-[foo3 [y] old]
\ No newline at end of file
+[foo3 [y] old]
Added: trunk/tools/quickbook/test/templates_1_5.gold
==============================================================================
--- (empty file)
+++ trunk/tools/quickbook/test/templates_1_5.gold	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="template_1_5" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+  <title>Template 1.5</title>
+  <articleinfo>
+  </articleinfo>
+  <para>
+    static scoping
+  </para>
+  <para>
+    new
+  </para>
+  <para>
+    foo foo
+  </para>
+</article>
Added: trunk/tools/quickbook/test/templates_1_5.quickbook
==============================================================================
--- (empty file)
+++ trunk/tools/quickbook/test/templates_1_5.quickbook	2009-08-31 07:36:47 EDT (Mon, 31 Aug 2009)
@@ -0,0 +1,23 @@
+[article Template 1.5
+    [quickbook 1.5]
+]
+
+[/ 1.5 uses static scoping ]
+
+[template x static scoping]
+[template foo1[] [x]]
+[template foo2[x] [foo1]]
+[foo2 dynamic scoping]
+
+[/ In 1.5 template arguments are scoped at the point they are defined]
+
+[template y new]
+[template foo3[a y] [a]]
+[foo3 [y] old]
+
+[/ From https://svn.boost.org/trac/boost/ticket/2034 ]
+
+[template same[x] [x]]
+[template echo[a b] [a] [b]]
+[template echo_twice[x] [echo [same [x]]..[same [x]]]]
+[echo_twice foo]