User Guide
codegen_cpp_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  */
8 
9 #include <filesystem>
10 
11 #include "config/config.h"
12 
13 #include "ast/all.hpp"
16 #include "utils/string_utils.hpp"
21 
22 namespace nmodl {
23 namespace codegen {
24 
25 using namespace ast;
26 
27 using visitor::DefUseAnalyzeVisitor;
28 using visitor::DUState;
29 using visitor::RenameVisitor;
30 using visitor::SymtabVisitor;
31 
33 
34 
35 /****************************************************************************************/
36 /* Common helper routines accross codegen functions */
37 /****************************************************************************************/
38 
40  return optimize_ion_variable_copies() && info.ion_has_write_variable();
41 }
42 
43 std::string CodegenCppVisitor::get_arg_str(const ParamVector& params) {
44  std::vector<std::string> variables;
45  for (const auto& param: params) {
46  variables.push_back(std::get<3>(param));
47  }
48  return fmt::format("{}", fmt::join(variables, ", "));
49 }
50 
51 
53  std::vector<std::string> variables;
54  for (const auto& param: params) {
55  variables.push_back(fmt::format("{}{} {}{}",
56  std::get<0>(param),
57  std::get<1>(param),
58  std::get<2>(param),
59  std::get<3>(param)));
60  }
61  return fmt::format("{}", fmt::join(variables, ", "));
62 }
63 
64 
65 template <typename T>
66 bool CodegenCppVisitor::has_parameter_of_name(const T& node, const std::string& name) {
67  auto parameters = node->get_parameters();
68  return std::any_of(parameters.begin(),
69  parameters.end(),
70  [&name](const decltype(*parameters.begin()) arg) {
71  return arg->get_node_name() == name;
72  });
73 }
74 
75 
76 std::string CodegenCppVisitor::table_update_function_name(const std::string& block_name) const {
77  return "update_table_" + method_name(block_name);
78 }
79 
80 
81 /**
82  * \details Certain statements like unit, comment, solve can/need to be skipped
83  * during code generation. Note that solve block is wrapped in expression
84  * statement and hence we have to check inner expression. It's also true
85  * for the initial block defined inside net receive block.
86  */
88  // clang-format off
89  if (node.is_unit_state()
90  || node.is_line_comment()
91  || node.is_block_comment()
92  || node.is_solve_block()
93  || node.is_conductance_hint()
94  || node.is_table_statement()) {
95  return true;
96  }
97  // clang-format on
98  if (node.is_expression_statement()) {
99  auto expression = dynamic_cast<const ExpressionStatement*>(&node)->get_expression();
100  if (expression->is_solve_block()) {
101  return true;
102  }
103  if (expression->is_initial_block()) {
104  return true;
105  }
106  }
107  return false;
108 }
109 
110 
112  if (net_receive_required() && !info.artificial_cell) {
113  if (info.net_event_used || info.net_send_used || info.is_watch_used()) {
114  return true;
115  }
116  }
117  return false;
118 }
119 
120 
122  return info.point_process && !info.artificial_cell && info.net_receive_node != nullptr;
123 }
124 
125 
127  if (info.artificial_cell) {
128  return false;
129  }
130  return info.nrn_state_block != nullptr || breakpoint_exist();
131 }
132 
133 
134 bool CodegenCppVisitor::nrn_cur_required() const noexcept {
135  return info.breakpoint_node != nullptr && !info.currents.empty();
136 }
137 
138 
140  return info.net_receive_node != nullptr;
141 }
142 
143 
144 bool CodegenCppVisitor::breakpoint_exist() const noexcept {
145  return info.breakpoint_node != nullptr;
146 }
147 
148 
150  return net_receive_exist();
151 }
152 
153 
154 /**
155  * \details When floating point data type is not default (i.e. double) then we
156  * have to copy old array to new type (for range variables).
157  */
159  return codegen::naming::DEFAULT_FLOAT_TYPE != float_data_type();
160 }
161 
162 
163 // check if there is a function or procedure defined with given name
164 bool CodegenCppVisitor::defined_method(const std::string& name) const {
165  const auto& function = program_symtab->lookup(name);
166  auto properties = NmodlType::function_block | NmodlType::procedure_block;
167  return function && function->has_any_property(properties);
168 }
169 
170 bool CodegenCppVisitor::is_function_table_call(const std::string& name) const {
171  auto it = std::find_if(info.function_tables.begin(),
172  info.function_tables.end(),
173  [name](const auto& node) { return node->get_node_name() == name; });
174  return it != info.function_tables.end();
175 }
176 
178  int n_floats = 0;
179  for (const auto& var: codegen_float_variables) {
180  n_floats += var->get_length();
181  }
182 
183  return n_floats;
184 }
185 
186 
188  const auto count_semantics = [](int sum, const IndexSemantics& sem) { return sum += sem.size; };
189  return std::accumulate(info.semantics.begin(), info.semantics.end(), 0, count_semantics);
190 }
191 
192 
193 /**
194  * \details We can directly print value but if user specify value as integer then
195  * then it gets printed as an integer. To avoid this, we use below wrapper.
196  * If user has provided integer then it gets printed as 1.0 (similar to mod2c
197  * and neuron where ".0" is appended). Otherwise we print double variables as
198  * they are represented in the mod file by user. If the value is in scientific
199  * representation (1e+20, 1E-15) then keep it as it is.
200  */
201 std::string CodegenCppVisitor::format_double_string(const std::string& s_value) {
202  return utils::format_double_string(s_value);
203 }
204 
205 
206 std::string CodegenCppVisitor::format_float_string(const std::string& s_value) {
207  return utils::format_float_string(s_value);
208 }
209 
210 
211 /**
212  * \details Statements like if, else etc. don't need semicolon at the end.
213  * (Note that it's valid to have "extraneous" semicolon). Also, statement
214  * block can appear as statement using expression statement which need to
215  * be inspected.
216  */
218  // clang-format off
219  if (node.is_if_statement()
220  || node.is_else_if_statement()
221  || node.is_else_statement()
222  || node.is_from_statement()
223  || node.is_verbatim()
224  || node.is_conductance_hint()
225  || node.is_while_statement()
226  || node.is_protect_statement()
227  || node.is_mutex_lock()
228  || node.is_mutex_unlock()) {
229  return false;
230  }
231  if (node.is_expression_statement()) {
232  auto expression = dynamic_cast<const ExpressionStatement&>(node).get_expression();
233  if (expression->is_statement_block()
234  || expression->is_eigen_newton_solver_block()
235  || expression->is_eigen_linear_solver_block()
236  || expression->is_solution_expression()
237  || expression->is_for_netcon()) {
238  return false;
239  }
240  }
241  // clang-format on
242  return true;
243 }
244 
245 /**
246  * \details Depending upon the block type, we have to print read/write ion variables
247  * during code generation. Depending on block/procedure being printed, this
248  * method return statements as vector. As different code backends could have
249  * different variable names, we rely on backend-specific read_ion_variable_name
250  * and write_ion_variable_name method which will be overloaded.
251  */
252 std::vector<std::string> CodegenCppVisitor::ion_read_statements(BlockType type) const {
253  if (optimize_ion_variable_copies()) {
254  return ion_read_statements_optimized(type);
255  }
256  std::vector<std::string> statements;
257  for (const auto& ion: info.ions) {
258  auto name = ion.name;
259  for (const auto& var: ion.reads) {
260  auto const iter = std::find(ion.implicit_reads.begin(), ion.implicit_reads.end(), var);
261  if (iter != ion.implicit_reads.end()) {
262  continue;
263  }
264  auto variable_names = read_ion_variable_name(var);
265  auto first = get_variable_name(variable_names.first);
266  auto second = get_variable_name(variable_names.second);
267  statements.push_back(fmt::format("{} = {};", first, second));
268  }
269  for (const auto& var: ion.writes) {
270  if (ion.is_ionic_conc(var)) {
271  auto variables = read_ion_variable_name(var);
272  auto first = get_variable_name(variables.first);
273  auto second = get_variable_name(variables.second);
274  statements.push_back(fmt::format("{} = {};", first, second));
275  }
276  }
277  }
278  return statements;
279 }
280 
281 
282 std::vector<std::string> CodegenCppVisitor::ion_read_statements_optimized(BlockType type) const {
283  std::vector<std::string> statements;
284  for (const auto& ion: info.ions) {
285  for (const auto& var: ion.writes) {
286  if (ion.is_ionic_conc(var)) {
287  auto variables = read_ion_variable_name(var);
288  auto first = "ionvar." + variables.first;
289  const auto& second = get_variable_name(variables.second);
290  statements.push_back(fmt::format("{} = {};", first, second));
291  }
292  }
293  }
294  return statements;
295 }
296 
297 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
298 std::vector<ShadowUseStatement> CodegenCppVisitor::ion_write_statements(BlockType type) {
299  std::vector<ShadowUseStatement> statements;
300  for (const auto& ion: info.ions) {
301  std::string concentration;
302  for (const auto& var: ion.writes) {
303  auto variable_names = write_ion_variable_name(var);
304  if (ion.is_ionic_current(var)) {
305  if (type == BlockType::Equation) {
306  auto current = breakpoint_current(var);
307  auto lhs = variable_names.first;
308  auto op = "+=";
309  auto rhs = get_variable_name(current);
310  if (info.point_process) {
311  auto area = get_variable_name(naming::NODE_AREA_VARIABLE);
312  rhs += fmt::format("*(1.e2/{})", area);
313  }
314  statements.push_back(ShadowUseStatement{lhs, op, rhs});
315  }
316  } else {
317  if (!ion.is_rev_potential(var)) {
318  concentration = var;
319  }
320  auto lhs = variable_names.first;
321  auto op = "=";
322  auto rhs = get_variable_name(variable_names.second);
323  statements.push_back(ShadowUseStatement{lhs, op, rhs});
324  }
325  }
326 
327  if (type == BlockType::Initial && !concentration.empty()) {
328  append_conc_write_statements(statements, ion, concentration);
329  }
330  }
331  return statements;
332 }
333 
334 /**
335  * If mechanisms dependency level execution is enabled then certain updates
336  * like ionic current contributions needs to be atomically updated. In this
337  * case we first update current mechanism's shadow vector and then add statement
338  * to queue that will be used in reduction queue.
339  */
341  BlockType /* type */) {
342  // when there is no operator or rhs then that statement doesn't need shadow update
343  if (statement.op.empty() && statement.rhs.empty()) {
344  auto text = statement.lhs + ";";
345  return text;
346  }
347 
348  // return regular statement
349  auto lhs = get_variable_name(statement.lhs);
350  auto text = fmt::format("{} {} {};", lhs, statement.op, statement.rhs);
351  return text;
352 }
353 
354 
355 /**
356  * \details Current variable used in breakpoint block could be local variable.
357  * In this case, neuron has already renamed the variable name by prepending
358  * "_l". In our implementation, the variable could have been renamed by
359  * one of the pass. And hence, we search all local variables and check if
360  * the variable is renamed. Note that we have to look into the symbol table
361  * of statement block and not breakpoint.
362  */
363 std::string CodegenCppVisitor::breakpoint_current(std::string current) const {
364  auto breakpoint = info.breakpoint_node;
365  if (breakpoint == nullptr) {
366  return current;
367  }
368  auto symtab = breakpoint->get_statement_block()->get_symbol_table();
369  auto variables = symtab->get_variables_with_properties(NmodlType::local_var);
370  for (const auto& var: variables) {
371  auto renamed_name = var->get_name();
372  auto original_name = var->get_original_name();
373  if (current == original_name) {
374  current = renamed_name;
375  break;
376  }
377  }
378  return current;
379 }
380 
381 
382 /**
383  * \details Depending programming model and compiler, we print compiler hint
384  * for parallelization. For example:
385  *
386  * \code
387  * #pragma omp simd
388  * for(int id = 0; id < nodecount; id++) {
389  *
390  * #pragma acc parallel loop
391  * for(int id = 0; id < nodecount; id++) {
392  * \endcode
393  */
395  const ast::Block* block) {
396  // ivdep allows SIMD parallelisation of a block/loop but doesn't provide
397  // a standard mechanism for atomics. Also, even with openmp 5.0, openmp
398  // atomics do not enable vectorisation under "omp simd" (gives compiler
399  // error with gcc < 9 if atomic and simd pragmas are nested). So, emit
400  // ivdep/simd pragma when no MUTEXLOCK/MUTEXUNLOCK/PROTECT statements
401  // are used in the given block.
402  std::vector<std::shared_ptr<const ast::Ast>> nodes;
403  if (block) {
404  nodes = collect_nodes(*block,
408  }
409  if (nodes.empty()) {
410  printer->add_line("#pragma omp simd");
411  printer->add_line("#pragma ivdep");
412  }
413 }
414 
415 
416 /****************************************************************************************/
417 /* Routines for returning variable name */
418 /****************************************************************************************/
419 
420 std::string CodegenCppVisitor::update_if_ion_variable_name(const std::string& name) const {
421  std::string result(name);
422  if (ion_variable_struct_required()) {
423  if (info.is_ion_read_variable(name)) {
424  result = naming::ION_VARNAME_PREFIX + name;
425  }
426  if (info.is_ion_write_variable(name)) {
427  result = "ionvar." + name;
428  }
429  if (info.is_current(name)) {
430  result = "ionvar." + name;
431  }
432  }
433  return result;
434 }
435 
436 
437 std::pair<std::string, std::string> CodegenCppVisitor::read_ion_variable_name(
438  const std::string& name) {
439  return {name, naming::ION_VARNAME_PREFIX + name};
440 }
441 
442 
443 std::pair<std::string, std::string> CodegenCppVisitor::write_ion_variable_name(
444  const std::string& name) {
445  return {naming::ION_VARNAME_PREFIX + name, name};
446 }
447 
448 
449 int CodegenCppVisitor::get_int_variable_index(const std::string& var_name) {
450  return get_index_from_name(codegen_int_variables, var_name);
451 }
452 
453 
454 /****************************************************************************************/
455 /* Main printing routines for code generation */
456 /****************************************************************************************/
457 
458 
460  time_t current_time{};
461  time(&current_time);
462  std::string data_time_str{std::ctime(&current_time)};
463  auto version = nmodl::Version::NMODL_VERSION + " [" + nmodl::Version::GIT_REVISION + "]";
464 
465  printer->add_line("/*********************************************************");
466  printer->add_line("Model Name : ", info.mod_suffix);
467  printer->add_line("Filename : ", info.mod_file, ".mod");
468  printer->add_line("NMODL Version : ", nmodl_version());
469  printer->fmt_line("Vectorized : {}", info.vectorize);
470  printer->fmt_line("Threadsafe : {}", info.thread_safe);
471  printer->add_line("Created : ", stringutils::trim(data_time_str));
472  printer->add_line("Simulator : ", simulator_name());
473  printer->add_line("Backend : ", backend_name());
474  printer->add_line("NMODL Compiler : ", version);
475  printer->add_line("*********************************************************/");
476 }
477 
478 
480  for (const auto& f: info.function_tables) {
481  printer->fmt_line("void* _ptable_{}{{}};", f->get_node_name());
482  codegen_global_variables.push_back(make_symbol("_ptable_" + f->get_node_name()));
483  }
484 }
485 
486 
488  // Assert some things that we assume when copying instances of this struct
489  // to the GPU and so on.
490  printer->fmt_line("static_assert(std::is_trivially_copy_constructible_v<{}>);",
491  global_struct());
492  printer->fmt_line("static_assert(std::is_trivially_move_constructible_v<{}>);",
493  global_struct());
494  printer->fmt_line("static_assert(std::is_trivially_copy_assignable_v<{}>);", global_struct());
495  printer->fmt_line("static_assert(std::is_trivially_move_assignable_v<{}>);", global_struct());
496  printer->fmt_line("static_assert(std::is_trivially_destructible_v<{}>);", global_struct());
497 }
498 
499 
501  printer->fmt_line("static {} {};", global_struct(), global_struct_instance());
502 }
503 
504 
506  const auto& name = node.get_node_name();
507 
508  // return C++ function name for RANDOM construct function
509  // e.g. nrnran123_negexp for random_negexp
510  auto get_renamed_random_function =
511  [&](const std::string& name) -> std::pair<std::string, bool> {
513  return {codegen::naming::RANDOM_FUNCTIONS_MAPPING[name], true};
514  }
515  return {name, false};
516  };
517  auto [function_name, is_random_function] = get_renamed_random_function(name);
518 
519  if (defined_method(name)) {
520  function_name = method_name(name);
521  }
522 
523  if (is_nrn_pointing(name)) {
524  print_nrn_pointing(node);
525  return;
526  }
527 
528  if (is_net_send(name)) {
529  print_net_send_call(node);
530  return;
531  }
532 
533  if (is_net_move(name)) {
534  print_net_move_call(node);
535  return;
536  }
537 
538  if (is_net_event(name)) {
539  print_net_event_call(node);
540  return;
541  }
542 
543  if (is_function_table_call(name)) {
544  print_function_table_call(node);
545  return;
546  }
547 
548  const auto& arguments = node.get_arguments();
549  printer->add_text(function_name, '(');
550 
551  if (defined_method(name)) {
552  auto internal_args = internal_method_arguments();
553  printer->add_text(internal_args);
554  if (!arguments.empty() && !internal_args.empty()) {
555  printer->add_text(", ");
556  }
557  }
558 
559  print_vector_elements(arguments, ", ");
560  printer->add_text(')');
561 }
562 
564  printer->add_text("nrn_pointing(&");
565  print_vector_elements(node.get_arguments(), ", ");
566  printer->add_text(")");
567 }
568 
570  print_function_procedure_helper(node);
571 }
572 
573 
575  auto name = node.get_node_name();
576 
577  // name of return variable
578  std::string return_var;
579  if (info.function_uses_table(name)) {
580  return_var = "ret_f_" + name;
581  } else {
582  return_var = "ret_" + name;
583  }
584 
585  // first rename return variable name
586  auto block = node.get_statement_block().get();
587  RenameVisitor v(name, return_var);
588  block->accept(v);
589 
590  print_function_procedure_helper(node);
591 }
592 
593 
595  auto name = node.get_node_name();
596  const auto& p = node.get_parameters();
597  auto [params, table_params] = function_table_parameters(node);
598  printer->fmt_push_block("double {}({})", method_name(name), get_parameter_str(params));
599  printer->fmt_line("double _arg[{}];", p.size());
600  for (size_t i = 0; i < p.size(); ++i) {
601  printer->fmt_line("_arg[{}] = {};", i, p[i]->get_node_name());
602  }
603  printer->fmt_line("return hoc_func_table({}, {}, _arg);",
604  get_variable_name(std::string("_ptable_" + name), true),
605  p.size());
606  printer->pop_block();
607 
608  printer->fmt_push_block("double table_{}({})",
609  method_name(name),
610  get_parameter_str(table_params));
611  printer->fmt_line("hoc_spec_table(&{}, {});",
612  get_variable_name(std::string("_ptable_" + name)),
613  p.size());
614  printer->add_line("return 0.;");
615  printer->pop_block();
616 }
617 
618 
620  printer->add_line("#ifndef NRN_PRCELLSTATE");
621  printer->add_line("#define NRN_PRCELLSTATE 0");
622  printer->add_line("#endif");
623 }
624 
625 
627  auto variable_printer = [&](const std::vector<SymbolType>& variables) {
628  for (const auto& v: variables) {
629  auto name = v->get_name();
630  if (!info.point_process) {
631  name += "_" + info.mod_suffix;
632  }
633  if (v->is_array()) {
634  name += fmt::format("[{}]", v->get_length());
635  }
636  printer->add_line(add_escape_quote(name), ",");
637  }
638  };
639 
640  printer->add_newline(2);
641  printer->add_line("/** channel information */");
642  printer->fmt_line("static const char *{}[] = {{", get_channel_info_var_name());
643  printer->increase_indent();
644  printer->add_line(add_escape_quote(nmodl_version()), ",");
645  printer->add_line(add_escape_quote(info.mod_suffix), ",");
646  variable_printer(info.range_parameter_vars);
647  printer->add_line("0,");
648  variable_printer(info.range_assigned_vars);
649  printer->add_line("0,");
650  variable_printer(info.range_state_vars);
651  printer->add_line("0,");
652  variable_printer(info.pointer_variables);
653  printer->add_line("0");
654  printer->decrease_indent();
655  printer->add_line("};");
656 }
657 
659  printer->fmt_line("using namespace {};", namespace_name());
660 }
661 
663  printer->add_newline(2);
664  printer->fmt_push_block("namespace {}", namespace_name());
665 }
666 
667 
669  printer->pop_block();
670 }
671 
672 
674  if (info.top_verbatim_blocks.empty()) {
675  return;
676  }
677  print_namespace_stop();
678 
679  printer->add_newline(2);
680  print_using_namespace();
681 
682  printing_top_verbatim_blocks = true;
683 
684  for (const auto& block: info.top_verbatim_blocks) {
685  printer->add_newline(2);
686  block->accept(*this);
687  }
688 
689  printing_top_verbatim_blocks = false;
690 
691  print_namespace_start();
692 }
693 
694 
695 /****************************************************************************************/
696 /* Printing routines for code generation */
697 /****************************************************************************************/
698 
699 
701  bool open_brace,
702  bool close_brace) {
703  if (open_brace) {
704  printer->push_block();
705  }
706 
707  const auto& statements = node.get_statements();
708  for (const auto& statement: statements) {
709  if (statement_to_skip(*statement)) {
710  continue;
711  }
712  /// not necessary to add indent for verbatim block (pretty-printing)
713  if (!statement->is_verbatim() && !statement->is_mutex_lock() &&
714  !statement->is_mutex_unlock() && !statement->is_protect_statement()) {
715  printer->add_indent();
716  }
717  statement->accept(*this);
718  if (need_semicolon(*statement)) {
719  printer->add_text(';');
720  }
721  if (!statement->is_mutex_lock() && !statement->is_mutex_unlock()) {
722  printer->add_newline();
723  }
724  }
725 
726  if (close_brace) {
727  printer->pop_block_nl(0);
728  }
729 }
730 
731 
733  const ast::StatementBlock& functor_block) {
734  // Create complete_block with both variable declarations (done in variable_block) and solver
735  // part (done in functor_block) to be able to run the SymtabVisitor and DefUseAnalyzeVisitor
736  // then and get the proper DUChains for the variables defined in the variable_block
737  ast::StatementBlock complete_block(functor_block);
738  // Typically variable_block has only one statement, a statement containing the declaration
739  // of the local variables
740  for (const auto& statement: variable_block.get_statements()) {
741  complete_block.insert_statement(complete_block.get_statements().begin(), statement);
742  }
743 
744  // Create Symbol Table for complete_block
745  auto model_symbol_table = std::make_shared<symtab::ModelSymbolTable>();
746  SymtabVisitor(model_symbol_table.get()).visit_statement_block(complete_block);
747  // Initialize DefUseAnalyzeVisitor to generate the DUChains for the variables defined in the
748  // variable_block
749  DefUseAnalyzeVisitor v(*complete_block.get_symbol_table());
750 
751  // Check the DUChains for all the variables in the variable_block
752  // If variable is defined in complete_block don't add const quilifier in operator()
753  auto is_functor_const = true;
754  const auto& variables = collect_nodes(variable_block, {ast::AstNodeType::LOCAL_VAR});
755  for (const auto& variable: variables) {
756  const auto& chain = v.analyze(complete_block, variable->get_node_name());
757  is_functor_const = !(chain.eval() == DUState::D || chain.eval() == DUState::LD ||
758  chain.eval() == DUState::CD);
759  if (!is_functor_const) {
760  break;
761  }
762  }
763 
764  return is_functor_const;
765 }
766 
767 
769  for (const auto& functor_name: info.functor_names) {
770  printer->add_newline(2);
771  print_functor_definition(*functor_name.first);
772  }
773 }
774 
776  // functor that evaluates F(X) and J(X) for
777  // Newton solver
778  auto float_type = default_float_data_type();
779  int N = node.get_n_state_vars()->get_value();
780 
781  const auto functor_name = info.functor_names[&node];
782  printer->fmt_push_block("struct {}", functor_name);
783 
784  auto params = functor_params();
785  for (const auto& param: params) {
786  printer->fmt_line("{}{} {};", std::get<0>(param), std::get<1>(param), std::get<3>(param));
787  }
788 
789  if (ion_variable_struct_required()) {
790  print_ion_variable();
791  }
792 
793  print_statement_block(*node.get_variable_block(), false, false);
794  printer->add_newline();
795 
796  printer->push_block("void initialize()");
797  print_statement_block(*node.get_initialize_block(), false, false);
798  printer->pop_block();
799  printer->add_newline();
800 
801  printer->fmt_line("{}({})", functor_name, get_parameter_str(params));
802  printer->increase_indent();
803  auto initializers = std::vector<std::string>();
804  for (const auto& param: params) {
805  initializers.push_back(fmt::format("{0}({0})", std::get<3>(param)));
806  }
807 
808  printer->add_multi_line(": " + fmt::format("{}", fmt::join(initializers, ", ")));
809  printer->decrease_indent();
810  printer->add_line("{}");
811 
812  printer->add_indent();
813 
814  const auto& variable_block = *node.get_variable_block();
815  const auto& functor_block = *node.get_functor_block();
816 
817  printer->fmt_text(
818  "void operator()(const Eigen::Matrix<{0}, {1}, 1>& nmodl_eigen_xm, Eigen::Matrix<{0}, {1}, "
819  "1>& nmodl_eigen_dxm, Eigen::Matrix<{0}, {1}, "
820  "1>& nmodl_eigen_fm, "
821  "Eigen::Matrix<{0}, {1}, {1}>& nmodl_eigen_jm) {2}",
822  float_type,
823  N,
824  is_functor_const(variable_block, functor_block) ? "const " : "");
825  printer->push_block();
826  printer->fmt_line("const {}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
827  printer->fmt_line("{}* nmodl_eigen_dx = nmodl_eigen_dxm.data();", float_type);
828  printer->fmt_line("{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
829  printer->fmt_line("{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
830 
831  for (size_t i = 0; i < N; ++i) {
832  printer->fmt_line(
833  "nmodl_eigen_dx[{0}] = std::max(1e-6, 0.02*std::fabs(nmodl_eigen_x[{0}]));", i);
834  }
835 
836  print_statement_block(functor_block, false, false);
837  printer->pop_block();
838  printer->add_newline();
839 
840  // assign newton solver results in matrix X to state vars
841  printer->push_block("void finalize()");
842  print_statement_block(*node.get_finalize_block(), false, false);
843  printer->pop_block();
844 
845  printer->pop_block(";");
846 }
847 
848 
849 void CodegenCppVisitor::print_eigen_linear_solver(const std::string& float_type, int N) {
850  if (N <= 4) {
851  // Faster compared to LU, given the template specialization in Eigen.
852  printer->add_multi_line(R"CODE(
853  bool invertible;
854  nmodl_eigen_jm.computeInverseWithCheck(nmodl_eigen_jm_inv,invertible);
855  nmodl_eigen_xm = nmodl_eigen_jm_inv*nmodl_eigen_fm;
856  if (!invertible) assert(false && "Singular or ill-conditioned matrix (Eigen::inverse)!");
857  )CODE");
858  } else {
859  // In Eigen the default storage order is ColMajor.
860  // Crout's implementation requires matrices stored in RowMajor order (C++-style arrays).
861  // Therefore, the transposeInPlace is critical such that the data() method to give the rows
862  // instead of the columns.
863  printer->add_line("if (!nmodl_eigen_jm.IsRowMajor) nmodl_eigen_jm.transposeInPlace();");
864 
865  // pivot vector
866  printer->fmt_line("Eigen::Matrix<int, {}, 1> pivot;", N);
867  printer->fmt_line("Eigen::Matrix<{0}, {1}, 1> rowmax;", float_type, N);
868 
869  // In-place LU-Decomposition (Crout Algo) : Jm is replaced by its LU-decomposition
870  printer->fmt_line(
871  "if (nmodl::crout::Crout<{0}>({1}, nmodl_eigen_jm.data(), pivot.data(), rowmax.data()) "
872  "< 0) assert(false && \"Singular or ill-conditioned matrix (nmodl::crout)!\");",
873  float_type,
874  N);
875 
876  // Solve the linear system : Forward/Backward substitution part
877  printer->fmt_line(
878  "nmodl::crout::solveCrout<{0}>({1}, nmodl_eigen_jm.data(), nmodl_eigen_fm.data(), "
879  "nmodl_eigen_xm.data(), pivot.data());",
880  float_type,
881  N);
882  }
883 }
884 
885 
886 /****************************************************************************************/
887 /* Main code printing entry points */
888 /****************************************************************************************/
889 
890 
891 /**
892  * NMODL constants from unit database
893  *
894  */
896  if (!info.factor_definitions.empty()) {
897  printer->add_newline(2);
898  printer->add_line("/** constants used in nmodl from UNITS */");
899  for (const auto& it: info.factor_definitions) {
900  const std::string format_string = "static const double {} = {};";
901  printer->fmt_line(format_string, it->get_node_name(), it->get_value()->get_value());
902  }
903  }
904 }
905 
906 
907 /****************************************************************************************/
908 /* Overloaded visitor routines */
909 /****************************************************************************************/
910 
911 
912 extern const std::regex regex_special_chars{R"([-[\]{}()*+?.,\^$|#\s])"};
913 
914 
916  std::string name = node.eval();
917  if (enable_variable_name_lookup) {
918  name = get_variable_name(name);
919  }
920  printer->add_text(name);
921 }
922 
923 
925  const auto& value = node.get_value();
926  printer->add_text(std::to_string(value));
927 }
928 
929 
931  printer->add_text(format_float_string(node.get_value()));
932 }
933 
934 
936  printer->add_text(format_double_string(node.get_value()));
937 }
938 
939 
941  printer->add_text(std::to_string(static_cast<int>(node.eval())));
942 }
943 
944 
946  node.visit_children(*this);
947 }
948 
949 
951  // do not print units
952 }
953 
954 
956  throw std::runtime_error("PRIME encountered during code generation, ODEs not solved?");
957 }
958 
959 
960 /**
961  * \todo : Validate how @ is being handled in neuron implementation
962  */
964  const auto& name = node.get_name();
965  const auto& at_index = node.get_at();
966  const auto& index = node.get_index();
967  name->accept(*this);
968  if (at_index) {
969  printer->add_text("@");
970  at_index->accept(*this);
971  }
972  if (index) {
973  printer->add_text("[");
974  printer->add_text("static_cast<int>(");
975  index->accept(*this);
976  printer->add_text(")");
977  printer->add_text("]");
978  }
979 }
980 
981 
983  node.get_name()->accept(*this);
984  printer->add_text("[");
985  printer->add_text("static_cast<int>(");
986  node.get_length()->accept(*this);
987  printer->add_text(")");
988  printer->add_text("]");
989 }
990 
991 
993  printer->add_text(local_var_type(), ' ');
994  print_vector_elements(node.get_variables(), ", ");
995 }
996 
997 
999  printer->add_text("if (");
1000  node.get_condition()->accept(*this);
1001  printer->add_text(") ");
1002  node.get_statement_block()->accept(*this);
1003  print_vector_elements(node.get_elseifs(), "");
1004  const auto& elses = node.get_elses();
1005  if (elses) {
1006  elses->accept(*this);
1007  }
1008 }
1009 
1010 
1012  printer->add_text(" else if (");
1013  node.get_condition()->accept(*this);
1014  printer->add_text(") ");
1015  node.get_statement_block()->accept(*this);
1016 }
1017 
1018 
1020  printer->add_text(" else ");
1021  node.visit_children(*this);
1022 }
1023 
1024 
1026  printer->add_text("while (");
1027  node.get_condition()->accept(*this);
1028  printer->add_text(") ");
1029  node.get_statement_block()->accept(*this);
1030 }
1031 
1032 
1034  auto name = node.get_node_name();
1035  const auto& from = node.get_from();
1036  const auto& to = node.get_to();
1037  const auto& inc = node.get_increment();
1038  const auto& block = node.get_statement_block();
1039  printer->fmt_text("for (int {} = ", name);
1040  from->accept(*this);
1041  printer->fmt_text("; {} <= ", name);
1042  to->accept(*this);
1043  if (inc) {
1044  printer->fmt_text("; {} += ", name);
1045  inc->accept(*this);
1046  } else {
1047  printer->fmt_text("; {}++", name);
1048  }
1049  printer->add_text(") ");
1050  block->accept(*this);
1051 }
1052 
1053 
1055  printer->add_text("(");
1056  node.get_expression()->accept(*this);
1057  printer->add_text(")");
1058 }
1059 
1060 
1062  auto op = node.get_op().eval();
1063  const auto& lhs = node.get_lhs();
1064  const auto& rhs = node.get_rhs();
1065  if (op == "^") {
1066  printer->add_text("pow(");
1067  lhs->accept(*this);
1068  printer->add_text(", ");
1069  rhs->accept(*this);
1070  printer->add_text(")");
1071  } else {
1072  lhs->accept(*this);
1073  printer->add_text(" " + op + " ");
1074  rhs->accept(*this);
1075  }
1076 }
1077 
1078 
1080  printer->add_text(node.eval());
1081 }
1082 
1083 
1085  printer->add_text(" " + node.eval());
1086 }
1087 
1088 
1089 /**
1090  * \details Statement block is top level construct (for every nmodl block).
1091  * Sometime we want to analyse ast nodes even if code generation is
1092  * false. Hence we visit children even if code generation is false.
1093  */
1095  print_statement_block(node);
1096 }
1097 
1098 
1100  print_function_call(node);
1101 }
1102 
1103 
1105  // dt change statement should be pulled outside already
1106 }
1107 
1108 
1110  printer->fmt_line("#pragma omp critical ({})", info.mod_suffix);
1111  printer->add_indent();
1112  printer->push_block();
1113 }
1114 
1115 
1117  printer->pop_block();
1118 }
1119 
1120 
1122  auto block = node.get_node_to_solve().get();
1123  if (block->is_statement_block()) {
1124  auto statement_block = dynamic_cast<ast::StatementBlock*>(block);
1125  print_statement_block(*statement_block, false, false);
1126  } else {
1127  block->accept(*this);
1128  }
1129 }
1130 
1131 
1133  // solution vector to store copy of state vars for Newton solver
1134  printer->add_newline();
1135 
1136  auto float_type = default_float_data_type();
1137  int N = node.get_n_state_vars()->get_value();
1138  printer->fmt_line("Eigen::Matrix<{}, {}, 1> nmodl_eigen_xm;", float_type, N);
1139  printer->fmt_line("{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1140 
1141  print_statement_block(*node.get_setup_x_block(), false, false);
1142 
1143  // call newton solver with functor and X matrix that contains state vars
1144  printer->add_line("// call newton solver");
1145  printer->fmt_line("{} newton_functor({});",
1146  info.functor_names[&node],
1147  get_arg_str(functor_params()));
1148  printer->add_line("newton_functor.initialize();");
1149  printer->add_line(
1150  "int newton_iterations = nmodl::newton::newton_solver(nmodl_eigen_xm, newton_functor);");
1151  printer->add_line(
1152  "if (newton_iterations < 0) assert(false && \"Newton solver did not converge!\");");
1153 
1154  // assign newton solver results in matrix X to state vars
1155  print_statement_block(*node.get_update_states_block(), false, false);
1156  printer->add_line("newton_functor.initialize(); // TODO mimic calling F again.");
1157  printer->add_line("newton_functor.finalize();");
1158 }
1159 
1160 
1162  printer->add_newline();
1163 
1164  const std::string float_type = default_float_data_type();
1165  int N = node.get_n_state_vars()->get_value();
1166  printer->fmt_line("Eigen::Matrix<{0}, {1}, 1> nmodl_eigen_xm, nmodl_eigen_fm;", float_type, N);
1167  printer->fmt_line("Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm;", float_type, N);
1168  if (N <= 4) {
1169  printer->fmt_line("Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm_inv;", float_type, N);
1170  }
1171  printer->fmt_line("{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1172  printer->fmt_line("{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
1173  printer->fmt_line("{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
1174  print_statement_block(*node.get_variable_block(), false, false);
1175  print_statement_block(*node.get_initialize_block(), false, false);
1176  print_statement_block(*node.get_setup_x_block(), false, false);
1177 
1178  printer->add_newline();
1179  print_eigen_linear_solver(float_type, N);
1180  printer->add_newline();
1181 
1182  print_statement_block(*node.get_update_states_block(), false, false);
1183  print_statement_block(*node.get_finalize_block(), false, false);
1184 }
1185 
1186 
1187 /**
1188  * \details Once variables are populated, update index semantics to register with coreneuron
1189  */
1190 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
1192  int index = 0;
1193  info.semantics.clear();
1194 
1195  if (info.point_process) {
1196  info.semantics.emplace_back(index++, naming::AREA_SEMANTIC, 1);
1197  info.semantics.emplace_back(index++, naming::POINT_PROCESS_SEMANTIC, 1);
1198  }
1199  for (const auto& ion: info.ions) {
1200  for (auto i = 0; i < ion.reads.size(); ++i) {
1201  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
1202  }
1203  for (const auto& var: ion.writes) {
1204  /// add if variable is not present in the read list
1205  if (std::find(ion.reads.begin(), ion.reads.end(), var) == ion.reads.end()) {
1206  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
1207  }
1208  if (ion.is_ionic_current(var)) {
1209  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
1210  }
1211  }
1212  if (ion.need_style) {
1213  info.semantics.emplace_back(index++, fmt::format("{}_ion", ion.name), 1);
1214  info.semantics.emplace_back(index++, fmt::format("#{}_ion", ion.name), 1);
1215  }
1216  }
1217  for (auto& var: info.pointer_variables) {
1218  if (info.first_pointer_var_index == -1) {
1219  info.first_pointer_var_index = index;
1220  }
1221  int size = var->get_length();
1222  if (var->has_any_property(NmodlType::pointer_var)) {
1223  info.semantics.emplace_back(index, naming::POINTER_SEMANTIC, size);
1224  } else {
1225  info.semantics.emplace_back(index, naming::CORE_POINTER_SEMANTIC, size);
1226  }
1227  index += size;
1228  }
1229 
1230  for (auto& var: info.random_variables) {
1231  if (info.first_random_var_index == -1) {
1232  info.first_random_var_index = index;
1233  }
1234  int size = var->get_length();
1235  info.semantics.emplace_back(index, naming::RANDOM_SEMANTIC, size);
1236  index += size;
1237  }
1238 
1239  if (info.diam_used) {
1240  info.semantics.emplace_back(index++, naming::DIAM_VARIABLE, 1);
1241  }
1242 
1243  if (info.area_used) {
1244  info.semantics.emplace_back(index++, naming::AREA_VARIABLE, 1);
1245  }
1246 
1247  if (info.net_send_used) {
1248  info.semantics.emplace_back(index++, naming::NET_SEND_SEMANTIC, 1);
1249  }
1250 
1251  /*
1252  * Number of semantics for watch is one greater than number of
1253  * actual watch statements in the mod file
1254  */
1255  if (!info.watch_statements.empty()) {
1256  for (int i = 0; i < info.watch_statements.size() + 1; i++) {
1257  info.semantics.emplace_back(index++, naming::WATCH_SEMANTIC, 1);
1258  }
1259  }
1260 
1261  if (info.for_netcon_used) {
1262  info.semantics.emplace_back(index++, naming::FOR_NETCON_SEMANTIC, 1);
1263  }
1264 }
1265 
1266 
1267 std::vector<CodegenCppVisitor::SymbolType> CodegenCppVisitor::get_float_variables() const {
1268  // sort with definition order
1269  auto comparator = [](const SymbolType& first, const SymbolType& second) -> bool {
1270  return first->get_definition_order() < second->get_definition_order();
1271  };
1272 
1273  auto assigned = info.assigned_vars;
1274  auto states = info.state_vars;
1275 
1276  // each state variable has corresponding Dstate variable
1277  for (const auto& state: states) {
1278  auto name = "D" + state->get_name();
1279  auto symbol = make_symbol(name);
1280  if (state->is_array()) {
1281  symbol->set_as_array(state->get_length());
1282  }
1283  symbol->set_definition_order(state->get_definition_order());
1284  assigned.push_back(symbol);
1285  }
1286  std::sort(assigned.begin(), assigned.end(), comparator);
1287 
1288  auto variables = info.range_parameter_vars;
1289  variables.insert(variables.end(),
1290  info.range_assigned_vars.begin(),
1291  info.range_assigned_vars.end());
1292  variables.insert(variables.end(), info.range_state_vars.begin(), info.range_state_vars.end());
1293 
1294  for (const auto& v: assigned) {
1295  auto it = std::find_if(info.external_variables.begin(),
1296  info.external_variables.end(),
1297  [&v](auto it) { return it->get_name() == get_name(v); });
1298 
1299  if (it == info.external_variables.end()) {
1300  variables.push_back(v);
1301  }
1302  }
1303 
1304  if (needs_v_unused()) {
1305  variables.push_back(make_symbol(naming::VOLTAGE_UNUSED_VARIABLE));
1306  }
1307 
1308  if (breakpoint_exist()) {
1309  std::string name = info.vectorize ? naming::CONDUCTANCE_UNUSED_VARIABLE
1311 
1312  // make sure conductance variable like `g` is not already defined
1313  if (auto r = std::find_if(variables.cbegin(),
1314  variables.cend(),
1315  [&](const auto& s) { return name == s->get_name(); });
1316  r == variables.cend()) {
1317  variables.push_back(make_symbol(name));
1318  }
1319  }
1320 
1321  if (net_receive_exist()) {
1322  variables.push_back(make_symbol(naming::T_SAVE_VARIABLE));
1323  }
1324 
1325  return variables;
1326 }
1327 
1328 
1329 /**
1330  * IndexVariableInfo has following constructor arguments:
1331  * - symbol
1332  * - is_vdata (false)
1333  * - is_index (false
1334  * - is_integer (false)
1335  *
1336  * Which variables are constant qualified?
1337  *
1338  * - node area is read only
1339  * - read ion variables are read only
1340  * - style_ionname is index / offset
1341  */
1342 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
1343 std::vector<IndexVariableInfo> CodegenCppVisitor::get_int_variables() {
1344  std::vector<IndexVariableInfo> variables;
1345  if (info.point_process) {
1346  variables.emplace_back(make_symbol(naming::NODE_AREA_VARIABLE));
1347  variables.back().is_constant = true;
1348 
1349  add_variable_point_process(variables);
1350  }
1351 
1352  for (auto& ion: info.ions) {
1353  bool need_style = false;
1354  std::unordered_map<std::string, int> ion_vars; // used to keep track of the variables to
1355  // not have doubles between read/write. Same
1356  // name variables are allowed
1357  // See if we need to add extra readion statements to match NEURON with SoA data
1358  auto const has_var = [&ion](const char* suffix) -> bool {
1359  auto const pred = [name = ion.name + suffix](auto const& x) { return x == name; };
1360  return std::any_of(ion.reads.begin(), ion.reads.end(), pred) ||
1361  std::any_of(ion.writes.begin(), ion.writes.end(), pred);
1362  };
1363  auto const add_implicit_read = [&ion](const char* suffix) {
1364  auto name = ion.name + suffix;
1365  ion.reads.push_back(name);
1366  ion.implicit_reads.push_back(std::move(name));
1367  };
1368  bool const have_ionin{has_var("i")}, have_ionout{has_var("o")};
1369  if (have_ionin && !have_ionout) {
1370  add_implicit_read("o");
1371  } else if (have_ionout && !have_ionin) {
1372  add_implicit_read("i");
1373  }
1374  for (const auto& var: ion.reads) {
1375  const std::string name = naming::ION_VARNAME_PREFIX + var;
1376  variables.emplace_back(make_symbol(name));
1377  variables.back().is_constant = true;
1378  ion_vars[name] = static_cast<int>(variables.size() - 1);
1379  }
1380 
1381  /// symbol for di_ion_dv var
1382  std::shared_ptr<symtab::Symbol> ion_di_dv_var = nullptr;
1383 
1384  for (const auto& var: ion.writes) {
1385  const std::string name = naming::ION_VARNAME_PREFIX + var;
1386 
1387  const auto ion_vars_it = ion_vars.find(name);
1388  if (ion_vars_it != ion_vars.end()) {
1389  variables[ion_vars_it->second].is_constant = false;
1390  } else {
1391  variables.emplace_back(make_symbol(naming::ION_VARNAME_PREFIX + var));
1392  }
1393  if (ion.is_ionic_current(var)) {
1394  ion_di_dv_var = make_symbol(std::string(naming::ION_VARNAME_PREFIX) + "di" +
1395  ion.name + "dv");
1396  }
1397  if (ion.is_intra_cell_conc(var) || ion.is_extra_cell_conc(var)) {
1398  need_style = true;
1399  }
1400  }
1401 
1402  /// insert after read/write variables but before style ion variable
1403  if (ion_di_dv_var != nullptr) {
1404  variables.emplace_back(ion_di_dv_var);
1405  }
1406 
1407  if (need_style) {
1408  variables.emplace_back(make_symbol(naming::ION_VARNAME_PREFIX + ion.name + "_erev"));
1409  variables.emplace_back(make_symbol("style_" + ion.name), false, true);
1410  variables.back().is_constant = true;
1411  }
1412  }
1413 
1414  for (const auto& var: info.pointer_variables) {
1415  auto name = var->get_name();
1416  if (var->has_any_property(NmodlType::pointer_var)) {
1417  variables.emplace_back(make_symbol(name));
1418  } else {
1419  variables.emplace_back(make_symbol(name), true);
1420  }
1421  }
1422 
1423  for (const auto& var: info.random_variables) {
1424  auto name = var->get_name();
1425  variables.emplace_back(make_symbol(name), true);
1426  variables.back().symbol->add_properties(NmodlType::random_var);
1427  }
1428 
1429  if (info.diam_used) {
1430  variables.emplace_back(make_symbol(naming::DIAM_VARIABLE));
1431  }
1432 
1433  if (info.area_used) {
1434  variables.emplace_back(make_symbol(naming::AREA_VARIABLE));
1435  }
1436 
1437  add_variable_tqitem(variables);
1438 
1439  /**
1440  * \note Variables for watch statements : there is one extra variable
1441  * used in coreneuron compared to actual watch statements for compatibility
1442  * with neuron (which uses one extra Datum variable)
1443  */
1444  if (!info.watch_statements.empty()) {
1445  for (int i = 0; i < info.watch_statements.size() + 1; i++) {
1446  variables.emplace_back(make_symbol(fmt::format("watch{}", i)), false, false, true);
1447  }
1448  }
1449 
1450  if (info.for_netcon_used) {
1451  variables.emplace_back(make_symbol(naming::FOR_NETCON_VARIABLE), false, false, true);
1452  }
1453  return variables;
1454 }
1455 
1456 
1458  program_symtab = node.get_symbol_table();
1459 
1460  CodegenHelperVisitor v(enable_cvode);
1461  info = v.analyze(node);
1462  info.mod_file = mod_filename;
1463 
1464  if (info.mod_suffix == "") {
1465  info.mod_suffix = std::filesystem::path(mod_filename).stem().string();
1466  }
1467  info.rsuffix = info.point_process ? "" : "_" + info.mod_suffix;
1468  if (info.mod_suffix == "nothing") {
1469  info.rsuffix = "";
1470  }
1471 
1472  if (!info.vectorize) {
1473  logger->warn("CodegenCppVisitor : MOD file uses non-thread safe constructs of NMODL");
1474  }
1475 
1476  codegen_float_variables = get_float_variables();
1477  codegen_int_variables = get_int_variables();
1478 
1479  update_index_semantics();
1480 
1481  info.semantic_variable_count = int_variables_size();
1482 }
1483 
1484 
1486  if (type == BlockType::Initial) {
1487  return method_name(naming::NRN_INIT_METHOD);
1488  }
1489  if (type == BlockType::Constructor) {
1490  return method_name(naming::NRN_CONSTRUCTOR_METHOD);
1491  }
1492  if (type == BlockType::Destructor) {
1493  return method_name(naming::NRN_DESTRUCTOR_METHOD);
1494  }
1495  if (type == BlockType::State) {
1496  return method_name(naming::NRN_STATE_METHOD);
1497  }
1498  if (type == BlockType::Equation) {
1499  return method_name(naming::NRN_CUR_METHOD);
1500  }
1501  if (type == BlockType::Watch) {
1502  return method_name(naming::NRN_WATCH_CHECK_METHOD);
1503  }
1504  throw std::logic_error("compute_method_name not implemented");
1505 }
1506 
1507 
1509  setup(node);
1510  print_codegen_routines();
1511 }
1512 
1513 
1515  auto name = node.get_node_name();
1516  auto statement = get_table_statement(node);
1517  auto table_variables = statement->get_table_vars();
1518  auto with = statement->get_with()->eval();
1519  auto use_table_var = get_variable_name(naming::USE_TABLE_VARIABLE);
1520  auto tmin_name = get_variable_name("tmin_" + name);
1521  auto mfac_name = get_variable_name("mfac_" + name);
1522  auto function_name = method_name("f_" + name);
1523 
1524  printer->add_newline(2);
1525  print_function_declaration(node, name);
1526  printer->push_block();
1527  {
1528  const auto& params = node.get_parameters();
1529  printer->fmt_push_block("if ({} == 0)", use_table_var);
1530  if (node.is_procedure_block()) {
1531  printer->fmt_line("{}({}, {});",
1532  function_name,
1533  internal_method_arguments(),
1534  params[0].get()->get_node_name());
1535  printer->add_line("return 0;");
1536  } else {
1537  printer->fmt_line("return {}({}, {});",
1538  function_name,
1539  internal_method_arguments(),
1540  params[0].get()->get_node_name());
1541  }
1542  printer->pop_block();
1543 
1544  printer->fmt_line("double xi = {} * ({} - {});",
1545  mfac_name,
1546  params[0].get()->get_node_name(),
1547  tmin_name);
1548  printer->push_block("if (isnan(xi))");
1549  if (node.is_procedure_block()) {
1550  for (const auto& var: table_variables) {
1551  auto var_name = get_variable_name(var->get_node_name());
1552  auto [is_array, array_length] = check_if_var_is_array(var->get_node_name());
1553  if (is_array) {
1554  for (int j = 0; j < array_length; j++) {
1555  printer->fmt_line("{}[{}] = xi;", var_name, j);
1556  }
1557  } else {
1558  printer->fmt_line("{} = xi;", var_name);
1559  }
1560  }
1561  printer->add_line("return 0;");
1562  } else {
1563  printer->add_line("return xi;");
1564  }
1565  printer->pop_block();
1566 
1567  printer->fmt_push_block("if (xi <= 0. || xi >= {}.)", with);
1568  printer->fmt_line("int index = (xi <= 0.) ? 0 : {};", with);
1569  if (node.is_procedure_block()) {
1570  for (const auto& variable: table_variables) {
1571  auto var_name = variable->get_node_name();
1572  auto instance_name = get_variable_name(var_name);
1573  auto table_name = get_variable_name("t_" + var_name);
1574  auto [is_array, array_length] = check_if_var_is_array(var_name);
1575  if (is_array) {
1576  for (int j = 0; j < array_length; j++) {
1577  printer->fmt_line(
1578  "{}[{}] = {}[{}][index];", instance_name, j, table_name, j);
1579  }
1580  } else {
1581  printer->fmt_line("{} = {}[index];", instance_name, table_name);
1582  }
1583  }
1584  printer->add_line("return 0;");
1585  } else {
1586  auto table_name = get_variable_name("t_" + name);
1587  printer->fmt_line("return {}[index];", table_name);
1588  }
1589  printer->pop_block();
1590 
1591  printer->add_line("int i = int(xi);");
1592  printer->add_line("double theta = xi - double(i);");
1593  if (node.is_procedure_block()) {
1594  for (const auto& var: table_variables) {
1595  auto var_name = var->get_node_name();
1596  auto instance_name = get_variable_name(var_name);
1597  auto table_name = get_variable_name("t_" + var_name);
1598  auto [is_array, array_length] = check_if_var_is_array(var->get_node_name());
1599  if (is_array) {
1600  for (size_t j = 0; j < array_length; j++) {
1601  printer->fmt_line(
1602  "{0}[{1}] = {2}[{1}][i] + theta*({2}[{1}][i+1]-{2}[{1}][i]);",
1603  instance_name,
1604  j,
1605  table_name);
1606  }
1607  } else {
1608  printer->fmt_line("{0} = {1}[i] + theta*({1}[i+1]-{1}[i]);",
1609  instance_name,
1610  table_name);
1611  }
1612  }
1613  printer->add_line("return 0;");
1614  } else {
1615  auto table_name = get_variable_name("t_" + name);
1616  printer->fmt_line("return {0}[i] + theta * ({0}[i+1] - {0}[i]);", table_name);
1617  }
1618  }
1619  printer->pop_block();
1620 }
1621 
1622 
1624  auto statement = get_table_statement(node);
1625  auto table_variables = statement->get_table_vars();
1626  auto depend_variables = statement->get_depend_vars();
1627  const auto& from = statement->get_from();
1628  const auto& to = statement->get_to();
1629  auto name = node.get_node_name();
1630  auto internal_params = internal_method_parameters();
1631  auto with = statement->get_with()->eval();
1632  auto use_table_var = get_variable_name(naming::USE_TABLE_VARIABLE);
1633  auto tmin_name = get_variable_name("tmin_" + name);
1634  auto mfac_name = get_variable_name("mfac_" + name);
1635  auto float_type = default_float_data_type();
1636 
1637  printer->add_newline(2);
1638  printer->fmt_push_block("void {}({})",
1639  table_update_function_name(name),
1640  get_parameter_str(internal_params));
1641  {
1642  printer->fmt_push_block("if ({} == 0)", use_table_var);
1643  printer->add_line("return;");
1644  printer->pop_block();
1645 
1646  printer->add_line("static bool make_table = true;");
1647  for (const auto& variable: depend_variables) {
1648  printer->fmt_line("static {} save_{};", float_type, variable->get_node_name());
1649  }
1650 
1651  for (const auto& variable: depend_variables) {
1652  const auto& var_name = variable->get_node_name();
1653  const auto& instance_name = get_variable_name(var_name);
1654  printer->fmt_push_block("if (save_{} != {})", var_name, instance_name);
1655  printer->add_line("make_table = true;");
1656  printer->pop_block();
1657  }
1658 
1659  printer->push_block("if (make_table)");
1660  {
1661  printer->add_line("make_table = false;");
1662 
1663  printer->add_indent();
1664  printer->add_text(tmin_name, " = ");
1665  from->accept(*this);
1666  printer->add_text(';');
1667  printer->add_newline();
1668 
1669  printer->add_indent();
1670  printer->add_text("double tmax = ");
1671  to->accept(*this);
1672  printer->add_text(';');
1673  printer->add_newline();
1674 
1675 
1676  printer->fmt_line("double dx = (tmax-{}) / {}.;", tmin_name, with);
1677  printer->fmt_line("{} = 1./dx;", mfac_name);
1678 
1679  printer->fmt_line("double x = {};", tmin_name);
1680  printer->fmt_push_block("for (std::size_t i = 0; i < {}; x += dx, i++)", with + 1);
1681  auto function = method_name("f_" + name);
1682  if (node.is_procedure_block()) {
1683  printer->fmt_line("{}({}, x);", function, internal_method_arguments());
1684  for (const auto& variable: table_variables) {
1685  auto var_name = variable->get_node_name();
1686  auto instance_name = get_variable_name(var_name);
1687  auto table_name = get_variable_name("t_" + var_name);
1688  auto [is_array, array_length] = check_if_var_is_array(var_name);
1689  if (is_array) {
1690  for (int j = 0; j < array_length; j++) {
1691  printer->fmt_line(
1692  "{}[{}][i] = {}[{}];", table_name, j, instance_name, j);
1693  }
1694  } else {
1695  printer->fmt_line("{}[i] = {};", table_name, instance_name);
1696  }
1697  }
1698  } else {
1699  auto table_name = get_variable_name("t_" + name);
1700  printer->fmt_line("{}[i] = {}({}, x);",
1701  table_name,
1702  function,
1703  internal_method_arguments());
1704  }
1705  printer->pop_block();
1706 
1707  for (const auto& variable: depend_variables) {
1708  auto var_name = variable->get_node_name();
1709  auto instance_name = get_variable_name(var_name);
1710  printer->fmt_line("save_{} = {};", var_name, instance_name);
1711  }
1712  }
1713  printer->pop_block();
1714  }
1715  printer->pop_block();
1716 }
1717 
1718 
1720  const std::unordered_set<CppObjectSpecifier>& specifiers) {
1721  std::string result;
1722  for (const auto& specifier: specifiers) {
1723  if (!result.empty()) {
1724  result += " ";
1725  }
1726  result += object_specifier_map[specifier];
1727  }
1728  return result;
1729 }
1730 
1731 
1733  const auto& table_statements = collect_nodes(node, {AstNodeType::TABLE_STATEMENT});
1734 
1735  if (table_statements.size() != 1) {
1736  auto message = fmt::format("One table statement expected in {} found {}",
1737  node.get_node_name(),
1738  table_statements.size());
1739  throw std::runtime_error(message);
1740  }
1741  return dynamic_cast<const ast::TableStatement*>(table_statements.front().get());
1742 }
1743 
1744 
1745 std::tuple<bool, int> CodegenCppVisitor::check_if_var_is_array(const std::string& name) {
1746  auto symbol = program_symtab->lookup_in_scope(name);
1747  if (!symbol) {
1748  throw std::runtime_error(
1749  fmt::format("CodegenCppVisitor:: {} not found in symbol table!", name));
1750  }
1751  if (symbol->is_array()) {
1752  return {true, symbol->get_length()};
1753  } else {
1754  return {false, 0};
1755  }
1756 }
1757 
1758 
1760  for (const auto& state: info.state_vars) {
1761  auto state_name = state->get_name();
1762  auto lhs = get_variable_name(state_name);
1763  auto rhs = get_variable_name(state_name + "0");
1764 
1765  if (state->is_array()) {
1766  for (int i = 0; i < state->get_length(); ++i) {
1767  printer->fmt_line("{}[{}] = {};", lhs, i, rhs);
1768  }
1769  } else {
1770  printer->fmt_line("{} = {};", lhs, rhs);
1771  }
1772  }
1773 }
1774 } // namespace codegen
1775 } // namespace nmodl
nmodl::ast::FunctionCall::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:7065
nmodl::ast::IndexedName::get_length
std::shared_ptr< Expression > get_length() const noexcept
Getter for member variable IndexedName::length.
Definition: indexed_name.hpp:176
nmodl::codegen::CodegenCppVisitor::table_update_function_name
std::string table_update_function_name(const std::string &block_name) const
The name of the function that updates the table value if the parameters changed.
Definition: codegen_cpp_visitor.cpp:76
nmodl::codegen::CodegenCppVisitor::visit_eigen_linear_solver_block
void visit_eigen_linear_solver_block(const ast::EigenLinearSolverBlock &node) override
visit node of type ast::EigenLinearSolverBlock
Definition: codegen_cpp_visitor.cpp:1161
nmodl::codegen::CodegenCppVisitor::ion_variable_struct_required
bool ion_variable_struct_required() const
Check if a structure for ion variables is required.
Definition: codegen_cpp_visitor.cpp:39
nmodl::codegen::CodegenCppVisitor::need_semicolon
static bool need_semicolon(const ast::Statement &node)
Check if a semicolon is required at the end of given statement.
Definition: codegen_cpp_visitor.cpp:217
nmodl::ast::UnaryOperator
TODO.
Definition: unary_operator.hpp:38
nmodl::codegen::CodegenCppVisitor::update_index_semantics
void update_index_semantics()
populate all index semantics needed for registration with coreneuron
Definition: codegen_cpp_visitor.cpp:1191
nmodl::ast::LocalListStatement::get_variables
const LocalVarVector & get_variables() const noexcept
Getter for member variable LocalListStatement::variables.
Definition: local_list_statement.hpp:205
nmodl::codegen::CodegenCppVisitor::print_table_replacement_function
void print_table_replacement_function(const ast::Block &)
Print replacement function for function or procedure using table.
Definition: codegen_cpp_visitor.cpp:1514
nmodl::ast::Unit
TODO.
Definition: unit.hpp:38
nmodl::codegen::naming::RANDOM_SEMANTIC
static constexpr char RANDOM_SEMANTIC[]
semantic type for RANDOM variable
Definition: codegen_naming.hpp:132
nmodl::codegen::naming::NET_SEND_SEMANTIC
static constexpr char NET_SEND_SEMANTIC[]
semantic type for net send call
Definition: codegen_naming.hpp:135
nmodl::codegen::CodegenCppVisitor::visit_name
void visit_name(const ast::Name &node) override
visit node of type ast::Name
Definition: codegen_cpp_visitor.cpp:945
nmodl::codegen::naming::FOR_NETCON_VARIABLE
static constexpr char FOR_NETCON_VARIABLE[]
name of the integer variabe to store FOR_NETCON info.
Definition: codegen_naming.hpp:144
nmodl::codegen::CodegenCppVisitor::has_parameter_of_name
bool has_parameter_of_name(const T &node, const std::string &name)
Check if function or procedure node has parameter with given name.
Definition: codegen_cpp_visitor.cpp:66
nmodl::codegen::CodegenCppVisitor::int_variables_size
int int_variables_size() const
Number of integer variables in the model.
Definition: codegen_cpp_visitor.cpp:187
nmodl::ast::Name::visit_children
void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:799
nmodl::codegen::CodegenCppVisitor::print_global_struct_function_table_ptrs
virtual void print_global_struct_function_table_ptrs()
Print the entries of for FUNCTION_TABLEs in the global struct.
Definition: codegen_cpp_visitor.cpp:479
nmodl::codegen::CodegenCppVisitor::visit_if_statement
void visit_if_statement(const ast::IfStatement &node) override
visit node of type ast::IfStatement
Definition: codegen_cpp_visitor.cpp:998
nmodl::codegen::CodegenCppVisitor::ion_write_statements
std::vector< ShadowUseStatement > ion_write_statements(BlockType type)
For a given output block type, return statements for writing back ion variables.
Definition: codegen_cpp_visitor.cpp:298
nmodl::codegen::CodegenCppVisitor::visit_else_statement
void visit_else_statement(const ast::ElseStatement &node) override
visit node of type ast::ElseStatement
Definition: codegen_cpp_visitor.cpp:1019
nmodl::codegen::CodegenCppVisitor::breakpoint_exist
bool breakpoint_exist() const noexcept
Check if breakpoint node exist.
Definition: codegen_cpp_visitor.cpp:144
nmodl::visitor::DUState
DUState
Represent a state in Def-Use chain.
Definition: defuse_analyze_visitor.hpp:28
nmodl::codegen::BlockType::Destructor
@ Destructor
destructor block
nmodl::ast::AstNodeType::MUTEX_UNLOCK
@ MUTEX_UNLOCK
type of ast::MutexUnlock
nmodl::codegen::CodegenCppVisitor::print_eigen_linear_solver
void print_eigen_linear_solver(const std::string &float_type, int N)
Print linear solver using Eigen.
Definition: codegen_cpp_visitor.cpp:849
nmodl::ast::Double
Represents a double variable.
Definition: double.hpp:53
nmodl::ast::FunctionBlock
TODO.
Definition: function_block.hpp:39
nmodl::codegen::CodegenCppVisitor::write_ion_variable_name
static std::pair< std::string, std::string > write_ion_variable_name(const std::string &name)
Return ion variable name and corresponding ion write variable name.
Definition: codegen_cpp_visitor.cpp:443
nmodl::ast::FunctionTableBlock::get_parameters
const ArgumentVector & get_parameters() const noexcept override
Getter for member variable FunctionTableBlock::parameters.
Definition: function_table_block.hpp:199
nmodl::codegen::CodegenCppVisitor::net_receive_exist
bool net_receive_exist() const noexcept
Check if net_receive node exist.
Definition: codegen_cpp_visitor.cpp:139
nmodl::codegen::CodegenCppVisitor::SymbolType
std::shared_ptr< symtab::Symbol > SymbolType
Definition: codegen_cpp_visitor.hpp:285
nmodl::codegen::CodegenCppVisitor::get_int_variable_index
int get_int_variable_index(const std::string &var_name)
Definition: codegen_cpp_visitor.cpp:449
nmodl::codegen::naming::VOLTAGE_UNUSED_VARIABLE
static constexpr char VOLTAGE_UNUSED_VARIABLE[]
range variable for voltage when unused (for vectorized model)
Definition: codegen_naming.hpp:87
nmodl::ast::FunctionTableBlock
TODO.
Definition: function_table_block.hpp:39
nmodl::codegen::naming::NRN_WATCH_CHECK_METHOD
static constexpr char NRN_WATCH_CHECK_METHOD[]
nrn_watch_check method in generated c++ file
Definition: codegen_naming.hpp:174
nmodl::codegen::CodegenCppVisitor::print_procedure
void print_procedure(const ast::ProcedureBlock &node)
Print NMODL procedure in target backend code.
Definition: codegen_cpp_visitor.cpp:569
nmodl::ast::Ast::is_conductance_hint
virtual bool is_conductance_hint() const noexcept
Check if the ast node is an instance of ast::ConductanceHint.
Definition: ast.cpp:224
nmodl::codegen::CodegenCppVisitor::float_variables_size
int float_variables_size() const
Number of float variables in the model.
Definition: codegen_cpp_visitor.cpp:177
nmodl::ast::AstNodeType::MUTEX_LOCK
@ MUTEX_LOCK
type of ast::MutexLock
nmodl::codegen::CodegenCppVisitor::print_backend_info
void print_backend_info()
Print top file header printed in generated code.
Definition: codegen_cpp_visitor.cpp:459
nmodl::codegen::CodegenCppVisitor::visit_from_statement
void visit_from_statement(const ast::FromStatement &node) override
visit node of type ast::FromStatement
Definition: codegen_cpp_visitor.cpp:1033
nmodl::codegen::CodegenCppVisitor::print_functor_definition
void print_functor_definition(const ast::EigenNewtonSolverBlock &node)
Based on the EigenNewtonSolverBlock passed print the definition needed for its functor.
Definition: codegen_cpp_visitor.cpp:775
nmodl::codegen::CodegenCppVisitor::print_global_var_struct_assertions
virtual void print_global_var_struct_assertions() const
Print static assertions about the global variable struct.
Definition: codegen_cpp_visitor.cpp:487
nmodl::codegen::CodegenCppVisitor::print_mechanism_info
void print_mechanism_info()
Print backend code for byte array that has mechanism information (to be registered with NEURON/CoreNE...
Definition: codegen_cpp_visitor.cpp:626
nmodl::codegen::CodegenCppVisitor::visit_eigen_newton_solver_block
void visit_eigen_newton_solver_block(const ast::EigenNewtonSolverBlock &node) override
visit node of type ast::EigenNewtonSolverBlock
Definition: codegen_cpp_visitor.cpp:1132
nmodl::codegen::CodegenCppVisitor::visit_prime_name
void visit_prime_name(const ast::PrimeName &node) override
visit node of type ast::PrimeName
Definition: codegen_cpp_visitor.cpp:955
nmodl::codegen::ShadowUseStatement::lhs
std::string lhs
Definition: codegen_cpp_visitor.hpp:167
nmodl::ast::EigenNewtonSolverBlock::get_initialize_block
std::shared_ptr< StatementBlock > get_initialize_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::initialize_block.
Definition: eigen_newton_solver_block.hpp:203
nmodl::codegen::ShadowUseStatement::rhs
std::string rhs
Definition: codegen_cpp_visitor.hpp:169
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::codegen::MemberType::index
@ index
index / int variables
nmodl::visitor::SymtabVisitor::visit_statement_block
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
Definition: symtab_visitor.cpp:99
nmodl::ast::EigenLinearSolverBlock::get_setup_x_block
std::shared_ptr< StatementBlock > get_setup_x_block() const noexcept
Getter for member variable EigenLinearSolverBlock::setup_x_block.
Definition: eigen_linear_solver_block.hpp:210
nmodl::codegen::naming::NRN_CONSTRUCTOR_METHOD
static constexpr char NRN_CONSTRUCTOR_METHOD[]
nrn_constructor method in generated code
Definition: codegen_naming.hpp:150
nmodl::ast::Integer::get_value
int get_value() const noexcept
Getter for member variable Integer::value.
Definition: integer.hpp:157
nmodl::ast::IndexedName::get_name
std::shared_ptr< Identifier > get_name() const noexcept
Getter for member variable IndexedName::name.
Definition: indexed_name.hpp:167
nmodl::ast::EigenLinearSolverBlock::get_variable_block
std::shared_ptr< StatementBlock > get_variable_block() const noexcept
Getter for member variable EigenLinearSolverBlock::variable_block.
Definition: eigen_linear_solver_block.hpp:192
nmodl::codegen::CodegenCppVisitor::range_variable_setup_required
bool range_variable_setup_required() const noexcept
Check if setup_range_variable function is required.
Definition: codegen_cpp_visitor.cpp:158
nmodl::ast::MutexLock
Represent MUTEXLOCK statement in NMODL.
Definition: mutex_lock.hpp:38
nmodl::codegen::CodegenCppVisitor::print_statement_block
void print_statement_block(const ast::StatementBlock &node, bool open_brace=true, bool close_brace=true)
Print any statement block in nmodl with option to (not) print braces.
Definition: codegen_cpp_visitor.cpp:700
nmodl::ast::Double::get_value
const std::string & get_value() const noexcept
Getter for member variable Double::value.
Definition: double.hpp:158
nmodl::ast::StatementBlock::insert_statement
StatementVector::const_iterator insert_statement(StatementVector::const_iterator position, const std::shared_ptr< Statement > &n)
Insert member to statements.
Definition: ast.cpp:3134
nmodl::ast::WhileStatement
TODO.
Definition: while_statement.hpp:38
nmodl::ast::Ast::is_procedure_block
virtual bool is_procedure_block() const noexcept
Check if the ast node is an instance of ast::ProcedureBlock.
Definition: ast.cpp:144
nmodl::ast::TableStatement
Represents TABLE statement in NMODL.
Definition: table_statement.hpp:39
nmodl::ast::Ast::is_protect_statement
virtual bool is_protect_statement() const noexcept
Check if the ast node is an instance of ast::ProtectStatement.
Definition: ast.cpp:228
nmodl::codegen::CodegenCppVisitor::visit_binary_expression
void visit_binary_expression(const ast::BinaryExpression &node) override
visit node of type ast::BinaryExpression
Definition: codegen_cpp_visitor.cpp:1061
nmodl::ast::VarName
Represents a variable.
Definition: var_name.hpp:43
nmodl::ast::Integer
Represents an integer variable.
Definition: integer.hpp:49
string_utils.hpp
Implement string manipulation functions.
nmodl::codegen::CodegenCppVisitor::get_object_specifiers
std::string get_object_specifiers(const std::unordered_set< CppObjectSpecifier > &)
Definition: codegen_cpp_visitor.cpp:1719
nmodl::codegen::CodegenCppVisitor::get_float_variables
std::vector< SymbolType > get_float_variables() const
Determine all float variables required during code generation.
Definition: codegen_cpp_visitor.cpp:1267
nmodl::ast::ElseIfStatement
TODO.
Definition: else_if_statement.hpp:38
nmodl::ast::Ast::is_expression_statement
virtual bool is_expression_statement() const noexcept
Check if the ast node is an instance of ast::ExpressionStatement.
Definition: ast.cpp:226
nmodl::codegen::naming::NODE_AREA_VARIABLE
static constexpr char NODE_AREA_VARIABLE[]
inbuilt neuron variable for area of the compartment
Definition: codegen_naming.hpp:66
nmodl::codegen::CodegenCppVisitor::print_top_verbatim_blocks
void print_top_verbatim_blocks()
Print top level (global scope) verbatim blocks.
Definition: codegen_cpp_visitor.cpp:673
nmodl::codegen::CodegenCppVisitor::print_function_tables
void print_function_tables(const ast::FunctionTableBlock &node)
Print the internal function for FUNCTION_TABLES.
Definition: codegen_cpp_visitor.cpp:594
nmodl::codegen::CodegenCppVisitor::visit_paren_expression
void visit_paren_expression(const ast::ParenExpression &node) override
visit node of type ast::ParenExpression
Definition: codegen_cpp_visitor.cpp:1054
nmodl::codegen::CodegenCppVisitor::print_namespace_start
void print_namespace_start()
Prints the start of the simulator namespace.
Definition: codegen_cpp_visitor.cpp:662
nmodl::visitor::SymtabVisitor
Concrete visitor for constructing symbol table from AST.
Definition: symtab_visitor.hpp:37
nmodl::codegen::CodegenCppVisitor::net_receive_buffering_required
bool net_receive_buffering_required() const noexcept
Check if net receive/send buffering kernels required.
Definition: codegen_cpp_visitor.cpp:121
nmodl::codegen::CodegenCppVisitor::update_if_ion_variable_name
std::string update_if_ion_variable_name(const std::string &name) const
Determine the updated name if the ion variable has been optimized.
Definition: codegen_cpp_visitor.cpp:420
nmodl::ast::ElseStatement::visit_children
void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:9859
nmodl::ast::EigenNewtonSolverBlock::get_n_state_vars
std::shared_ptr< Integer > get_n_state_vars() const noexcept
Getter for member variable EigenNewtonSolverBlock::n_state_vars.
Definition: eigen_newton_solver_block.hpp:185
nmodl::codegen::CodegenCppVisitor::print_function
void print_function(const ast::FunctionBlock &node)
Print NMODL function in target backend code.
Definition: codegen_cpp_visitor.cpp:574
nmodl::ast::VarName::get_index
std::shared_ptr< Expression > get_index() const noexcept
Getter for member variable VarName::index.
Definition: var_name.hpp:182
nmodl::Version::GIT_REVISION
static const std::string GIT_REVISION
git revision id
Definition: config.h:33
nmodl::logger
logger_type logger
Definition: logger.cpp:34
nmodl::codegen::ShadowUseStatement::op
std::string op
Definition: codegen_cpp_visitor.hpp:168
nmodl::codegen::CodegenCppVisitor::visit_mutex_unlock
void visit_mutex_unlock(const ast::MutexUnlock &node) override
visit node of type ast::MutexUnlock
Definition: codegen_cpp_visitor.cpp:1116
nmodl::visitor::DefUseAnalyzeVisitor
Visitor to return Def-Use chain for a given variable in the block/node
Definition: defuse_analyze_visitor.hpp:214
nmodl::codegen::utils::format_float_string
std::string format_float_string(const std::string &s_value)
Handles the float constants format being printed in the generated code.
Definition: codegen_utils.cpp:32
nmodl::codegen::CodegenCppVisitor::visit_unit
void visit_unit(const ast::Unit &node) override
visit node of type ast::Unit
Definition: codegen_cpp_visitor.cpp:950
nmodl::ast::BinaryExpression::get_rhs
std::shared_ptr< Expression > get_rhs() const noexcept
Getter for member variable BinaryExpression::rhs.
Definition: binary_expression.hpp:179
nmodl::ast::EigenNewtonSolverBlock
Represent newton solver solution block based on Eigen.
Definition: eigen_newton_solver_block.hpp:38
nmodl::ast::Boolean::eval
bool eval() const
Return value of the ast node.
Definition: boolean.hpp:243
nmodl::codegen::CodegenCppVisitor::visit_update_dt
void visit_update_dt(const ast::UpdateDt &node) override
visit node of type ast::UpdateDt
Definition: codegen_cpp_visitor.cpp:1104
codegen_helper_visitor.hpp
Helper visitor to gather AST information to help code generation.
nmodl::ast::FromStatement::get_increment
std::shared_ptr< Expression > get_increment() const noexcept
Getter for member variable FromStatement::increment.
Definition: from_statement.hpp:204
nmodl::codegen::naming::CONDUCTANCE_VARIABLE
static constexpr char CONDUCTANCE_VARIABLE[]
range variable for conductance
Definition: codegen_naming.hpp:78
nmodl::ast::VarName::get_at
std::shared_ptr< Integer > get_at() const noexcept
Getter for member variable VarName::at.
Definition: var_name.hpp:173
nmodl::codegen::CodegenCppVisitor::is_function_table_call
bool is_function_table_call(const std::string &name) const
Definition: codegen_cpp_visitor.cpp:170
nmodl::ast::EigenLinearSolverBlock::get_initialize_block
std::shared_ptr< StatementBlock > get_initialize_block() const noexcept
Getter for member variable EigenLinearSolverBlock::initialize_block.
Definition: eigen_linear_solver_block.hpp:201
nmodl::visitor::DefUseAnalyzeVisitor::analyze
DUChain analyze(const ast::Ast &node, const std::string &name)
compute def-use chain for a variable within the node
Definition: defuse_analyze_visitor.cpp:419
nmodl::codegen::naming::DEFAULT_FLOAT_TYPE
static constexpr char DEFAULT_FLOAT_TYPE[]
default float variable type
Definition: codegen_naming.hpp:111
nmodl::ast::FunctionTableBlock::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:3804
nmodl::ast::EigenLinearSolverBlock::get_update_states_block
std::shared_ptr< StatementBlock > get_update_states_block() const noexcept
Getter for member variable EigenLinearSolverBlock::update_states_block.
Definition: eigen_linear_solver_block.hpp:219
nmodl::codegen::CodegenCppVisitor::get_int_variables
std::vector< IndexVariableInfo > get_int_variables()
Determine all int variables required during code generation.
Definition: codegen_cpp_visitor.cpp:1343
codegen_cpp_visitor.hpp
Visitor for printing C++ code compatible with legacy api of CoreNEURON
nmodl::ast::StatementBlock::get_statements
const StatementVector & get_statements() const noexcept
Getter for member variable StatementBlock::statements.
Definition: statement_block.hpp:221
nmodl::ast::ExpressionStatement
TODO.
Definition: expression_statement.hpp:38
nmodl::codegen::CodegenCppVisitor::visit_function_call
void visit_function_call(const ast::FunctionCall &node) override
visit node of type ast::FunctionCall
Definition: codegen_cpp_visitor.cpp:1099
nmodl::ast::Block
Base class for all block scoped nodes.
Definition: block.hpp:41
nmodl::ast::IfStatement::get_elseifs
const ElseIfStatementVector & get_elseifs() const noexcept
Getter for member variable IfStatement::elseifs.
Definition: if_statement.hpp:182
nmodl::ast::EigenNewtonSolverBlock::get_setup_x_block
std::shared_ptr< StatementBlock > get_setup_x_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::setup_x_block.
Definition: eigen_newton_solver_block.hpp:212
nmodl::ast::Ast::is_mutex_lock
virtual bool is_mutex_lock() const noexcept
Check if the ast node is an instance of ast::MutexLock.
Definition: ast.cpp:242
nmodl::codegen::CodegenCppVisitor::print_parallel_iteration_hint
virtual void print_parallel_iteration_hint(BlockType type, const ast::Block *block)
Print pragma annotations for channel iterations.
Definition: codegen_cpp_visitor.cpp:394
nmodl::ast::IfStatement::get_condition
std::shared_ptr< Expression > get_condition() const noexcept
Getter for member variable IfStatement::condition.
Definition: if_statement.hpp:164
nmodl::ast::LocalListStatement
TODO.
Definition: local_list_statement.hpp:39
nmodl::ast::Ast::is_if_statement
virtual bool is_if_statement() const noexcept
Check if the ast node is an instance of ast::IfStatement.
Definition: ast.cpp:234
nmodl::stringutils::trim
static std::string trim(std::string text)
Definition: string_utils.hpp:63
visitor_utils.hpp
Utility functions for visitors implementation.
nmodl::codegen::BlockType::Equation
@ Equation
breakpoint block
nmodl::codegen::naming::USE_TABLE_VARIABLE
static constexpr char USE_TABLE_VARIABLE[]
global variable to indicate if table is used
Definition: codegen_naming.hpp:81
nmodl::ast::Float::get_value
const std::string & get_value() const noexcept
Getter for member variable Float::value.
Definition: float.hpp:148
nmodl::ast::EigenLinearSolverBlock::get_finalize_block
std::shared_ptr< StatementBlock > get_finalize_block() const noexcept
Getter for member variable EigenLinearSolverBlock::finalize_block.
Definition: eigen_linear_solver_block.hpp:228
nmodl::ast::Float
Represents a float variable.
Definition: float.hpp:44
nmodl::ast::Ast::is_verbatim
virtual bool is_verbatim() const noexcept
Check if the ast node is an instance of ast::Verbatim.
Definition: ast.cpp:282
nmodl::ast::IndexedName
Represents specific element of an array variable.
Definition: indexed_name.hpp:48
nmodl::ast::String::eval
std::string eval() const
Return value of the ast node.
Definition: string.hpp:237
nmodl::codegen::regex_special_chars
const std::regex regex_special_chars
Definition: codegen_cpp_visitor.cpp:912
nmodl::ast::FunctionCall
TODO.
Definition: function_call.hpp:38
nmodl::ast::FromStatement::get_from
std::shared_ptr< Expression > get_from() const noexcept
Getter for member variable FromStatement::from.
Definition: from_statement.hpp:186
nmodl::codegen::CodegenCppVisitor::setup
virtual void setup(const ast::Program &node)
Definition: codegen_cpp_visitor.cpp:1457
nmodl::codegen::CodegenCppVisitor::visit_unary_operator
void visit_unary_operator(const ast::UnaryOperator &node) override
visit node of type ast::UnaryOperator
Definition: codegen_cpp_visitor.cpp:1084
nmodl::codegen::naming::POINT_PROCESS_SEMANTIC
static constexpr char POINT_PROCESS_SEMANTIC[]
semantic type for point process variable
Definition: codegen_naming.hpp:123
nmodl::codegen::CodegenCppVisitor::visit_mutex_lock
void visit_mutex_lock(const ast::MutexLock &node) override
visit node of type ast::MutexLock
Definition: codegen_cpp_visitor.cpp:1109
nmodl::codegen::CodegenCppVisitor::visit_boolean
void visit_boolean(const ast::Boolean &node) override
visit node of type ast::Boolean
Definition: codegen_cpp_visitor.cpp:940
nmodl::ast::Ast::is_else_if_statement
virtual bool is_else_if_statement() const noexcept
Check if the ast node is an instance of ast::ElseIfStatement.
Definition: ast.cpp:236
nmodl::codegen::CodegenCppVisitor::nrn_cur_required
bool nrn_cur_required() const noexcept
Check if nrn_cur function is required.
Definition: codegen_cpp_visitor.cpp:134
nmodl::ast::Ast::is_table_statement
virtual bool is_table_statement() const noexcept
Check if the ast node is an instance of ast::TableStatement.
Definition: ast.cpp:258
nmodl::codegen::CodegenCppVisitor::ion_read_statements_optimized
std::vector< std::string > ion_read_statements_optimized(BlockType type) const
For a given output block type, return minimal statements for all read ion variables.
Definition: codegen_cpp_visitor.cpp:282
nmodl::codegen::BlockType::Constructor
@ Constructor
constructor block
nmodl::ast::MutexUnlock
Represent MUTEXUNLOCK statement in NMODL.
Definition: mutex_unlock.hpp:38
nmodl::ast::StatementBlock::get_symbol_table
symtab::SymbolTable * get_symbol_table() const override
Return associated symbol table for the current ast node.
Definition: statement_block.hpp:164
nmodl::codegen::CodegenCppVisitor::visit_double
void visit_double(const ast::Double &node) override
visit node of type ast::Double
Definition: codegen_cpp_visitor.cpp:935
nmodl::codegen::CodegenCppVisitor::print_using_namespace
void print_using_namespace()
Prints f"using namespace {namespace_name()}".
Definition: codegen_cpp_visitor.cpp:658
nmodl::codegen::CodegenCppVisitor::net_send_buffer_required
bool net_send_buffer_required() const noexcept
Check if net_send_buffer is required.
Definition: codegen_cpp_visitor.cpp:111
nmodl::is_nrn_pointing
bool is_nrn_pointing(const std::string &name)
Is given name nrn_pointing.
Definition: visitor_utils.cpp:301
nmodl::codegen::CodegenCppVisitor::visit_float
void visit_float(const ast::Float &node) override
visit node of type ast::Float
Definition: codegen_cpp_visitor.cpp:930
nmodl::codegen::CodegenCppVisitor::visit_string
void visit_string(const ast::String &node) override
visit node of type ast::String
Definition: codegen_cpp_visitor.cpp:915
nmodl::codegen::IndexSemantics
Represent semantic information for index variable.
Definition: codegen_info.hpp:270
nmodl::codegen::BlockType::Watch
@ Watch
watch block
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:282
nmodl::ast::Ast::is_block_comment
virtual bool is_block_comment() const noexcept
Check if the ast node is an instance of ast::BlockComment.
Definition: ast.cpp:286
nmodl::codegen::CodegenCppVisitor::visit_solution_expression
void visit_solution_expression(const ast::SolutionExpression &node) override
visit node of type ast::SolutionExpression
Definition: codegen_cpp_visitor.cpp:1121
nmodl::codegen::naming::NRN_INIT_METHOD
static constexpr char NRN_INIT_METHOD[]
nrn_init method in generated code
Definition: codegen_naming.hpp:147
nmodl::codegen::CodegenCppVisitor::print_nrn_pointing
virtual void print_nrn_pointing(const ast::FunctionCall &node)
Print nrn_pointing.
Definition: codegen_cpp_visitor.cpp:563
nmodl::ast::FunctionCall::get_arguments
const ExpressionVector & get_arguments() const noexcept
Getter for member variable FunctionCall::arguments.
Definition: function_call.hpp:166
nmodl::codegen::naming::POINTER_SEMANTIC
static constexpr char POINTER_SEMANTIC[]
semantic type for pointer variable
Definition: codegen_naming.hpp:126
nmodl::codegen::CodegenCppVisitor::print_global_var_struct_decl
virtual void print_global_var_struct_decl()
Instantiate global var instance.
Definition: codegen_cpp_visitor.cpp:500
nmodl::codegen::naming::AREA_SEMANTIC
static constexpr char AREA_SEMANTIC[]
semantic type for area variable
Definition: codegen_naming.hpp:120
nmodl::codegen::CodegenCppVisitor::visit_var_name
void visit_var_name(const ast::VarName &node) override
Definition: codegen_cpp_visitor.cpp:963
nmodl::codegen::CodegenInfo::mod_file
std::string mod_file
name of mod file
Definition: codegen_info.hpp:337
nmodl::codegen::CodegenCppVisitor::print_nmodl_constants
void print_nmodl_constants()
Print the nmodl constants used in backend code.
Definition: codegen_cpp_visitor.cpp:895
nmodl::ast::ParenExpression::get_expression
std::shared_ptr< Expression > get_expression() const noexcept
Getter for member variable ParenExpression::expression.
Definition: paren_expression.hpp:143
nmodl::ast::BinaryExpression::get_op
const BinaryOperator & get_op() const noexcept
Getter for member variable BinaryExpression::op.
Definition: binary_expression.hpp:170
nmodl::codegen::CodegenCppVisitor::print_table_check_function
void print_table_check_function(const ast::Block &)
Print check_function() for functions or procedure using table.
Definition: codegen_cpp_visitor.cpp:1623
nmodl::ast::Ast::is_from_statement
virtual bool is_from_statement() const noexcept
Check if the ast node is an instance of ast::FromStatement.
Definition: ast.cpp:230
nmodl::ast::PrimeName
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
nmodl::codegen::CodegenCppVisitor::read_ion_variable_name
static std::pair< std::string, std::string > read_ion_variable_name(const std::string &name)
Return ion variable name and corresponding ion read variable name.
Definition: codegen_cpp_visitor.cpp:437
nmodl::ast::EigenLinearSolverBlock::get_n_state_vars
std::shared_ptr< Integer > get_n_state_vars() const noexcept
Getter for member variable EigenLinearSolverBlock::n_state_vars.
Definition: eigen_linear_solver_block.hpp:183
nmodl::ast::ElseIfStatement::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable ElseIfStatement::statement_block.
Definition: else_if_statement.hpp:168
nmodl::visitor::RenameVisitor
Blindly rename given variable to new name
Definition: rename_visitor.hpp:43
nmodl::codegen::CodegenCppVisitor::get_arg_str
static std::string get_arg_str(const ParamVector &params)
Generate the string representing the parameters in a function call.
Definition: codegen_cpp_visitor.cpp:43
nmodl::codegen::naming::NRN_CUR_METHOD
static constexpr char NRN_CUR_METHOD[]
nrn_cur method in generated code
Definition: codegen_naming.hpp:168
nmodl::ast::UnaryOperator::eval
std::string eval() const
Return enum value in string form.
Definition: unary_operator.hpp:214
nmodl::codegen::naming::RANDOM_FUNCTIONS_MAPPING
static std::unordered_map< std::string, std::string > RANDOM_FUNCTIONS_MAPPING
Definition: codegen_naming.hpp:241
codegen_utils.hpp
Implement utility functions for codegen visitors.
nmodl::ast::IfStatement
TODO.
Definition: if_statement.hpp:39
nmodl::ast::Boolean
Represents a boolean variable.
Definition: boolean.hpp:42
nmodl::ast::BinaryOperator::eval
std::string eval() const
Return enum value in string form.
Definition: binary_operator.hpp:214
nmodl::ast::Ast::is_mutex_unlock
virtual bool is_mutex_unlock() const noexcept
Check if the ast node is an instance of ast::MutexUnlock.
Definition: ast.cpp:244
nmodl::ast::AstNodeType::LOCAL_VAR
@ LOCAL_VAR
type of ast::LocalVar
nmodl::codegen::CodegenHelperVisitor::analyze
codegen::CodegenInfo analyze(const ast::Program &node)
run visitor and return information for code generation
Definition: codegen_helper_visitor.cpp:821
nmodl::ast::WhileStatement::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable WhileStatement::statement_block.
Definition: while_statement.hpp:168
nmodl::codegen::CodegenCppVisitor::visit_integer
void visit_integer(const ast::Integer &node) override
visit node of type ast::Integer
Definition: codegen_cpp_visitor.cpp:924
nmodl::ast::EigenLinearSolverBlock
Represent linear solver solution block based on Eigen.
Definition: eigen_linear_solver_block.hpp:38
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
defuse_analyze_visitor.hpp
Visitor to return Def-Use chain for a given variable in the block/node
nmodl::ast::FunctionBlock::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:3967
nmodl::ast::UpdateDt
Statement to indicate a change in timestep in a given block.
Definition: update_dt.hpp:38
nmodl::ast::EigenNewtonSolverBlock::get_functor_block
std::shared_ptr< StatementBlock > get_functor_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::functor_block.
Definition: eigen_newton_solver_block.hpp:221
nmodl::codegen::CodegenCppVisitor::get_table_statement
const ast::TableStatement * get_table_statement(const ast::Block &)
Definition: codegen_cpp_visitor.cpp:1732
nmodl::ast::Statement
TODO.
Definition: statement.hpp:38
nmodl::codegen::CodegenCppVisitor::format_float_string
std::string format_float_string(const std::string &value)
Convert a given float value to its string representation.
Definition: codegen_cpp_visitor.cpp:206
nmodl::codegen::CodegenCppVisitor::check_if_var_is_array
std::tuple< bool, int > check_if_var_is_array(const std::string &name)
Check if the given name exist in the symbol.
Definition: codegen_cpp_visitor.cpp:1745
nmodl::codegen::CodegenCppVisitor::is_functor_const
bool is_functor_const(const ast::StatementBlock &variable_block, const ast::StatementBlock &functor_block)
Checks whether the functor_block generated by sympy solver modifies any variable outside its scope.
Definition: codegen_cpp_visitor.cpp:732
nmodl::ast::SolutionExpression::get_node_to_solve
std::shared_ptr< Expression > get_node_to_solve() const noexcept
Getter for member variable SolutionExpression::node_to_solve.
Definition: solution_expression.hpp:154
nmodl::codegen::CodegenCppVisitor::get_parameter_str
static std::string get_parameter_str(const ParamVector &params)
Generate the string representing the procedure parameter declaration.
Definition: codegen_cpp_visitor.cpp:52
nmodl::ast::IfStatement::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable IfStatement::statement_block.
Definition: if_statement.hpp:173
nmodl::ast::AstNodeType::PROTECT_STATEMENT
@ PROTECT_STATEMENT
type of ast::ProtectStatement
nmodl::ast::StatementBlock
Represents block encapsulating list of statements.
Definition: statement_block.hpp:53
nmodl::codegen::utils::format_double_string
std::string format_double_string(const std::string &s_value)
Handles the double constants format being printed in the generated code.
Definition: codegen_utils.cpp:23
nmodl::ast::Ast::is_unit_state
virtual bool is_unit_state() const noexcept
Check if the ast node is an instance of ast::UnitState.
Definition: ast.cpp:210
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::codegen::CodegenCppVisitor::net_receive_required
bool net_receive_required() const noexcept
Check if net_receive function is required.
Definition: codegen_cpp_visitor.cpp:149
nmodl::codegen::naming::CORE_POINTER_SEMANTIC
static constexpr char CORE_POINTER_SEMANTIC[]
semantic type for core pointer variable
Definition: codegen_naming.hpp:129
nmodl::ast::ParenExpression
TODO.
Definition: paren_expression.hpp:38
nmodl::ast::EigenNewtonSolverBlock::get_variable_block
std::shared_ptr< StatementBlock > get_variable_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::variable_block.
Definition: eigen_newton_solver_block.hpp:194
nmodl::codegen::CodegenCppVisitor::visit_local_list_statement
void visit_local_list_statement(const ast::LocalListStatement &node) override
visit node of type ast::LocalListStatement
Definition: codegen_cpp_visitor.cpp:992
nmodl::codegen::ShadowUseStatement
Represents ion write statement during code generation.
Definition: codegen_cpp_visitor.hpp:166
nmodl::ast::ProcedureBlock
TODO.
Definition: procedure_block.hpp:39
nmodl::codegen::naming::WATCH_SEMANTIC
static constexpr char WATCH_SEMANTIC[]
semantic type for watch statement
Definition: codegen_naming.hpp:138
nmodl::ast::BinaryOperator
Operator used in ast::BinaryExpression.
Definition: binary_operator.hpp:38
nmodl::codegen::CodegenCppVisitor::defined_method
bool defined_method(const std::string &name) const
Check if given method is defined in this model.
Definition: codegen_cpp_visitor.cpp:164
nmodl::ast::ElseIfStatement::get_condition
std::shared_ptr< Expression > get_condition() const noexcept
Getter for member variable ElseIfStatement::condition.
Definition: else_if_statement.hpp:159
nmodl::Version::NMODL_VERSION
static const std::string NMODL_VERSION
project tagged version in the cmake
Definition: config.h:36
nmodl::codegen::CodegenCppVisitor::print_function_call
virtual void print_function_call(const ast::FunctionCall &node)
Print call to internal or external function.
Definition: codegen_cpp_visitor.cpp:505
nmodl::ast::SolutionExpression
Represent solution of a block in the AST.
Definition: solution_expression.hpp:38
nmodl::codegen::CodegenCppVisitor::process_shadow_update_statement
std::string process_shadow_update_statement(const ShadowUseStatement &statement, BlockType type)
Process shadow update statement.
Definition: codegen_cpp_visitor.cpp:340
nmodl::ast::FunctionBlock::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable FunctionBlock::statement_block.
Definition: function_block.hpp:219
nmodl::codegen::CodegenHelperVisitor
Helper visitor to gather AST information to help code generation.
Definition: codegen_helper_visitor.hpp:47
nmodl::codegen::BlockType
BlockType
Helper to represent various block types.
Definition: codegen_cpp_visitor.hpp:56
nmodl::ast::VarName::get_name
std::shared_ptr< Identifier > get_name() const noexcept
Getter for member variable VarName::name.
Definition: var_name.hpp:164
nmodl::ast::Program::get_symbol_table
symtab::SymbolTable * get_symbol_table() const override
Return associated symbol table for the current ast node.
Definition: program.hpp:153
nmodl::codegen::naming::NRN_STATE_METHOD
static constexpr char NRN_STATE_METHOD[]
nrn_state method in generated code
Definition: codegen_naming.hpp:165
nmodl::codegen::CodegenCppVisitor::breakpoint_current
std::string breakpoint_current(std::string current) const
Determine the variable name for the "current" used in breakpoint block taking into account intermedia...
Definition: codegen_cpp_visitor.cpp:363
nmodl::codegen::CodegenCppVisitor::visit_binary_operator
void visit_binary_operator(const ast::BinaryOperator &node) override
visit node of type ast::BinaryOperator
Definition: codegen_cpp_visitor.cpp:1079
config.h
Version information and units file path.
nmodl::ast::Ast::is_solve_block
virtual bool is_solve_block() const noexcept
Check if the ast node is an instance of ast::SolveBlock.
Definition: ast.cpp:148
nmodl::codegen::CodegenCppVisitor::visit_else_if_statement
void visit_else_if_statement(const ast::ElseIfStatement &node) override
visit node of type ast::ElseIfStatement
Definition: codegen_cpp_visitor.cpp:1011
nmodl::ast::IfStatement::get_elses
std::shared_ptr< ElseStatement > get_elses() const noexcept
Getter for member variable IfStatement::elses.
Definition: if_statement.hpp:191
nmodl::ast::BinaryExpression::get_lhs
std::shared_ptr< Expression > get_lhs() const noexcept
Getter for member variable BinaryExpression::lhs.
Definition: binary_expression.hpp:161
nmodl::ast::Ast::is_line_comment
virtual bool is_line_comment() const noexcept
Check if the ast node is an instance of ast::LineComment.
Definition: ast.cpp:284
nmodl::codegen::CodegenCppVisitor::compute_method_name
std::string compute_method_name(BlockType type) const
Definition: codegen_cpp_visitor.cpp:1485
nmodl::codegen::naming::AREA_VARIABLE
static constexpr char AREA_VARIABLE[]
similar to node_area but user can explicitly declare it as area
Definition: codegen_naming.hpp:69
nmodl::ast::Name
Represents a name.
Definition: name.hpp:44
nmodl::ast::Ast::is_while_statement
virtual bool is_while_statement() const noexcept
Check if the ast node is an instance of ast::WhileStatement.
Definition: ast.cpp:232
nmodl::codegen::CodegenCppVisitor::visit_program
void visit_program(const ast::Program &program) override
Main and only member function to call after creating an instance of this class.
Definition: codegen_cpp_visitor.cpp:1508
nmodl::ast::Ast::is_else_statement
virtual bool is_else_statement() const noexcept
Check if the ast node is an instance of ast::ElseStatement.
Definition: ast.cpp:238
nmodl::ast::FromStatement::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable FromStatement::statement_block.
Definition: from_statement.hpp:213
nmodl::ast::Program
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
nmodl::codegen::CodegenCppVisitor::visit_indexed_name
void visit_indexed_name(const ast::IndexedName &node) override
visit node of type ast::IndexedName
Definition: codegen_cpp_visitor.cpp:982
nmodl::ast::FromStatement::get_to
std::shared_ptr< Expression > get_to() const noexcept
Getter for member variable FromStatement::to.
Definition: from_statement.hpp:195
nmodl::codegen::naming::T_SAVE_VARIABLE
static constexpr char T_SAVE_VARIABLE[]
variable t indicating last execution time of net receive block
Definition: codegen_naming.hpp:90
nmodl::codegen::CodegenCppVisitor::print_prcellstate_macros
void print_prcellstate_macros() const
Print declaration of macro NRN_PRCELLSTATE for debugging.
Definition: codegen_cpp_visitor.cpp:619
nmodl::codegen::naming::FOR_NETCON_SEMANTIC
static constexpr char FOR_NETCON_SEMANTIC[]
semantic type for for_netcon statement
Definition: codegen_naming.hpp:141
nmodl::ast::EigenNewtonSolverBlock::get_update_states_block
std::shared_ptr< StatementBlock > get_update_states_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::update_states_block.
Definition: eigen_newton_solver_block.hpp:230
nmodl::codegen::CodegenCppVisitor::print_rename_state_vars
void print_rename_state_vars() const
Definition: codegen_cpp_visitor.cpp:1759
rename_visitor.hpp
Blindly rename given variable to new name
nmodl::codegen::BlockType::State
@ State
derivative block
nmodl::codegen::CodegenCppVisitor::nrn_state_required
bool nrn_state_required() const noexcept
Check if nrn_state function is required.
Definition: codegen_cpp_visitor.cpp:126
nmodl::ast::ElseStatement
TODO.
Definition: else_statement.hpp:38
nmodl::codegen::naming::DIAM_VARIABLE
static constexpr char DIAM_VARIABLE[]
inbuilt neuron variable for diameter of the compartment
Definition: codegen_naming.hpp:63
symtab_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
nmodl::ast::Block::get_parameters
virtual const ArgumentVector & get_parameters() const
Definition: block.hpp:50
nmodl::ast::BinaryExpression
Represents binary expression in the NMODL.
Definition: binary_expression.hpp:52
nmodl::codegen::naming::NRN_DESTRUCTOR_METHOD
static constexpr char NRN_DESTRUCTOR_METHOD[]
nrn_destructor method in generated code
Definition: codegen_naming.hpp:153
nmodl::codegen::naming::CONDUCTANCE_UNUSED_VARIABLE
static constexpr char CONDUCTANCE_UNUSED_VARIABLE[]
range variable when conductance is not used (for vectorized model)
Definition: codegen_naming.hpp:84
nmodl::codegen::BlockType::Initial
@ Initial
initial block
nmodl::codegen::CodegenCppVisitor::statement_to_skip
static bool statement_to_skip(const ast::Statement &node)
Check if given statement should be skipped during code generation.
Definition: codegen_cpp_visitor.cpp:87
nmodl::codegen::CodegenCppVisitor::ion_read_statements
std::vector< std::string > ion_read_statements(BlockType type) const
For a given output block type, return statements for all read ion variables.
Definition: codegen_cpp_visitor.cpp:252
nmodl::codegen::CodegenCppVisitor::print_functors_definitions
void print_functors_definitions()
Print all Newton functor structs.
Definition: codegen_cpp_visitor.cpp:768
nmodl::ast::EigenNewtonSolverBlock::get_finalize_block
std::shared_ptr< StatementBlock > get_finalize_block() const noexcept
Getter for member variable EigenNewtonSolverBlock::finalize_block.
Definition: eigen_newton_solver_block.hpp:239
nmodl::codegen::CodegenCppVisitor::format_double_string
std::string format_double_string(const std::string &value)
Convert a given double value to its string representation.
Definition: codegen_cpp_visitor.cpp:201
nmodl::codegen::get_index_from_name
int get_index_from_name(const std::vector< T > &variables, const std::string &name)
Definition: codegen_cpp_visitor.hpp:185
nmodl::codegen::CodegenCppVisitor::print_namespace_stop
void print_namespace_stop()
Prints the end of the simulator namespace.
Definition: codegen_cpp_visitor.cpp:668
nmodl::ast::Ast::get_node_name
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
nmodl::ast::String
Represents a string.
Definition: string.hpp:52
all.hpp
Auto generated AST classes declaration.
nmodl::ast::FromStatement
TODO.
Definition: from_statement.hpp:38
nmodl::ast::FromStatement::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:9200
nmodl::codegen::CodegenCppVisitor::visit_while_statement
void visit_while_statement(const ast::WhileStatement &node) override
visit node of type ast::WhileStatement
Definition: codegen_cpp_visitor.cpp:1025
nmodl::codegen::CodegenCppVisitor::ParamVector
std::vector< std::tuple< std::string, std::string, std::string, std::string > > ParamVector
A vector of parameters represented by a 4-tuple of strings:
Definition: codegen_cpp_visitor.hpp:297
nmodl::codegen::naming::ION_VARNAME_PREFIX
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
Definition: codegen_naming.hpp:201
nmodl::ast::WhileStatement::get_condition
std::shared_ptr< Expression > get_condition() const noexcept
Getter for member variable WhileStatement::condition.
Definition: while_statement.hpp:159
nmodl::codegen::CodegenCppVisitor::visit_statement_block
void visit_statement_block(const ast::StatementBlock &node) override
Definition: codegen_cpp_visitor.cpp:1094