23 #include "utils/logger.hpp"
33 std::unordered_set<std::string> procedure_vars{};
34 for (
const auto& proc_node: procedure_nodes) {
36 for (
const auto& table_node: table_nodes) {
37 const auto& table_vars =
38 std::dynamic_pointer_cast<const ast::TableStatement>(table_node)->get_table_vars();
39 for (
const auto& table_var: table_vars) {
40 const auto& [var_name,
41 inserted] = procedure_vars.insert(table_var->get_node_name());
44 fmt::format(
"SemanticAnalysisVisitor :: TABLE statement variable {} used "
61 for (
const auto& binary_expr_node: binary_expr_nodes) {
62 const auto& expr = std::dynamic_pointer_cast<const ast::BinaryExpression>(binary_expr_node);
63 const auto& lhs = expr->get_lhs();
64 const auto& op = expr->get_op();
65 if (op.eval() ==
"=" && lhs->get_node_name() == func_name) {
77 return !verbatim_blocks.empty();
85 for (
const auto& func_node: function_nodes) {
86 const auto&
func = std::dynamic_pointer_cast<const ast::FunctionBlock>(func_node);
89 if (!has_return_statement) {
90 if (!has_verbatim_block) {
92 "SemanticAnalysisVisitor :: FUNCTION {} does not have a return statement",
93 func->get_node_name()));
96 fmt::format(
"SemanticAnalysisVisitor :: FUNCTION {} does not have an explicit "
97 "return statement, but VERBATIM block detected (possible return "
98 "statement in VERBATIM block?)",
99 func->get_node_name()));
109 std::set<std::string> range_vars{};
110 for (
const auto& range_node: range_nodes) {
111 range_vars.insert(range_node->get_node_name());
114 const auto& function_nodes =
116 std::set<std::string> func_vars{};
117 for (
const auto& function_node: function_nodes) {
118 func_vars.insert(function_node->get_node_name());
121 std::vector<std::string>
result;
122 std::set_intersection(func_vars.begin(),
126 std::back_inserter(
result));
136 if (!suffix_node.empty()) {
137 const auto&
suffix = std::dynamic_pointer_cast<const ast::Suffix>(suffix_node[0]);
138 const auto&
type =
suffix->get_type()->get_node_name();
146 using namespace symtab::syminfo;
147 const auto& with_prop = NmodlType::read_ion_var | NmodlType::write_ion_var;
149 const auto& sym_table =
node.get_symbol_table();
150 assert(sym_table !=
nullptr);
153 const auto& ion_variables = sym_table->get_variables_with_properties(with_prop,
false);
156 for (
const auto&
var: ion_variables) {
157 if (
var->has_any_property(NmodlType::constant_var)) {
159 fmt::format(
"SemanticAnalysisVisitor :: ion variable {} from the USEION statement "
160 "can not be re-declared in a CONSTANT block",
176 if (derivative_block_nodes.size() > 1) {
177 logger->critical(
"It is not supported to have several DERIVATIVE blocks");
181 node.visit_children(*
this);
188 node.visit_children(*
this);
197 node.visit_children(*
this);
217 auto parent =
node.get_parent();
220 if (parent && parent->is_random_var()) {
224 if (parent && parent->is_var_name()) {
225 parent = parent->get_parent();
226 if (parent && parent->is_function_call()) {
227 auto fname = parent->get_node_name();
233 if (!arguments.empty() && arguments.front()->is_var_name() &&
234 arguments.front()->get_node_name() ==
name) {
237 node.visit_children(*
this);
245 auto position =
node.get_token()->position();
247 fmt::format(
"SemanticAnalysisVisitor :: RANDOM variable {} at {}"
248 " can be used only as the first arg of a random function",
249 node.get_node_name(),
253 node.visit_children(*
this);
261 auto fname =
node.get_node_name();
262 auto position =
node.get_name()->get_token()->position();
265 const auto& arguments =
node.get_arguments();
266 if (!arguments.empty()) {
267 auto arg0 = arguments.front();
268 if (arg0->is_var_name()) {
269 auto name = arg0->get_node_name();
272 node.visit_children(*
this);
278 fmt::format(
"SemanticAnalysisVisitor :: random function {} at {} :: The first arg must "
279 "be a random variable",
286 if (
size_t args_size =
node.get_arguments().size(); args_size != 1) {
288 fmt::format(
"nrn_pointing excepts exactly one argument, got: {}", args_size));
293 node.visit_children(*
this);
301 "SemanticAnalysisVisitor :: The procedure or function containing the TABLE statement "
302 "should contains exactly one argument.");
310 "SemanticAnalysisVisitor :: TABLE statement in FUNCTION cannot have a table name "
315 "SemanticAnalysisVisitor :: TABLE statement in PROCEDURE must have a table name list.");
324 "SemanticAnalysisVisitor :: This mod file is not point process but contains a "
333 for (
const auto&
n:
node.get_variables()) {
334 if (
n->get_value()->get_value() !=
"t") {
336 "SemanticAnalysisVisitor :: '{}' cannot be used as an independent variable, only "
338 n->get_value()->get_value());
346 if (
node.get_parameters().size() < 1) {
348 "SemanticAnalysisVisitor :: Function table '{}' must have one or more arguments.",
349 node.get_node_name());
358 logger->error(
"PROTECT statement is not supported with GPU execution");
361 logger->warn(
"SemanticAnalysisVisitor :: Find a PROTECT inside a already locked part.");
369 logger->error(
"MUTEXLOCK statement is not supported with GPU execution");
372 logger->warn(
"SemanticAnalysisVisitor :: Found a MUTEXLOCK inside an already locked part.");
381 logger->error(
"MUTEXUNLOCK statement is not supported with GPU execution");
384 logger->warn(
"SemanticAnalysisVisitor :: Found a MUTEXUNLOCK outside a locked part.");
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Represents a DESTRUCTOR block in the NMODL.
const ExpressionVector & get_arguments() const noexcept
Getter for member variable FunctionCall::arguments.
Represents a INDEPENDENT block in the NMODL.
Represent MUTEXLOCK statement in NMODL.
Represent MUTEXUNLOCK statement in NMODL.
Represents top level AST node for whole NMODL input.
Represents TABLE statement in NMODL.
const NameVector & get_table_vars() const noexcept
Getter for member variable TableStatement::table_vars.
std::shared_ptr< Symbol > lookup(const std::string &name) const
check if symbol with given name exist in the current table (but not in parents)
void visit_program(const ast::Program &node) override
Check number of DERIVATIVE blocks.
void visit_destructor_block(const ast::DestructorBlock &node) override
Visit destructor and check that the file is of type POINT_PROCESS or ARTIFICIAL_CELL.
bool accel_backend
true if accelerator backend is used for code generation
void visit_independent_block(const ast::IndependentBlock &node) override
Visit independent block and check if one of the variable is not t.
void visit_procedure_block(const ast::ProcedureBlock &node) override
Store if we are in a procedure and if the arity of this is 1.
void visit_mutex_lock(const ast::MutexLock &node) override
Look if MUTEXLOCK is inside a locked block.
void check_functions_have_return_statements(const ast::Program &node)
Check functions have return statements, log warning otherwise.
void visit_table_statement(const ast::TableStatement &node) override
Visit a table statement and check that the arity of the block were 1.
void visit_mutex_unlock(const ast::MutexUnlock &node) override
Look if MUTEXUNLOCK is outside a locked block.
bool in_mutex
true if we are inside a mutex locked part
bool in_function
true if we are in a function block
bool in_procedure
true if we are in a procedure block
void visit_protect_statement(const ast::ProtectStatement &node) override
Look if protect is inside a locked block.
void visit_function_table_block(const ast::FunctionTableBlock &node) override
Visit function table to check that number of args > 0.
void visit_name(const ast::Name &node) override
Only use of random_var is as first arg in random function.
void visit_function_call(const ast::FunctionCall &node) override
random function first arg must be random_var
void visit_function_block(const ast::FunctionBlock &node) override
Store if we are in a function and if the arity of this is 1.
bool is_point_process
true if the mod file is of type point process
bool one_arg_in_procedure_function
true if the procedure or the function contains only one argument
symtab::SymbolTable * program_symtab
bool check_table_vars(const ast::Program &node)
bool check(const ast::Program &node)
bool check_name_conflict(const ast::Program &node)
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Auto generated AST classes declaration.
virtual std::string get_node_name() const
Return name of of the node.
@ DERIVATIVE_BLOCK
type of ast::DerivativeBlock
@ BINARY_EXPRESSION
type of ast::BinaryExpression
@ RANGE_VAR
type of ast::RangeVar
@ FUNCTION_BLOCK
type of ast::FunctionBlock
@ VERBATIM
type of ast::Verbatim
@ TABLE_STATEMENT
type of ast::TableStatement
@ SUFFIX
type of ast::Suffix
@ PROCEDURE_BLOCK
type of ast::ProcedureBlock
Auto generated AST classes declaration.
double var(InputIterator begin, InputIterator end)
@ random_var
Randomvar Type.
static bool check_function_has_return_statement(const ast::FunctionBlock &node)
static bool check_function_has_verbatim_block(const ast::FunctionBlock &node)
encapsulates code generation backend implementations
bool is_random_construct_function(const std::string &name)
Is given name a one of the function for RANDOM construct.
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
bool is_nrn_pointing(const std::string &name)
Is given name nrn_pointing.
static Node * node(Object *)
int const size_t const size_t n
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Visitor to check some semantic rules on the AST
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Auto generated AST classes declaration.
Implement various classes to represent various Symbol properties.
Auto generated AST classes declaration.
Utility functions for visitors implementation.