13 #include "utils/logger.hpp"
25 bool to_inline =
true;
27 for (
const auto& statement: statements) {
29 if (statement->is_table_statement() || statement->is_lag_statement()) {
35 if (statement->is_verbatim()) {
36 const auto node =
dynamic_cast<const Verbatim*
>(statement.get());
38 auto text =
node->get_statement()->eval();
41 if (
driver.has_token(
"return")) {
54 auto statement = std::make_shared<ExpressionStatement>(expression);
67 if (!statement->is_expression_statement()) {
71 bool to_replace =
false;
74 auto e = es->get_expression();
75 if (e->is_wrapped_expression()) {
77 assert(wrapped_expression);
78 if (wrapped_expression->get_expression()->is_function_call()) {
80 const auto& function_call = std::static_pointer_cast<FunctionCall>(
81 wrapped_expression->get_expression());
82 const auto& function_name = function_call->get_node_name();
83 const auto& symbol = program_symtab->lookup_in_scope(function_name);
84 to_replace = !symbol->is_external_variable();
94 if (caller_expressions.empty()) {
101 for (
const auto& argument: callee_parameters) {
102 auto name = argument->get_name()->clone();
103 auto old_name =
name->get_node_name();
104 auto new_name =
get_new_name(old_name,
"in", inlined_variables);
105 name->set_name(new_name);
114 auto lhs =
new VarName(
name->clone(),
nullptr,
nullptr);
115 auto rhs = caller_expressions.at(counter)->clone();
119 auto statement = std::make_shared<ExpressionStatement>(expression);
121 static_cast<std::ptrdiff_t
>(counter + 1ul),
135 logger->debug(
"Can not inline function call to {}", function_name);
143 v.visit_statement_block(caller);
145 const auto& caller_arguments =
node.get_arguments();
146 std::string new_varname =
get_new_name(function_name,
"in", inlined_variables);
149 bool to_replace = can_replace_statement(caller_statement);
157 name->set_token(tok);
161 if (local_list_statement ==
nullptr) {
162 throw std::logic_error(
"got local statement as nullptr");
164 local_list_statement->emplace_back_local_var(std::make_shared<ast::LocalVar>(
name));
168 auto inlined_block = std::unique_ptr<ast::StatementBlock>(
174 inlined_block->visit_children(visitor);
176 inlined_block->set_symbol_table(
nullptr);
179 inline_arguments(*inlined_block, callee.
get_parameters(), caller_arguments);
183 add_return_variable(*inlined_block, new_varname);
189 replaced_statements[caller_statement] = statement;
191 inlined_statements[caller_statement].push_back(
192 std::shared_ptr<ast::ExpressionStatement>(statement));
196 replaced_fun_calls[&
node] = new_varname;
203 node.visit_children(*
this);
205 const auto& function_name =
node.get_name()->get_node_name();
206 auto symbol = program_symtab->lookup_in_scope(function_name);
209 if (symbol ==
nullptr || symbol->is_external_variable()) {
213 auto nodes = symbol->get_nodes_by_type(
214 {AstNodeType::FUNCTION_BLOCK, AstNodeType::PROCEDURE_BLOCK});
216 throw std::runtime_error(
"symbol table doesn't have ast node for " + function_name);
218 auto f_block = nodes.front();
221 f_block->visit_children(*
this);
223 bool inlined =
false;
225 auto block =
dynamic_cast<ast::Block*
>(f_block);
227 inlined = inline_function_call(*block,
node, *caller_block);
230 symbol->mark_inlined();
240 caller_block = &
node;
241 statementblock_stack.push(&
node);
251 const auto& statements =
node.get_statements();
253 for (
const auto& statement: statements) {
254 caller_statement = statement;
255 statement_stack.push(statement);
256 caller_statement->visit_children(*
this);
257 statement_stack.pop();
262 if (local_list_statement->get_variables().empty()) {
263 node.erase_statement(statements.begin());
268 for (
auto it = statements.begin(); it < statements.end(); ++it) {
269 const auto& statement = *it;
270 if (replaced_statements.find(statement) != replaced_statements.end()) {
271 node.reset_statement(it, replaced_statements[statement]);
276 for (
auto& element: inlined_statements) {
277 auto it =
std::find(statements.begin(), statements.end(), element.first);
278 if (it != statements.end()) {
279 node.insert_statement(it, element.second, element.second.begin(), element.second.end());
280 element.second.clear();
291 statementblock_stack.pop();
293 if (!statement_stack.empty()) {
294 caller_statement = statement_stack.top();
296 if (!statementblock_stack.empty()) {
297 caller_block = statementblock_stack.top();
306 node.visit_children(*
this);
307 const auto& e =
node.get_expression();
308 if (e->is_function_call()) {
312 if (replaced_fun_calls.find(expression) != replaced_fun_calls.end()) {
313 auto var = replaced_fun_calls[expression];
314 node.set_expression(std::make_shared<Name>(
new String(
var)));
315 replaced_fun_calls.erase(expression);
321 program_symtab =
node.get_symbol_table();
322 if (program_symtab ==
nullptr) {
323 throw std::runtime_error(
"Program node doesn't have symbol table");
325 node.visit_children(*
this);
Auto generated AST classes declaration.
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
Represent token returned by scanner.
Represents binary expression in the NMODL.
Operator used in ast::BinaryExpression.
Base class for all block scoped nodes.
virtual const ArgumentVector & get_parameters() const
Represents an integer variable.
Represents top level AST node for whole NMODL input.
Represents block encapsulating list of statements.
const StatementVector & get_statements() const noexcept
Getter for member variable StatementBlock::statements.
void emplace_back_statement(Statement *n)
Add member to statements by raw pointer.
void visit_children(visitor::Visitor &v) override
visit children i.e.
StatementVector::const_iterator insert_statement(StatementVector::const_iterator position, const std::shared_ptr< Statement > &n)
Insert member to statements.
Represents a C code block.
Wrap any other expression type.
Class that binds all pieces together for parsing C verbatim blocks.
static void add_return_variable(ast::StatementBlock &block, std::string &varname)
add assignment statement at end of block (to use as a return statement in case of procedure blocks)
static bool can_inline_block(const ast::StatementBlock &block)
true if given statement block can be inlined
void visit_program(ast::Program &node) override
visit node of type ast::Program
bool inline_function_call(ast::Block &callee, ast::FunctionCall &node, ast::StatementBlock &caller)
inline function/procedure into caller block
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
void visit_function_call(ast::FunctionCall &node) override
visit node of type ast::FunctionCall
bool can_replace_statement(const std::shared_ptr< ast::Statement > &statement)
true if statement can be replaced with inlined body this is possible for standalone function/procedur...
void visit_wrapped_expression(ast::WrappedExpression &node) override
Visit all wrapped expressions which can contain function calls.
void inline_arguments(ast::StatementBlock &inlined_block, const ast::ArgumentVector &callee_parameters, const ast::ExpressionVector &caller_expressions)
add assignment statements into given statement block to inline arguments
Visitor to rename local variables conflicting with global scope
Blindly rename given variable to new name
virtual bool is_function_block() const noexcept
Check if the ast node is an instance of ast::FunctionBlock.
virtual std::shared_ptr< StatementBlock > get_statement_block() const
Return associated statement block for the AST node.
virtual std::string get_node_name() const
Return name of of the node.
virtual bool is_procedure_block() const noexcept
Check if the ast node is an instance of ast::ProcedureBlock.
std::vector< std::shared_ptr< Argument > > ArgumentVector
std::vector< std::shared_ptr< Expression > > ExpressionVector
Visitor to inline local procedure and function calls
double var(InputIterator begin, InputIterator end)
Visitor to rename local variables conflicting with global scope
void move(Item *q1, Item *q2, Item *q3)
LocalVar * add_local_variable(StatementBlock &node, Identifier *varname)
std::string get_new_name(const std::string &name, const std::string &suffix, std::map< std::string, int > &variables)
Return new name variable by appending _suffix_COUNT where COUNT is number of times the given variable...
void add_local_statement(StatementBlock &node)
Add empty local statement to given block if already doesn't exist.
std::shared_ptr< ast::LocalListStatement > get_local_list_statement(const StatementBlock &node)
Return pointer to local statement in the given block, otherwise nullptr.
encapsulates code generation backend implementations
static Node * node(Object *)
Blindly rename given variable to new name
int find(const int, const int, const int, const int, const int)
nmodl::parser::UnitDriver driver
Utility functions for visitors implementation.