Use a structure for template symbol info.

[SVN r63808]
This commit is contained in:
Daniel James
2010-07-10 11:24:07 +00:00
parent df0ab8082e
commit a6712ee34f
7 changed files with 102 additions and 98 deletions

View File

@@ -233,8 +233,9 @@ namespace quickbook
template_ =
"template"
>> hard_space [clear_a(actions.template_info)]
>> template_id [push_back_a(actions.template_info)]
>> hard_space
>> template_id [assign_a(actions.template_identifier)]
[clear_a(actions.template_info)]
>>
!(
space >> '['

View File

@@ -600,19 +600,17 @@ namespace quickbook
void template_body_action::operator()(iterator first, iterator last) const
{
BOOST_ASSERT(actions.template_info.size());
if (actions.templates.find_top_scope(actions.template_info[0]))
if (!actions.templates.add(
template_symbol(actions.template_identifier, actions.template_info,
std::string(first, last), first.get_position())))
{
boost::spirit::classic::file_position const pos = first.get_position();
detail::outerr(pos.file,pos.line)
<< "Template Redefinition: " << actions.template_info[0] << std::endl;
<< "Template Redefinition: " << actions.template_identifier << std::endl;
++actions.error_count;
}
actions.template_info.push_back(std::string(first, last));
actions.templates.add(
actions.template_info[0]
, template_symbol(actions.template_info, first.get_position()));
actions.template_identifier.clear();
actions.template_info.clear();
}
@@ -669,8 +667,8 @@ namespace quickbook
}
bool break_arguments(
std::vector<std::string>& template_info
, std::vector<std::string> const& template_
std::vector<std::string>& args
, std::vector<std::string> const& params
, boost::spirit::classic::file_position const& pos
)
{
@@ -681,17 +679,16 @@ namespace quickbook
// then use whitespace to separate them
// (2 = template name + argument).
if (qbk_version_n < 105 || template_info.size() == 2)
if (qbk_version_n < 105 || args.size() == 1)
{
// template_.size() - 1 because template_ also includes the body.
while (template_info.size() < template_.size()-1 )
while (args.size() < params.size() )
{
// Try to break the last argument at the first space found
// and push it into the back of template_info. 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 = template_info.back();
std::string& str = args.back();
std::string::size_type l_pos = find_first_seperator(str);
if (l_pos == std::string::npos)
break;
@@ -701,17 +698,17 @@ namespace quickbook
break;
std::string second(str.begin()+r_pos, str.end());
str = first;
template_info.push_back(second);
args.push_back(second);
}
}
if (template_info.size() != template_.size()-1)
if (args.size() != params.size())
{
detail::outerr(pos.file, pos.line)
<< "Invalid number of arguments passed. Expecting: "
<< template_.size()-2
<< params.size()
<< " argument(s), got: "
<< template_info.size()-1
<< args.size()
<< " argument(s) instead."
<< std::endl;
return false;
@@ -721,56 +718,49 @@ namespace quickbook
std::pair<bool, std::vector<std::string>::const_iterator>
get_arguments(
std::vector<std::string>& template_info
, std::vector<std::string> const& template_
std::vector<std::string>& args
, std::vector<std::string> const& params
, template_scope const& scope
, boost::spirit::classic::file_position const& pos
, quickbook::actions& actions
)
{
std::vector<std::string>::const_iterator arg = template_info.begin()+1;
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();
std::vector<std::string> empty_params;
// Store each of the argument passed in as local templates:
while (arg != template_info.end())
while (arg != args.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))
if (!actions.templates.add(
template_symbol(*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
, bool& is_block
, boost::spirit::classic::file_position const& template_pos
, quickbook::actions& actions
)
{
simple_phrase_grammar<quickbook::actions> phrase_p(actions);
block_grammar<quickbook::actions, true> block_p(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.
body.reserve(body.size() + 2);
std::string::const_iterator iter = body.begin();
while (iter != body.end() && ((*iter == ' ') || (*iter == '\t')))
++iter; // skip spaces and tabs
@@ -786,6 +776,8 @@ namespace quickbook
}
else if (!is_block)
{
simple_phrase_grammar<quickbook::actions> phrase_p(actions);
// do a phrase level parse
iterator first(body.begin(), body.end(), actions.filename.file_string().c_str());
first.set_position(template_pos);
@@ -795,6 +787,8 @@ namespace quickbook
}
else
{
block_grammar<quickbook::actions, true> 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.
@@ -809,13 +803,21 @@ namespace quickbook
actions.inside_paragraph();
actions.out.swap(result);
}
return r;
}
}
void do_template_action::operator()(iterator first, iterator) const
{
// Get the arguments and clear values stored in action.
std::vector<std::string> args;
std::string identifier;
std::swap(args, actions.template_info);
std::swap(identifier, actions.template_identifier);
boost::spirit::classic::file_position const pos = first.get_position();
++actions.template_depth;
if (actions.template_depth > actions.max_template_depth)
{
@@ -833,8 +835,7 @@ namespace quickbook
// arguments are expanded.
template_scope const& call_scope = actions.templates.top_scope();
template_symbol const* symbol =
actions.templates.find(actions.template_info[0]);
template_symbol const* symbol = actions.templates.find(identifier);
BOOST_ASSERT(symbol);
std::string result;
@@ -845,26 +846,16 @@ namespace quickbook
// [section] and [endsect] tags in the template are balanced.
actions.min_section_level = actions.section_level;
template_symbol const* symbol =
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);
std::vector<std::string> template_info;
std::swap(template_info, actions.template_info);
actions.templates.set_parent_scope(*symbol->parent);
///////////////////////////////////
// Break the arguments
if (!break_arguments(template_info, template_, pos))
if (!break_arguments(args, symbol->params, pos))
{
actions.pop(); // restore the actions' states
--actions.template_depth;
@@ -877,7 +868,7 @@ namespace quickbook
bool get_arg_result;
std::vector<std::string>::const_iterator tpl;
boost::tie(get_arg_result, tpl) =
get_arguments(template_info, template_,
get_arguments(args, symbol->params,
call_scope, pos, actions);
if (!get_arg_result)
@@ -889,17 +880,15 @@ namespace quickbook
///////////////////////////////////
// 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, is_block, template_pos, actions))
if (!parse_template(symbol->body, result, is_block, symbol->position, actions))
{
boost::spirit::classic::file_position const pos = first.get_position();
detail::outerr(pos.file,pos.line)
<< "Expanding template:" << template_info[0] << std::endl
<< "Expanding template:" << symbol->identifier << std::endl
<< std::endl
<< "------------------begin------------------" << std::endl
<< body
<< symbol->body
<< "------------------end--------------------" << std::endl
<< std::endl;
actions.pop(); // restore the actions' states
@@ -907,12 +896,12 @@ namespace quickbook
++actions.error_count;
return;
}
if (actions.section_level != actions.min_section_level)
{
boost::spirit::classic::file_position const pos = first.get_position();
detail::outerr(pos.file,pos.line)
<< "Mismatched sections in template " << template_info[0] << std::endl;
<< "Mismatched sections in template " << identifier << std::endl;
actions.pop(); // restore the actions' states
--actions.template_depth;
++actions.error_count;
@@ -1282,10 +1271,8 @@ namespace quickbook
}
}
std::vector<std::string> tinfo;
tinfo.push_back(id);
tinfo.push_back(snippet);
storage.push_back(template_symbol(tinfo, first.get_position()));
std::vector<std::string> empty_params;
storage.push_back(template_symbol(id, empty_params, snippet, first.get_position()));
callout_id += callouts.size();
callouts.clear();
@@ -1366,18 +1353,14 @@ namespace quickbook
BOOST_FOREACH(template_symbol const& ts, storage)
{
std::string tname = boost::get<0>(ts)[0];
if (actions.templates.find_top_scope(tname))
std::string tname = ts.identifier;
if (!actions.templates.add(ts))
{
boost::spirit::classic::file_position const pos = boost::get<1>(ts);
boost::spirit::classic::file_position const pos = ts.position;
detail::outerr(pos.file, pos.line)
<< "Template Redefinition: " << tname << std::endl;
++actions.error_count;
}
else
{
actions.templates.add(tname, ts);
}
}
}

View File

@@ -60,6 +60,7 @@ namespace quickbook
, macro_id()
, list_marks()
, list_indent(-1)
, template_identifier()
, template_info()
, template_depth(0)
, template_escape(false)

View File

@@ -89,6 +89,7 @@ namespace quickbook
std::stack<mark_type> list_marks;
int list_indent;
std::vector<bool> conditions;
std::string template_identifier;
string_list template_info;
int template_depth;
bool template_escape;

View File

@@ -49,13 +49,22 @@ namespace quickbook
}
// TODO: Should symbols defined by '[import]' use the current scope?
void template_stack::add(std::string const& symbol, template_symbol const& ts)
bool template_stack::add(template_symbol const& ts)
{
BOOST_ASSERT(!scopes.empty());
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()));
}
if (this->find_top_scope(ts.identifier)) {
return false;
}
template_symbol symbol(ts);
if(!ts.parent) symbol.parent = &top_scope();
boost::spirit::classic::add(scopes.front().symbols, ts.identifier.c_str(),
symbol);
return true;
}
void template_stack::push()
{

View File

@@ -23,23 +23,30 @@ 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)
struct template_symbol
{
template_symbol(
std::string const& identifier,
std::vector<std::string> const& params,
std::string const& body,
boost::spirit::classic::file_position const& position,
template_scope const* parent = 0)
: identifier(identifier)
, params(params)
, body(body)
, position(position)
, parent(parent) {}
typedef boost::tuple<
std::vector<std::string>
, boost::spirit::classic::file_position
, template_scope const*>
template_symbol;
std::string identifier;
std::vector<std::string> params;
std::string body;
boost::spirit::classic::file_position position;
// This is only used for quickbook 1.5+, 1.4 uses the dynamic scope.
// TODO: I should probably call this something like lexical_parent
// or static_parent for clarity.
template_scope const* parent;
};
typedef boost::spirit::classic::symbols<template_symbol> template_symbols;
@@ -101,7 +108,7 @@ namespace quickbook
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);
bool add(template_symbol const&);
void push();
void pop();

View File

@@ -126,17 +126,19 @@ namespace quickbook
ch_p('`') [assign_a(actions.template_escape,true_)]
|
eps_p [assign_a(actions.template_escape,false_)]
) [clear_a(actions.template_info)]
)
>>
( (
(eps_p(punct_p)
>> actions.templates.scope
) [push_back_a(actions.template_info)]
) [assign_a(actions.template_identifier)]
[clear_a(actions.template_info)]
>> !template_args
) | (
(actions.templates.scope
>> eps_p(hard_space)
) [push_back_a(actions.template_info)]
) [assign_a(actions.template_identifier)]
[clear_a(actions.template_info)]
>> space
>> !template_args
) )