User Guide
codegen_compatibility_visitor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
9 
10 #include "ast/all.hpp"
11 #include "parser/c11_driver.hpp"
12 #include "utils/logger.hpp"
14 
15 
16 namespace nmodl {
17 namespace codegen {
18 
19 const std::map<ast::AstNodeType, CodegenCompatibilityVisitor::FunctionPointer>
21  {{AstNodeType::DISCRETE_BLOCK,
22  &CodegenCompatibilityVisitor::return_error_with_name<DiscreteBlock>},
23  {AstNodeType::SOLVE_BLOCK,
25  {AstNodeType::GLOBAL_VAR, &CodegenCompatibilityVisitor::return_error_global_var},
26  {AstNodeType::PARAM_ASSIGN, &CodegenCompatibilityVisitor::return_error_param_var},
27  {AstNodeType::BBCORE_POINTER_VAR,
29  {AstNodeType::EXTERNAL, &CodegenCompatibilityVisitor::return_error_extern}});
30 
31 
33  ast::Ast& /* node */,
34  const std::shared_ptr<ast::Ast>& ast_node) const {
35  auto solve_block_ast_node = std::dynamic_pointer_cast<ast::SolveBlock>(ast_node);
36  std::stringstream unhandled_method_error_message;
37  auto method = solve_block_ast_node->get_method();
38  if (!method) {
39  return {};
40  }
41  auto unhandled_solver_method = handled_solvers.find(method->get_node_name()) ==
42  handled_solvers.end();
43  if (unhandled_solver_method) {
44  unhandled_method_error_message << fmt::format(
45  "\"{}\" solving method used at [{}] not handled. Supported methods are cnexp, euler, "
46  "derivimplicit and sparse\n",
47  method->get_node_name(),
48  method->get_token()->position());
49  }
50  return unhandled_method_error_message.str();
51 }
52 
53 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
55  ast::Ast& node,
56  const std::shared_ptr<ast::Ast>& ast_node) const {
57  if (simulator == "neuron") {
58  // When generating code for NEURON, NMODL supports EXTERNAL variables,
59  // same as nocmodl.
60  return "";
61  }
62 
63  // When generating code for CoreNEURON EXTERNAL variables aren't permitted.
64  auto external = std::dynamic_pointer_cast<ast::External>(ast_node);
65  return fmt::format("Found EXTERNAL at [{}] while generating code for CoreNEURON.\n",
66  external->get_token()->position());
67 }
68 
69 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
71  ast::Ast& node,
72  const std::shared_ptr<ast::Ast>& ast_node) const {
73  if (simulator == "neuron") {
74  // When generating code for NEURON, NMODL support all GLOBALS, same as
75  // nocmodl.
76  return "";
77  }
78 
79  // When generating code for CoreNEURON only read-only GLOBALs are
80  // supported.
81  auto global_var = std::dynamic_pointer_cast<ast::GlobalVar>(ast_node);
82  std::stringstream error_message_global_var;
83  if (node.get_symbol_table()->lookup(global_var->get_node_name())->get_write_count() > 0) {
84  error_message_global_var << fmt::format(
85  "\"{}\" variable found at [{}] should be defined as a RANGE variable instead of GLOBAL "
86  "to enable backend transformations\n",
87  global_var->get_node_name(),
88  global_var->get_token()->position());
89  }
90  return error_message_global_var.str();
91 }
92 
93 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
95  ast::Ast& node,
96  const std::shared_ptr<ast::Ast>& ast_node) const {
97  auto param_assign = std::dynamic_pointer_cast<ast::ParamAssign>(ast_node);
98  std::stringstream error_message_global_var;
99  auto symbol = node.get_symbol_table()->lookup(param_assign->get_node_name());
100  if (!symbol->is_writable() && symbol->get_write_count() > 0) {
101  error_message_global_var << fmt::format(
102  "\"{}\" variable found at [{}] should be writable if it needs to be written\n",
103  symbol->get_name(),
104  symbol->get_token().position());
105  }
106  return error_message_global_var.str();
107 }
108 
109 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
111  ast::Ast& node,
112  const std::shared_ptr<ast::Ast>& /* ast_node */) const {
113  std::stringstream error_message_no_bbcore_read_write;
114  const auto& verbatim_nodes = collect_nodes(node, {AstNodeType::VERBATIM});
115  auto found_bbcore_read = false;
116  auto found_bbcore_write = false;
117  for (const auto& it: verbatim_nodes) {
118  auto verbatim = std::dynamic_pointer_cast<ast::Verbatim>(it);
119 
120  auto verbatim_statement_string = verbatim->get_statement()->get_value();
121 
122  // Parse verbatim block to find out if there is a token "bbcore_read" or
123  // "bbcore_write". If there is not, then the function is not defined or
124  // is commented.
126 
127  driver.scan_string(verbatim_statement_string);
128  auto tokens = driver.all_tokens();
129 
130  for (const auto& token: tokens) {
131  if (token == "bbcore_read") {
132  found_bbcore_read = true;
133  }
134  if (token == "bbcore_write") {
135  found_bbcore_write = true;
136  }
137  }
138  }
139  if (!found_bbcore_read) {
140  error_message_no_bbcore_read_write
141  << "\"bbcore_read\" function not defined in any VERBATIM block\n";
142  }
143  if (!found_bbcore_write) {
144  error_message_no_bbcore_read_write
145  << "\"bbcore_write\" function not defined in any VERBATIM block\n";
146  }
147  return error_message_no_bbcore_read_write.str();
148 }
149 
150 /**
151  * \details Checks all the ast::AstNodeType that are not handled in NMODL code
152  * generation backend for CoreNEURON and prints related messages. If there is
153  * some kind of incompatibility return false.
154  */
155 
157  std::vector<ast::AstNodeType> unhandled_ast_types;
158  unhandled_ast_types.reserve(unhandled_ast_types_func.size());
159  for (auto [node_type, _]: unhandled_ast_types_func) {
160  unhandled_ast_types.push_back(node_type);
161  }
162  const auto& unhandled_ast_nodes = collect_nodes(node, unhandled_ast_types);
163 
164  std::ostringstream ss;
165  for (const auto& it: unhandled_ast_nodes) {
166  auto node_type = it->get_node_type();
167  ss << (this->*unhandled_ast_types_func.find(node_type)->second)(node, it);
168  }
169  if (!ss.str().empty()) {
170  logger->error("Code incompatibility detected");
171  logger->error("Cannot translate mod file to .cpp file");
172  logger->error("Fix the following errors and try again");
173  std::string line;
174  std::istringstream ss_stringstream(ss.str());
175  while (std::getline(ss_stringstream, line)) {
176  if (!line.empty()) {
177  logger->error(fmt::format("Code Incompatibility :: {}", line));
178  }
179  }
180  return true;
181  }
182  return false;
183 }
184 
185 } // namespace codegen
186 } // namespace nmodl
nmodl::ast::Ast
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:69
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::codegen::CodegenCompatibilityVisitor::return_error_if_no_bbcore_read_write
std::string return_error_if_no_bbcore_read_write(ast::Ast &node, const std::shared_ptr< ast::Ast > &ast_node) const
Takes as parameter the ast::Ast and checks if the functions "bbcore_read" and "bbcore_write" are defi...
Definition: codegen_compatibility_visitor.cpp:110
nmodl::codegen::CodegenCompatibilityVisitor::return_error_param_var
std::string return_error_param_var(ast::Ast &node, const std::shared_ptr< ast::Ast > &ast_node) const
Definition: codegen_compatibility_visitor.cpp:94
nmodl::logger
logger_type logger
Definition: logger.cpp:34
nmodl::parser::CDriver
Class that binds all pieces together for parsing C verbatim blocks.
Definition: c11_driver.hpp:37
visitor_utils.hpp
Utility functions for visitors implementation.
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::ast::Ast::get_symbol_table
virtual symtab::SymbolTable * get_symbol_table() const
Return associated symbol table for the AST node.
Definition: ast.cpp:38
c11_driver.hpp
codegen_compatibility_visitor.hpp
Visitor for printing compatibility issues of the mod file
nmodl::codegen::CodegenCompatibilityVisitor::return_error_global_var
std::string return_error_global_var(ast::Ast &node, const std::shared_ptr< ast::Ast > &ast_node) const
Takes as parameter the ast::Ast to read the symbol table and an std::shared_ptr<ast::Ast> node and re...
Definition: codegen_compatibility_visitor.cpp:70
nmodl::collect_nodes
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
Definition: visitor_utils.cpp:206
nmodl::codegen::CodegenCompatibilityVisitor::handled_solvers
static const std::set< std::string > handled_solvers
Set of handled solvers by the NMODL C++ code generator.
Definition: codegen_compatibility_visitor.hpp:54
logger.hpp
Implement logger based on spdlog library.
nmodl::codegen::CodegenCompatibilityVisitor::find_unhandled_ast_nodes
bool find_unhandled_ast_nodes(Ast &node) const
Search the ast::Ast for nodes that are incompatible with NMODL C++ code generator.
Definition: codegen_compatibility_visitor.cpp:156
nmodl::codegen::CodegenCompatibilityVisitor::simulator
const std::string simulator
Definition: codegen_compatibility_visitor.hpp:60
nmodl::codegen::CodegenCompatibilityVisitor::unhandled_ast_types_func
static const std::map< ast::AstNodeType, FunctionPointer > unhandled_ast_types_func
associated container to find the function needed to be called in for every ast::AstNodeType that is u...
Definition: codegen_compatibility_visitor.hpp:51
nmodl::codegen::CodegenCompatibilityVisitor::return_error_extern
std::string return_error_extern(ast::Ast &node, const std::shared_ptr< ast::Ast > &ast_node) const
Callback when detecting EXTERNAL.
Definition: codegen_compatibility_visitor.cpp:54
nmodl::codegen::CodegenCompatibilityVisitor::return_error_if_solve_method_is_unhandled
std::string return_error_if_solve_method_is_unhandled(ast::Ast &node, const std::shared_ptr< ast::Ast > &ast_node) const
Takes as parameter an std::shared_ptr<ast::Ast>, searches if the method used for solving is supported...
Definition: codegen_compatibility_visitor.cpp:32
nmodl::symtab::SymbolTable::lookup
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)
Definition: symbol_table.hpp:199
all.hpp
Auto generated AST classes declaration.