InlineContentInjector::InlineContentInjector():
source_func(0),
- remap_names(0)
+ pass(DEPENDS)
{ }
const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
{
- staging_block.parent = &tgt_blk;
source_func = &src;
+
+ // Collect all declarations the inlined function depends on.
+ pass = DEPENDS;
+ source_func->visit(*this);
+
+ /* Populate referenced_names from the target function so we can rename
+ variables from the inlined function that would conflict. */
+ pass = REFERENCED;
+ target_func.visit(*this);
+
+ /* Inline and rename passes must be interleaved so used variable names are
+ known when inlining the return statement. */
+ pass = INLINE;
+ staging_block.parent = &tgt_blk;
+ staging_block.variables.clear();
remap_prefix = source_func->name;
for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
if(!r_inlined_statement)
r_inlined_statement = (*i)->clone();
- SetForScope<unsigned> set_remap(remap_names, 2);
+ SetForScope<Pass> set_pass(pass, RENAME);
r_inlined_statement->visit(*this);
- staging_block.body.push_back(r_inlined_statement);
+
+ staging_block.body.push_back(0);
+ staging_block.body.back() = r_inlined_statement;
}
- SetForScope<unsigned> set_remap(remap_names, 1);
- SetForScope<string> set_prefix(remap_prefix, target_func.name);
+ /* Now collect names from the staging block. Local variables that would
+ have conflicted with the target function were renamed earlier. */
+ pass = REFERENCED;
+ referenced_names.clear();
staging_block.variables.clear();
+ staging_block.visit(*this);
+
+ /* Rename variables in the target function so they don't interfere with
+ global identifiers used by the source function. */
+ pass = RENAME;
+ staging_block.parent = source_func->body.parent;
+ remap_prefix = target_func.name;
target_func.visit(*this);
tgt_blk.body.splice(ins_pt, staging_block.body);
void InlineContentInjector::visit(VariableReference &var)
{
- if(remap_names)
+ if(pass==RENAME)
{
map<string, VariableDeclaration *>::const_iterator i = staging_block.variables.find(var.name);
if(i!=staging_block.variables.end())
var.name = i->second->name;
}
- else if(var.declaration)
+ else if(pass==DEPENDS && var.declaration)
{
- if(!staging_block.variables.count(var.name))
- {
- dependencies.insert(var.declaration);
- referenced_names.insert(var.name);
- }
+ dependencies.insert(var.declaration);
var.declaration->visit(*this);
}
+ else if(pass==REFERENCED)
+ referenced_names.insert(var.name);
}
void InlineContentInjector::visit(InterfaceBlockReference &iface)
{
- if(!remap_names && iface.declaration)
+ if(pass==DEPENDS && iface.declaration)
{
dependencies.insert(iface.declaration);
- referenced_names.insert(iface.name);
iface.declaration->visit(*this);
}
+ else if(pass==REFERENCED)
+ referenced_names.insert(iface.name);
}
void InlineContentInjector::visit(FunctionCall &call)
{
- if(!remap_names && call.declaration)
- {
+ if(pass==DEPENDS && call.declaration)
dependencies.insert(call.declaration);
+ else if(pass==REFERENCED)
referenced_names.insert(call.name);
- }
TraversingVisitor::visit(call);
}
{
TraversingVisitor::visit(var);
- if(remap_names)
+ if(pass==RENAME)
{
- if(remap_names==2 || referenced_names.count(var.name))
+ staging_block.variables[var.name] = &var;
+ if(referenced_names.count(var.name))
{
string mapped_name = get_unused_variable_name(staging_block, var.name, remap_prefix);
- staging_block.variables[var.name] = &var;
if(mapped_name!=var.name)
+ {
staging_block.variables[mapped_name] = &var;
- var.name = mapped_name;
+ var.name = mapped_name;
+ }
}
}
- else if(var.type_declaration)
+ else if(pass==DEPENDS && var.type_declaration)
{
dependencies.insert(var.type_declaration);
- referenced_names.insert(var.type_declaration->name);
var.type_declaration->visit(*this);
}
+ else if(pass==REFERENCED)
+ referenced_names.insert(var.type);
}
void InlineContentInjector::visit(Return &ret)
{
TraversingVisitor::visit(ret);
- if(!remap_names && ret.expression)
+ if(pass==INLINE && ret.expression)
{
- /* Create a new variable to hold the return value of the inlined
- function. */
+ // Create a new variable to hold the return value of the inlined function.
r_result_name = get_unused_variable_name(staging_block, "_return", source_func->name);
RefPtr<VariableDeclaration> var = new VariableDeclaration;
var->source = ret.source;