User Guide
codegen_neuron_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  */
7 
9 
10 #include <algorithm>
11 #include <chrono>
12 #include <cmath>
13 #include <ctime>
14 #include <optional>
15 #include <regex>
16 #include <stdexcept>
17 
18 #include "ast/all.hpp"
19 #include "ast/procedure_block.hpp"
22 #include "codegen_naming.hpp"
23 #include "config/config.h"
24 #include "parser/c11_driver.hpp"
25 #include "solver/solver.hpp"
26 #include "utils/string_utils.hpp"
30 
31 namespace nmodl {
32 namespace codegen {
33 
34 using namespace ast;
35 
36 using visitor::RenameVisitor;
37 using visitor::VarUsageVisitor;
38 
40 
41 /****************************************************************************************/
42 /* Generic information getters */
43 /****************************************************************************************/
44 
45 
47  return "NEURON";
48 }
49 
50 
52  return "C++ (api-compatibility)";
53 }
54 
55 
57  return "_check_table_thread";
58 }
59 
61  return true;
62 }
63 
64 
65 /****************************************************************************************/
66 /* Common helper routines accross codegen functions */
67 /****************************************************************************************/
68 
69 int CodegenNeuronCppVisitor::position_of_float_var(const std::string& name) const {
70  return get_index_from_name(codegen_float_variables, name);
71 }
72 
73 
74 int CodegenNeuronCppVisitor::position_of_int_var(const std::string& name) const {
75  return get_index_from_name(codegen_int_variables, name);
76 }
77 
78 
79 /****************************************************************************************/
80 /* Backend specific routines */
81 /****************************************************************************************/
82 
84  if (optimize_ionvar_copies) {
85  throw std::runtime_error("Not implemented.");
86  }
87  return false;
88 }
89 
90 
91 /****************************************************************************************/
92 /* Printing routines for code generation */
93 /****************************************************************************************/
94 
95 
97  if (info.point_process) {
98  printer->add_multi_line(R"CODE(
99  /* Point Process specific functions */
100  static void* _hoc_create_pnt(Object* _ho) {
101  return create_point_process(_pointtype, _ho);
102  }
103  )CODE");
104  printer->push_block("static void _hoc_destroy_pnt(void* _vptr)");
105  if (info.is_watch_used() || info.for_netcon_used) {
106  printer->add_line("Prop* _prop = ((Point_process*)_vptr)->prop;");
107  printer->push_block("if (_prop)");
108  printer->add_line("Datum* _ppvar = _nrn_mechanism_access_dparam(_prop);");
109  if (info.is_watch_used()) {
110  printer->fmt_line("_nrn_free_watch(_ppvar, {}, {});",
111  info.watch_count,
112  info.is_watch_used());
113  }
114  if (info.for_netcon_used) {
115  auto fornetcon_data = get_variable_name("fornetcon_data", false);
116  printer->fmt_line("_nrn_free_fornetcon(&{});", fornetcon_data);
117  }
118  printer->pop_block();
119  }
120  printer->add_line("destroy_point_process(_vptr);");
121  printer->pop_block();
122  printer->add_multi_line(R"CODE(
123  static double _hoc_loc_pnt(void* _vptr) {
124  return loc_point_process(_pointtype, _vptr);
125  }
126 
127  static double _hoc_has_loc(void* _vptr) {
128  return has_loc_point(_vptr);
129  }
130 
131  static double _hoc_get_loc_pnt(void* _vptr) {
132  return (get_loc_point_process(_vptr));
133  }
134  )CODE");
135  }
136 }
137 
138 
140  if (info.table_count == 0) {
141  return;
142  }
143 
144  // print declarations of `check_*` functions
145  for (const auto& function: info.functions_with_table) {
146  auto name = function->get_node_name();
147  auto internal_params = internal_method_parameters();
148  printer->fmt_line("void {}({});",
149  table_update_function_name(name),
150  get_parameter_str(internal_params));
151  }
152 
153  ParamVector args = {{"", "Memb_list*", "", "_ml"},
154  {"", "size_t", "", "id"},
155  {"", "Datum*", "", "_ppvar"},
156  {"", "Datum*", "", "_thread"},
157  {"", "double*", "", "_globals"},
158  {"", "NrnThread*", "", "nt"},
159  {"", "int", "", "_type"},
160  {"", "const _nrn_model_sorted_token&", "", "_sorted_token"}};
161 
162  // definition of `_check_table_thread` function
163  // signature must be same as the `nrn_thread_table_check_t` type
164  printer->fmt_line("static void {}({})", table_thread_function_name(), get_parameter_str(args));
165  printer->push_block();
166  printer->add_line("_nrn_mechanism_cache_range _lmc{_sorted_token, *nt, *_ml, _type};");
167  printer->fmt_line("auto inst = make_instance_{}(&_lmc);", info.mod_suffix);
168  if (!info.artificial_cell) {
169  printer->fmt_line("auto node_data = make_node_data_{}(*nt, *_ml);", info.mod_suffix);
170  }
171  if (!codegen_thread_variables.empty()) {
172  printer->fmt_line("auto _thread_vars = {}(_thread[{}].get<double*>());",
173  thread_variables_struct(),
174  info.thread_var_thread_id);
175  }
176 
177  for (const auto& function: info.functions_with_table) {
178  auto method_name = function->get_node_name();
179  auto method_args = get_arg_str(internal_method_parameters());
180  printer->fmt_line("{}({});", table_update_function_name(method_name), method_args);
181  }
182  printer->pop_block();
183 }
184 
185 
187  printer->add_line("/* Neuron setdata functions */");
188  printer->add_line("extern void _nrn_setdata_reg(int, void(*)(Prop*));");
189  printer->push_block("static void _setdata(Prop* _prop)");
190  if (!info.point_process) {
191  printer->add_multi_line(R"CODE(
192  _extcall_prop = _prop;
193  _prop_id = _nrn_get_prop_id(_prop);
194  )CODE");
195  }
196  printer->pop_block();
197 
198  if (info.point_process) {
199  printer->push_block("static void _hoc_setdata(void* _vptr)");
200  printer->add_multi_line(R"CODE(
201  Prop* _prop;
202  _prop = ((Point_process*)_vptr)->prop;
203  _setdata(_prop);
204  )CODE");
205  } else {
206  printer->push_block("static void _hoc_setdata()");
207  printer->add_multi_line(R"CODE(
208  Prop *_prop = hoc_getdata_range(mech_type);
209  _setdata(_prop);
210  hoc_retpushx(1.);
211  )CODE");
212  }
213  printer->pop_block();
214 }
215 
216 
218  printer->add_newline(2);
219 
220  auto print_decl = [this](const auto& callables) {
221  for (const auto& node: callables) {
222  print_function_declaration(*node, node->get_node_name());
223  printer->add_text(';');
224  printer->add_newline();
225  }
226  };
227 
228  printer->add_line("/* Mechanism procedures and functions */");
229  print_decl(info.functions);
230  print_decl(info.procedures);
231 
232  for (const auto& node: info.function_tables) {
233  auto [params, table_params] = function_table_parameters(*node);
234  printer->fmt_line("double {}({});",
235  method_name(node->get_node_name()),
236  get_parameter_str(params));
237  printer->fmt_line("double {}({});",
238  method_name("table_" + node->get_node_name()),
239  get_parameter_str(table_params));
240  }
241 }
242 
243 
245  const ast::Block& node,
246  const std::string& name,
247  const std::unordered_set<CppObjectSpecifier>& specifiers) {
248  printer->add_newline(2);
249  print_function_declaration(node, name, specifiers);
250  printer->add_text(" ");
251  printer->push_block();
252 
253  // function requires return variable declaration
254  if (node.is_function_block()) {
255  auto type = default_float_data_type();
256  printer->fmt_line("{} ret_{} = 0.0;", type, name);
257  } else {
258  printer->fmt_line("int ret_{} = 0;", name);
259  }
260 
261  if (info.mod_suffix != "nothing" && !info.artificial_cell) {
262  printer->add_line(
263  "double v = node_data.node_voltages ? "
264  "node_data.node_voltages[node_data.nodeindices[id]] : 0.0;");
265  }
266 
267  print_statement_block(*node.get_statement_block(), false, false);
268  printer->fmt_line("return ret_{};", name);
269  printer->pop_block();
270 }
271 
272 
274  auto name = node.get_node_name();
275  if (info.function_uses_table(name)) {
276  auto new_name = "f_" + name;
277  print_function_or_procedure(node,
278  new_name,
280  print_table_check_function(node);
281  print_table_replacement_function(node);
282  } else {
283  print_function_or_procedure(node, name);
284  }
285 }
286 
288  const ast::Block* function_or_procedure_block,
289  InterpreterWrapper wrapper_type) {
290  const auto block_name = function_or_procedure_block->get_node_name();
291 
292  const auto get_func_call_str = [&]() {
293  const auto& params = function_or_procedure_block->get_parameters();
294  const auto func_proc_name = block_name + "_" + info.mod_suffix;
295  std::vector<std::string> args;
296  args.reserve(params.size());
297  for (int i = 0; i < params.size(); ++i) {
298  args.push_back(fmt::format("*getarg({})", i + 1));
299  }
300 
301  auto internal_args = internal_method_arguments();
302  return fmt::format("{}({})",
303  func_proc_name,
304  stringutils::join_arguments(internal_args,
305  fmt::format("{}", fmt::join(args, ", "))));
306  };
307 
308  printer->add_line("double _r = 0.0;");
309  if (function_or_procedure_block->is_function_block()) {
310  printer->add_indent();
311  printer->fmt_text("_r = {};", get_func_call_str());
312  printer->add_newline();
313  } else {
314  printer->add_line("_r = 1.;");
315  printer->fmt_line("{};", get_func_call_str());
316  }
317  if (info.point_process || wrapper_type != InterpreterWrapper::HOC) {
318  printer->add_line("return(_r);");
319  } else if (wrapper_type == InterpreterWrapper::HOC) {
320  printer->add_line("hoc_retpushx(_r);");
321  }
322 }
323 
325  const ast::Block* function_or_procedure_block,
326  InterpreterWrapper wrapper_type) {
327  if (info.mod_suffix == "nothing") {
328  return;
329  }
330 
331  const auto block_name = function_or_procedure_block->get_node_name();
332  printer->add_multi_line(R"CODE(
333  Datum* _ppvar;
334  Datum* _thread;
335  NrnThread* nt;
336  )CODE");
337 
338  std::string prop_name;
339  if (info.point_process) {
340  printer->add_multi_line(R"CODE(
341  auto* const _pnt = static_cast<Point_process*>(_vptr);
342  auto* const _p = _pnt->prop;
343  if (!_p) {
344  hoc_execerror("POINT_PROCESS data instance not valid", nullptr);
345  }
346  _nrn_mechanism_cache_instance _lmc{_p};
347  size_t const id{};
348  _ppvar = _nrn_mechanism_access_dparam(_p);
349  _thread = _extcall_thread.data();
350  nt = static_cast<NrnThread*>(_pnt->_vnt);
351  )CODE");
352 
353  prop_name = "_p";
354  } else if (wrapper_type == InterpreterWrapper::HOC) {
355  if (program_symtab->lookup(block_name)->has_all_properties(NmodlType::use_range_ptr_var)) {
356  printer->push_block("if (!_prop_id)");
357  printer->fmt_line(
358  "hoc_execerror(\"No data for {}_{}. Requires prior call to setdata_{} and that the "
359  "specified mechanism instance still be in existence.\", nullptr);",
360  function_or_procedure_block->get_node_name(),
361  info.mod_suffix,
362  info.mod_suffix);
363  printer->pop_block();
364  printer->add_line("Prop* _local_prop = _extcall_prop;");
365  } else {
366  printer->add_line("Prop* _local_prop = _prop_id ? _extcall_prop : nullptr;");
367  }
368  printer->add_multi_line(R"CODE(
369  _nrn_mechanism_cache_instance _lmc{_local_prop};
370  size_t const id{};
371  _ppvar = _local_prop ? _nrn_mechanism_access_dparam(_local_prop) : nullptr;
372  _thread = _extcall_thread.data();
373  nt = nrn_threads;
374  )CODE");
375  prop_name = "_local_prop";
376  } else { // wrapper_type == InterpreterWrapper::Python
377  printer->add_multi_line(R"CODE(
378  _nrn_mechanism_cache_instance _lmc{_prop};
379  size_t const id = 0;
380  _ppvar = _nrn_mechanism_access_dparam(_prop);
381  _thread = _extcall_thread.data();
382  nt = nrn_threads;
383  )CODE");
384  prop_name = "_prop";
385  }
386 
387  printer->fmt_line("auto inst = make_instance_{}({} ? &_lmc : nullptr);",
388  info.mod_suffix,
389  prop_name);
390  if (!info.artificial_cell) {
391  printer->fmt_line("auto node_data = make_node_data_{}({});", info.mod_suffix, prop_name);
392  }
393  if (!codegen_thread_variables.empty()) {
394  printer->fmt_line("auto _thread_vars = {}(_thread[{}].get<double*>());",
395  thread_variables_struct(),
396  info.thread_var_thread_id);
397  }
398  if (info.function_uses_table(block_name)) {
399  printer->fmt_line("{}({});",
400  table_update_function_name(block_name),
401  internal_method_arguments());
402  }
403 }
404 
405 
407  const ast::Block* function_or_procedure_block,
408  InterpreterWrapper wrapper_type) {
409  const auto block_name = function_or_procedure_block->get_node_name();
410  if (wrapper_type == InterpreterWrapper::HOC) {
411  return hoc_function_signature(block_name);
412  } else {
413  return py_function_signature(block_name);
414  }
415 }
416 
417 void CodegenNeuronCppVisitor::print_hoc_py_wrapper(const ast::Block* function_or_procedure_block,
418  InterpreterWrapper wrapper_type) {
419  if (info.point_process && wrapper_type == InterpreterWrapper::Python) {
420  return;
421  }
422 
423  printer->push_block(hoc_py_wrapper_signature(function_or_procedure_block, wrapper_type));
424 
425  print_hoc_py_wrapper_setup(function_or_procedure_block, wrapper_type);
426  print_hoc_py_wrapper_call_impl(function_or_procedure_block, wrapper_type);
427 
428  printer->pop_block();
429 }
430 
431 
433  auto print_wrappers = [this](const auto& callables) {
434  for (const auto& callable: callables) {
435  print_hoc_py_wrapper(callable, InterpreterWrapper::HOC);
436  print_hoc_py_wrapper(callable, InterpreterWrapper::Python);
437  }
438  };
439 
440  print_wrappers(info.procedures);
441  print_wrappers(info.functions);
442 
443  for (const auto& node: info.function_tables) {
444  auto name = node->get_node_name();
445  auto table_name = "table_" + node->get_node_name();
446 
447 
448  auto args = std::vector<std::string>{};
449  for (size_t i = 0; i < node->get_parameters().size(); ++i) {
450  args.push_back(fmt::format("*getarg({})", i + 1));
451  }
452 
453  // HOC
454  std::string return_statement = info.point_process ? "return _ret;" : "hoc_retpushx(_ret);";
455 
456  printer->fmt_push_block("{}", hoc_function_signature(name));
457  printer->fmt_line("double _ret = {}({});", method_name(name), fmt::join(args, ", "));
458  printer->add_line(return_statement);
459  printer->pop_block();
460 
461  printer->fmt_push_block("{}", hoc_function_signature(table_name));
462  printer->fmt_line("double _ret = {}();", method_name(table_name));
463  printer->add_line(return_statement);
464  printer->pop_block();
465 
466  // Python
467  printer->fmt_push_block("{}", py_function_signature(name));
468  printer->fmt_line("return {}({});", method_name(name), fmt::join(args, ", "));
469  printer->pop_block();
470 
471  printer->fmt_push_block("{}", py_function_signature(table_name));
472  printer->fmt_line("return {}();", method_name(table_name));
473  printer->pop_block();
474  }
475 }
476 
478  return ParamVector{{"", "ldifusfunc2_t", "", "_f"},
479  {"", "const _nrn_model_sorted_token&", "", "_sorted_token"},
480  {"", "NrnThread&", "", "_nt"}};
481 }
482 
483 
485  return ParamVector{{"", "int", "", "_i"},
486  {"", "Memb_list*", "", "_ml_arg"},
487  {"", "size_t", "", "id"},
488  {"", "Datum*", "", "_ppvar"},
489  {"", "double*", "", "_pdvol"},
490  {"", "double*", "", "_pdfcdc"},
491  {"", "Datum*", "", "/* _thread */"},
492  {"", "NrnThread*", "", "nt"},
493  {"", "const _nrn_model_sorted_token&", "", "_sorted_token"}};
494 }
495 
497  auto coeff_callback_name = [](const std::string& var_name) {
498  return fmt::format("_diffusion_coefficient_{}", var_name);
499  };
500 
501  auto space_name = [](const std::string& var_name) {
502  return fmt::format("_diffusion_space_{}", var_name);
503  };
504 
505  for (auto [var_name, values]: info.longitudinal_diffusion_info) {
506  printer->fmt_line("static void* {};", space_name(var_name));
507  printer->fmt_push_block("static double {}({})",
508  coeff_callback_name(var_name),
509  get_parameter_str(ldifusfunc3_parameters()));
510 
511  print_entrypoint_setup_code_from_memb_list();
512 
513  auto volume_expr = values.volume("_i");
514  auto mu_expr = values.diffusion_rate("_i");
515 
516  printer->add_indent();
517  printer->add_text("*_pdvol= ");
518  volume_expr->accept(*this);
519  printer->add_text(";");
520  printer->add_newline();
521 
522  printer->add_line("*_pdfcdc = 0.0;");
523  printer->add_indent();
524  printer->add_text("return ");
525  mu_expr->accept(*this);
526  printer->add_text(";");
527  printer->add_newline();
528 
529  printer->pop_block();
530  }
531 
532  printer->fmt_push_block("static void _apply_diffusion_function({})",
533  get_parameter_str(ldifusfunc1_parameters()));
534  for (auto [var_name, values]: info.longitudinal_diffusion_info) {
535  auto var = program_symtab->lookup(var_name);
536  size_t array_size = var->get_length();
537  printer->fmt_push_block("for(size_t _i = 0; _i < {}; ++_i)", array_size);
538  printer->fmt_line(
539  "(*_f)(mech_type, {}, &{}, _i, /* x pos */ {}, /* Dx pos */ {}, _sorted_token, _nt);",
540  coeff_callback_name(var_name),
541  space_name(var_name),
542  position_of_float_var(var_name),
543  position_of_float_var("D" + var_name));
544  printer->pop_block();
545  }
546  printer->pop_block();
547  printer->add_newline();
548 }
549 
550 /****************************************************************************************/
551 /* Code-specific helper routines */
552 /****************************************************************************************/
553 
554 void CodegenNeuronCppVisitor::add_variable_tqitem(std::vector<IndexVariableInfo>& variables) {
555  if (info.net_send_used) {
556  variables.emplace_back(make_symbol(naming::TQITEM_VARIABLE), false, false, true);
557  variables.back().is_constant = true;
558  info.tqitem_index = static_cast<int>(variables.size() - 1);
559  }
560 }
561 
563  std::vector<IndexVariableInfo>& variables) {
564  variables.emplace_back(make_symbol(naming::POINT_PROCESS_VARIABLE), false, false, true);
565  variables.back().is_constant = true;
566 }
567 
569  const auto& args = internal_method_parameters();
570  return get_arg_str(args);
571 }
572 
573 
575  if (info.mod_suffix == "nothing") {
576  return {};
577  }
578 
579  ParamVector params;
580  params.emplace_back("", "_nrn_mechanism_cache_range&", "", "_lmc");
581  params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst");
582  if (!info.artificial_cell) {
583  params.emplace_back("", fmt::format("{}&", node_data_struct()), "", "node_data");
584  }
585  params.emplace_back("", "size_t", "", "id");
586  params.emplace_back("", "Datum*", "", "_ppvar");
587  params.emplace_back("", "Datum*", "", "_thread");
588  if (!codegen_thread_variables.empty()) {
589  params.emplace_back("", fmt::format("{}&", thread_variables_struct()), "", "_thread_vars");
590  }
591  params.emplace_back("", "NrnThread*", "", "nt");
592  return params;
593 }
594 
595 
596 /// TODO: Edit for NEURON
598  return {};
599 }
600 
601 
602 /// TODO: Edit for NEURON
604  bool table) noexcept {
605  return {};
606 }
607 
608 
610  return internal_method_parameters();
611 }
612 
613 
615  return {{"", "Memb_list*", "", "_ml"},
616  {"", "size_t", "", "_iml"},
617  {"", "Datum*", "", "_ppvar"},
618  {"", "Datum*", "", "_thread"},
619  {"", "double*", "", "_globals"},
620  {"", "NrnThread*", "", "_nt"}};
621 }
622 
623 
624 /// TODO: Edit for NEURON
626  return {};
627 }
628 
629 
630 /// TODO: Edit for NEURON
632  return {};
633 }
634 
635 std::pair<CodegenNeuronCppVisitor::ParamVector, CodegenNeuronCppVisitor::ParamVector>
637  auto params = ParamVector{};
638 
639  for (const auto& i: node.get_parameters()) {
640  params.emplace_back("", "double", "", i->get_node_name());
641  }
642  return {params, {}};
643 }
644 
645 
646 /** Map of the non-(global/top-local) LOCAL variables.
647  *
648  * The map associates the name in the MOD file, e.g. `a` with
649  * the current name of that LOCAL variable, e.g. `a_r_4`.
650  *
651  * auto map = get_nonglobal_local_variable_names();
652  * assert map["a"] == "a_r_4";
653  *
654  * The two names can differ, because an early pass makes all
655  * names unique by renaming local variables.
656  */
657 std::unordered_map<std::string, std::string> get_nonglobal_local_variable_names(
658  const symtab::SymbolTable& symtab) {
659  if (symtab.global_scope()) {
660  return {};
661  }
662 
663  auto local_variables = symtab.get_variables(NmodlType::local_var);
664  auto parent_symtab = symtab.get_parent_table();
665  if (parent_symtab == nullptr) {
666  throw std::runtime_error(
667  "Internal NMODL error: non top-level symbol table doesn't have a parent.");
668  }
669 
670  auto variable_names = get_nonglobal_local_variable_names(*parent_symtab);
671 
672  for (const auto& symbol: local_variables) {
673  auto status = symbol->get_status();
674  bool is_renamed = (status & symtab::syminfo::Status::renamed) !=
676  auto current_name = symbol->get_name();
677  auto mod_name = is_renamed ? symbol->get_original_name() : current_name;
678 
679  variable_names[mod_name] = current_name;
680  }
681 
682  return variable_names;
683 }
684 
685 
687  const ast::Verbatim& node,
688  const std::string& verbatim) {
689  // Note, the logic for reducing the number of macros printed, aims to
690  // improve legibility of the generated code by reducing number of lines of
691  // code. It would be correct to print all macros, because that's
692  // essentially what NOCMODL does. Therefore, the logic isn't sharp (and
693  // doesn't have to be).
694 
695  std::vector<std::string> macros_defined;
696  auto print_macro = [this, &verbatim, &macros_defined](const std::string& macro_name,
697  const std::string& macro_value) {
698  if (verbatim.find(macro_name) != std::string::npos) {
699  printer->fmt_line("#define {} {}", macro_name, macro_value);
700  macros_defined.push_back(macro_name);
701  }
702  };
703 
704  printer->add_line("// Setup for VERBATIM");
705  for (const auto& var: codegen_float_variables) {
706  auto name = get_name(var);
707  print_macro(name, get_variable_name(name));
708  }
709 
710  for (const auto& var: codegen_int_variables) {
711  auto name = get_name(var);
712  std::string macro_value = get_variable_name(name);
713  print_macro(name, macro_value);
714  if (verbatim.find("_p_" + name) != std::string::npos) {
715  print_macro("_p_" + name, get_pointer_name(name));
716  }
717  }
718 
719  for (const auto& var: codegen_global_variables) {
720  auto name = get_name(var);
721  print_macro(name, get_variable_name(name));
722  }
723 
724  for (const auto& var: codegen_thread_variables) {
725  auto name = get_name(var);
726  print_macro(name, get_variable_name(name));
727  }
728 
729  for (const auto& func: info.functions) {
730  auto name = get_name(func);
731  print_macro(name, method_name(name));
732  print_macro(fmt::format("_l{}", name), fmt::format("ret_{}", name));
733  }
734 
735  for (const auto& proc: info.procedures) {
736  auto name = get_name(proc);
737  print_macro(name, method_name(name));
738  }
739 
740 
741  auto symtab = node.get_parent()->get_symbol_table();
742  auto locals = get_nonglobal_local_variable_names(*symtab);
743  for (const auto& [mod_name, current_name]: locals) {
744  print_macro(fmt::format("_l{}", mod_name), get_variable_name(current_name));
745  }
746 
747  print_macro(naming::NTHREAD_T_VARIABLE, "nt->_t");
748  print_macro("_nt", "nt");
749  print_macro("_tqitem", "tqitem");
750 
751  auto print_args_macro = [this, print_macro](const std::string& macro_basename,
752  const ParamVector& params) {
753  print_macro("_" + macro_basename + "_", get_arg_str(params));
754  print_macro("_" + macro_basename + "comma_", get_arg_str(params) + ",");
755  print_macro("_" + macro_basename + "proto_", get_parameter_str(params));
756  print_macro("_" + macro_basename + "protocomma_", get_parameter_str(params) + ",");
757  };
758 
759  print_args_macro("internalthreadargs", internalthreadargs_parameters());
760  print_args_macro("threadargs", threadargs_parameters());
761 
762  return macros_defined;
763 }
764 
765 
767  const std::vector<std::string>& macros_defined) {
768  for (const auto& macro: macros_defined) {
769  printer->fmt_line("#undef {}", macro);
770  }
771  printer->add_line("// End of cleanup for VERBATIM");
772 }
773 
774 
775 std::string CodegenNeuronCppVisitor::process_verbatim_text(const std::string& verbatim) {
777  driver.scan_string(verbatim);
778  auto tokens = driver.all_tokens();
779  std::string result;
780  for (size_t i = 0; i < tokens.size(); i++) {
781  auto token = tokens[i];
782 
783  // check if we have function call in the verbatim block where
784  // function is defined in the same mod file
785  if (program_symtab->is_method_defined(token) && tokens[i + 1] == "(") {
786  result += token + "(";
787  if (tokens[i + 2] == naming::THREAD_ARGS) {
789  } else if (tokens[i + 2] == naming::THREAD_ARGS_COMMA) {
791  } else {
792  result += tokens[i + 2];
793  }
794 
795  i += 2;
796  } else {
797  result += token;
798  }
799  }
800  return result;
801 }
802 
803 
805  const auto& verbatim_code = node.get_statement()->eval();
806  auto massaged_verbatim = process_verbatim_text(verbatim_code);
807 
808  auto macros_defined = print_verbatim_setup(node, massaged_verbatim);
809  printer->add_line("// Begin VERBATIM");
810  const auto& lines = stringutils::split_string(massaged_verbatim, '\n');
811  for (const auto& line: lines) {
812  printer->add_line(line);
813  }
814  printer->add_line("// End VERBATIM");
815  print_verbatim_cleanup(macros_defined);
816 }
817 
818 
819 /// TODO: Write for NEURON
821  return {};
822 };
823 
824 
826  const std::string& function_or_procedure_name) const {
827  return fmt::format("_hoc_{}", function_or_procedure_name);
828 }
829 
830 
832  const std::string& function_or_procedure_name) const {
833  return fmt::format("static {} {}({})",
834  info.point_process ? "double" : "void",
835  hoc_function_name(function_or_procedure_name),
836  info.point_process ? "void * _vptr" : "");
837 }
838 
839 
841  const std::string& function_or_procedure_name) const {
842  return fmt::format("_npy_{}", function_or_procedure_name);
843 }
844 
845 
847  const std::string& function_or_procedure_name) const {
848  return fmt::format("static double {}(Prop* _prop)",
849  py_function_name(function_or_procedure_name));
850 }
851 
852 
853 /****************************************************************************************/
854 /* Code-specific printing routines for code generation */
855 /****************************************************************************************/
856 
858  return "neuron";
859 }
860 
861 
863  std::vector<ShadowUseStatement>& statements,
864  const Ion& ion,
865  const std::string& /* concentration */) {
866  auto ion_name = ion.name;
867  int dparam_index = get_int_variable_index(fmt::format("style_{}", ion_name));
868 
869  auto style_name = fmt::format("_style_{}", ion_name);
870  auto style_stmt = fmt::format("int {} = *(_ppvar[{}].get<int*>())", style_name, dparam_index);
871  statements.push_back(ShadowUseStatement{style_stmt, "", ""});
872 
873 
874  auto wrote_conc_stmt = fmt::format("nrn_wrote_conc(_{}_sym, {}, {}, {}, {})",
875  ion_name,
876  get_variable_name(ion.rev_potential_pointer_name()),
877  get_variable_name(ion.intra_conc_pointer_name()),
878  get_variable_name(ion.extra_conc_pointer_name()),
879  style_name);
880  statements.push_back(ShadowUseStatement{wrote_conc_stmt, "", ""});
881 }
882 
883 /****************************************************************************************/
884 /* Routines for returning variable name */
885 /****************************************************************************************/
886 
887 
889  bool use_instance) const {
890  if (!use_instance) {
891  throw std::runtime_error("Printing non-instance variables is not implemented.");
892  }
893 
894  auto name = symbol->get_name();
895  auto dimension = symbol->get_length();
896  if (symbol->is_array()) {
897  return fmt::format("(inst.{}+id*{})", name, dimension);
898  } else {
899  return fmt::format("inst.{}[id]", name);
900  }
901 }
902 
903 
905  const std::string& name,
906  bool use_instance) const {
907  auto position = position_of_int_var(name);
908 
909  if (info.semantics[position].name == naming::RANDOM_SEMANTIC) {
910  return fmt::format("(nrnran123_State*) _ppvar[{}].literal_value<void*>()", position);
911  }
912 
913  if (info.semantics[position].name == naming::FOR_NETCON_SEMANTIC) {
914  return fmt::format("_ppvar[{}].literal_value<void*>()", position);
915  }
916 
917  if (info.semantics[position].name == naming::POINTER_SEMANTIC) {
918  return fmt::format("(*_ppvar[{}].get<double*>())", position);
919  }
920 
921  if (symbol.is_index) {
922  if (use_instance) {
923  throw std::runtime_error("Not implemented. [wiejo]");
924  // return fmt::format("inst->{}[{}]", name, position);
925  }
926  throw std::runtime_error("Not implemented. [ncuwi]");
927  // return fmt::format("indexes[{}]", position);
928  }
929  if (symbol.is_integer) {
930  if (use_instance) {
931  return fmt::format("inst.{}[id]", name);
932  }
933  return fmt::format("_ppvar[{}]", position);
934  }
935  if (use_instance) {
936  return fmt::format("(*inst.{}[id])", name);
937  }
938 
939 
940  throw std::runtime_error("Not implemented. [nvueir]");
941 }
942 
943 
945  bool use_instance) const {
946  auto i_var = var_info.offset;
947  auto var_name = var_info.symbol->get_name();
948 
949  if (use_instance) {
950  if (var_info.symbol->is_array()) {
951  return fmt::format("(_thread_vars.{}_ptr(id))", var_name);
952  } else {
953  return fmt::format("_thread_vars.{}(id)", var_name);
954  }
955  } else {
956  if (var_info.symbol->is_array()) {
957  return fmt::format("({}.thread_data + {})", global_struct_instance(), i_var);
958  } else {
959  return fmt::format("{}.thread_data[{}]", global_struct_instance(), i_var);
960  }
961  }
962 }
963 
964 
966  bool use_instance) const {
967  if (use_instance) {
968  return fmt::format("inst.{}->{}", naming::INST_GLOBAL_MEMBER, symbol->get_name());
969  } else {
970  return fmt::format("{}.{}", global_struct_instance(), symbol->get_name());
971  }
972 }
973 
974 
975 std::string CodegenNeuronCppVisitor::get_pointer_name(const std::string& name) const {
976  auto name_comparator = [&name](const auto& sym) { return name == get_name(sym); };
977 
978  auto var =
979  std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), name_comparator);
980 
981  if (var == codegen_int_variables.end()) {
982  throw std::runtime_error("Only integer variables have a 'pointer name'.");
983  }
984  auto position = position_of_int_var(name);
985  return fmt::format("_ppvar[{}].literal_value<void*>()", position);
986 }
987 
988 
989 std::string CodegenNeuronCppVisitor::get_variable_name(const std::string& name,
990  bool use_instance) const {
991  std::string varname = update_if_ion_variable_name(name);
992  if (!info.artificial_cell && varname == "v") {
994  }
995 
996  auto name_comparator = [&varname](const auto& sym) { return varname == get_name(sym); };
997 
998  if (name == naming::POINT_PROCESS_VARIABLE) {
999  if (printing_net_receive) {
1000  // In net_receive blocks, the point process is passed in as an
1001  // argument called:
1002  return "_pnt";
1003  }
1004  // The "integer variable" branch will pick up the correct `_ppvar` when
1005  // not printing a NET_RECEIVE block.
1006  }
1007 
1008  if (stringutils::starts_with(name, "_ptable_")) {
1009  return fmt::format("{}.{}", global_struct_instance(), name);
1010  }
1011 
1012  // float variable
1013  auto f = std::find_if(codegen_float_variables.begin(),
1014  codegen_float_variables.end(),
1015  name_comparator);
1016  if (f != codegen_float_variables.end()) {
1017  return float_variable_name(*f, use_instance);
1018  }
1019 
1020  // integer variable
1021  auto i =
1022  std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), name_comparator);
1023  if (i != codegen_int_variables.end()) {
1024  return int_variable_name(*i, varname, use_instance);
1025  }
1026 
1027  // thread variable
1028  auto t = std::find_if(codegen_thread_variables.begin(),
1029  codegen_thread_variables.end(),
1030  name_comparator);
1031  if (t != codegen_thread_variables.end()) {
1032  return thread_variable_name(*t, use_instance);
1033  }
1034 
1035  // global variable
1036  auto g = std::find_if(codegen_global_variables.begin(),
1037  codegen_global_variables.end(),
1038  name_comparator);
1039  if (g != codegen_global_variables.end()) {
1040  return global_variable_name(*g, use_instance);
1041  }
1042 
1043  if (varname == naming::NTHREAD_DT_VARIABLE) {
1044  return std::string("nt->_") + naming::NTHREAD_DT_VARIABLE;
1045  }
1046 
1047  if (varname == naming::NTHREAD_T_VARIABLE) {
1048  return std::string("nt->_") + naming::NTHREAD_T_VARIABLE;
1049  }
1050 
1051  // external variable
1052  auto e = std::find_if(info.external_variables.begin(),
1053  info.external_variables.end(),
1054  name_comparator);
1055  if (e != info.external_variables.end()) {
1056  return fmt::format("{}()", varname);
1057  }
1058 
1059  auto const iter =
1060  std::find_if(info.neuron_global_variables.begin(),
1061  info.neuron_global_variables.end(),
1062  [&varname](auto const& entry) { return entry.first->get_name() == varname; });
1063  if (iter != info.neuron_global_variables.end()) {
1064  std::string ret;
1065  if (use_instance) {
1066  ret = "*(inst.";
1067  }
1068  ret.append(varname);
1069  if (use_instance) {
1070  ret.append(")");
1071  }
1072  return ret;
1073  }
1074 
1075  // otherwise return original name
1076  return varname;
1077 }
1078 
1079 
1080 /****************************************************************************************/
1081 /* Main printing routines for code generation */
1082 /****************************************************************************************/
1083 
1084 
1086  printer->add_newline();
1087  printer->add_multi_line(R"CODE(
1088  #include <Eigen/Dense>
1089  #include <Eigen/LU>
1090  #include <math.h>
1091  #include <stdio.h>
1092  #include <stdlib.h>
1093  #include <vector>
1094  )CODE");
1095  if (info.eigen_newton_solver_exist) {
1096  printer->add_multi_line(nmodl::solvers::newton_hpp);
1097  }
1098 }
1099 
1100 
1102  printer->add_newline();
1103  printer->add_multi_line(R"CODE(
1104  #include "mech_api.h"
1105  #include "neuron/cache/mechanism_range.hpp"
1106  #include "nmodlmutex.h"
1107  #include "nrniv_mf.h"
1108  #include "section_fwd.hpp"
1109  )CODE");
1110 }
1111 
1112 
1113 void CodegenNeuronCppVisitor::print_sdlists_init(bool /* print_initializers */) {
1114  /// _initlists() should only be called once by the mechanism registration function
1115  /// (_<mod_file>_reg())
1116  printer->add_newline(2);
1117  printer->push_block("static void _initlists()");
1118  for (auto i = 0; i < info.prime_variables_by_order.size(); ++i) {
1119  const auto& prime_var = info.prime_variables_by_order[i];
1120  /// TODO: Something similar needs to happen for slist/dlist2 but I don't know their usage at
1121  // the moment
1122  /// TODO: We have to do checks and add errors similar to nocmodl in the
1123  // SemanticAnalysisVisitor
1124  if (prime_var->is_array()) {
1125  /// TODO: Needs a for loop here. Look at
1126  // https://github.com/neuronsimulator/nrn/blob/df001a436bcb4e23d698afe66c2a513819a6bfe8/src/nmodl/deriv.cpp#L524
1127  /// TODO: Also needs a test
1128  printer->fmt_push_block("for (int _i = 0; _i < {}; ++_i)", prime_var->get_length());
1129  printer->fmt_line("/* {}[{}] */", prime_var->get_name(), prime_var->get_length());
1130  printer->fmt_line("_slist1[{}+_i] = {{{}, _i}};",
1131  i,
1132  position_of_float_var(prime_var->get_name()));
1133  const auto prime_var_deriv_name = "D" + prime_var->get_name();
1134  printer->fmt_line("/* {}[{}] */", prime_var_deriv_name, prime_var->get_length());
1135  printer->fmt_line("_dlist1[{}+_i] = {{{}, _i}};",
1136  i,
1137  position_of_float_var(prime_var_deriv_name));
1138  printer->pop_block();
1139  } else {
1140  printer->fmt_line("/* {} */", prime_var->get_name());
1141  printer->fmt_line("_slist1[{}] = {{{}, 0}};",
1142  i,
1143  position_of_float_var(prime_var->get_name()));
1144  const auto prime_var_deriv_name = "D" + prime_var->get_name();
1145  printer->fmt_line("/* {} */", prime_var_deriv_name);
1146  printer->fmt_line("_dlist1[{}] = {{{}, 0}};",
1147  i,
1148  position_of_float_var(prime_var_deriv_name));
1149  }
1150  }
1151  printer->pop_block();
1152 }
1153 
1155  auto params = internal_method_parameters();
1156 
1157  return params;
1158 }
1159 
1161  const auto value_initialize = print_initializers ? "{}" : "";
1162 
1163  /// TODO: Print only global variables printed in NEURON
1164  printer->add_newline(2);
1165  printer->add_line("/* NEURON global variables */");
1166  if (info.primes_size != 0) {
1167  printer->fmt_line("static neuron::container::field_index _slist1[{0}], _dlist1[{0}];",
1168  info.primes_size);
1169  }
1170 
1171  for (const auto& ion: info.ions) {
1172  printer->fmt_line("static Symbol* _{}_sym;", ion.name);
1173  }
1174 
1175  if (info.emit_cvode) {
1176  printer->add_line("static Symbol** _atollist;");
1177  printer->push_block("static HocStateTolerance _hoc_state_tol[] =");
1178  printer->add_line("{0, 0}");
1179  printer->pop_block(";");
1180  }
1181 
1182  printer->add_line("static int mech_type;");
1183 
1184  if (info.point_process) {
1185  printer->add_line("static int _pointtype;");
1186  } else {
1187  printer->add_multi_line(R"CODE(
1188  static Prop* _extcall_prop;
1189  /* _prop_id kind of shadows _extcall_prop to allow validity checking. */
1190  static _nrn_non_owning_id_without_container _prop_id{};)CODE");
1191  }
1192 
1193  printer->add_line("static _nrn_mechanism_std_vector<Datum> _extcall_thread;");
1194 
1195  // Start printing the CNRN-style global variables.
1196  auto float_type = default_float_data_type();
1197  printer->add_newline(2);
1198  printer->add_line("/** all global variables */");
1199  printer->fmt_push_block("struct {}", global_struct());
1200 
1201  if (!info.ions.empty()) {
1202  // TODO implement these when needed.
1203  }
1204 
1205  if (!info.thread_variables.empty()) {
1206  size_t prefix_sum = 0;
1207  for (size_t i = 0; i < info.thread_variables.size(); ++i) {
1208  const auto& var = info.thread_variables[i];
1209  codegen_thread_variables.push_back({var, i, prefix_sum});
1210 
1211  prefix_sum += var->get_length();
1212  }
1213  }
1214 
1215 
1216  for (const auto& var: info.global_variables) {
1217  codegen_global_variables.push_back(var);
1218  }
1219 
1220  if (info.vectorize && !info.top_local_variables.empty()) {
1221  size_t prefix_sum = info.thread_var_data_size;
1222  size_t n_thread_vars = codegen_thread_variables.size();
1223  for (size_t i = 0; i < info.top_local_variables.size(); ++i) {
1224  const auto& var = info.top_local_variables[i];
1225  codegen_thread_variables.push_back({var, n_thread_vars + i, prefix_sum});
1226 
1227  prefix_sum += var->get_length();
1228  }
1229  }
1230 
1231  if (!info.vectorize && !info.top_local_variables.empty()) {
1232  for (size_t i = 0; i < info.top_local_variables.size(); ++i) {
1233  const auto& var = info.top_local_variables[i];
1234  codegen_global_variables.push_back(var);
1235  }
1236  }
1237 
1238 
1239  if (!codegen_thread_variables.empty()) {
1240  if (!info.vectorize) {
1241  // MOD files that aren't "VECTORIZED" don't have thread data.
1242  throw std::runtime_error("Found thread variables with `vectorize == false`.");
1243  }
1244 
1245  codegen_global_variables.push_back(make_symbol("thread_data_in_use"));
1246 
1247  auto symbol = make_symbol("thread_data");
1248  auto thread_data_size = info.thread_var_data_size + info.top_local_thread_size;
1249  symbol->set_as_array(thread_data_size);
1250  codegen_global_variables.push_back(symbol);
1251  }
1252 
1253  for (const auto& var: info.state_vars) {
1254  auto name = var->get_name() + "0";
1255  auto symbol = program_symtab->lookup(name);
1256  if (symbol == nullptr) {
1257  codegen_global_variables.push_back(make_symbol(name));
1258  }
1259  }
1260 
1261  for (const auto& var: info.constant_variables) {
1262  codegen_global_variables.push_back(var);
1263  }
1264 
1265  for (const auto& var: codegen_global_variables) {
1266  auto name = var->get_name();
1267  auto length = var->get_length();
1268  if (var->is_array()) {
1269  printer->fmt_line("{} {}[{}] /* TODO init const-array */;", float_type, name, length);
1270  } else {
1271  double value{};
1272  if (auto const& value_ptr = var->get_value()) {
1273  value = *value_ptr;
1274  }
1275  printer->fmt_line("{} {}{};",
1276  float_type,
1277  name,
1278  print_initializers ? fmt::format("{{{:g}}}", value) : std::string{});
1279  }
1280  }
1281 
1282  if (info.table_count > 0) {
1283  // basically the same code as coreNEURON uses
1284  printer->fmt_line("double usetable{};", print_initializers ? "{1}" : "");
1285  codegen_global_variables.push_back(make_symbol(naming::USE_TABLE_VARIABLE));
1286 
1287  for (const auto& block: info.functions_with_table) {
1288  const auto& name = block->get_node_name();
1289  printer->fmt_line("{} tmin_{}{};", float_type, name, value_initialize);
1290  printer->fmt_line("{} mfac_{}{};", float_type, name, value_initialize);
1291  codegen_global_variables.push_back(make_symbol("tmin_" + name));
1292  codegen_global_variables.push_back(make_symbol("mfac_" + name));
1293  }
1294 
1295  for (const auto& variable: info.table_statement_variables) {
1296  auto const name = "t_" + variable->get_name();
1297  auto const num_values = variable->get_num_values();
1298  if (variable->is_array()) {
1299  int array_len = variable->get_length();
1300  printer->fmt_line(
1301  "{} {}[{}][{}]{};", float_type, name, array_len, num_values, value_initialize);
1302  } else {
1303  printer->fmt_line("{} {}[{}]{};", float_type, name, num_values, value_initialize);
1304  }
1305  codegen_global_variables.push_back(make_symbol(name));
1306  }
1307  }
1308 
1309  print_global_struct_function_table_ptrs();
1310 
1311  if (info.vectorize && info.thread_data_index) {
1312  // TODO compare CoreNEURON something extcall stuff.
1313  // throw std::runtime_error("Not implemented, global vectorize something else.");
1314  }
1315 
1316  if (info.diam_used) {
1317  printer->fmt_line("Symbol* _morphology_sym;");
1318  }
1319 
1320  printer->pop_block(";");
1321 
1322  print_global_var_struct_assertions();
1323  print_global_var_struct_decl();
1324  print_global_var_external_access();
1325 
1326  print_global_param_default_values();
1327 }
1328 
1330  for (const auto& var: codegen_global_variables) {
1331  auto var_name = get_name(var);
1332  auto var_expr = get_variable_name(var_name, false);
1333 
1334  printer->fmt_push_block("auto {}() -> std::decay<decltype({})>::type ",
1335  method_name(var_name),
1336  var_expr);
1337  printer->fmt_line("return {};", var_expr);
1338  printer->pop_block();
1339  }
1340  if (!codegen_global_variables.empty()) {
1341  printer->add_newline();
1342  }
1343 
1344  for (const auto& var: info.external_variables) {
1345  auto var_name = get_name(var);
1346  printer->fmt_line("double {}();", var_name);
1347  }
1348  if (!info.external_variables.empty()) {
1349  printer->add_newline();
1350  }
1351 }
1352 
1354  printer->push_block("static std::vector<double> _parameter_defaults =");
1355 
1356  std::vector<std::string> defaults;
1357  for (const auto& p: info.range_parameter_vars) {
1358  double value = p->get_value() == nullptr ? 0.0 : *p->get_value();
1359  defaults.push_back(fmt::format("{:g} /* {} */", value, p->get_name()));
1360  }
1361 
1362  printer->add_multi_line(fmt::format("{}", fmt::join(defaults, ",\n")));
1363  printer->pop_block(";");
1364 }
1365 
1367  auto variable_printer = [&](const std::vector<SymbolType>& variables, bool if_array) {
1368  for (const auto& variable: variables) {
1369  if (variable->is_array() == if_array) {
1370  // false => do not use the instance struct, which is not
1371  // defined in the global declaration that we are printing
1372  auto name = get_variable_name(variable->get_name(), false);
1373  auto ename = add_escape_quote(variable->get_name() + "_" + info.mod_suffix);
1374  if (if_array) {
1375  auto length = variable->get_length();
1376  printer->fmt_line("{{{}, {}, {}}},", ename, name, length);
1377  } else {
1378  printer->fmt_line("{{{}, &{}}},", ename, name);
1379  }
1380  }
1381  }
1382  };
1383 
1384  auto globals = info.global_variables;
1385  auto thread_vars = info.thread_variables;
1386 
1387  if (info.table_count > 0) {
1388  globals.push_back(make_symbol(naming::USE_TABLE_VARIABLE));
1389  }
1390 
1391  printer->add_newline(2);
1392  printer->add_line("/** connect global (scalar) variables to hoc -- */");
1393  printer->add_line("static DoubScal hoc_scalar_double[] = {");
1394  printer->increase_indent();
1395  variable_printer(globals, false);
1396  variable_printer(thread_vars, false);
1397  printer->add_line("{nullptr, nullptr}");
1398  printer->decrease_indent();
1399  printer->add_line("};");
1400 
1401  printer->add_newline(2);
1402  printer->add_line("/** connect global (array) variables to hoc -- */");
1403  printer->add_line("static DoubVec hoc_vector_double[] = {");
1404  printer->increase_indent();
1405  variable_printer(globals, true);
1406  variable_printer(thread_vars, true);
1407  printer->add_line("{nullptr, nullptr, 0}");
1408  printer->decrease_indent();
1409  printer->add_line("};");
1410 
1411  printer->add_newline(2);
1412  printer->add_line("/* declaration of user functions */");
1413 
1414  auto print_entrypoint_decl = [this](const auto& callables, auto get_name) {
1415  for (const auto& node: callables) {
1416  const auto name = get_name(node);
1417  printer->fmt_line("{};", hoc_function_signature(name));
1418 
1419  if (!info.point_process) {
1420  printer->fmt_line("{};", py_function_signature(name));
1421  }
1422  }
1423  };
1424 
1425  auto get_name = [](const auto& node) { return node->get_node_name(); };
1426  print_entrypoint_decl(info.functions, get_name);
1427  print_entrypoint_decl(info.procedures, get_name);
1428  print_entrypoint_decl(info.function_tables, get_name);
1429  print_entrypoint_decl(info.function_tables, [](const auto& node) {
1430  auto node_name = node->get_node_name();
1431  return "table_" + node_name;
1432  });
1433 
1434  printer->add_newline(2);
1435  printer->add_line("/* connect user functions to hoc names */");
1436  printer->add_line("static VoidFunc hoc_intfunc[] = {");
1437  printer->increase_indent();
1438  if (info.point_process) {
1439  printer->add_line("{0, 0}");
1440  printer->decrease_indent();
1441  printer->add_line("};");
1442  printer->add_line("static Member_func _member_func[] = {");
1443  printer->increase_indent();
1444  printer->add_multi_line(R"CODE(
1445  {"loc", _hoc_loc_pnt},
1446  {"has_loc", _hoc_has_loc},
1447  {"get_loc", _hoc_get_loc_pnt},)CODE");
1448  } else {
1449  if (info.mod_suffix != "nothing") {
1450  printer->fmt_line("{{\"setdata_{}\", _hoc_setdata}},", info.mod_suffix);
1451  }
1452  }
1453 
1454  auto print_callable_reg = [this](const auto& callables, auto get_name) {
1455  for (const auto& node: callables) {
1456  const auto name = get_name(node);
1457  printer->fmt_line("{{\"{}{}\", {}}},", name, info.rsuffix, hoc_function_name(name));
1458  }
1459  };
1460 
1461  print_callable_reg(info.procedures, get_name);
1462  print_callable_reg(info.functions, get_name);
1463  print_callable_reg(info.function_tables, get_name);
1464  print_callable_reg(info.function_tables, [](const auto& node) {
1465  auto node_name = node->get_node_name();
1466  return "table_" + node_name;
1467  });
1468 
1469  printer->add_line("{nullptr, nullptr}");
1470  printer->decrease_indent();
1471  printer->add_line("};");
1472 
1473 
1474  auto print_py_callable_reg = [this](const auto& callables, auto get_name) {
1475  for (const auto& callable: callables) {
1476  const auto name = get_name(callable);
1477  printer->fmt_line("{{\"{}\", {}}},", name, py_function_name(name));
1478  }
1479  };
1480 
1481  if (!info.point_process) {
1482  printer->push_block("static NPyDirectMechFunc npy_direct_func_proc[] =");
1483  print_py_callable_reg(info.procedures,
1484  [](const auto& callable) { return callable->get_node_name(); });
1485  print_py_callable_reg(info.functions,
1486  [](const auto& callable) { return callable->get_node_name(); });
1487  print_py_callable_reg(info.function_tables,
1488  [](const auto& callable) { return callable->get_node_name(); });
1489  print_py_callable_reg(info.function_tables, [](const auto& callable) {
1490  return "table_" + callable->get_node_name();
1491  });
1492  printer->add_line("{nullptr, nullptr}");
1493  printer->pop_block(";");
1494  }
1495 }
1496 
1498  printer->add_newline(2);
1499  printer->fmt_push_block("extern \"C\" void _{}_reg()", info.mod_file);
1500  if (info.mod_suffix == "nothing") {
1501  print_mechanism_register_nothing();
1502  } else {
1503  print_mechanism_register_regular();
1504  }
1505  printer->pop_block();
1506 }
1507 
1509  printer->add_line("_initlists();");
1510  printer->add_newline();
1511 
1512  for (const auto& ion: info.ions) {
1513  double valence = ion.valence.value_or(-10000.0);
1514  printer->fmt_line("ion_reg(\"{}\", {});", ion.name, valence);
1515  }
1516  if (!info.ions.empty()) {
1517  printer->add_newline();
1518  }
1519 
1520  for (const auto& ion: info.ions) {
1521  printer->fmt_line("_{0}_sym = hoc_lookup(\"{0}_ion\");", ion.name);
1522  }
1523  if (!info.ions.empty()) {
1524  printer->add_newline();
1525  }
1526 
1527  const auto compute_functions_parameters =
1528  breakpoint_exist()
1529  ? fmt::format("{}, {}, {}",
1530  nrn_cur_required() ? method_name(naming::NRN_CUR_METHOD) : "nullptr",
1531  method_name(naming::NRN_JACOB_METHOD),
1532  nrn_state_required() ? method_name(naming::NRN_STATE_METHOD) : "nullptr")
1533  : "nullptr, nullptr, nullptr";
1534 
1535 
1536  const auto register_mech_args = fmt::format("{}, {}, {}, {}, {}, {}",
1537  get_channel_info_var_name(),
1538  method_name(naming::NRN_ALLOC_METHOD),
1539  compute_functions_parameters,
1540  method_name(naming::NRN_INIT_METHOD),
1541  info.first_pointer_var_index,
1542  1 + info.thread_data_index);
1543  if (info.point_process) {
1544  printer->fmt_line(
1545  "_pointtype = point_register_mech({}, _hoc_create_pnt, _hoc_destroy_pnt, "
1546  "_member_func);",
1547  register_mech_args);
1548 
1549  if (info.destructor_node) {
1550  printer->fmt_line("register_destructor({});",
1551  method_name(naming::NRN_DESTRUCTOR_METHOD));
1552  }
1553  } else {
1554  printer->fmt_line("register_mech({});", register_mech_args);
1555  }
1556 
1557 
1558  if (info.thread_callback_register) {
1559  printer->fmt_line("_extcall_thread.resize({});", info.thread_data_index + 1);
1560  printer->fmt_line("thread_mem_init(_extcall_thread.data());");
1561  printer->fmt_line("{} = 0;", get_variable_name("thread_data_in_use", false));
1562  }
1563 
1564 
1565  /// type related information
1566  printer->add_newline();
1567  printer->fmt_line("mech_type = nrn_get_mechtype({}[1]);", get_channel_info_var_name());
1568 
1569  printer->add_line("hoc_register_parm_default(mech_type, &_parameter_defaults);");
1570 
1571  // register the table-checking function
1572  if (info.table_count > 0) {
1573  printer->fmt_line("_nrn_thread_table_reg(mech_type, {});", table_thread_function_name());
1574  }
1575 
1576  printer->add_line("_nrn_mechanism_register_data_fields(mech_type,");
1577  printer->increase_indent();
1578 
1579  const auto codegen_float_variables_size = codegen_float_variables.size();
1580  std::vector<std::string> mech_register_args;
1581 
1582  for (int i = 0; i < codegen_float_variables_size; ++i) {
1583  const auto& float_var = codegen_float_variables[i];
1584  if (float_var->is_array()) {
1585  mech_register_args.push_back(
1586  fmt::format("_nrn_mechanism_field<double>{{\"{}\", {}}} /* {} */",
1587  float_var->get_name(),
1588  float_var->get_length(),
1589  i));
1590  } else {
1591  mech_register_args.push_back(fmt::format(
1592  "_nrn_mechanism_field<double>{{\"{}\"}} /* {} */", float_var->get_name(), i));
1593  }
1594  }
1595 
1596  const auto codegen_int_variables_size = codegen_int_variables.size();
1597  for (int i = 0; i < codegen_int_variables_size; ++i) {
1598  const auto& int_var = codegen_int_variables[i];
1599  const auto& name = int_var.symbol->get_name();
1600  if (i != info.semantics[i].index) {
1601  throw std::runtime_error("Broken logic.");
1602  }
1603  const auto& semantic = info.semantics[i].name;
1604 
1605  auto type = "double*";
1606  if (name == naming::POINT_PROCESS_VARIABLE) {
1607  type = "Point_process*";
1608  } else if (name == naming::TQITEM_VARIABLE) {
1609  type = "void*";
1610  } else if (stringutils::starts_with(name, "style_") &&
1611  stringutils::starts_with(semantic, "#") &&
1612  stringutils::ends_with(semantic, "_ion")) {
1613  type = "int*";
1614  } else if (semantic == naming::FOR_NETCON_SEMANTIC) {
1615  type = "void*";
1616  }
1617 
1618  mech_register_args.push_back(
1619  fmt::format("_nrn_mechanism_field<{}>{{\"{}\", \"{}\"}} /* {} */",
1620  type,
1621  name,
1622  info.semantics[i].name,
1623  i));
1624  }
1625 
1626  if (info.emit_cvode) {
1627  mech_register_args.push_back(
1628  fmt::format("_nrn_mechanism_field<int>{{\"{}\", \"cvodeieq\"}} /* {} */",
1630  codegen_int_variables_size));
1631  }
1632 
1633  printer->add_multi_line(fmt::format("{}", fmt::join(mech_register_args, ",\n")));
1634 
1635  printer->decrease_indent();
1636  printer->add_line(");");
1637  printer->add_newline();
1638 
1639  printer->fmt_line("hoc_register_prop_size(mech_type, {}, {});",
1640  float_variables_size(),
1641  int_variables_size() + static_cast<int>(info.emit_cvode));
1642 
1643  for (int i = 0; i < codegen_int_variables_size; ++i) {
1644  if (i != info.semantics[i].index) {
1645  throw std::runtime_error("Broken logic.");
1646  }
1647 
1648  printer->fmt_line("hoc_register_dparam_semantics(mech_type, {}, \"{}\");",
1649  i,
1650  info.semantics[i].name);
1651  }
1652 
1653  if (!info.longitudinal_diffusion_info.empty()) {
1654  printer->fmt_line("hoc_register_ldifus1(_apply_diffusion_function);");
1655  }
1656 
1657 
1658  if (info.write_concentration) {
1659  printer->fmt_line("nrn_writes_conc(mech_type, 0);");
1660  }
1661 
1662  if (info.artificial_cell) {
1663  printer->fmt_line("add_nrn_artcell(mech_type, {});", info.tqitem_index);
1664  }
1665 
1666  if (info.net_event_used) {
1667  printer->add_line("add_nrn_has_net_event(mech_type);");
1668  }
1669 
1670  if (info.for_netcon_used) {
1671  auto dparam_it =
1672  std::find_if(info.semantics.begin(), info.semantics.end(), [](const IndexSemantics& a) {
1673  return a.name == naming::FOR_NETCON_SEMANTIC;
1674  });
1675  if (dparam_it == info.semantics.end()) {
1676  throw std::runtime_error("Couldn't find `fornetcon` variable.");
1677  }
1678 
1679  int dparam_index = dparam_it->index;
1680  printer->fmt_line("add_nrn_fornetcons(mech_type, {});", dparam_index);
1681  }
1682 
1683  printer->add_line("hoc_register_var(hoc_scalar_double, hoc_vector_double, hoc_intfunc);");
1684  if (!info.point_process) {
1685  printer->add_line("hoc_register_npy_direct(mech_type, npy_direct_func_proc);");
1686  }
1687  if (info.net_receive_node) {
1688  printer->fmt_line("pnt_receive[mech_type] = nrn_net_receive_{};", info.mod_suffix);
1689  printer->fmt_line("pnt_receive_size[mech_type] = {};", info.num_net_receive_parameters);
1690  }
1691 
1692  if (info.net_receive_initial_node) {
1693  printer->fmt_line("pnt_receive_init[mech_type] = net_init;");
1694  }
1695 
1696  if (info.thread_callback_register) {
1697  printer->add_line("_nrn_thread_reg(mech_type, 1, thread_mem_init);");
1698  printer->add_line("_nrn_thread_reg(mech_type, 0, thread_mem_cleanup);");
1699  }
1700 
1701  if (info.diam_used) {
1702  printer->fmt_line("{}._morphology_sym = hoc_lookup(\"morphology\");",
1703  global_struct_instance());
1704  }
1705 
1706  if (info.emit_cvode) {
1707  printer->fmt_line("hoc_register_dparam_semantics(mech_type, {}, \"cvodeieq\");",
1708  codegen_int_variables_size);
1709  printer->fmt_line("hoc_register_cvode(mech_type, {}, {}, {}, {});",
1710  method_name(naming::CVODE_COUNT_NAME),
1713  method_name(naming::CVODE_SETUP_STIFF_NAME));
1714  printer->fmt_line("hoc_register_tolerance(mech_type, _hoc_state_tol, &_atollist);");
1715  }
1716 }
1717 
1718 
1720  printer->add_line("hoc_register_var(hoc_scalar_double, hoc_vector_double, hoc_intfunc);");
1721 }
1722 
1723 
1725  if (!info.thread_callback_register) {
1726  return;
1727  }
1728 
1729  auto static_thread_data = get_variable_name("thread_data", false);
1730  auto inuse = get_variable_name("thread_data_in_use", false);
1731  auto thread_data_index = info.thread_var_thread_id;
1732  printer->push_block("static void thread_mem_init(Datum* _thread) ");
1733  printer->push_block(fmt::format("if({})", inuse));
1734  printer->fmt_line("_thread[{}] = {{neuron::container::do_not_search, new double[{}]{{}}}};",
1735  thread_data_index,
1736  info.thread_var_data_size + info.top_local_thread_size);
1737  printer->pop_block();
1738  printer->push_block("else");
1739  printer->fmt_line("_thread[{}] = {{neuron::container::do_not_search, {}}};",
1740  thread_data_index,
1741  static_thread_data);
1742  printer->fmt_line("{} = 1;", inuse);
1743  printer->pop_block();
1744  printer->pop_block();
1745 
1746  printer->push_block("static void thread_mem_cleanup(Datum* _thread) ");
1747  printer->fmt_line("double * _thread_data_ptr = _thread[{}].get<double*>();", thread_data_index);
1748  printer->push_block(fmt::format("if(_thread_data_ptr == {})", static_thread_data));
1749  printer->fmt_line("{} = 0;", inuse);
1750  printer->pop_block();
1751  printer->push_block("else");
1752  printer->add_line("delete[] _thread_data_ptr;");
1753  printer->pop_block();
1754  printer->pop_block();
1755 }
1756 
1757 
1759  for (auto const& [var, type]: info.neuron_global_variables) {
1760  auto const name = var->get_name();
1761  printer->fmt_line("extern {} {};", type, name);
1762  }
1763 }
1764 
1766  auto const value_initialize = print_initializers ? "{}" : "";
1767  printer->add_newline(2);
1768  printer->add_line("/** all mechanism instance variables and global variables */");
1769  printer->fmt_push_block("struct {} ", instance_struct());
1770 
1771  for (auto const& [var, type]: info.neuron_global_variables) {
1772  auto const name = var->get_name();
1773  printer->fmt_line("{}* {}{};",
1774  type,
1775  name,
1776  print_initializers ? fmt::format("{{&::{}}}", name) : std::string{});
1777  }
1778  for (auto& var: codegen_float_variables) {
1779  const auto& name = var->get_name();
1780  printer->fmt_line("double* {}{};", name, value_initialize);
1781  }
1782  for (auto& var: codegen_int_variables) {
1783  const auto& name = var.symbol->get_name();
1784  auto position = position_of_int_var(name);
1785 
1786  if (name == naming::POINT_PROCESS_VARIABLE) {
1787  continue;
1788  } else if (var.is_index || var.is_integer) {
1789  // In NEURON we don't create caches for `int*`. Hence, do nothing.
1790  } else if (info.semantics[position].name == naming::POINTER_SEMANTIC) {
1791  // we don't need these either.
1792  } else {
1793  auto qualifier = var.is_constant ? "const " : "";
1794  auto type = var.is_vdata ? "void*" : default_float_data_type();
1795  printer->fmt_line("{}{}* const* {}{};", qualifier, type, name, value_initialize);
1796  }
1797  }
1798 
1799  printer->fmt_line("{}* {}{};",
1800  global_struct(),
1802  print_initializers ? fmt::format("{{&{}}}", global_struct_instance())
1803  : std::string{});
1804  printer->pop_block(";");
1805 }
1806 
1808  printer->add_newline(2);
1809  printer->fmt_push_block("static {} make_instance_{}(_nrn_mechanism_cache_range* _lmc)",
1810  instance_struct(),
1811  info.mod_suffix);
1812 
1813  printer->push_block("if(_lmc == nullptr)");
1814  printer->fmt_line("return {}();", instance_struct());
1815  printer->pop_block_nl(2);
1816 
1817  printer->fmt_push_block("return {}", instance_struct());
1818 
1819  std::vector<std::string> make_instance_args;
1820 
1821 
1822  for (auto const& [var, type]: info.neuron_global_variables) {
1823  auto const name = var->get_name();
1824  make_instance_args.push_back(fmt::format("&::{}", name));
1825  }
1826 
1827 
1828  const auto codegen_float_variables_size = codegen_float_variables.size();
1829  for (int i = 0; i < codegen_float_variables_size; ++i) {
1830  const auto& float_var = codegen_float_variables[i];
1831  if (float_var->is_array()) {
1832  make_instance_args.push_back(
1833  fmt::format("_lmc->template data_array_ptr<{}, {}>()", i, float_var->get_length()));
1834  } else {
1835  make_instance_args.push_back(fmt::format("_lmc->template fpfield_ptr<{}>()", i));
1836  }
1837  }
1838 
1839  const auto codegen_int_variables_size = codegen_int_variables.size();
1840  for (size_t i = 0; i < codegen_int_variables_size; ++i) {
1841  const auto& var = codegen_int_variables[i];
1842  auto name = var.symbol->get_name();
1843  auto sem = info.semantics[i].name;
1844  auto const variable = [&var, &sem, i]() -> std::string {
1845  if (var.is_index || var.is_integer) {
1846  return "";
1847  } else if (var.is_vdata) {
1848  return "";
1849  } else if (sem == naming::POINTER_SEMANTIC) {
1850  return "";
1851  } else {
1852  return fmt::format("_lmc->template dptr_field_ptr<{}>()", i);
1853  }
1854  }();
1855  if (variable != "") {
1856  make_instance_args.push_back(variable);
1857  }
1858  }
1859 
1860  printer->add_multi_line(fmt::format("{}", fmt::join(make_instance_args, ",\n")));
1861 
1862  printer->pop_block(";");
1863  printer->pop_block();
1864 }
1865 
1867  printer->add_newline(2);
1868  printer->fmt_push_block("struct {} ", node_data_struct());
1869 
1870  // Pointers to node variables
1871  printer->add_line("int const * nodeindices;");
1872  printer->add_line("double const * node_voltages;");
1873  printer->add_line("double * node_diagonal;");
1874  printer->add_line("double * node_rhs;");
1875  printer->add_line("int nodecount;");
1876 
1877  printer->pop_block(";");
1878 }
1879 
1881  printer->add_newline(2);
1882  printer->fmt_push_block("static {} make_node_data_{}(NrnThread& nt, Memb_list& _ml_arg)",
1883  node_data_struct(),
1884  info.mod_suffix);
1885 
1886  std::vector<std::string> make_node_data_args = {"_ml_arg.nodeindices",
1887  "nt.node_voltage_storage()",
1888  "nt.node_d_storage()",
1889  "nt.node_rhs_storage()",
1890  "_ml_arg.nodecount"};
1891 
1892  printer->fmt_push_block("return {}", node_data_struct());
1893  printer->add_multi_line(fmt::format("{}", fmt::join(make_node_data_args, ",\n")));
1894 
1895  printer->pop_block(";");
1896  printer->pop_block();
1897 
1898 
1899  printer->fmt_push_block("static {} make_node_data_{}(Prop * _prop)",
1900  node_data_struct(),
1901  info.mod_suffix);
1902 
1903  printer->push_block("if(!_prop)");
1904  printer->fmt_line("return {}();", node_data_struct());
1905  printer->pop_block_nl(2);
1906 
1907  printer->add_line("static std::vector<int> node_index{0};");
1908  printer->add_line("Node* _node = _nrn_mechanism_access_node(_prop);");
1909 
1910  make_node_data_args = {"node_index.data()",
1911  "&_nrn_mechanism_access_voltage(_node)",
1912  "&_nrn_mechanism_access_d(_node)",
1913  "&_nrn_mechanism_access_rhs(_node)",
1914  "1"};
1915 
1916  printer->fmt_push_block("return {}", node_data_struct());
1917  printer->add_multi_line(fmt::format("{}", fmt::join(make_node_data_args, ",\n")));
1918 
1919  printer->pop_block(";");
1920  printer->pop_block();
1921  printer->add_newline();
1922 }
1923 
1925  if (codegen_thread_variables.empty()) {
1926  return;
1927  }
1928 
1929  printer->add_newline(2);
1930  printer->fmt_push_block("struct {} ", thread_variables_struct());
1931  printer->add_line("double * thread_data;");
1932  printer->add_newline();
1933 
1934  std::string simd_width = "1";
1935 
1936 
1937  for (const auto& var_info: codegen_thread_variables) {
1938  printer->fmt_push_block("double * {}_ptr(size_t id)", var_info.symbol->get_name());
1939  printer->fmt_line("return thread_data + {} + (id % {});", var_info.offset, simd_width);
1940  printer->pop_block();
1941 
1942  printer->fmt_push_block("double & {}(size_t id)", var_info.symbol->get_name());
1943  printer->fmt_line("return thread_data[{} + (id % {})];", var_info.offset, simd_width);
1944  printer->pop_block();
1945  }
1946  printer->add_newline();
1947 
1948  printer->push_block(fmt::format("{}(double * const thread_data)", thread_variables_struct()));
1949  printer->fmt_line("this->thread_data = thread_data;");
1950  printer->pop_block();
1951 
1952  printer->pop_block(";");
1953 }
1954 
1955 
1957  // read ion statements
1958  auto read_statements = ion_read_statements(BlockType::Initial);
1959  for (auto& statement: read_statements) {
1960  printer->add_line(statement);
1961  }
1962 
1963  // initial block
1964  if (node != nullptr) {
1965  const auto& block = node->get_statement_block();
1966  print_statement_block(*block, false, false);
1967  }
1968 
1969  // write ion statements
1970  auto write_statements = ion_write_statements(BlockType::Initial);
1971  for (auto& statement: write_statements) {
1972  auto text = process_shadow_update_statement(statement, BlockType::Initial);
1973  printer->add_line(text);
1974  }
1975 }
1976 
1978  if (info.mod_suffix == "nothing") {
1979  return;
1980  }
1981 
1982  printer->add_line(
1983  "_nrn_mechanism_cache_range _lmc{_sorted_token, *nt, *_ml_arg, _ml_arg->type()};");
1984  printer->fmt_line("auto inst = make_instance_{}(&_lmc);", info.mod_suffix);
1985  if (!info.artificial_cell) {
1986  printer->fmt_line("auto node_data = make_node_data_{}(*nt, *_ml_arg);", info.mod_suffix);
1987  }
1988  printer->add_line("auto* _thread = _ml_arg->_thread;");
1989  if (!codegen_thread_variables.empty()) {
1990  printer->fmt_line("auto _thread_vars = {}(_thread[{}].get<double*>());",
1991  thread_variables_struct(),
1992  info.thread_var_thread_id);
1993  }
1994 }
1995 
1996 
1998  if (info.mod_suffix == "nothing") {
1999  return;
2000  }
2001 
2002  printer->add_line("Datum* _ppvar = _nrn_mechanism_access_dparam(prop);");
2003  printer->add_line("_nrn_mechanism_cache_instance _lmc{prop};");
2004  printer->add_line("const size_t id = 0;");
2005 
2006  printer->fmt_line("auto inst = make_instance_{}(prop ? &_lmc : nullptr);", info.mod_suffix);
2007  if (!info.artificial_cell) {
2008  printer->fmt_line("auto node_data = make_node_data_{}(prop);", info.mod_suffix);
2009  }
2010 
2011  if (!codegen_thread_variables.empty()) {
2012  printer->fmt_line("auto _thread_vars = {}({}_global.thread_data);",
2013  thread_variables_struct(),
2014  info.mod_suffix);
2015  }
2016 
2017  printer->add_newline();
2018 }
2019 
2020 
2022  const std::string& function_name) {
2023  std::string method = function_name.empty() ? compute_method_name(type) : function_name;
2024  ParamVector args = {{"", "const _nrn_model_sorted_token&", "", "_sorted_token"},
2025  {"", "NrnThread*", "", "nt"},
2026  {"", "Memb_list*", "", "_ml_arg"},
2027  {"", "int", "", "_type"}};
2028  printer->fmt_push_block("static void {}({})", method, get_parameter_str(args));
2029  print_entrypoint_setup_code_from_memb_list();
2030  printer->add_line("auto nodecount = _ml_arg->nodecount;");
2031 }
2032 
2033 
2034 void CodegenNeuronCppVisitor::print_nrn_init(bool skip_init_check) {
2035  printer->add_newline(2);
2036 
2037  print_global_function_common_code(BlockType::Initial);
2038 
2039  printer->push_block("for (int id = 0; id < nodecount; id++)");
2040 
2041  printer->add_line("auto* _ppvar = _ml_arg->pdata[id];");
2042  if (!info.artificial_cell) {
2043  printer->add_line("int node_id = node_data.nodeindices[id];");
2044  printer->add_line("inst.v_unused[id] = node_data.node_voltages[node_id];");
2045  }
2046 
2047  print_rename_state_vars();
2048 
2049  if (!info.changed_dt.empty()) {
2050  printer->fmt_line("double _save_prev_dt = {};",
2051  get_variable_name(naming::NTHREAD_DT_VARIABLE));
2052  printer->fmt_line("{} = {};",
2053  get_variable_name(naming::NTHREAD_DT_VARIABLE),
2054  info.changed_dt);
2055  }
2056 
2057  print_initial_block(info.initial_node);
2058 
2059  if (!info.changed_dt.empty()) {
2060  printer->fmt_line("{} = _save_prev_dt;", get_variable_name(naming::NTHREAD_DT_VARIABLE));
2061  }
2062 
2063  printer->pop_block();
2064  printer->pop_block();
2065 }
2066 
2068  printer->add_newline(2);
2069 
2070  ParamVector args = {{"", "const _nrn_model_sorted_token&", "", "_sorted_token"},
2071  {"", "NrnThread*", "", "nt"},
2072  {"", "Memb_list*", "", "_ml_arg"},
2073  {"", "int", "", "_type"}};
2074 
2075  printer->fmt_push_block("static void {}({})",
2076  method_name(naming::NRN_JACOB_METHOD),
2077  get_parameter_str(args)); // begin function
2078 
2079 
2080  print_entrypoint_setup_code_from_memb_list();
2081  printer->fmt_line("auto nodecount = _ml_arg->nodecount;");
2082  printer->push_block("for (int id = 0; id < nodecount; id++)"); // begin for
2083 
2084  if (breakpoint_exist()) {
2085  printer->add_line("int node_id = node_data.nodeindices[id];");
2086  printer->fmt_line("node_data.node_diagonal[node_id] {} inst.{}[id];",
2087  operator_for_d(),
2088  info.vectorize ? naming::CONDUCTANCE_UNUSED_VARIABLE
2090  }
2091 
2092  printer->pop_block(); // end for
2093  printer->pop_block(); // end function
2094 }
2095 
2096 
2098  if (info.constructor_node) {
2099  printer->fmt_line("static void {}(Prop* prop);",
2100  method_name(naming::NRN_CONSTRUCTOR_METHOD));
2101  }
2102 }
2103 
2105  if (info.constructor_node) {
2106  printer->fmt_push_block("static void {}(Prop* prop)",
2107  method_name(naming::NRN_CONSTRUCTOR_METHOD));
2108 
2109  print_entrypoint_setup_code_from_prop();
2110 
2111  auto block = info.constructor_node->get_statement_block();
2112  print_statement_block(*block, false, false);
2113 
2114  printer->pop_block();
2115  }
2116 }
2117 
2118 
2120  printer->fmt_line("static void {}(Prop* prop);", method_name(naming::NRN_DESTRUCTOR_METHOD));
2121 }
2122 
2124  printer->fmt_push_block("static void {}(Prop* prop)",
2125  method_name(naming::NRN_DESTRUCTOR_METHOD));
2126  print_entrypoint_setup_code_from_prop();
2127 
2128  for (const auto& rv: info.random_variables) {
2129  printer->fmt_line("nrnran123_deletestream((nrnran123_State*) {});",
2130  get_variable_name(get_name(rv), false));
2131  }
2132 
2133 
2134  if (info.destructor_node) {
2135  auto block = info.destructor_node->get_statement_block();
2136  print_statement_block(*block, false, false);
2137  }
2138 
2139  printer->pop_block();
2140 }
2141 
2142 
2144  printer->add_newline(2);
2145 
2146  auto method = method_name(naming::NRN_ALLOC_METHOD);
2147  printer->fmt_push_block("static void {}(Prop* _prop)", method);
2148  printer->add_line("Datum *_ppvar = nullptr;");
2149 
2150  if (info.point_process) {
2151  printer->push_block("if (nrn_point_prop_)");
2152  printer->add_multi_line(R"CODE(
2153  _nrn_mechanism_access_alloc_seq(_prop) = _nrn_mechanism_access_alloc_seq(nrn_point_prop_);
2154  _ppvar = _nrn_mechanism_access_dparam(nrn_point_prop_);
2155  )CODE");
2156  printer->chain_block("else");
2157  }
2158  if (info.semantic_variable_count || info.emit_cvode) {
2159  printer->fmt_line("_ppvar = nrn_prop_datum_alloc(mech_type, {}, _prop);",
2160  info.semantic_variable_count + static_cast<int>(info.emit_cvode));
2161  printer->add_line("_nrn_mechanism_access_dparam(_prop) = _ppvar;");
2162  }
2163  printer->add_multi_line(R"CODE(
2164  _nrn_mechanism_cache_instance _lmc{_prop};
2165  size_t const _iml = 0;
2166  )CODE");
2167  printer->fmt_line("assert(_nrn_mechanism_get_num_vars(_prop) == {});",
2168  codegen_float_variables.size());
2169  if (float_variables_size()) {
2170  printer->add_line("/*initialize range parameters*/");
2171  for (size_t i_param = 0; i_param < info.range_parameter_vars.size(); ++i_param) {
2172  const auto var = info.range_parameter_vars[i_param];
2173  if (var->is_array()) {
2174  continue;
2175  }
2176  const auto& var_name = var->get_name();
2177  auto var_pos = position_of_float_var(var_name);
2178 
2179  printer->fmt_line("_lmc.template fpfield<{}>(_iml) = {}; /* {} */",
2180  var_pos,
2181  fmt::format("_parameter_defaults[{}]", i_param),
2182  var_name);
2183  }
2184  }
2185  if (info.point_process) {
2186  printer->pop_block();
2187  }
2188 
2189  if (info.semantic_variable_count) {
2190  printer->add_line("_nrn_mechanism_access_dparam(_prop) = _ppvar;");
2191  }
2192 
2193  const auto codegen_int_variables_size = codegen_int_variables.size();
2194 
2195  if (info.diam_used || info.area_used) {
2196  for (size_t i = 0; i < codegen_int_variables.size(); ++i) {
2197  auto var_info = codegen_int_variables[i];
2198  if (var_info.symbol->get_name() == naming::DIAM_VARIABLE) {
2199  printer->fmt_line("Prop * morphology_prop = need_memb({}._morphology_sym);",
2200  global_struct_instance());
2201  printer->fmt_line(
2202  "_ppvar[{}] = _nrn_mechanism_get_param_handle(morphology_prop, 0);", i);
2203  }
2204  if (var_info.symbol->get_name() == naming::AREA_VARIABLE) {
2205  printer->fmt_line("_ppvar[{}] = _nrn_mechanism_get_area_handle(nrn_alloc_node_);",
2206  i);
2207  }
2208  }
2209  }
2210 
2211  for (const auto& ion: info.ions) {
2212  printer->fmt_line("Symbol * {}_sym = hoc_lookup(\"{}_ion\");", ion.name, ion.name);
2213  printer->fmt_line("Prop * {}_prop = need_memb({}_sym);", ion.name, ion.name);
2214 
2215  if (ion.is_exterior_conc_written()) {
2216  printer->fmt_line("nrn_check_conc_write(_prop, {}_prop, 0);", ion.name);
2217  }
2218 
2219  if (ion.is_interior_conc_written()) {
2220  printer->fmt_line("nrn_check_conc_write(_prop, {}_prop, 1);", ion.name);
2221  }
2222 
2223  int conc = ion.is_conc_written() ? 3 : int(ion.is_conc_read());
2224  int rev = ion.is_rev_written() ? 3 : int(ion.is_rev_read());
2225 
2226  printer->fmt_line("nrn_promote({}_prop, {}, {});", ion.name, conc, rev);
2227 
2228  for (size_t i = 0; i < codegen_int_variables_size; ++i) {
2229  const auto& var = codegen_int_variables[i];
2230 
2231  const std::string& var_name = var.symbol->get_name();
2232 
2233  if (stringutils::starts_with(var_name, "ion_")) {
2234  std::string ion_var_name = std::string(var_name.begin() + 4, var_name.end());
2235  if (ion.is_ionic_variable(ion_var_name) ||
2236  ion.is_current_derivative(ion_var_name) || ion.is_rev_potential(ion_var_name)) {
2237  printer->fmt_line("_ppvar[{}] = _nrn_mechanism_get_param_handle({}_prop, {});",
2238  i,
2239  ion.name,
2240  ion.variable_index(ion_var_name));
2241  }
2242  } else {
2243  if (ion.is_style(var_name)) {
2244  printer->fmt_line(
2245  "_ppvar[{}] = {{neuron::container::do_not_search, "
2246  "&(_nrn_mechanism_access_dparam({}_prop)[0].literal_value<int>())}};",
2247  i,
2248  ion.name);
2249  }
2250  }
2251  }
2252  }
2253 
2254  if (!info.random_variables.empty()) {
2255  for (const auto& rv: info.random_variables) {
2256  auto position = position_of_int_var(get_name(rv));
2257  printer->fmt_line("_ppvar[{}].literal_value<void*>() = nrnran123_newstream();",
2258  position);
2259  }
2260  printer->fmt_line("nrn_mech_inst_destruct[mech_type] = neuron::{};",
2261  method_name(naming::NRN_DESTRUCTOR_METHOD));
2262  }
2263 
2264  if (info.point_process || info.artificial_cell) {
2265  printer->fmt_push_block("if(!nrn_point_prop_)");
2266 
2267  if (info.constructor_node) {
2268  printer->fmt_line("{}(_prop);", method_name(naming::NRN_CONSTRUCTOR_METHOD));
2269  }
2270  printer->pop_block();
2271  }
2272 
2273  printer->pop_block();
2274 }
2275 
2276 
2277 /****************************************************************************************/
2278 /* Print nrn_state routine */
2279 /****************************************************************************************/
2280 
2282  if (!nrn_state_required()) {
2283  return;
2284  }
2285 
2286  printer->add_newline(2);
2287  print_global_function_common_code(BlockType::State);
2288 
2289  printer->push_block("for (int id = 0; id < nodecount; id++)");
2290  printer->add_line("int node_id = node_data.nodeindices[id];");
2291  printer->add_line("auto* _ppvar = _ml_arg->pdata[id];");
2292  if (!info.artificial_cell) {
2293  printer->add_line("inst.v_unused[id] = node_data.node_voltages[node_id];");
2294  }
2295 
2296  /**
2297  * \todo Eigen solver node also emits IonCurVar variable in the functor
2298  * but that shouldn't update ions in derivative block
2299  */
2300  if (ion_variable_struct_required()) {
2301  throw std::runtime_error("Not implemented.");
2302  }
2303 
2304  auto read_statements = ion_read_statements(BlockType::State);
2305  for (auto& statement: read_statements) {
2306  printer->add_line(statement);
2307  }
2308 
2309  if (info.nrn_state_block) {
2310  info.nrn_state_block->visit_children(*this);
2311  }
2312 
2313  if (info.currents.empty() && info.breakpoint_node != nullptr) {
2314  auto block = info.breakpoint_node->get_statement_block();
2315  print_statement_block(*block, false, false);
2316  }
2317 
2318  const auto& write_statements = ion_write_statements(BlockType::State);
2319  for (auto& statement: write_statements) {
2320  const auto& text = process_shadow_update_statement(statement, BlockType::State);
2321  printer->add_line(text);
2322  }
2323 
2324  printer->pop_block();
2325  printer->pop_block();
2326 }
2327 
2328 
2329 /****************************************************************************************/
2330 /* Print nrn_cur related routines */
2331 /****************************************************************************************/
2332 
2334  return get_arg_str(nrn_current_parameters());
2335 }
2336 
2337 
2339  if (ion_variable_struct_required()) {
2340  throw std::runtime_error("Not implemented.");
2341  }
2342 
2343  ParamVector params = {{"", "_nrn_mechanism_cache_range&", "", "_lmc"},
2344  {"", "NrnThread*", "", "nt"},
2345  {"", "Datum*", "", "_ppvar"},
2346  {"", "Datum*", "", "_thread"}};
2347 
2348  if (info.thread_callback_register) {
2349  auto type_name = fmt::format("{}&", thread_variables_struct());
2350  params.emplace_back("", type_name, "", "_thread_vars");
2351  }
2352  params.emplace_back("", "size_t", "", "id");
2353  params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst");
2354  params.emplace_back("", fmt::format("{}&", node_data_struct()), "", "node_data");
2355  params.emplace_back("", "double", "", "v");
2356  return params;
2357 }
2358 
2359 
2361  const auto& args = nrn_current_parameters();
2362  const auto& block = node.get_statement_block();
2363  printer->add_newline(2);
2364  printer->fmt_push_block("static inline double nrn_current_{}({})",
2365  info.mod_suffix,
2366  get_parameter_str(args));
2367  printer->add_line("inst.v_unused[id] = v;");
2368  printer->add_line("double current = 0.0;");
2369  print_statement_block(*block, false, false);
2370  for (auto& current: info.currents) {
2371  const auto& name = get_variable_name(current);
2372  printer->fmt_line("current += {};", name);
2373  }
2374  printer->add_line("return current;");
2375  printer->pop_block();
2376 }
2377 
2378 
2380  const auto& block = node.get_statement_block();
2381  print_statement_block(*block, false, false);
2382  if (!info.currents.empty()) {
2383  std::string sum;
2384  for (const auto& current: info.currents) {
2385  auto var = breakpoint_current(current);
2386  sum += get_variable_name(var);
2387  if (&current != &info.currents.back()) {
2388  sum += "+";
2389  }
2390  }
2391  printer->fmt_line("double rhs = {};", sum);
2392  }
2393 
2394  std::string sum;
2395  for (const auto& conductance: info.conductances) {
2396  auto var = breakpoint_current(conductance.variable);
2397  sum += get_variable_name(var);
2398  if (&conductance != &info.conductances.back()) {
2399  sum += "+";
2400  }
2401  }
2402  printer->fmt_line("double g = {};", sum);
2403 
2404  for (const auto& conductance: info.conductances) {
2405  if (!conductance.ion.empty()) {
2406  const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + conductance.ion +
2407  "dv";
2408  const auto& rhs = get_variable_name(conductance.variable);
2409  const ShadowUseStatement statement{lhs, "+=", rhs};
2410  const auto& text = process_shadow_update_statement(statement, BlockType::Equation);
2411  printer->add_line(text);
2412  }
2413  }
2414 }
2415 
2416 
2418  printer->fmt_line("double I1 = nrn_current_{}({}+0.001);",
2419  info.mod_suffix,
2420  nrn_current_arguments());
2421  for (auto& ion: info.ions) {
2422  for (auto& var: ion.writes) {
2423  if (ion.is_ionic_current(var)) {
2424  const auto& name = get_variable_name(var);
2425  printer->fmt_line("double di{} = {};", ion.name, name);
2426  }
2427  }
2428  }
2429  printer->fmt_line("double I0 = nrn_current_{}({});", info.mod_suffix, nrn_current_arguments());
2430  printer->add_line("double rhs = I0;");
2431 
2432  printer->add_line("double g = (I1-I0)/0.001;");
2433  for (auto& ion: info.ions) {
2434  for (auto& var: ion.writes) {
2435  if (ion.is_ionic_current(var)) {
2436  const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + ion.name + "dv";
2437  auto rhs = fmt::format("(di{}-{})/0.001", ion.name, get_variable_name(var));
2438  if (info.point_process) {
2439  auto area = get_variable_name(naming::NODE_AREA_VARIABLE);
2440  rhs += fmt::format("*1.e2/{}", area);
2441  }
2442  const ShadowUseStatement statement{lhs, "+=", rhs};
2443  const auto& text = process_shadow_update_statement(statement, BlockType::Equation);
2444  printer->add_line(text);
2445  }
2446  }
2447  }
2448 }
2449 
2450 
2452  printer->add_line("int node_id = node_data.nodeindices[id];");
2453  printer->add_line("double v = node_data.node_voltages[node_id];");
2454  printer->add_line("auto* _ppvar = _ml_arg->pdata[id];");
2455  const auto& read_statements = ion_read_statements(BlockType::Equation);
2456  for (auto& statement: read_statements) {
2457  printer->add_line(statement);
2458  }
2459 
2460  if (info.conductances.empty()) {
2461  print_nrn_cur_non_conductance_kernel();
2462  } else {
2463  print_nrn_cur_conductance_kernel(node);
2464  }
2465 
2466  const auto& write_statements = ion_write_statements(BlockType::Equation);
2467  for (auto& statement: write_statements) {
2468  auto text = process_shadow_update_statement(statement, BlockType::Equation);
2469  printer->add_line(text);
2470  }
2471 
2472  if (info.point_process) {
2473  const auto& area = get_variable_name(naming::NODE_AREA_VARIABLE);
2474  printer->fmt_line("double mfactor = 1.e2/{};", area);
2475  printer->add_line("g = g*mfactor;");
2476  printer->add_line("rhs = rhs*mfactor;");
2477  }
2478 
2479  // print_g_unused();
2480 }
2481 
2482 
2483 /// TODO: Edit for NEURON
2485  return;
2486 }
2487 
2488 
2489 /// TODO: Edit for NEURON
2491  if (!nrn_cur_required()) {
2492  return;
2493  }
2494 
2495  if (info.conductances.empty()) {
2496  print_nrn_current(*info.breakpoint_node);
2497  }
2498 
2499  printer->add_newline(2);
2500  printer->add_line("/** update current */");
2501  print_global_function_common_code(BlockType::Equation);
2502  // print_channel_iteration_block_parallel_hint(BlockType::Equation, info.breakpoint_node);
2503  printer->push_block("for (int id = 0; id < nodecount; id++)");
2504  print_nrn_cur_kernel(*info.breakpoint_node);
2505  // print_nrn_cur_matrix_shadow_update();
2506  // if (!nrn_cur_reduction_loop_required()) {
2507  // print_fast_imem_calculation();
2508  // }
2509 
2510 
2511  printer->fmt_line("node_data.node_rhs[node_id] {} rhs;", operator_for_rhs());
2512 
2513  if (breakpoint_exist()) {
2514  printer->fmt_line("inst.{}[id] = g;",
2515  info.vectorize ? naming::CONDUCTANCE_UNUSED_VARIABLE
2517  }
2518  printer->pop_block();
2519 
2520  // if (nrn_cur_reduction_loop_required()) {
2521  // printer->push_block("for (int id = 0; id < nodecount; id++)");
2522  // print_nrn_cur_matrix_shadow_reduction();
2523  // printer->pop_block();
2524  // print_fast_imem_calculation();
2525  // }
2526 
2527  // print_kernel_data_present_annotation_block_end();
2528  printer->pop_block();
2529 }
2530 
2531 
2532 /****************************************************************************************/
2533 /* Main code printing entry points */
2534 /****************************************************************************************/
2535 
2537  print_standard_includes();
2538  print_neuron_includes();
2539 
2540  if (info.thread_callback_register) {
2541  printer->add_line("extern void _nrn_thread_reg(int, int, void(*)(Datum*));");
2542  }
2543 }
2544 
2545 
2547  print_global_macros();
2548  print_mechanism_variables_macros();
2549 
2550  printer->add_line("extern Node* nrn_alloc_node_;");
2551 }
2552 
2553 
2555  printer->add_newline();
2556  printer->add_line("/* NEURON global macro definitions */");
2557  if (info.vectorize) {
2558  printer->add_multi_line(R"CODE(
2559  /* VECTORIZED */
2560  #define NRN_VECTORIZED 1
2561  )CODE");
2562  } else {
2563  printer->add_multi_line(R"CODE(
2564  /* NOT VECTORIZED */
2565  #define NRN_VECTORIZED 0
2566  )CODE");
2567  }
2568 }
2569 
2570 
2572  printer->add_newline();
2573  printer->add_line("static constexpr auto number_of_datum_variables = ",
2574  std::to_string(int_variables_size()),
2575  ";");
2576  printer->add_line("static constexpr auto number_of_floating_point_variables = ",
2577  std::to_string(codegen_float_variables.size()),
2578  ";");
2579  printer->add_newline();
2580  printer->add_multi_line(R"CODE(
2581  namespace {
2582  template <typename T>
2583  using _nrn_mechanism_std_vector = std::vector<T>;
2584  using _nrn_model_sorted_token = neuron::model_sorted_token;
2585  using _nrn_mechanism_cache_range = neuron::cache::MechanismRange<number_of_floating_point_variables, number_of_datum_variables>;
2586  using _nrn_mechanism_cache_instance = neuron::cache::MechanismInstance<number_of_floating_point_variables, number_of_datum_variables>;
2587  using _nrn_non_owning_id_without_container = neuron::container::non_owning_identifier_without_container;
2588  template <typename T>
2589  using _nrn_mechanism_field = neuron::mechanism::field<T>;
2590  template <typename... Args>
2591  void _nrn_mechanism_register_data_fields(Args&&... args) {
2592  neuron::mechanism::register_data_fields(std::forward<Args>(args)...);
2593  }
2594  } // namespace
2595  )CODE");
2596 
2597  if (info.point_process) {
2598  printer->add_line("extern Prop* nrn_point_prop_;");
2599  } else {
2600  printer->add_line("Prop* hoc_getdata_range(int type);");
2601  }
2602  // for registration of tables
2603  if (info.table_count > 0) {
2604  printer->add_line("void _nrn_thread_table_reg(int, nrn_thread_table_check_t);");
2605  }
2606  // for CVODE
2607  printer->add_line("extern void _cvode_abstol(Symbol**, double*, int);");
2608  if (info.for_netcon_used) {
2609  printer->add_line("int _nrn_netcon_args(void*, double***);");
2610  }
2611 }
2612 
2613 
2614 void CodegenNeuronCppVisitor::print_data_structures(bool print_initializers) {
2615  print_mechanism_global_var_structure(print_initializers);
2616  print_mechanism_range_var_structure(print_initializers);
2617  print_node_data_structure(print_initializers);
2618  print_thread_variables_structure(print_initializers);
2619  print_make_instance();
2620  print_make_node_data();
2621 }
2622 
2623 
2625  if (!info.vectorize) {
2626  return;
2627  }
2628  printer->add_multi_line(R"CODE(
2629  #if NRN_PRCELLSTATE
2630  inst->v_unused[id] = v;
2631  #endif
2632  )CODE");
2633 }
2634 
2635 
2637  printer->add_multi_line(R"CODE(
2638  #if NRN_PRCELLSTATE
2639  inst->g_unused[id] = g;
2640  #endif
2641  )CODE");
2642 }
2643 
2645  print_hoc_py_wrapper_function_definitions();
2646  for (const auto& procedure: info.procedures) {
2647  print_procedure(*procedure);
2648  }
2649  for (const auto& function: info.functions) {
2650  print_function(*function);
2651  }
2652  for (const auto& function_table: info.function_tables) {
2653  print_function_tables(*function_table);
2654  }
2655 }
2656 
2658  print_nrn_init();
2659  print_nrn_cur();
2660  print_nrn_state();
2661  print_nrn_jacob();
2662  print_net_receive();
2663  print_net_init();
2664 }
2665 
2667  print_backend_info();
2668  print_headers_include();
2669  print_macro_definitions();
2670  print_neuron_global_variable_declarations();
2671  print_namespace_start();
2672  print_nmodl_constants();
2673  print_prcellstate_macros();
2674  print_mechanism_info();
2675  print_data_structures(true);
2676  print_nrn_constructor_declaration();
2677  print_nrn_destructor_declaration();
2678  print_nrn_alloc();
2679  print_function_prototypes();
2680  print_longitudinal_diffusion_callbacks();
2681  print_cvode_definitions();
2682  print_point_process_function_definitions();
2683  print_setdata_functions();
2684  print_check_table_entrypoint();
2685  print_top_verbatim_blocks();
2686  print_functors_definitions();
2687  print_global_variables_for_hoc();
2688  print_thread_memory_callbacks();
2689  print_function_definitions();
2690  print_compute_functions(); // only nrn_cur and nrn_state
2691  print_nrn_constructor();
2692  print_nrn_destructor();
2693  print_sdlists_init(true);
2694  print_mechanism_register();
2695  print_namespace_stop();
2696 }
2697 
2699  print_backend_info();
2700  print_headers_include();
2701  print_namespace_start();
2702  print_function_prototypes();
2703  print_top_verbatim_blocks();
2704  print_global_variables_for_hoc();
2705  print_function_definitions();
2706  print_mechanism_register();
2707  print_namespace_stop();
2708 }
2709 
2711  if (info.mod_suffix == "nothing") {
2712  print_codegen_routines_nothing();
2713  } else {
2714  print_codegen_routines_regular();
2715  }
2716 }
2717 
2719  throw std::runtime_error("Not implemented.");
2720 }
2721 
2722 
2724  auto const& arguments = node.get_arguments();
2725 
2726  if (printing_net_init) {
2727  throw std::runtime_error("Not implemented. [jfiwoei]");
2728  }
2729 
2730  std::string weight_pointer = "nullptr";
2731  auto point_process = get_variable_name(naming::POINT_PROCESS_VARIABLE,
2732  /* use_instance */ false);
2733  if (!printing_net_receive) {
2734  point_process += ".get<Point_process*>()";
2735  }
2736  const auto& tqitem = get_variable_name("tqitem", /* use_instance */ false);
2737 
2738  printer->fmt_text("{}(/* tqitem */ &{}, {}, {}, {} + ",
2739  info.artificial_cell ? "artcell_net_send" : "net_send",
2740  tqitem,
2741  weight_pointer,
2742  point_process,
2743  get_variable_name("t"));
2744  print_vector_elements(arguments, ", ");
2745  printer->add_text(')');
2746 }
2747 
2749  const auto& point_process = get_variable_name("point_process", /* use_instance */ false);
2750  const auto& tqitem = get_variable_name("tqitem", /* use_instance */ false);
2751 
2752  printer->fmt_text("{}(/* tqitem */ &{}, {}, ",
2753  info.artificial_cell ? "artcell_net_move" : "net_move",
2754  tqitem,
2755  point_process);
2756 
2757  print_vector_elements(node.get_arguments(), ", ");
2758  printer->add_text(')');
2759 }
2760 
2762  const auto& point_process = get_variable_name(naming::POINT_PROCESS_VARIABLE,
2763  /* use_instance */ false);
2764  printer->fmt_text("net_event({}, t)", point_process);
2765 }
2766 
2768  auto name = node.get_node_name();
2769  const auto& arguments = node.get_arguments();
2770  printer->add_text(method_name(name), "(");
2771  print_vector_elements(arguments, ", ");
2772  printer->add_text(')');
2773 }
2774 
2775 /**
2776  * Rename arguments to NET_RECEIVE block with corresponding pointer variable
2777  *
2778  * \code{.mod}
2779  * NET_RECEIVE (weight, R){
2780  * x = R
2781  * }
2782  * \endcode
2783  *
2784  * then generated code should be:
2785  *
2786  * \code{.cpp}
2787  * x[id] = _args[1];
2788  * \endcode
2789  *
2790  * So, the `R` in AST needs to be renamed with `_args[1]`.
2791  */
2792 static void rename_net_receive_arguments(const ast::NetReceiveBlock& net_receive_node,
2793  const ast::Node& node) {
2794  const auto& parameters = net_receive_node.get_parameters();
2795 
2796  auto n_parameters = parameters.size();
2797  for (size_t i = 0; i < n_parameters; ++i) {
2798  const auto& name = parameters[i]->get_node_name();
2799  auto var_used = VarUsageVisitor().variable_used(node, name);
2800  if (var_used) {
2801  RenameVisitor vr(name, fmt::format("_args[{}]", i));
2802  node.get_statement_block()->visit_children(vr);
2803  }
2804  }
2805 }
2806 
2807 
2809  return {{"", "Point_process*", "", "_pnt"},
2810  {"", "double*", "", "_args"},
2811  {"", "double", "", "flag"}};
2812 }
2813 
2814 
2816  printer->add_line("_nrn_mechanism_cache_instance _lmc{_pnt->prop};");
2817  printer->add_line("auto * nt = static_cast<NrnThread*>(_pnt->_vnt);");
2818  printer->add_line("auto * _ppvar = _nrn_mechanism_access_dparam(_pnt->prop);");
2819 
2820  printer->fmt_line("auto inst = make_instance_{}(&_lmc);", info.mod_suffix);
2821  if (!info.artificial_cell) {
2822  printer->fmt_line("auto node_data = make_node_data_{}(_pnt->prop);", info.mod_suffix);
2823  }
2824  printer->fmt_line("// nocmodl has a nullptr dereference for thread variables.");
2825  printer->fmt_line("// NMODL will fail to compile at a later point, because of");
2826  printer->fmt_line("// missing '_thread_vars'.");
2827  printer->fmt_line("Datum * _thread = nullptr;");
2828 
2829  printer->add_line("size_t id = 0;");
2830  printer->add_line("double t = nt->_t;");
2831 }
2832 
2834  return {{"", "const _nrn_model_sorted_token&", "", "_sorted_token"},
2835  {"", "NrnThread*", "", "nt"},
2836  {"", "Memb_list*", "", "_ml_arg"},
2837  {"", "int", "", "_type"}};
2838 }
2839 
2841  ParamVector args = {{"", "_nrn_mechanism_cache_range&", "", "_lmc"},
2842  {"", fmt::format("{}_Instance&", info.mod_suffix), "", "inst"},
2843  {"", fmt::format("{}_NodeData&", info.mod_suffix), "", "node_data"},
2844  {"", "size_t", "", "id"},
2845  {"", "Datum*", "", "_ppvar"},
2846  {"", "Datum*", "", "_thread"},
2847  {"", "NrnThread*", "", "nt"}};
2848 
2849  if (info.thread_callback_register) {
2850  auto type_name = fmt::format("{}&", thread_variables_struct());
2851  args.emplace_back("", type_name, "", "_thread_vars");
2852  }
2853  return args;
2854 }
2855 
2856 
2858  printer->fmt_push_block("static constexpr int {}(int _type)",
2859  method_name(naming::CVODE_COUNT_NAME));
2860  printer->fmt_line("return {};", info.cvode_block->get_n_odes()->get_value());
2861  printer->pop_block();
2862  printer->add_newline(2);
2863 }
2864 
2866  const CodegenNeuronCppVisitor::ParamVector tolerances_parameters = {
2867  {"", "Prop*", "", "_prop"},
2868  {"", "int", "", "equation_index"},
2869  {"", "neuron::container::data_handle<double>*", "", "_pv"},
2870  {"", "neuron::container::data_handle<double>*", "", "_pvdot"},
2871  {"", "double*", "", "_atol"},
2872  {"", "int", "", "_type"}};
2873 
2874  auto get_param_name = [](const auto& item) { return std::get<3>(item); };
2875 
2876  auto prop_name = get_param_name(tolerances_parameters[0]);
2877  auto eqindex_name = get_param_name(tolerances_parameters[1]);
2878  auto pv_name = get_param_name(tolerances_parameters[2]);
2879  auto pvdot_name = get_param_name(tolerances_parameters[3]);
2880  auto atol_name = get_param_name(tolerances_parameters[4]);
2881 
2882  printer->fmt_push_block("static void {}({})",
2884  get_parameter_str(tolerances_parameters));
2885  printer->fmt_line("auto* _ppvar = _nrn_mechanism_access_dparam({});", prop_name);
2886  printer->fmt_line("_ppvar[{}].literal_value<int>() = {};", int_variables_size(), eqindex_name);
2887  printer->fmt_push_block("for (int i = 0; i < {}(0); i++)",
2888  method_name(naming::CVODE_COUNT_NAME));
2889  printer->fmt_line("{}[i] = _nrn_mechanism_get_param_handle({}, _slist1[i]);",
2890  pv_name,
2891  prop_name);
2892  printer->fmt_line("{}[i] = _nrn_mechanism_get_param_handle({}, _dlist1[i]);",
2893  pvdot_name,
2894  prop_name);
2895  printer->fmt_line("_cvode_abstol(_atollist, {}, i);", atol_name);
2896  printer->pop_block();
2897  printer->pop_block();
2898  printer->add_newline(2);
2899 }
2900 
2901 void CodegenNeuronCppVisitor::print_cvode_update(const std::string& name,
2902  const ast::StatementBlock& block) {
2903  printer->fmt_push_block("static int {}({})",
2904  method_name(name),
2905  get_parameter_str(cvode_update_parameters()));
2906  printer->add_line(
2907  "auto v = node_data.node_voltages ? "
2908  "node_data.node_voltages[node_data.nodeindices[id]] : 0.0;");
2909 
2910  print_statement_block(block, false, false);
2911 
2912  printer->add_line("return 0;");
2913  printer->pop_block();
2914  printer->add_newline(2);
2915 }
2916 
2917 void CodegenNeuronCppVisitor::print_cvode_setup(const std::string& setup_name,
2918  const std::string& update_name) {
2919  printer->fmt_push_block("static void {}({})",
2920  method_name(setup_name),
2921  get_parameter_str(cvode_setup_parameters()));
2922  print_entrypoint_setup_code_from_memb_list();
2923  printer->fmt_line("auto nodecount = _ml_arg->nodecount;");
2924  printer->push_block("for (int id = 0; id < nodecount; id++)");
2925  printer->add_line("auto* _ppvar = _ml_arg->pdata[id];");
2926  printer->add_line(
2927  "auto v = node_data.node_voltages ? "
2928  "node_data.node_voltages[node_data.nodeindices[id]] : 0.0;");
2929  printer->fmt_line("{}({});", method_name(update_name), get_arg_str(cvode_update_parameters()));
2930 
2931  printer->pop_block();
2932  printer->pop_block();
2933 
2934  printer->add_newline(2);
2935 }
2936 
2938  if (!info.emit_cvode) {
2939  return;
2940  }
2941 
2942  printer->add_newline(2);
2943  printer->add_line("/* Functions related to CVODE codegen */");
2944  print_cvode_count();
2945  print_cvode_tolerances();
2946  print_cvode_update(naming::CVODE_UPDATE_NON_STIFF_NAME,
2947  *info.cvode_block->get_non_stiff_block());
2948  print_cvode_update(naming::CVODE_UPDATE_STIFF_NAME, *info.cvode_block->get_stiff_block());
2951 }
2952 
2954  printing_net_receive = true;
2955  auto node = info.net_receive_node;
2956  if (!node) {
2957  return;
2958  }
2959 
2960  printer->fmt_push_block("static void nrn_net_receive_{}({})",
2961  info.mod_suffix,
2962  get_parameter_str(net_receive_args()));
2963 
2964  rename_net_receive_arguments(*node, *node);
2965  print_net_receive_common_code();
2966 
2967 
2968  print_statement_block(*node->get_statement_block(), false, false);
2969 
2970  printer->add_newline();
2971  printer->pop_block();
2972  printing_net_receive = false;
2973 }
2974 
2976  const auto node = info.net_receive_initial_node;
2977  if (node == nullptr) {
2978  return;
2979  }
2980 
2981  // rename net_receive arguments used in the initial block of net_receive
2982  rename_net_receive_arguments(*info.net_receive_node, *node);
2983 
2984  printing_net_init = true;
2985  printer->add_newline(2);
2986  printer->fmt_push_block("static void net_init({})", get_parameter_str(net_receive_args()));
2987 
2988  auto block = node->get_statement_block().get();
2989  if (!block->get_statements().empty()) {
2990  print_net_receive_common_code();
2991  print_statement_block(*block, false, false);
2992  }
2993  printer->pop_block();
2994  printing_net_init = false;
2995 }
2996 
2997 
2998 /****************************************************************************************/
2999 /* Overloaded visitor routines */
3000 /****************************************************************************************/
3001 
3002 /// TODO: Edit for NEURON
3004  return;
3005 }
3006 
3008  const ast::LongitudinalDiffusionBlock& /* node */) {
3009  // These are handled via `print_longitdudinal_*`.
3010 }
3011 
3013  // These are handled via `print_longitdudinal_*`.
3014 }
3015 
3017  // The setup for enabling this loop is:
3018  // double ** _fornetcon_data = ...;
3019  // for(size_t i = 0; i < n_netcons; ++i) {
3020  // double * _netcon_data = _fornetcon_data[i];
3021  //
3022  // // loop body.
3023  // }
3024  //
3025  // Where `_fornetcon_data` is an array of pointers to the arguments, one
3026  // for each netcon; and `_netcon_data` points to the arguments for the
3027  // current netcon.
3028  //
3029  // Similar to the CoreNEURON solution, we replace all arguments with the
3030  // C++ string that implements them, i.e. `_netcon_data[{}]`. The arguments
3031  // are positional and thus simply numbered through.
3032  const auto& args = node.get_parameters();
3033  RenameVisitor v;
3034  const auto& statement_block = node.get_statement_block();
3035  for (size_t i_arg = 0; i_arg < args.size(); ++i_arg) {
3036  auto old_name = args[i_arg]->get_node_name();
3037  auto new_name = fmt::format("_netcon_data[{}]", i_arg);
3038  v.set(old_name, new_name);
3039  statement_block->accept(v);
3040  }
3041 
3042  auto dparam_it =
3043  std::find_if(info.semantics.begin(), info.semantics.end(), [](const IndexSemantics& a) {
3044  return a.name == naming::FOR_NETCON_SEMANTIC;
3045  });
3046  if (dparam_it == info.semantics.end()) {
3047  throw std::runtime_error("Couldn't find `fornetcon` variable.");
3048  }
3049 
3050  int dparam_index = dparam_it->index;
3051  auto netcon_var = get_name(codegen_int_variables[dparam_index]);
3052 
3053  // This is called from `print_statement_block` which pre-indents the
3054  // current line. Hence `add_text` only.
3055  printer->add_text("double ** _fornetcon_data;");
3056  printer->add_newline();
3057 
3058  printer->fmt_line("int _n_netcons = _nrn_netcon_args({}, &_fornetcon_data);",
3059  get_variable_name(netcon_var, false));
3060 
3061  printer->push_block("for (size_t _i = 0; _i < _n_netcons; ++_i)");
3062  printer->add_line("double * _netcon_data = _fornetcon_data[_i];");
3063  print_statement_block(*statement_block, false, false);
3064  printer->pop_block();
3065 }
3066 
3068  printer->add_line("_NMODLMUTEXLOCK");
3069  printer->add_indent();
3070  node.get_expression()->accept(*this);
3071  printer->add_text(";");
3072  printer->add_line("_NMODLMUTEXUNLOCK");
3073 }
3074 
3075 
3076 } // namespace codegen
3077 } // 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::codegen::CodegenNeuronCppVisitor::print_verbatim_cleanup
void print_verbatim_cleanup(const std::vector< std::string > &macros_defined)
Print #undefs to erase all compatibility macros.
Definition: codegen_neuron_cpp_visitor.cpp:766
nmodl::codegen::naming::RANDOM_SEMANTIC
static constexpr char RANDOM_SEMANTIC[]
semantic type for RANDOM variable
Definition: codegen_naming.hpp:132
nmodl::stringutils::starts_with
static bool starts_with(const std::string &haystack, const std::string &needle)
Check if haystack starts with needle.
Definition: string_utils.hpp:154
nmodl::codegen::naming::THREAD_ARGS_COMMA
static constexpr char THREAD_ARGS_COMMA[]
verbatim name of the variable for nrn thread arguments, sometimes with trailing comma
Definition: codegen_naming.hpp:180
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_destructor
void print_nrn_destructor() override
Print nrn_destructor function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2123
nmodl::codegen::CodegenNeuronCppVisitor::print_global_var_external_access
void print_global_var_external_access()
Print functions for EXTERNAL use.
Definition: codegen_neuron_cpp_visitor.cpp:1329
nmodl::ast::Node
Base class for all AST node.
Definition: node.hpp:40
nmodl::codegen::IndexVariableInfo::is_index
bool is_index
if this is pure index (e.g.
Definition: codegen_cpp_visitor.hpp:137
nmodl::ast::Verbatim
Represents a C code block.
Definition: verbatim.hpp:38
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_cur_non_conductance_kernel
void print_nrn_cur_non_conductance_kernel() override
Print the nrn_cur kernel without NMODL conductance keyword provisions.
Definition: codegen_neuron_cpp_visitor.cpp:2417
nmodl::codegen::CodegenNeuronCppVisitor::py_function_signature
std::string py_function_signature(const std::string &function_or_procedure_name) const
Get the signature of the npy <func_or_proc_name> function.
Definition: codegen_neuron_cpp_visitor.cpp:846
nmodl::codegen::naming::CVODE_SETUP_TOLERANCES_NAME
static constexpr char CVODE_SETUP_TOLERANCES_NAME[]
name of CVODE method for setting up tolerances
Definition: codegen_naming.hpp:219
nmodl::codegen::IndexVariableInfo
Helper to represent information about index/int variables.
Definition: codegen_cpp_visitor.hpp:127
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_cur
void print_nrn_cur() override
Print nrn_cur / current update function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2490
nmodl::codegen::CodegenNeuronCppVisitor::print_macro_definitions
void print_macro_definitions()
Print all NEURON macros.
Definition: codegen_neuron_cpp_visitor.cpp:2546
nmodl::symtab::SymbolTable::global_scope
bool global_scope() const noexcept
Definition: symbol_table.hpp:174
nmodl::codegen::CodegenNeuronCppVisitor::print_function_definitions
void print_function_definitions()
Print function and procedures prototype definitions.
Definition: codegen_neuron_cpp_visitor.cpp:2644
nmodl::symtab::SymbolTable::get_parent_table
SymbolTable * get_parent_table() const noexcept
Definition: symbol_table.hpp:126
nmodl::codegen::CodegenNeuronCppVisitor::print_net_event_call
void print_net_event_call(const ast::FunctionCall &node) override
Print call to net_event.
Definition: codegen_neuron_cpp_visitor.cpp:2761
nmodl::codegen::naming::POINT_PROCESS_VARIABLE
static constexpr char POINT_PROCESS_VARIABLE[]
inbuilt neuron variable for point process
Definition: codegen_naming.hpp:72
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::CodegenNeuronCppVisitor::hoc_py_wrapper_signature
std::string hoc_py_wrapper_signature(const ast::Block *function_or_procedure_block, InterpreterWrapper wrapper_type)
Return the wrapper signature.
Definition: codegen_neuron_cpp_visitor.cpp:406
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_constructor_declaration
void print_nrn_constructor_declaration()
Definition: codegen_neuron_cpp_visitor.cpp:2097
nmodl::codegen::CodegenNeuronCppVisitor::print_neuron_includes
void print_neuron_includes()
Print includes from NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:1101
nmodl::codegen::CodegenNeuronCppVisitor::print_codegen_routines_regular
void print_codegen_routines_regular()
Anything not SUFFIX nothing.
Definition: codegen_neuron_cpp_visitor.cpp:2666
nmodl::codegen::naming::NRN_JACOB_METHOD
static constexpr char NRN_JACOB_METHOD[]
nrn_jacob method in generated code
Definition: codegen_naming.hpp:171
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_init
void print_nrn_init(bool skip_init_check=true)
Print the nrn_init function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2034
nmodl::ast::NetReceiveBlock
TODO.
Definition: net_receive_block.hpp:39
nmodl::codegen::CodegenNeuronCppVisitor::internal_method_arguments
std::string internal_method_arguments() override
Arguments for functions that are defined and used internally.
Definition: codegen_neuron_cpp_visitor.cpp:568
nmodl::stringutils::join_arguments
std::string join_arguments(const std::string &lhs, const std::string &rhs)
Joint two (list of) arguments.
Definition: string_utils.cpp:30
nmodl::codegen::CodegenCppVisitor::SymbolType
std::shared_ptr< symtab::Symbol > SymbolType
Definition: codegen_cpp_visitor.hpp:285
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_alloc
void print_nrn_alloc() override
Print nrn_alloc function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2143
nmodl::codegen::ThreadVariableInfo
Definition: codegen_neuron_cpp_visitor.hpp:62
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::CodegenNeuronCppVisitor::register_mechanism_arguments
std::string register_mechanism_arguments() const override
Arguments for register_mech or point_register_mech function.
Definition: codegen_neuron_cpp_visitor.cpp:820
nmodl::codegen::get_name
std::string get_name(ast::Ast const *sym)
Definition: codegen_cpp_visitor.hpp:172
nmodl::codegen::CodegenNeuronCppVisitor::position_of_int_var
int position_of_int_var(const std::string &name) const override
Determine the position in the data array for a given int variable.
Definition: codegen_neuron_cpp_visitor.cpp:74
nmodl::ast::NetReceiveBlock::get_parameters
const ArgumentVector & get_parameters() const noexcept override
Getter for member variable NetReceiveBlock::parameters.
Definition: net_receive_block.hpp:176
nmodl::codegen::CodegenNeuronCppVisitor::visit_lon_diffuse
void visit_lon_diffuse(const ast::LonDiffuse &node) override
visit node of type ast::LonDiffuse
Definition: codegen_neuron_cpp_visitor.cpp:3012
nmodl::codegen::CodegenNeuronCppVisitor::nrn_current_arguments
std::string nrn_current_arguments()
Definition: codegen_neuron_cpp_visitor.cpp:2333
nmodl::codegen::CodegenNeuronCppVisitor::table_thread_function_name
std::string table_thread_function_name() const
Name of the threaded table checking function.
Definition: codegen_neuron_cpp_visitor.cpp:56
nmodl::codegen::CodegenNeuronCppVisitor::optimize_ion_variable_copies
bool optimize_ion_variable_copies() const override
Check if ion variable copies should be avoided.
Definition: codegen_neuron_cpp_visitor.cpp:83
nmodl::codegen::naming::CVODE_COUNT_NAME
static constexpr char CVODE_COUNT_NAME[]
name of CVODE method for counting # of ODEs
Definition: codegen_naming.hpp:204
nmodl::codegen::naming::CVODE_SETUP_NON_STIFF_NAME
static constexpr char CVODE_SETUP_NON_STIFF_NAME[]
name of CVODE method for setting up non-stiff systems
Definition: codegen_naming.hpp:213
nmodl::codegen::CodegenNeuronCppVisitor::print_cvode_tolerances
void print_cvode_tolerances()
Print the CVODE function for setup of tolerances.
Definition: codegen_neuron_cpp_visitor.cpp:2865
nmodl::codegen::CodegenNeuronCppVisitor::hoc_function_name
std::string hoc_function_name(const std::string &function_or_procedure_name) const
All functions and procedures need a hoc <func_or_proc_name> to be available to the HOC interpreter.
Definition: codegen_neuron_cpp_visitor.cpp:825
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::ast::InitialBlock::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable InitialBlock::statement_block.
Definition: initial_block.hpp:184
nmodl::codegen::CodegenNeuronCppVisitor::global_variable_name
std::string global_variable_name(const SymbolType &symbol, bool use_instance=true) const override
Determine the variable name for a global variable given its symbol.
Definition: codegen_neuron_cpp_visitor.cpp:965
nmodl::codegen::Ion
Represent ions used in mod file.
Definition: codegen_info.hpp:53
nmodl::codegen::CodegenNeuronCppVisitor::nrn_thread_internal_arguments
std::string nrn_thread_internal_arguments() override
Arguments for "_threadargs_" macro in neuron implementation.
Definition: codegen_neuron_cpp_visitor.cpp:631
nmodl::codegen::naming::NRN_CONSTRUCTOR_METHOD
static constexpr char NRN_CONSTRUCTOR_METHOD[]
nrn_constructor method in generated code
Definition: codegen_naming.hpp:150
codegen_neuron_cpp_visitor.hpp
Visitor for printing C++ code compatible with legacy api of NEURON
nmodl::codegen::CodegenNeuronCppVisitor::backend_name
std::string backend_name() const override
Name of the code generation backend.
Definition: codegen_neuron_cpp_visitor.cpp:51
nmodl::codegen::CodegenNeuronCppVisitor::nrn_current_parameters
ParamVector nrn_current_parameters()
Definition: codegen_neuron_cpp_visitor.cpp:2338
nmodl::codegen::CodegenNeuronCppVisitor::print_entrypoint_setup_code_from_prop
void print_entrypoint_setup_code_from_prop()
Prints setup code for entrypoints NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:1997
nmodl::codegen::CodegenNeuronCppVisitor::print_global_param_default_values
void print_global_param_default_values()
Print global struct with default value of RANGE PARAMETERs.
Definition: codegen_neuron_cpp_visitor.cpp:1353
nmodl::codegen::CodegenNeuronCppVisitor::ldifusfunc1_parameters
ParamVector ldifusfunc1_parameters() const
Parameters for what NEURON calls ldifusfunc1_t.
Definition: codegen_neuron_cpp_visitor.cpp:477
nmodl::codegen::Ion::name
std::string name
name of the ion
Definition: codegen_info.hpp:55
nmodl::codegen::naming::NTHREAD_DT_VARIABLE
static constexpr char NTHREAD_DT_VARIABLE[]
dt variable in neuron thread structure
Definition: codegen_naming.hpp:108
nmodl::codegen::CodegenNeuronCppVisitor::print_g_unused
void print_g_unused() const override
Set g_unused (conductance) for NRN_PRCELLSTATE feature.
Definition: codegen_neuron_cpp_visitor.cpp:2636
nmodl::codegen::CodegenNeuronCppVisitor::visit_watch_statement
void visit_watch_statement(const ast::WatchStatement &node) override
TODO: Edit for NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:3003
nmodl::codegen::CodegenNeuronCppVisitor::print_net_send_call
void print_net_send_call(const ast::FunctionCall &node) override
Print call to net_send.
Definition: codegen_neuron_cpp_visitor.cpp:2723
var_usage_visitor.hpp
Check if variable is used in given block.
string_utils.hpp
Implement string manipulation functions.
nmodl::codegen::CodegenNeuronCppVisitor::print_net_move_call
void print_net_move_call(const ast::FunctionCall &node) override
Print call to net_move.
Definition: codegen_neuron_cpp_visitor.cpp:2748
nmodl::codegen::CodegenNeuronCppVisitor::thread_variable_name
std::string thread_variable_name(const ThreadVariableInfo &var_info, bool use_instance=true) const
Determine the C++ string to print for thread variables.
Definition: codegen_neuron_cpp_visitor.cpp:944
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::CodegenNeuronCppVisitor::print_cvode_setup
void print_cvode_setup(const std::string &setup_name, const std::string &update_name)
Print the CVODE setup function setup_name that calls the CVODE update function update_name.
Definition: codegen_neuron_cpp_visitor.cpp:2917
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_state
void print_nrn_state() override
Print nrn_state / state update function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2281
nmodl::ast::Ast::is_function_block
virtual bool is_function_block() const noexcept
Check if the ast node is an instance of ast::FunctionBlock.
Definition: ast.cpp:142
nmodl::codegen::naming::NRN_ALLOC_METHOD
static constexpr char NRN_ALLOC_METHOD[]
nrn_alloc method in generated code
Definition: codegen_naming.hpp:162
nmodl::codegen::CodegenNeuronCppVisitor::print_initial_block
void print_initial_block(const ast::InitialBlock *node)
Print the initial block.
Definition: codegen_neuron_cpp_visitor.cpp:1956
nmodl::codegen::IndexVariableInfo::is_integer
bool is_integer
if this is an integer (e.g.
Definition: codegen_cpp_visitor.hpp:141
nmodl::ast::Verbatim::get_statement
std::shared_ptr< String > get_statement() const noexcept
Getter for member variable Verbatim::statement.
Definition: verbatim.hpp:157
nmodl::parser::CDriver
Class that binds all pieces together for parsing C verbatim blocks.
Definition: c11_driver.hpp:37
nmodl::codegen::CodegenNeuronCppVisitor::needs_v_unused
bool needs_v_unused() const override
Definition: codegen_neuron_cpp_visitor.cpp:60
nmodl::codegen::CodegenNeuronCppVisitor::print_global_function_common_code
void print_global_function_common_code(BlockType type, const std::string &function_name="") override
Print common code for global functions like nrn_init, nrn_cur and nrn_state.
Definition: codegen_neuron_cpp_visitor.cpp:2021
nmodl::codegen::CodegenNeuronCppVisitor::float_variable_name
std::string float_variable_name(const SymbolType &symbol, bool use_instance) const override
Determine the name of a float variable given its symbol.
Definition: codegen_neuron_cpp_visitor.cpp:888
nmodl::codegen::Ion::extra_conc_pointer_name
std::string extra_conc_pointer_name() const
Definition: codegen_info.hpp:194
procedure_block.hpp
Auto generated AST classes declaration.
nmodl::ast::BreakpointBlock::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable BreakpointBlock::statement_block.
Definition: breakpoint_block.hpp:188
nmodl::codegen::CodegenNeuronCppVisitor::print_hoc_py_wrapper_function_definitions
void print_hoc_py_wrapper_function_definitions()
Definition: codegen_neuron_cpp_visitor.cpp:432
nmodl::codegen::Ion::rev_potential_pointer_name
std::string rev_potential_pointer_name() const
Definition: codegen_info.hpp:202
nmodl::codegen::CodegenNeuronCppVisitor::print_cvode_definitions
void print_cvode_definitions()
Print all callbacks for CVODE.
Definition: codegen_neuron_cpp_visitor.cpp:2937
nmodl::codegen::CodegenNeuronCppVisitor::print_v_unused
void print_v_unused() const override
Set v_unused (voltage) for NRN_PRCELLSTATE feature.
Definition: codegen_neuron_cpp_visitor.cpp:2624
nmodl::codegen::CodegenNeuronCppVisitor::print_ion_variable
void print_ion_variable() override
Definition: codegen_neuron_cpp_visitor.cpp:2718
nmodl::codegen::naming::CONDUCTANCE_VARIABLE
static constexpr char CONDUCTANCE_VARIABLE[]
range variable for conductance
Definition: codegen_naming.hpp:78
nmodl::codegen::CodegenNeuronCppVisitor::functor_params
ParamVector functor_params() override
The parameters of the Newton solver "functor".
Definition: codegen_neuron_cpp_visitor.cpp:1154
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_register_regular
void print_mechanism_register_regular()
Function body for anything not SUFFIX nothing.
Definition: codegen_neuron_cpp_visitor.cpp:1508
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_register_nothing
void print_mechanism_register_nothing()
Function body for SUFFIX nothing.
Definition: codegen_neuron_cpp_visitor.cpp:1719
codegen_cpp_visitor.hpp
Visitor for printing C++ code compatible with legacy api of CoreNEURON
nmodl::symtab::SymbolTable::get_variables
std::vector< std::shared_ptr< Symbol > > get_variables(syminfo::NmodlType with=syminfo::NmodlType::empty, syminfo::NmodlType without=syminfo::NmodlType::empty) const
get variables
Definition: symbol_table.cpp:107
codegen_naming.hpp
nmodl::visitor::VarUsageVisitor
Check if variable is used in given block.
Definition: var_usage_visitor.hpp:35
nmodl::ast::Block
Base class for all block scoped nodes.
Definition: block.hpp:41
nmodl::codegen::naming::CVODE_UPDATE_STIFF_NAME
static constexpr char CVODE_UPDATE_STIFF_NAME[]
name of CVODE method for updating stiff systems
Definition: codegen_naming.hpp:210
nmodl::ast::InitialBlock
Represents a INITIAL block in the NMODL.
Definition: initial_block.hpp:49
nmodl::codegen::CodegenNeuronCppVisitor::print_point_process_function_definitions
void print_point_process_function_definitions()
Print POINT_PROCESS related functions Wrap external NEURON functions related to POINT_PROCESS mechani...
Definition: codegen_neuron_cpp_visitor.cpp:96
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_destructor_declaration
void print_nrn_destructor_declaration()
Definition: codegen_neuron_cpp_visitor.cpp:2119
visitor_utils.hpp
Utility functions for visitors implementation.
nmodl::codegen::CodegenNeuronCppVisitor::print_net_init
void print_net_init()
Print NET_RECEIVE{ INITIAL{ ...
Definition: codegen_neuron_cpp_visitor.cpp:2975
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::WatchStatement
Represent WATCH statement in NMODL.
Definition: watch_statement.hpp:39
nmodl::codegen::CodegenNeuronCppVisitor::print_neuron_global_variable_declarations
void print_neuron_global_variable_declarations()
Print extern declarations for neuron global variables.
Definition: codegen_neuron_cpp_visitor.cpp:1758
nmodl::ast::BreakpointBlock
Represents a BREAKPOINT block in NMODL.
Definition: breakpoint_block.hpp:53
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_cur_conductance_kernel
void print_nrn_cur_conductance_kernel(const ast::BreakpointBlock &node) override
Print the nrn_cur kernel with NMODL conductance keyword provisions.
Definition: codegen_neuron_cpp_visitor.cpp:2379
nmodl::codegen::CodegenNeuronCppVisitor::int_variable_name
std::string int_variable_name(const IndexVariableInfo &symbol, const std::string &name, bool use_instance) const override
Determine the name of an int variable given its symbol.
Definition: codegen_neuron_cpp_visitor.cpp:904
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::codegen::InterpreterWrapper
InterpreterWrapper
Enum to switch between HOC and Python wrappers for functions and procedures defined in mechanisms.
Definition: codegen_neuron_cpp_visitor.hpp:52
nmodl::ast::Ast::get_symbol_table
virtual symtab::SymbolTable * get_symbol_table() const
Return associated symbol table for the AST node.
Definition: ast.cpp:38
nmodl::ast::FunctionCall
TODO.
Definition: function_call.hpp:38
nmodl::codegen::CodegenNeuronCppVisitor::print_global_variables_for_hoc
void print_global_variables_for_hoc() override
Print byte arrays that register scalar and vector variables for hoc interface.
Definition: codegen_neuron_cpp_visitor.cpp:1366
nmodl::codegen::naming::INTERNAL_THREAD_ARGS
static constexpr char INTERNAL_THREAD_ARGS[]
variation of _threadargs_ for "internal" functions.
Definition: codegen_naming.hpp:189
nmodl::codegen::CodegenNeuronCppVisitor::cvode_setup_parameters
ParamVector cvode_setup_parameters()
Get the parameters for functions that setup (initialize) CVODE.
Definition: codegen_neuron_cpp_visitor.cpp:2833
nmodl::codegen::CodegenNeuronCppVisitor::internalthreadargs_parameters
ParamVector internalthreadargs_parameters()
The parameters for the four macros _internalthreadargs*_.
Definition: codegen_neuron_cpp_visitor.cpp:609
nmodl::codegen::CodegenNeuronCppVisitor::get_pointer_name
std::string get_pointer_name(const std::string &name) const
Determine the C++ string to replace pointer names with.
Definition: codegen_neuron_cpp_visitor.cpp:975
nmodl::codegen::CodegenNeuronCppVisitor::print_standard_includes
void print_standard_includes() override
Print standard C/C++ includes.
Definition: codegen_neuron_cpp_visitor.cpp:1085
nmodl::ast::ProtectStatement
TODO.
Definition: protect_statement.hpp:38
nmodl::ast::LongitudinalDiffusionBlock
Extracts information required for LONGITUDINAL_DIFFUSION for each KINETIC block.
Definition: longitudinal_diffusion_block.hpp:38
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_range_var_structure
void print_mechanism_range_var_structure(bool print_initializers) override
Print the structure that wraps all range and int variables required for the NMODL.
Definition: codegen_neuron_cpp_visitor.cpp:1765
nmodl::codegen::CodegenNeuronCppVisitor::add_variable_tqitem
void add_variable_tqitem(std::vector< IndexVariableInfo > &variables) override
Add the variable tqitem during get_int_variables.
Definition: codegen_neuron_cpp_visitor.cpp:554
nmodl::codegen::CodegenNeuronCppVisitor::hoc_function_signature
std::string hoc_function_signature(const std::string &function_or_procedure_name) const
Get the signature of the hoc <func_or_proc_name> function.
Definition: codegen_neuron_cpp_visitor.cpp:831
nmodl::codegen::CodegenNeuronCppVisitor::function_table_parameters
std::pair< ParamVector, ParamVector > function_table_parameters(const ast::FunctionTableBlock &) override
Parameters of the function itself "{}" and "table_{}".
Definition: codegen_neuron_cpp_visitor.cpp:636
c11_driver.hpp
nmodl::ast::ForNetcon::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable ForNetcon::statement_block.
Definition: for_netcon.hpp:185
nmodl::codegen::get_nonglobal_local_variable_names
std::unordered_map< std::string, std::string > get_nonglobal_local_variable_names(const symtab::SymbolTable &symtab)
Map of the non-(global/top-local) LOCAL variables.
Definition: codegen_neuron_cpp_visitor.cpp:657
nmodl::codegen::CodegenNeuronCppVisitor::print_thread_variables_structure
void print_thread_variables_structure(bool print_initializers)
Print the data structure used to access thread variables.
Definition: codegen_neuron_cpp_visitor.cpp:1924
nmodl::codegen::IndexSemantics
Represent semantic information for index variable.
Definition: codegen_info.hpp:270
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:282
nmodl::codegen::CodegenNeuronCppVisitor::visit_longitudinal_diffusion_block
void visit_longitudinal_diffusion_block(const ast::LongitudinalDiffusionBlock &node) override
visit node of type ast::LongitudinalDiffusionBlock
Definition: codegen_neuron_cpp_visitor.cpp:3007
nmodl::codegen::CodegenNeuronCppVisitor::print_function_table_call
void print_function_table_call(const ast::FunctionCall &node) override
Print special code when calling FUNCTION_TABLEs.
Definition: codegen_neuron_cpp_visitor.cpp:2767
nmodl::codegen::CodegenNeuronCppVisitor::print_compute_functions
void print_compute_functions() override
Print all compute functions for every backend.
Definition: codegen_neuron_cpp_visitor.cpp:2657
nmodl::codegen::naming::NRN_INIT_METHOD
static constexpr char NRN_INIT_METHOD[]
nrn_init method in generated code
Definition: codegen_naming.hpp:147
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::THREAD_ARGS
static constexpr char THREAD_ARGS[]
verbatim name of the variable for nrn thread arguments
Definition: codegen_naming.hpp:177
nmodl::codegen::naming::POINTER_SEMANTIC
static constexpr char POINTER_SEMANTIC[]
semantic type for pointer variable
Definition: codegen_naming.hpp:126
nmodl::codegen::CodegenNeuronCppVisitor::print_thread_memory_callbacks
void print_thread_memory_callbacks()
Print thread variable (de-)initialization functions.
Definition: codegen_neuron_cpp_visitor.cpp:1724
nmodl::codegen::naming::CVODE_VARIABLE_NAME
static constexpr char CVODE_VARIABLE_NAME[]
name of the CVODE variable (can be arbitrary)
Definition: codegen_naming.hpp:222
nmodl::codegen::rename_net_receive_arguments
static void rename_net_receive_arguments(const ast::NetReceiveBlock &net_receive_node, const ast::Node &node)
Rename arguments to NET_RECEIVE block with corresponding pointer variable.
Definition: codegen_coreneuron_cpp_visitor.cpp:2266
nmodl::codegen::CodegenNeuronCppVisitor::print_entrypoint_setup_code_from_memb_list
void print_entrypoint_setup_code_from_memb_list()
Prints setup code for entrypoints from NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:1977
nmodl::codegen::CodegenNeuronCppVisitor::visit_verbatim
void visit_verbatim(const ast::Verbatim &node) override
visit node of type ast::Verbatim
Definition: codegen_neuron_cpp_visitor.cpp:804
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_cur_kernel
void print_nrn_cur_kernel(const ast::BreakpointBlock &node) override
Print main body of nrn_cur function.
Definition: codegen_neuron_cpp_visitor.cpp:2451
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:168
nmodl::codegen::naming::CVODE_UPDATE_NON_STIFF_NAME
static constexpr char CVODE_UPDATE_NON_STIFF_NAME[]
name of CVODE method for updating non-stiff systems
Definition: codegen_naming.hpp:207
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_register
void print_mechanism_register() override
Print the mechanism registration function.
Definition: codegen_neuron_cpp_visitor.cpp:1497
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:75
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_jacob
void print_nrn_jacob()
Print nrn_jacob function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2067
nmodl::codegen::CodegenNeuronCppVisitor::print_net_receive_common_code
void print_net_receive_common_code()
Definition: codegen_neuron_cpp_visitor.cpp:2815
nmodl::codegen::HOC
@ HOC
Definition: codegen_neuron_cpp_visitor.hpp:52
nmodl::codegen::CodegenNeuronCppVisitor::print_fast_imem_calculation
void print_fast_imem_calculation() override
Print fast membrane current calculation code.
Definition: codegen_neuron_cpp_visitor.cpp:2484
nmodl::symtab::SymbolTable
Represent symbol table for a NMODL block.
Definition: symbol_table.hpp:57
nmodl::codegen::naming::CVODE_SETUP_STIFF_NAME
static constexpr char CVODE_SETUP_STIFF_NAME[]
name of CVODE method for setting up stiff systems
Definition: codegen_naming.hpp:216
nmodl::visitor::RenameVisitor::set
void set(const std::string &old_name, std::string new_name)
Definition: rename_visitor.hpp:97
nmodl::codegen::CodegenNeuronCppVisitor::print_verbatim_setup
std::vector< std::string > print_verbatim_setup(const ast::Verbatim &node, const std::string &verbatim)
Print compatibility macros required for VERBATIM blocks.
Definition: codegen_neuron_cpp_visitor.cpp:686
nmodl::codegen::CodegenNeuronCppVisitor::print_data_structures
void print_data_structures(bool print_initializers) override
Print all classes.
Definition: codegen_neuron_cpp_visitor.cpp:2614
nmodl::codegen::CodegenNeuronCppVisitor::print_sdlists_init
void print_sdlists_init(bool print_initializers) override
Definition: codegen_neuron_cpp_visitor.cpp:1113
nmodl::codegen::CodegenNeuronCppVisitor::external_method_arguments
const std::string external_method_arguments() noexcept override
Arguments for external functions called from generated code.
Definition: codegen_neuron_cpp_visitor.cpp:597
nmodl::ast::LonDiffuse
Represent LONGITUDINAL_DIFFUSION statement in NMODL.
Definition: lon_diffuse.hpp:39
nmodl::codegen::CodegenNeuronCppVisitor::py_function_name
std::string py_function_name(const std::string &function_or_procedure_name) const
In non POINT_PROCESS mechanisms all functions and procedures need a py <func_or_proc_name> to be avai...
Definition: codegen_neuron_cpp_visitor.cpp:840
nmodl::codegen::ThreadVariableInfo::offset
size_t offset
The global variables ahead of this one require offset doubles to store.
Definition: codegen_neuron_cpp_visitor.hpp:73
nmodl::codegen::CodegenNeuronCppVisitor::print_node_data_structure
void print_node_data_structure(bool print_initializers)
Print the structure that wraps all node variables required for the NMODL.
Definition: codegen_neuron_cpp_visitor.cpp:1866
nmodl::codegen::CppObjectSpecifier::Inline
@ Inline
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::CodegenNeuronCppVisitor::visit_protect_statement
void visit_protect_statement(const ast::ProtectStatement &node) override
visit node of type ast::ProtectStatement
Definition: codegen_neuron_cpp_visitor.cpp:3067
nmodl::codegen::naming::INST_GLOBAL_MEMBER
static constexpr char INST_GLOBAL_MEMBER[]
instance struct member pointing to the global variable structure
Definition: codegen_naming.hpp:102
nmodl::codegen::CodegenNeuronCppVisitor::print_cvode_update
void print_cvode_update(const std::string &name, const ast::StatementBlock &block)
Print the CVODE update function name contained in block.
Definition: codegen_neuron_cpp_visitor.cpp:2901
nmodl::codegen::CodegenNeuronCppVisitor::print_make_instance
void print_make_instance() const
Print make_*_instance.
Definition: codegen_neuron_cpp_visitor.cpp:1807
nmodl::ast::StatementBlock
Represents block encapsulating list of statements.
Definition: statement_block.hpp:53
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::ast::ForNetcon
TODO.
Definition: for_netcon.hpp:39
nmodl::ast::ForNetcon::get_parameters
const ArgumentVector & get_parameters() const noexcept override
Getter for member variable ForNetcon::parameters.
Definition: for_netcon.hpp:176
nmodl::codegen::CodegenNeuronCppVisitor::print_setdata_functions
void print_setdata_functions()
Print NEURON functions related to setting global variables of the mechanism.
Definition: codegen_neuron_cpp_visitor.cpp:186
nmodl::codegen::ShadowUseStatement
Represents ion write statement during code generation.
Definition: codegen_cpp_visitor.hpp:166
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_variables_macros
void print_mechanism_variables_macros()
Print mechanism variables' related macros.
Definition: codegen_neuron_cpp_visitor.cpp:2571
nmodl::codegen::CodegenNeuronCppVisitor::threadargs_parameters
ParamVector threadargs_parameters()
The parameters for the four macros _threadargs*_.
Definition: codegen_neuron_cpp_visitor.cpp:614
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_constructor
void print_nrn_constructor() override
Print nrn_constructor function definition.
Definition: codegen_neuron_cpp_visitor.cpp:2104
nmodl::codegen::BlockType
BlockType
Helper to represent various block types.
Definition: codegen_cpp_visitor.hpp:56
nmodl::symtab::syminfo::Status::empty
@ empty
nmodl::codegen::CodegenNeuronCppVisitor::print_headers_include
void print_headers_include() override
Print all includes.
Definition: codegen_neuron_cpp_visitor.cpp:2536
nmodl::codegen::CodegenNeuronCppVisitor::print_check_table_entrypoint
void print_check_table_entrypoint()
Print all check_* function declarations.
Definition: codegen_neuron_cpp_visitor.cpp:139
nmodl::codegen::CodegenNeuronCppVisitor::external_method_parameters
const ParamVector external_method_parameters(bool table=false) noexcept override
Parameters for functions in generated code that are called back from external code.
Definition: codegen_neuron_cpp_visitor.cpp:603
nmodl::codegen::CodegenNeuronCppVisitor::visit_for_netcon
void visit_for_netcon(const ast::ForNetcon &node) override
visit node of type ast::ForNetcon
Definition: codegen_neuron_cpp_visitor.cpp:3016
nmodl::codegen::CodegenNeuronCppVisitor::print_function_or_procedure
void print_function_or_procedure(const ast::Block &node, const std::string &name, const std::unordered_set< CppObjectSpecifier > &specifiers={ CppObjectSpecifier::Inline}) override
Print nmodl function or procedure (common code)
Definition: codegen_neuron_cpp_visitor.cpp:244
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::ThreadVariableInfo::symbol
const std::shared_ptr< symtab::Symbol > symbol
Definition: codegen_neuron_cpp_visitor.hpp:63
config.h
Version information and units file path.
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_current
void print_nrn_current(const ast::BreakpointBlock &node) override
Print the nrn_current kernel.
Definition: codegen_neuron_cpp_visitor.cpp:2360
nmodl::codegen::CodegenNeuronCppVisitor::position_of_float_var
int position_of_float_var(const std::string &name) const override
Determine the position in the data array for a given float variable.
Definition: codegen_neuron_cpp_visitor.cpp:69
nmodl::codegen::CodegenNeuronCppVisitor::get_variable_name
std::string get_variable_name(const std::string &name, bool use_instance=true) const override
Determine the C++ string to replace variable names with.
Definition: codegen_neuron_cpp_visitor.cpp:989
nmodl::codegen::CodegenNeuronCppVisitor::print_hoc_py_wrapper_call_impl
void print_hoc_py_wrapper_call_impl(const ast::Block *function_or_procedure_block, InterpreterWrapper wrapper_type)
Print the code that calls the impl from the HOC/Py wrapper.
Definition: codegen_neuron_cpp_visitor.cpp:287
nmodl::codegen::CodegenNeuronCppVisitor::print_codegen_routines_nothing
void print_codegen_routines_nothing()
SUFFIX nothing is special.
Definition: codegen_neuron_cpp_visitor.cpp:2698
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::codegen::CodegenNeuronCppVisitor::print_make_node_data
void print_make_node_data() const
Print make_*_node_data.
Definition: codegen_neuron_cpp_visitor.cpp:1880
nmodl::ast::Ast::get_statement_block
virtual std::shared_ptr< StatementBlock > get_statement_block() const
Return associated statement block for the AST node.
Definition: ast.cpp:32
nmodl::codegen::CodegenNeuronCppVisitor::simulator_name
std::string simulator_name() override
Name of the simulator the code was generated for.
Definition: codegen_neuron_cpp_visitor.cpp:46
nmodl::codegen::CodegenNeuronCppVisitor::print_function_procedure_helper
void print_function_procedure_helper(const ast::Block &node) override
Common helper function to help printing function or procedure blocks.
Definition: codegen_neuron_cpp_visitor.cpp:273
nmodl::codegen::CodegenNeuronCppVisitor::process_verbatim_text
std::string process_verbatim_text(const std::string &verbatim)
Definition: codegen_neuron_cpp_visitor.cpp:775
nmodl::codegen::naming::FOR_NETCON_SEMANTIC
static constexpr char FOR_NETCON_SEMANTIC[]
semantic type for for_netcon statement
Definition: codegen_naming.hpp:141
nmodl::codegen::naming::NTHREAD_T_VARIABLE
static constexpr char NTHREAD_T_VARIABLE[]
t variable in neuron thread structure
Definition: codegen_naming.hpp:105
nmodl::codegen::CppObjectSpecifier::Static
@ Static
nmodl::codegen::CodegenNeuronCppVisitor::add_variable_point_process
void add_variable_point_process(std::vector< IndexVariableInfo > &variables) override
Add the variable point_process during get_int_variables.
Definition: codegen_neuron_cpp_visitor.cpp:562
rename_visitor.hpp
Blindly rename given variable to new name
nmodl::codegen::BlockType::State
@ State
derivative block
nmodl::codegen::naming::DIAM_VARIABLE
static constexpr char DIAM_VARIABLE[]
inbuilt neuron variable for diameter of the compartment
Definition: codegen_naming.hpp:63
nmodl::codegen::naming::INTERNAL_THREAD_ARGS_COMMA
static constexpr char INTERNAL_THREAD_ARGS_COMMA[]
variation of _threadargs_ for "internal" functions, with comma (maybe).
Definition: codegen_naming.hpp:192
nmodl::ast::Block::get_parameters
virtual const ArgumentVector & get_parameters() const
Definition: block.hpp:50
nmodl::visitor::VarUsageVisitor::variable_used
bool variable_used(const ast::Node &node, std::string name)
Definition: var_usage_visitor.cpp:26
nmodl::codegen::CodegenNeuronCppVisitor::nrn_thread_arguments
std::string nrn_thread_arguments() const override
Arguments for "_threadargs_" macro in neuron implementation.
Definition: codegen_neuron_cpp_visitor.cpp:625
nmodl::stringutils::ends_with
static bool ends_with(const std::string &haystack, const std::string &needle)
Check if haystack ends with needle.
Definition: string_utils.hpp:135
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::CodegenNeuronCppVisitor::ldifusfunc3_parameters
ParamVector ldifusfunc3_parameters() const
Parameters for what NEURON calls ldifusfunc3_t.
Definition: codegen_neuron_cpp_visitor.cpp:484
nmodl::codegen::CodegenNeuronCppVisitor::cvode_update_parameters
ParamVector cvode_update_parameters()
Get the parameters for functions that update state at given timestep in CVODE.
Definition: codegen_neuron_cpp_visitor.cpp:2840
nmodl::codegen::Python
@ Python
Definition: codegen_neuron_cpp_visitor.hpp:52
nmodl::codegen::CodegenNeuronCppVisitor::print_codegen_routines
void print_codegen_routines() override
Print entry point to code generation.
Definition: codegen_neuron_cpp_visitor.cpp:2710
nmodl::codegen::BlockType::Initial
@ Initial
initial block
nmodl::symtab::syminfo::Status::renamed
@ renamed
renamed
nmodl::codegen::CodegenNeuronCppVisitor::append_conc_write_statements
void append_conc_write_statements(std::vector< ShadowUseStatement > &statements, const Ion &ion, const std::string &concentration) override
Generate Function call statement for nrn_wrote_conc.
Definition: codegen_neuron_cpp_visitor.cpp:862
nmodl::codegen::CodegenNeuronCppVisitor::print_longitudinal_diffusion_callbacks
void print_longitudinal_diffusion_callbacks()
Prints the callbacks required for LONGITUDINAL_DIFFUSION.
Definition: codegen_neuron_cpp_visitor.cpp:496
nmodl::codegen::CodegenNeuronCppVisitor::internal_method_parameters
ParamVector internal_method_parameters() override
Parameters for internally defined functions.
Definition: codegen_neuron_cpp_visitor.cpp:574
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::ast::Ast::get_parent
virtual Ast * get_parent() const
Parent getter.
Definition: ast.cpp:311
nmodl::ast::Ast::get_node_name
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
nmodl::codegen::CodegenNeuronCppVisitor::print_hoc_py_wrapper
void print_hoc_py_wrapper(const ast::Block *function_or_procedure_block, InterpreterWrapper wrapper_type)
Print the wrapper for calling FUNCION/PROCEDURES from HOC/Py.
Definition: codegen_neuron_cpp_visitor.cpp:417
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::codegen::CodegenNeuronCppVisitor::print_cvode_count
void print_cvode_count()
Print the CVODE function returning the number of ODEs to solve.
Definition: codegen_neuron_cpp_visitor.cpp:2857
nmodl::codegen::CodegenNeuronCppVisitor::net_receive_args
ParamVector net_receive_args()
Definition: codegen_neuron_cpp_visitor.cpp:2808
all.hpp
Auto generated AST classes declaration.
nmodl::codegen::CodegenNeuronCppVisitor::print_net_receive
void print_net_receive()
Print net_receive call-back.
Definition: codegen_neuron_cpp_visitor.cpp:2953
nmodl::codegen::CodegenNeuronCppVisitor::print_function_prototypes
void print_function_prototypes() override
Print function and procedures prototype declaration.
Definition: codegen_neuron_cpp_visitor.cpp:217
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_global_var_structure
void print_mechanism_global_var_structure(bool print_initializers) override
Print the structure that wraps all global variables used in the NMODL.
Definition: codegen_neuron_cpp_visitor.cpp:1160
nmodl::codegen::CodegenNeuronCppVisitor::print_hoc_py_wrapper_setup
void print_hoc_py_wrapper_setup(const ast::Block *function_or_procedure_block, InterpreterWrapper wrapper_type)
Print the setup code for HOC/Py wrapper.
Definition: codegen_neuron_cpp_visitor.cpp:324
nmodl::codegen::CodegenNeuronCppVisitor::namespace_name
std::string namespace_name() override
Name of "our" namespace.
Definition: codegen_neuron_cpp_visitor.cpp:857
nmodl::codegen::CodegenNeuronCppVisitor::print_global_macros
void print_global_macros()
Print NEURON global variable macros.
Definition: codegen_neuron_cpp_visitor.cpp:2554
nmodl::codegen::Ion::intra_conc_pointer_name
std::string intra_conc_pointer_name() const
Definition: codegen_info.hpp:186
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