mirror of
https://github.com/boostorg/quickbook.git
synced 2026-03-05 03:02:15 +00:00
@@ -512,7 +512,7 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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 @@ namespace quickbook
|
||||
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();
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace quickbook
|
||||
|
||||
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 @@ namespace quickbook
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 @@ namespace quickbook
|
||||
// 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 @@ namespace quickbook
|
||||
// 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 @@ namespace quickbook
|
||||
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:
|
||||
|
||||
@@ -176,6 +176,7 @@ Features include:
|
||||
* 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]
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ test-suite quickbook.test :
|
||||
[ 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 @@ test-suite quickbook.test :
|
||||
[ quickbook-fail-test fail-post-process ]
|
||||
[ quickbook-fail-test fail-parse-error1 ]
|
||||
[ quickbook-fail-test fail-parse-error2 ]
|
||||
[ quickbook-fail-test fail-template-lookup1 ]
|
||||
;
|
||||
|
||||
|
||||
|
||||
7
test/fail-template-lookup1.quickbook
Normal file
7
test/fail-template-lookup1.quickbook
Normal file
@@ -0,0 +1,7 @@
|
||||
[article Fail Template Lookup 1
|
||||
[quickbook 1.5]
|
||||
]
|
||||
|
||||
[template test1[] [a]]
|
||||
[template test2[a] [test1]]
|
||||
[test2 1]
|
||||
@@ -13,4 +13,4 @@
|
||||
|
||||
[template y new]
|
||||
[template foo3[a y] [a]]
|
||||
[foo3 [y] old]
|
||||
[foo3 [y] old]
|
||||
|
||||
17
test/templates_1_5.gold
Normal file
17
test/templates_1_5.gold
Normal file
@@ -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>
|
||||
23
test/templates_1_5.quickbook
Normal file
23
test/templates_1_5.quickbook
Normal file
@@ -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]
|
||||
Reference in New Issue
Block a user