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 "ast/all.hpp"
14 
15 namespace nmodl {
16 namespace codegen {
17 
18 using namespace ast;
19 
20 using visitor::RenameVisitor;
21 
23 
24 
25 /****************************************************************************************/
26 /* Common helper routines accross codegen functions */
27 /****************************************************************************************/
28 
30  return optimize_ion_variable_copies() && info.ion_has_write_variable();
31 }
32 
33 
35  std::string str;
36  bool is_first = true;
37  for (const auto& param: params) {
38  if (is_first) {
39  is_first = false;
40  } else {
41  str += ", ";
42  }
43  str += fmt::format("{}{} {}{}",
44  std::get<0>(param),
45  std::get<1>(param),
46  std::get<2>(param),
47  std::get<3>(param));
48  }
49  return str;
50 }
51 
52 
53 template <typename T>
54 bool CodegenCppVisitor::has_parameter_of_name(const T& node, const std::string& name) {
55  auto parameters = node->get_parameters();
56  return std::any_of(parameters.begin(),
57  parameters.end(),
58  [&name](const decltype(*parameters.begin()) arg) {
59  return arg->get_node_name() == name;
60  });
61 }
62 
63 
64 /**
65  * \details Certain statements like unit, comment, solve can/need to be skipped
66  * during code generation. Note that solve block is wrapped in expression
67  * statement and hence we have to check inner expression. It's also true
68  * for the initial block defined inside net receive block.
69  */
71  // clang-format off
72  if (node.is_unit_state()
73  || node.is_line_comment()
74  || node.is_block_comment()
75  || node.is_solve_block()
76  || node.is_conductance_hint()
77  || node.is_table_statement()) {
78  return true;
79  }
80  // clang-format on
81  if (node.is_expression_statement()) {
82  auto expression = dynamic_cast<const ExpressionStatement*>(&node)->get_expression();
83  if (expression->is_solve_block()) {
84  return true;
85  }
86  if (expression->is_initial_block()) {
87  return true;
88  }
89  }
90  return false;
91 }
92 
93 
95  if (net_receive_required() && !info.artificial_cell) {
96  if (info.net_event_used || info.net_send_used || info.is_watch_used()) {
97  return true;
98  }
99  }
100  return false;
101 }
102 
103 
105  return info.point_process && !info.artificial_cell && info.net_receive_node != nullptr;
106 }
107 
108 
110  if (info.artificial_cell) {
111  return false;
112  }
113  return info.nrn_state_block != nullptr || breakpoint_exist();
114 }
115 
116 
117 bool CodegenCppVisitor::nrn_cur_required() const noexcept {
118  return info.breakpoint_node != nullptr && !info.currents.empty();
119 }
120 
121 
123  return info.net_receive_node != nullptr;
124 }
125 
126 
127 bool CodegenCppVisitor::breakpoint_exist() const noexcept {
128  return info.breakpoint_node != nullptr;
129 }
130 
131 
133  return net_receive_exist();
134 }
135 
136 
137 /**
138  * \details When floating point data type is not default (i.e. double) then we
139  * have to copy old array to new type (for range variables).
140  */
142  return codegen::naming::DEFAULT_FLOAT_TYPE != float_data_type();
143 }
144 
145 
146 // check if there is a function or procedure defined with given name
147 bool CodegenCppVisitor::defined_method(const std::string& name) const {
148  const auto& function = program_symtab->lookup(name);
149  auto properties = NmodlType::function_block | NmodlType::procedure_block;
150  return function && function->has_any_property(properties);
151 }
152 
154  return codegen_float_variables.size();
155 }
156 
157 
159  const auto count_semantics = [](int sum, const IndexSemantics& sem) { return sum += sem.size; };
160  return std::accumulate(info.semantics.begin(), info.semantics.end(), 0, count_semantics);
161 }
162 
163 
164 /**
165  * \details We can directly print value but if user specify value as integer then
166  * then it gets printed as an integer. To avoid this, we use below wrapper.
167  * If user has provided integer then it gets printed as 1.0 (similar to mod2c
168  * and neuron where ".0" is appended). Otherwise we print double variables as
169  * they are represented in the mod file by user. If the value is in scientific
170  * representation (1e+20, 1E-15) then keep it as it is.
171  */
172 std::string CodegenCppVisitor::format_double_string(const std::string& s_value) {
174 }
175 
176 
177 std::string CodegenCppVisitor::format_float_string(const std::string& s_value) {
179 }
180 
181 
182 /**
183  * \details Statements like if, else etc. don't need semicolon at the end.
184  * (Note that it's valid to have "extraneous" semicolon). Also, statement
185  * block can appear as statement using expression statement which need to
186  * be inspected.
187  */
189  // clang-format off
190  if (node.is_if_statement()
191  || node.is_else_if_statement()
192  || node.is_else_statement()
193  || node.is_from_statement()
194  || node.is_verbatim()
195  || node.is_conductance_hint()
196  || node.is_while_statement()
197  || node.is_protect_statement()
198  || node.is_mutex_lock()
199  || node.is_mutex_unlock()) {
200  return false;
201  }
202  if (node.is_expression_statement()) {
203  auto expression = dynamic_cast<const ExpressionStatement&>(node).get_expression();
204  if (expression->is_statement_block()
205  || expression->is_eigen_newton_solver_block()
206  || expression->is_eigen_linear_solver_block()
207  || expression->is_solution_expression()
208  || expression->is_for_netcon()) {
209  return false;
210  }
211  }
212  // clang-format on
213  return true;
214 }
215 
216 /**
217  * \details Depending upon the block type, we have to print read/write ion variables
218  * during code generation. Depending on block/procedure being printed, this
219  * method return statements as vector. As different code backends could have
220  * different variable names, we rely on backend-specific read_ion_variable_name
221  * and write_ion_variable_name method which will be overloaded.
222  */
223 std::vector<std::string> CodegenCppVisitor::ion_read_statements(BlockType type) const {
224  if (optimize_ion_variable_copies()) {
225  return ion_read_statements_optimized(type);
226  }
227  std::vector<std::string> statements;
228  for (const auto& ion: info.ions) {
229  auto name = ion.name;
230  for (const auto& var: ion.reads) {
231  auto const iter = std::find(ion.implicit_reads.begin(), ion.implicit_reads.end(), var);
232  if (iter != ion.implicit_reads.end()) {
233  continue;
234  }
235  auto variable_names = read_ion_variable_name(var);
236  auto first = get_variable_name(variable_names.first);
237  auto second = get_variable_name(variable_names.second);
238  statements.push_back(fmt::format("{} = {};", first, second));
239  }
240  for (const auto& var: ion.writes) {
241  if (ion.is_ionic_conc(var)) {
242  auto variables = read_ion_variable_name(var);
243  auto first = get_variable_name(variables.first);
244  auto second = get_variable_name(variables.second);
245  statements.push_back(fmt::format("{} = {};", first, second));
246  }
247  }
248  }
249  return statements;
250 }
251 
252 
253 std::vector<std::string> CodegenCppVisitor::ion_read_statements_optimized(BlockType type) const {
254  std::vector<std::string> statements;
255  for (const auto& ion: info.ions) {
256  for (const auto& var: ion.writes) {
257  if (ion.is_ionic_conc(var)) {
258  auto variables = read_ion_variable_name(var);
259  auto first = "ionvar." + variables.first;
260  const auto& second = get_variable_name(variables.second);
261  statements.push_back(fmt::format("{} = {};", first, second));
262  }
263  }
264  }
265  return statements;
266 }
267 
268 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
269 std::vector<ShadowUseStatement> CodegenCppVisitor::ion_write_statements(BlockType type) {
270  std::vector<ShadowUseStatement> statements;
271  for (const auto& ion: info.ions) {
272  std::string concentration;
273  auto name = ion.name;
274  for (const auto& var: ion.writes) {
275  auto variable_names = write_ion_variable_name(var);
276  if (ion.is_ionic_current(var)) {
277  if (type == BlockType::Equation) {
278  auto current = breakpoint_current(var);
279  auto lhs = variable_names.first;
280  auto op = "+=";
281  auto rhs = get_variable_name(current);
282  if (info.point_process) {
283  auto area = get_variable_name(naming::NODE_AREA_VARIABLE);
284  rhs += fmt::format("*(1.e2/{})", area);
285  }
286  statements.push_back(ShadowUseStatement{lhs, op, rhs});
287  }
288  } else {
289  if (!ion.is_rev_potential(var)) {
290  concentration = var;
291  }
292  auto lhs = variable_names.first;
293  auto op = "=";
294  auto rhs = get_variable_name(variable_names.second);
295  statements.push_back(ShadowUseStatement{lhs, op, rhs});
296  }
297  }
298 
299  if (type == BlockType::Initial && !concentration.empty()) {
300  int index = 0;
301  if (ion.is_intra_cell_conc(concentration)) {
302  index = 1;
303  } else if (ion.is_extra_cell_conc(concentration)) {
304  index = 2;
305  } else {
306  /// \todo Unhandled case in neuron implementation
307  throw std::logic_error(fmt::format("codegen error for {} ion", ion.name));
308  }
309  auto ion_type_name = fmt::format("{}_type", ion.name);
310  auto lhs = fmt::format("int {}", ion_type_name);
311  auto op = "=";
312  auto rhs = get_variable_name(ion_type_name);
313  statements.push_back(ShadowUseStatement{lhs, op, rhs});
314  auto statement = conc_write_statement(ion.name, concentration, index);
315  statements.push_back(ShadowUseStatement{statement, "", ""});
316  }
317  }
318  return statements;
319 }
320 
321 /**
322  * If mechanisms dependency level execution is enabled then certain updates
323  * like ionic current contributions needs to be atomically updated. In this
324  * case we first update current mechanism's shadow vector and then add statement
325  * to queue that will be used in reduction queue.
326  */
328  BlockType /* type */) {
329  // when there is no operator or rhs then that statement doesn't need shadow update
330  if (statement.op.empty() && statement.rhs.empty()) {
331  auto text = statement.lhs + ";";
332  return text;
333  }
334 
335  // return regular statement
336  auto lhs = get_variable_name(statement.lhs);
337  auto text = fmt::format("{} {} {};", lhs, statement.op, statement.rhs);
338  return text;
339 }
340 
341 
342 /**
343  * \details Current variable used in breakpoint block could be local variable.
344  * In this case, neuron has already renamed the variable name by prepending
345  * "_l". In our implementation, the variable could have been renamed by
346  * one of the pass. And hence, we search all local variables and check if
347  * the variable is renamed. Note that we have to look into the symbol table
348  * of statement block and not breakpoint.
349  */
350 std::string CodegenCppVisitor::breakpoint_current(std::string current) const {
351  auto breakpoint = info.breakpoint_node;
352  if (breakpoint == nullptr) {
353  return current;
354  }
355  auto symtab = breakpoint->get_statement_block()->get_symbol_table();
356  auto variables = symtab->get_variables_with_properties(NmodlType::local_var);
357  for (const auto& var: variables) {
358  auto renamed_name = var->get_name();
359  auto original_name = var->get_original_name();
360  if (current == original_name) {
361  current = renamed_name;
362  break;
363  }
364  }
365  return current;
366 }
367 
368 
369 /****************************************************************************************/
370 /* Routines for returning variable name */
371 /****************************************************************************************/
372 
373 std::string CodegenCppVisitor::update_if_ion_variable_name(const std::string& name) const {
374  std::string result(name);
375  if (ion_variable_struct_required()) {
376  if (info.is_ion_read_variable(name)) {
377  result = naming::ION_VARNAME_PREFIX + name;
378  }
379  if (info.is_ion_write_variable(name)) {
380  result = "ionvar." + name;
381  }
382  if (info.is_current(name)) {
383  result = "ionvar." + name;
384  }
385  }
386  return result;
387 }
388 
389 
390 std::pair<std::string, std::string> CodegenCppVisitor::read_ion_variable_name(
391  const std::string& name) {
392  return {name, naming::ION_VARNAME_PREFIX + name};
393 }
394 
395 
396 std::pair<std::string, std::string> CodegenCppVisitor::write_ion_variable_name(
397  const std::string& name) {
398  return {naming::ION_VARNAME_PREFIX + name, name};
399 }
400 
401 
402 /****************************************************************************************/
403 /* Main printing routines for code generation */
404 /****************************************************************************************/
405 
406 
408  // Assert some things that we assume when copying instances of this struct
409  // to the GPU and so on.
410  printer->fmt_line("static_assert(std::is_trivially_copy_constructible_v<{}>);",
411  global_struct());
412  printer->fmt_line("static_assert(std::is_trivially_move_constructible_v<{}>);",
413  global_struct());
414  printer->fmt_line("static_assert(std::is_trivially_copy_assignable_v<{}>);", global_struct());
415  printer->fmt_line("static_assert(std::is_trivially_move_assignable_v<{}>);", global_struct());
416  printer->fmt_line("static_assert(std::is_trivially_destructible_v<{}>);", global_struct());
417 }
418 
419 
421  printer->add_line(global_struct(), ' ', global_struct_instance(), ';');
422 }
423 
424 
426  const auto& name = node.get_node_name();
427 
428  // return C++ function name for RANDOM construct function
429  // e.g. nrnran123_negexp for random_negexp
430  auto get_renamed_random_function =
431  [&](const std::string& name) -> std::pair<std::string, bool> {
433  return {codegen::naming::RANDOM_FUNCTIONS_MAPPING[name], true};
434  }
435  return {name, false};
436  };
437  std::string function_name;
438  bool is_random_function;
439  std::tie(function_name, is_random_function) = get_renamed_random_function(name);
440 
441  if (defined_method(name)) {
442  function_name = method_name(name);
443  }
444 
445  if (is_net_send(name)) {
446  print_net_send_call(node);
447  return;
448  }
449 
450  if (is_net_move(name)) {
451  print_net_move_call(node);
452  return;
453  }
454 
455  if (is_net_event(name)) {
456  print_net_event_call(node);
457  return;
458  }
459 
460  const auto& arguments = node.get_arguments();
461  printer->add_text(function_name, '(');
462 
463  if (defined_method(name)) {
464  printer->add_text(internal_method_arguments());
465  if (!arguments.empty()) {
466  printer->add_text(", ");
467  }
468  }
469 
470  // first argument to random functions need to be type casted
471  // from void* to nrnran123_State*.
472  if (is_random_function && !arguments.empty()) {
473  printer->add_text("(nrnran123_State*)");
474  }
475 
476  print_vector_elements(arguments, ", ");
477  printer->add_text(')');
478 }
479 
480 
482  printer->add_line("#ifndef NRN_PRCELLSTATE");
483  printer->add_line("#define NRN_PRCELLSTATE 0");
484  printer->add_line("#endif");
485 }
486 
487 
489  auto variable_printer = [&](const std::vector<SymbolType>& variables) {
490  for (const auto& v: variables) {
491  auto name = v->get_name();
492  if (!info.point_process) {
493  name += "_" + info.mod_suffix;
494  }
495  if (v->is_array()) {
496  name += fmt::format("[{}]", v->get_length());
497  }
498  printer->add_line(add_escape_quote(name), ",");
499  }
500  };
501 
502  printer->add_newline(2);
503  printer->add_line("/** channel information */");
504  printer->fmt_line("static const char *{}[] = {{", get_channel_info_var_name());
505  printer->increase_indent();
506  printer->add_line(add_escape_quote(nmodl_version()), ",");
507  printer->add_line(add_escape_quote(info.mod_suffix), ",");
508  variable_printer(info.range_parameter_vars);
509  printer->add_line("0,");
510  variable_printer(info.range_assigned_vars);
511  printer->add_line("0,");
512  variable_printer(info.range_state_vars);
513  printer->add_line("0,");
514  variable_printer(info.pointer_variables);
515  printer->add_line("0");
516  printer->decrease_indent();
517  printer->add_line("};");
518 }
519 
520 
521 /****************************************************************************************/
522 /* Printing routines for code generation */
523 /****************************************************************************************/
524 
525 
527  bool open_brace,
528  bool close_brace) {
529  if (open_brace) {
530  printer->push_block();
531  }
532 
533  const auto& statements = node.get_statements();
534  for (const auto& statement: statements) {
535  if (statement_to_skip(*statement)) {
536  continue;
537  }
538  /// not necessary to add indent for verbatim block (pretty-printing)
539  if (!statement->is_verbatim() && !statement->is_mutex_lock() &&
540  !statement->is_mutex_unlock() && !statement->is_protect_statement()) {
541  printer->add_indent();
542  }
543  statement->accept(*this);
544  if (need_semicolon(*statement)) {
545  printer->add_text(';');
546  }
547  if (!statement->is_mutex_lock() && !statement->is_mutex_unlock()) {
548  printer->add_newline();
549  }
550  }
551 
552  if (close_brace) {
553  printer->pop_block_nl(0);
554  }
555 }
556 
557 
558 /**
559  * \todo Issue with verbatim renaming. e.g. pattern.mod has info struct with
560  * index variable. If we use "index" instead of "indexes" as default argument
561  * then during verbatim replacement we don't know the index is which one. This
562  * is because verbatim renaming pass has already stripped out prefixes from
563  * the text.
564  */
566  const auto& default_arguments = stringutils::split_string(nrn_thread_arguments(), ',');
567  for (const auto& dirty_arg: default_arguments) {
568  const auto& arg = stringutils::trim(dirty_arg);
569  RenameVisitor v(arg, "arg_" + arg);
570  for (const auto& function: info.functions) {
571  if (has_parameter_of_name(function, arg)) {
572  function->accept(v);
573  }
574  }
575  for (const auto& function: info.procedures) {
576  if (has_parameter_of_name(function, arg)) {
577  function->accept(v);
578  }
579  }
580  }
581 }
582 
583 
584 /****************************************************************************************/
585 /* Main code printing entry points */
586 /****************************************************************************************/
587 
588 
589 /**
590  * NMODL constants from unit database
591  *
592  */
594  if (!info.factor_definitions.empty()) {
595  printer->add_newline(2);
596  printer->add_line("/** constants used in nmodl from UNITS */");
597  for (const auto& it: info.factor_definitions) {
598  const std::string format_string = "static const double {} = {};";
599  printer->fmt_line(format_string, it->get_node_name(), it->get_value()->get_value());
600  }
601  }
602 }
603 
604 
605 /****************************************************************************************/
606 /* Overloaded visitor routines */
607 /****************************************************************************************/
608 
609 
610 extern const std::regex regex_special_chars{R"([-[\]{}()*+?.,\^$|#\s])"};
611 
612 
614  std::string name = node.eval();
615  if (enable_variable_name_lookup) {
616  name = get_variable_name(name);
617  }
618  printer->add_text(name);
619 }
620 
621 
623  const auto& value = node.get_value();
624  printer->add_text(std::to_string(value));
625 }
626 
627 
629  printer->add_text(format_float_string(node.get_value()));
630 }
631 
632 
634  printer->add_text(format_double_string(node.get_value()));
635 }
636 
637 
639  printer->add_text(std::to_string(static_cast<int>(node.eval())));
640 }
641 
642 
644  node.visit_children(*this);
645 }
646 
647 
649  // do not print units
650 }
651 
652 
654  throw std::runtime_error("PRIME encountered during code generation, ODEs not solved?");
655 }
656 
657 
658 /**
659  * \todo : Validate how @ is being handled in neuron implementation
660  */
662  const auto& name = node.get_name();
663  const auto& at_index = node.get_at();
664  const auto& index = node.get_index();
665  name->accept(*this);
666  if (at_index) {
667  printer->add_text("@");
668  at_index->accept(*this);
669  }
670  if (index) {
671  printer->add_text("[");
672  printer->add_text("static_cast<int>(");
673  index->accept(*this);
674  printer->add_text(")");
675  printer->add_text("]");
676  }
677 }
678 
679 
681  node.get_name()->accept(*this);
682  printer->add_text("[");
683  printer->add_text("static_cast<int>(");
684  node.get_length()->accept(*this);
685  printer->add_text(")");
686  printer->add_text("]");
687 }
688 
689 
691  printer->add_text(local_var_type(), ' ');
692  print_vector_elements(node.get_variables(), ", ");
693 }
694 
695 
697  printer->add_text("if (");
698  node.get_condition()->accept(*this);
699  printer->add_text(") ");
700  node.get_statement_block()->accept(*this);
701  print_vector_elements(node.get_elseifs(), "");
702  const auto& elses = node.get_elses();
703  if (elses) {
704  elses->accept(*this);
705  }
706 }
707 
708 
710  printer->add_text(" else if (");
711  node.get_condition()->accept(*this);
712  printer->add_text(") ");
713  node.get_statement_block()->accept(*this);
714 }
715 
716 
718  printer->add_text(" else ");
719  node.visit_children(*this);
720 }
721 
722 
724  printer->add_text("while (");
725  node.get_condition()->accept(*this);
726  printer->add_text(") ");
727  node.get_statement_block()->accept(*this);
728 }
729 
730 
732  auto name = node.get_node_name();
733  const auto& from = node.get_from();
734  const auto& to = node.get_to();
735  const auto& inc = node.get_increment();
736  const auto& block = node.get_statement_block();
737  printer->fmt_text("for (int {} = ", name);
738  from->accept(*this);
739  printer->fmt_text("; {} <= ", name);
740  to->accept(*this);
741  if (inc) {
742  printer->fmt_text("; {} += ", name);
743  inc->accept(*this);
744  } else {
745  printer->fmt_text("; {}++", name);
746  }
747  printer->add_text(") ");
748  block->accept(*this);
749 }
750 
751 
753  printer->add_text("(");
754  node.get_expression()->accept(*this);
755  printer->add_text(")");
756 }
757 
758 
760  auto op = node.get_op().eval();
761  const auto& lhs = node.get_lhs();
762  const auto& rhs = node.get_rhs();
763  if (op == "^") {
764  printer->add_text("pow(");
765  lhs->accept(*this);
766  printer->add_text(", ");
767  rhs->accept(*this);
768  printer->add_text(")");
769  } else {
770  lhs->accept(*this);
771  printer->add_text(" " + op + " ");
772  rhs->accept(*this);
773  }
774 }
775 
776 
778  printer->add_text(node.eval());
779 }
780 
781 
783  printer->add_text(" " + node.eval());
784 }
785 
786 
787 /**
788  * \details Statement block is top level construct (for every nmodl block).
789  * Sometime we want to analyse ast nodes even if code generation is
790  * false. Hence we visit children even if code generation is false.
791  */
793  print_statement_block(node);
794 }
795 
796 
798  print_function_call(node);
799 }
800 
801 
803  const auto& text = node.get_statement()->eval();
804  const auto& result = process_verbatim_text(text);
805 
806  const auto& statements = stringutils::split_string(result, '\n');
807  for (const auto& statement: statements) {
808  const auto& trimed_stmt = stringutils::trim_newline(statement);
809  if (trimed_stmt.find_first_not_of(' ') != std::string::npos) {
810  printer->add_line(trimed_stmt);
811  }
812  }
813 }
814 
815 
817  // dt change statement should be pulled outside already
818 }
819 
820 
822  print_atomic_reduction_pragma();
823  printer->add_indent();
824  node.get_expression()->accept(*this);
825  printer->add_text(";");
826 }
827 
828 
830  printer->fmt_line("#pragma omp critical ({})", info.mod_suffix);
831  printer->add_indent();
832  printer->push_block();
833 }
834 
835 
837  printer->pop_block();
838 }
839 
840 
842  auto block = node.get_node_to_solve().get();
843  if (block->is_statement_block()) {
844  auto statement_block = dynamic_cast<ast::StatementBlock*>(block);
845  print_statement_block(*statement_block, false, false);
846  } else {
847  block->accept(*this);
848  }
849 }
850 
851 
852 /**
853  * \details Once variables are populated, update index semantics to register with coreneuron
854  */
855 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
857  int index = 0;
858  info.semantics.clear();
859 
860  if (info.point_process) {
861  info.semantics.emplace_back(index++, naming::AREA_SEMANTIC, 1);
862  info.semantics.emplace_back(index++, naming::POINT_PROCESS_SEMANTIC, 1);
863  }
864  for (const auto& ion: info.ions) {
865  for (auto i = 0; i < ion.reads.size(); ++i) {
866  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
867  }
868  for (const auto& var: ion.writes) {
869  /// add if variable is not present in the read list
870  if (std::find(ion.reads.begin(), ion.reads.end(), var) == ion.reads.end()) {
871  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
872  }
873  if (ion.is_ionic_current(var)) {
874  info.semantics.emplace_back(index++, ion.name + "_ion", 1);
875  }
876  }
877  if (ion.need_style) {
878  info.semantics.emplace_back(index++, fmt::format("{}_ion", ion.name), 1);
879  info.semantics.emplace_back(index++, fmt::format("#{}_ion", ion.name), 1);
880  }
881  }
882  for (auto& var: info.pointer_variables) {
883  if (info.first_pointer_var_index == -1) {
884  info.first_pointer_var_index = index;
885  }
886  int size = var->get_length();
887  if (var->has_any_property(NmodlType::pointer_var)) {
888  info.semantics.emplace_back(index, naming::POINTER_SEMANTIC, size);
889  } else {
890  info.semantics.emplace_back(index, naming::CORE_POINTER_SEMANTIC, size);
891  }
892  index += size;
893  }
894 
895  for (auto& var: info.random_variables) {
896  if (info.first_random_var_index == -1) {
897  info.first_random_var_index = index;
898  }
899  int size = var->get_length();
900  info.semantics.emplace_back(index, naming::RANDOM_SEMANTIC, size);
901  index += size;
902  }
903 
904  if (info.diam_used) {
905  info.semantics.emplace_back(index++, naming::DIAM_VARIABLE, 1);
906  }
907 
908  if (info.area_used) {
909  info.semantics.emplace_back(index++, naming::AREA_VARIABLE, 1);
910  }
911 
912  if (info.net_send_used) {
913  info.semantics.emplace_back(index++, naming::NET_SEND_SEMANTIC, 1);
914  }
915 
916  /*
917  * Number of semantics for watch is one greater than number of
918  * actual watch statements in the mod file
919  */
920  if (!info.watch_statements.empty()) {
921  for (int i = 0; i < info.watch_statements.size() + 1; i++) {
922  info.semantics.emplace_back(index++, naming::WATCH_SEMANTIC, 1);
923  }
924  }
925 
926  if (info.for_netcon_used) {
927  info.semantics.emplace_back(index++, naming::FOR_NETCON_SEMANTIC, 1);
928  }
929 }
930 
931 
932 std::vector<CodegenCppVisitor::SymbolType> CodegenCppVisitor::get_float_variables() const {
933  // sort with definition order
934  auto comparator = [](const SymbolType& first, const SymbolType& second) -> bool {
935  return first->get_definition_order() < second->get_definition_order();
936  };
937 
938  auto assigned = info.assigned_vars;
939  auto states = info.state_vars;
940 
941  // each state variable has corresponding Dstate variable
942  for (const auto& state: states) {
943  auto name = "D" + state->get_name();
944  auto symbol = make_symbol(name);
945  if (state->is_array()) {
946  symbol->set_as_array(state->get_length());
947  }
948  symbol->set_definition_order(state->get_definition_order());
949  assigned.push_back(symbol);
950  }
951  std::sort(assigned.begin(), assigned.end(), comparator);
952 
953  auto variables = info.range_parameter_vars;
954  variables.insert(variables.end(),
955  info.range_assigned_vars.begin(),
956  info.range_assigned_vars.end());
957  variables.insert(variables.end(), info.range_state_vars.begin(), info.range_state_vars.end());
958  variables.insert(variables.end(), assigned.begin(), assigned.end());
959 
960  if (info.vectorize) {
961  variables.push_back(make_symbol(naming::VOLTAGE_UNUSED_VARIABLE));
962  }
963 
964  if (breakpoint_exist()) {
965  std::string name = info.vectorize ? naming::CONDUCTANCE_UNUSED_VARIABLE
967 
968  // make sure conductance variable like `g` is not already defined
969  if (auto r = std::find_if(variables.cbegin(),
970  variables.cend(),
971  [&](const auto& s) { return name == s->get_name(); });
972  r == variables.cend()) {
973  variables.push_back(make_symbol(name));
974  }
975  }
976 
977  if (net_receive_exist()) {
978  variables.push_back(make_symbol(naming::T_SAVE_VARIABLE));
979  }
980  return variables;
981 }
982 
983 
984 /**
985  * IndexVariableInfo has following constructor arguments:
986  * - symbol
987  * - is_vdata (false)
988  * - is_index (false
989  * - is_integer (false)
990  *
991  * Which variables are constant qualified?
992  *
993  * - node area is read only
994  * - read ion variables are read only
995  * - style_ionname is index / offset
996  */
997 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
998 std::vector<IndexVariableInfo> CodegenCppVisitor::get_int_variables() {
999  std::vector<IndexVariableInfo> variables;
1000  if (info.point_process) {
1001  variables.emplace_back(make_symbol(naming::NODE_AREA_VARIABLE));
1002  variables.back().is_constant = true;
1003  /// note that this variable is not printed in neuron implementation
1004  if (info.artificial_cell) {
1005  variables.emplace_back(make_symbol(naming::POINT_PROCESS_VARIABLE), true);
1006  } else {
1007  variables.emplace_back(make_symbol(naming::POINT_PROCESS_VARIABLE), false, false, true);
1008  variables.back().is_constant = true;
1009  }
1010  }
1011 
1012  for (auto& ion: info.ions) {
1013  bool need_style = false;
1014  std::unordered_map<std::string, int> ion_vars; // used to keep track of the variables to
1015  // not have doubles between read/write. Same
1016  // name variables are allowed
1017  // See if we need to add extra readion statements to match NEURON with SoA data
1018  auto const has_var = [&ion](const char* suffix) -> bool {
1019  auto const pred = [name = ion.name + suffix](auto const& x) { return x == name; };
1020  return std::any_of(ion.reads.begin(), ion.reads.end(), pred) ||
1021  std::any_of(ion.writes.begin(), ion.writes.end(), pred);
1022  };
1023  auto const add_implicit_read = [&ion](const char* suffix) {
1024  auto name = ion.name + suffix;
1025  ion.reads.push_back(name);
1026  ion.implicit_reads.push_back(std::move(name));
1027  };
1028  bool const have_ionin{has_var("i")}, have_ionout{has_var("o")};
1029  if (have_ionin && !have_ionout) {
1030  add_implicit_read("o");
1031  } else if (have_ionout && !have_ionin) {
1032  add_implicit_read("i");
1033  }
1034  for (const auto& var: ion.reads) {
1035  const std::string name = naming::ION_VARNAME_PREFIX + var;
1036  variables.emplace_back(make_symbol(name));
1037  variables.back().is_constant = true;
1038  ion_vars[name] = static_cast<int>(variables.size() - 1);
1039  }
1040 
1041  /// symbol for di_ion_dv var
1042  std::shared_ptr<symtab::Symbol> ion_di_dv_var = nullptr;
1043 
1044  for (const auto& var: ion.writes) {
1045  const std::string name = naming::ION_VARNAME_PREFIX + var;
1046 
1047  const auto ion_vars_it = ion_vars.find(name);
1048  if (ion_vars_it != ion_vars.end()) {
1049  variables[ion_vars_it->second].is_constant = false;
1050  } else {
1051  variables.emplace_back(make_symbol(naming::ION_VARNAME_PREFIX + var));
1052  }
1053  if (ion.is_ionic_current(var)) {
1054  ion_di_dv_var = make_symbol(std::string(naming::ION_VARNAME_PREFIX) + "di" +
1055  ion.name + "dv");
1056  }
1057  if (ion.is_intra_cell_conc(var) || ion.is_extra_cell_conc(var)) {
1058  need_style = true;
1059  }
1060  }
1061 
1062  /// insert after read/write variables but before style ion variable
1063  if (ion_di_dv_var != nullptr) {
1064  variables.emplace_back(ion_di_dv_var);
1065  }
1066 
1067  if (need_style) {
1068  variables.emplace_back(make_symbol(naming::ION_VARNAME_PREFIX + ion.name + "_erev"));
1069  variables.emplace_back(make_symbol("style_" + ion.name), false, true);
1070  variables.back().is_constant = true;
1071  }
1072  }
1073 
1074  for (const auto& var: info.pointer_variables) {
1075  auto name = var->get_name();
1076  if (var->has_any_property(NmodlType::pointer_var)) {
1077  variables.emplace_back(make_symbol(name));
1078  } else {
1079  variables.emplace_back(make_symbol(name), true);
1080  }
1081  }
1082 
1083  for (const auto& var: info.random_variables) {
1084  auto name = var->get_name();
1085  variables.emplace_back(make_symbol(name), true);
1086  variables.back().symbol->add_properties(NmodlType::random_var);
1087  }
1088 
1089  if (info.diam_used) {
1090  variables.emplace_back(make_symbol(naming::DIAM_VARIABLE));
1091  }
1092 
1093  if (info.area_used) {
1094  variables.emplace_back(make_symbol(naming::AREA_VARIABLE));
1095  }
1096 
1097  // for non-artificial cell, when net_receive buffering is enabled
1098  // then tqitem is an offset
1099  if (info.net_send_used) {
1100  if (info.artificial_cell) {
1101  variables.emplace_back(make_symbol(naming::TQITEM_VARIABLE), true);
1102  } else {
1103  variables.emplace_back(make_symbol(naming::TQITEM_VARIABLE), false, false, true);
1104  variables.back().is_constant = true;
1105  }
1106  info.tqitem_index = static_cast<int>(variables.size() - 1);
1107  }
1108 
1109  /**
1110  * \note Variables for watch statements : there is one extra variable
1111  * used in coreneuron compared to actual watch statements for compatibility
1112  * with neuron (which uses one extra Datum variable)
1113  */
1114  if (!info.watch_statements.empty()) {
1115  for (int i = 0; i < info.watch_statements.size() + 1; i++) {
1116  variables.emplace_back(make_symbol(fmt::format("watch{}", i)), false, false, true);
1117  }
1118  }
1119  return variables;
1120 }
1121 
1122 
1124  program_symtab = node.get_symbol_table();
1125 
1127  info = v.analyze(node);
1128  info.mod_file = mod_filename;
1129 
1130  if (!info.vectorize) {
1131  logger->warn(
1132  "CodegenCoreneuronCppVisitor : MOD file uses non-thread safe constructs of NMODL");
1133  }
1134 
1135  codegen_float_variables = get_float_variables();
1136  codegen_int_variables = get_int_variables();
1137 
1138  update_index_semantics();
1139  rename_function_arguments();
1140 
1141  info.semantic_variable_count = int_variables_size();
1142 }
1143 
1145  if (type == BlockType::Initial) {
1146  return method_name(naming::NRN_INIT_METHOD);
1147  }
1148  if (type == BlockType::Constructor) {
1149  return method_name(naming::NRN_CONSTRUCTOR_METHOD);
1150  }
1151  if (type == BlockType::Destructor) {
1152  return method_name(naming::NRN_DESTRUCTOR_METHOD);
1153  }
1154  if (type == BlockType::State) {
1155  return method_name(naming::NRN_STATE_METHOD);
1156  }
1157  if (type == BlockType::Equation) {
1158  return method_name(naming::NRN_CUR_METHOD);
1159  }
1160  if (type == BlockType::Watch) {
1161  return method_name(naming::NRN_WATCH_CHECK_METHOD);
1162  }
1163  throw std::logic_error("compute_method_name not implemented");
1164 }
1165 
1166 
1168  setup(node);
1169  print_codegen_routines();
1170 }
1171 
1172 } // namespace codegen
1173 } // namespace nmodl
nmodl::ast::FunctionCall::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:7061
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::ion_variable_struct_required
bool ion_variable_struct_required() const
Check if a structure for ion variables is required.
Definition: codegen_cpp_visitor.cpp:29
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:188
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:856
nmodl::codegen::utils::format_double_string< CodegenCppVisitor >
std::string format_double_string< CodegenCppVisitor >(const std::string &s_value)
Definition: codegen_utils.cpp:24
nmodl::ast::LocalListStatement::get_variables
const LocalVarVector & get_variables() const noexcept
Getter for member variable LocalListStatement::variables.
Definition: local_list_statement.hpp:205
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:123
nmodl::ast::Verbatim
Represents a C code block.
Definition: verbatim.hpp:38
nmodl::codegen::naming::NET_SEND_SEMANTIC
static constexpr char NET_SEND_SEMANTIC[]
semantic type for net send call
Definition: codegen_naming.hpp:126
nmodl::codegen::CodegenCppVisitor::visit_name
void visit_name(const ast::Name &node) override
visit node of type ast::Name
Definition: codegen_cpp_visitor.cpp:643
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:54
nmodl::codegen::CodegenCppVisitor::int_variables_size
int int_variables_size() const
Number of integer variables in the model.
Definition: codegen_cpp_visitor.cpp:158
nmodl::ast::Name::visit_children
void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:795
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:696
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:269
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:717
nmodl::codegen::CodegenCppVisitor::breakpoint_exist
bool breakpoint_exist() const noexcept
Check if breakpoint node exist.
Definition: codegen_cpp_visitor.cpp:127
nmodl::codegen::BlockType::Destructor
@ Destructor
destructor block
nmodl::ast::Double
Represents a double variable.
Definition: double.hpp:53
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:396
nmodl::codegen::naming::POINT_PROCESS_VARIABLE
static constexpr char POINT_PROCESS_VARIABLE[]
inbuilt neuron variable for point process
Definition: codegen_naming.hpp:63
nmodl::codegen::CodegenCppVisitor::net_receive_exist
bool net_receive_exist() const noexcept
Check if net_receive node exist.
Definition: codegen_cpp_visitor.cpp:122
nmodl::codegen::CodegenCppVisitor::SymbolType
std::shared_ptr< symtab::Symbol > SymbolType
Definition: codegen_cpp_visitor.hpp:238
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:78
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:162
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:153
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:731
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:407
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:488
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:653
nmodl::codegen::ShadowUseStatement::lhs
std::string lhs
Definition: codegen_cpp_visitor.hpp:151
nmodl::codegen::ShadowUseStatement::rhs
std::string rhs
Definition: codegen_cpp_visitor.hpp:153
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::codegen::MemberType::index
@ index
index / int variables
nmodl::codegen::naming::NRN_CONSTRUCTOR_METHOD
static constexpr char NRN_CONSTRUCTOR_METHOD[]
nrn_constructor method in generated code
Definition: codegen_naming.hpp:138
nmodl::codegen::utils::format_float_string< CodegenCppVisitor >
std::string format_float_string< CodegenCppVisitor >(const std::string &s_value)
Definition: codegen_utils.cpp:34
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::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:141
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:526
nmodl::ast::Double::get_value
const std::string & get_value() const noexcept
Getter for member variable Double::value.
Definition: double.hpp:158
nmodl::ast::WhileStatement
TODO.
Definition: while_statement.hpp:38
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:759
nmodl::ast::VarName
Represents a variable.
Definition: var_name.hpp:43
nmodl::ast::Integer
Represents an integer variable.
Definition: integer.hpp:49
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:932
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:57
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:752
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:104
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:373
nmodl::ast::ElseStatement::visit_children
void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:9855
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::logger
logger_type logger
Definition: logger.cpp:34
nmodl::codegen::ShadowUseStatement::op
std::string op
Definition: codegen_cpp_visitor.hpp:152
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:836
nmodl::ast::Verbatim::get_statement
std::shared_ptr< String > get_statement() const noexcept
Getter for member variable Verbatim::statement.
Definition: verbatim.hpp:157
nmodl::codegen::CodegenCppVisitor::visit_unit
void visit_unit(const ast::Unit &node) override
visit node of type ast::Unit
Definition: codegen_cpp_visitor.cpp:648
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::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:816
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:69
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::stringutils::trim_newline
static std::string trim_newline(std::string text)
Definition: string_utils.hpp:83
nmodl::codegen::naming::DEFAULT_FLOAT_TYPE
static constexpr char DEFAULT_FLOAT_TYPE[]
default float variable type
Definition: codegen_naming.hpp:102
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:998
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:797
nmodl::ast::IfStatement::get_elseifs
const ElseIfStatementVector & get_elseifs() const noexcept
Getter for member variable IfStatement::elseifs.
Definition: if_statement.hpp:182
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::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::ast::Float::get_value
const std::string & get_value() const noexcept
Getter for member variable Float::value.
Definition: float.hpp:148
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:610
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
void setup(const ast::Program &node)
Setup the target backend code generator.
Definition: codegen_cpp_visitor.cpp:1123
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:782
nmodl::codegen::naming::POINT_PROCESS_SEMANTIC
static constexpr char POINT_PROCESS_SEMANTIC[]
semantic type for point process variable
Definition: codegen_naming.hpp:114
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:829
nmodl::codegen::CodegenCppVisitor::visit_boolean
void visit_boolean(const ast::Boolean &node) override
visit node of type ast::Boolean
Definition: codegen_cpp_visitor.cpp:638
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:117
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::ast::ProtectStatement
TODO.
Definition: protect_statement.hpp:38
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:253
nmodl::codegen::BlockType::Constructor
@ Constructor
constructor block
nmodl::ast::MutexUnlock
Represent MUTEXUNLOCK statement in NMODL.
Definition: mutex_unlock.hpp:38
nmodl::codegen::CodegenCppVisitor::visit_double
void visit_double(const ast::Double &node) override
visit node of type ast::Double
Definition: codegen_cpp_visitor.cpp:633
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:94
nmodl::codegen::CodegenCppVisitor::visit_float
void visit_float(const ast::Float &node) override
visit node of type ast::Float
Definition: codegen_cpp_visitor.cpp:628
nmodl::codegen::CodegenCppVisitor::visit_string
void visit_string(const ast::String &node) override
visit node of type ast::String
Definition: codegen_cpp_visitor.cpp:613
nmodl::codegen::IndexSemantics
Represent semantic information for index variable.
Definition: codegen_info.hpp:170
nmodl::codegen::BlockType::Watch
@ Watch
watch block
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:279
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::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.
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:841
nmodl::codegen::naming::NRN_INIT_METHOD
static constexpr char NRN_INIT_METHOD[]
nrn_init method in generated code
Definition: codegen_naming.hpp:135
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:117
nmodl::codegen::CodegenCppVisitor::print_global_var_struct_decl
virtual void print_global_var_struct_decl()
Instantiate global var instance.
Definition: codegen_cpp_visitor.cpp:420
nmodl::codegen::naming::AREA_SEMANTIC
static constexpr char AREA_SEMANTIC[]
semantic type for area variable
Definition: codegen_naming.hpp:111
nmodl::codegen::CodegenCppVisitor::visit_var_name
void visit_var_name(const ast::VarName &node) override
Definition: codegen_cpp_visitor.cpp:661
nmodl::codegen::CodegenInfo::mod_file
std::string mod_file
name of mod file
Definition: codegen_info.hpp:199
nmodl::codegen::CodegenCppVisitor::print_nmodl_constants
void print_nmodl_constants()
Print the nmodl constants used in backend code.
Definition: codegen_cpp_visitor.cpp:593
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::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:390
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::naming::NRN_CUR_METHOD
static constexpr char NRN_CUR_METHOD[]
nrn_cur method in generated code
Definition: codegen_naming.hpp:156
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:192
codegen_utils.hpp
Implement utility functions for codegen visitors.
nmodl::codegen::naming::TQITEM_VARIABLE
static constexpr char TQITEM_VARIABLE[]
inbuilt neuron variable for tqitem process
Definition: codegen_naming.hpp:66
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::codegen::CodegenHelperVisitor::analyze
codegen::CodegenInfo analyze(const ast::Program &node)
run visitor and return information for code generation
Definition: codegen_helper_visitor.cpp:736
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:622
nmodl::ast::UpdateDt
Statement to indicate a change in timestep in a given block.
Definition: update_dt.hpp:38
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:177
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::stringutils::split_string
static std::vector< std::string > split_string(const std::string &text, char delimiter)
Split a text in a list of words, using a given delimiter character.
Definition: string_utils.hpp:116
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:34
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::StatementBlock
Represents block encapsulating list of statements.
Definition: statement_block.hpp:53
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:132
nmodl::codegen::naming::CORE_POINTER_SEMANTIC
static constexpr char CORE_POINTER_SEMANTIC[]
semantic type for core pointer variable
Definition: codegen_naming.hpp:120
nmodl::ast::ParenExpression
TODO.
Definition: paren_expression.hpp:38
nmodl::codegen::CodegenCppVisitor::rename_function_arguments
void rename_function_arguments()
Rename function/procedure arguments that conflict with default arguments.
Definition: codegen_cpp_visitor.cpp:565
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:690
nmodl::codegen::CodegenCppVisitor::visit_protect_statement
void visit_protect_statement(const ast::ProtectStatement &node) override
visit node of type ast::ProtectStatement
Definition: codegen_cpp_visitor.cpp:821
nmodl::codegen::ShadowUseStatement
Represents ion write statement during code generation.
Definition: codegen_cpp_visitor.hpp:150
nmodl::codegen::naming::WATCH_SEMANTIC
static constexpr char WATCH_SEMANTIC[]
semantic type for watch statement
Definition: codegen_naming.hpp:129
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:147
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::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:425
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:327
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:153
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:350
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:777
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:709
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:1144
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:60
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:1167
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:680
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:81
nmodl::codegen::CodegenCppVisitor::print_prcellstate_macros
void print_prcellstate_macros() const
Print declaration of macro NRN_PRCELLSTATE for debugging.
Definition: codegen_cpp_visitor.cpp:481
nmodl::codegen::naming::FOR_NETCON_SEMANTIC
static constexpr char FOR_NETCON_SEMANTIC[]
semantic type for for_netcon statement
Definition: codegen_naming.hpp:132
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.
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:109
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:54
nmodl::codegen::CodegenCppVisitor::visit_verbatim
void visit_verbatim(const ast::Verbatim &node) override
visit node of type ast::Verbatim
Definition: codegen_cpp_visitor.cpp:802
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:141
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:75
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:70
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:223
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:172
nmodl::ast::ProtectStatement::get_expression
std::shared_ptr< Expression > get_expression() const noexcept
Getter for member variable ProtectStatement::expression.
Definition: protect_statement.hpp:157
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:9196
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:723
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:250
nmodl::codegen::naming::ION_VARNAME_PREFIX
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
Definition: codegen_naming.hpp:171
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:792