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 <regex>
15 
16 #include "ast/all.hpp"
18 #include "config/config.h"
19 #include "utils/string_utils.hpp"
22 
23 namespace nmodl {
24 namespace codegen {
25 
26 using namespace ast;
27 
28 using visitor::RenameVisitor;
29 
31 
32 
33 /****************************************************************************************/
34 /* Generic information getters */
35 /****************************************************************************************/
36 
37 
39  return "NEURON";
40 }
41 
42 
44  return "C++ (api-compatibility)";
45 }
46 
47 
48 /****************************************************************************************/
49 /* Common helper routines accross codegen functions */
50 /****************************************************************************************/
51 
52 
53 int CodegenNeuronCppVisitor::position_of_float_var(const std::string& name) const {
54  const auto has_name = [&name](const SymbolType& symbol) { return symbol->get_name() == name; };
55  const auto var_iter =
56  std::find_if(codegen_float_variables.begin(), codegen_float_variables.end(), has_name);
57  if (var_iter != codegen_float_variables.end()) {
58  return var_iter - codegen_float_variables.begin();
59  } else {
60  throw std::logic_error(name + " variable not found");
61  }
62 }
63 
64 
65 int CodegenNeuronCppVisitor::position_of_int_var(const std::string& name) const {
66  const auto has_name = [&name](const IndexVariableInfo& index_var_symbol) {
67  return index_var_symbol.symbol->get_name() == name;
68  };
69  const auto var_iter =
70  std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), has_name);
71  if (var_iter != codegen_int_variables.end()) {
72  return var_iter - codegen_int_variables.begin();
73  } else {
74  throw std::logic_error(name + " variable not found");
75  }
76 }
77 
78 
79 /****************************************************************************************/
80 /* Backend specific routines */
81 /****************************************************************************************/
82 
83 
84 /// TODO: Edit for NEURON
86  return;
87 }
88 
90  if (optimize_ionvar_copies) {
91  throw std::runtime_error("Not implemented.");
92  }
93  return false;
94 }
95 
96 
97 /****************************************************************************************/
98 /* Printing routines for code generation */
99 /****************************************************************************************/
100 
101 
103  if (info.point_process) {
104  printer->add_multi_line(R"CODE(
105  /* Point Process specific functions */
106  static void* _hoc_create_pnt(Object* _ho) {
107  return create_point_process(_pointtype, _ho);
108  }
109  )CODE");
110  printer->push_block("static void _hoc_destroy_pnt(void* _vptr)");
111  if (info.is_watch_used() || info.for_netcon_used) {
112  printer->add_line("Prop* _prop = ((Point_process*)_vptr)->prop;");
113  }
114  if (info.is_watch_used()) {
115  printer->push_block("if (_prop)");
116  printer->fmt_line("_nrn_free_watch(_nrn_mechanism_access_dparam(_prop), {}, {});",
117  info.watch_count,
118  info.is_watch_used());
119  printer->pop_block();
120  }
121  if (info.for_netcon_used) {
122  printer->push_block("if (_prop)");
123  printer->fmt_line(
124  "_nrn_free_fornetcon(&(_nrn_mechanism_access_dparam(_prop)[_fnc_index].literal_"
125  "value<void*>()));");
126  printer->pop_block();
127  }
128  printer->add_line("destroy_point_process(_vptr);");
129  printer->pop_block();
130  printer->add_multi_line(R"CODE(
131  static double _hoc_loc_pnt(void* _vptr) {
132  return loc_point_process(_pointtype, _vptr);
133  }
134 
135  static double _hoc_has_loc(void* _vptr) {
136  return has_loc_point(_vptr);
137  }
138 
139  static double _hoc_get_loc_pnt(void* _vptr) {
140  return (get_loc_point_process(_vptr));
141  }
142  )CODE");
143  }
144 }
145 
146 
148  printer->add_line("/* Neuron setdata functions */");
149  printer->add_line("extern void _nrn_setdata_reg(int, void(*)(Prop*));");
150  printer->push_block("static void _setdata(Prop* _prop)");
151  if (!info.point_process) {
152  printer->add_multi_line(R"CODE(
153  _extcall_prop = _prop;
154  _prop_id = _nrn_get_prop_id(_prop);
155  )CODE");
156  }
157  if (!info.vectorize) {
158  printer->add_multi_line(R"CODE(
159  neuron::legacy::set_globals_from_prop(_prop, _ml_real, _ml, _iml);
160  _ppvar = _nrn_mechanism_access_dparam(_prop);
161  )CODE");
162  }
163  printer->pop_block();
164 
165  if (info.point_process) {
166  printer->push_block("static void _hoc_setdata(void* _vptr)");
167  printer->add_multi_line(R"CODE(
168  Prop* _prop;
169  _prop = ((Point_process*)_vptr)->prop;
170  _setdata(_prop);
171  )CODE");
172  } else {
173  printer->push_block("static void _hoc_setdata()");
174  printer->add_multi_line(R"CODE(
175  Prop *_prop = hoc_getdata_range(mech_type);
176  _setdata(_prop);
177  hoc_retpushx(1.);
178  )CODE");
179  }
180  printer->pop_block();
181 
182  printer->add_line("/* Mechanism procedures and functions */");
183  for (const auto& node: info.functions) {
184  print_function_declaration(*node, node->get_node_name());
185  printer->add_text(';');
186  printer->add_newline();
187  }
188  for (const auto& node: info.procedures) {
189  print_function_declaration(*node, node->get_node_name());
190  printer->add_text(';');
191  printer->add_newline();
192  }
193 }
194 
195 
196 /// TODO: Edit for NEURON
198  printer->add_newline(2);
199 
200  print_point_process_function_definitions();
201  print_setdata_functions();
202 
203  /// TODO: Add mechanism function and procedures declarations
204 }
205 
206 
208  const std::string& name) {
209  printer->add_newline(2);
210  print_function_declaration(node, name);
211  printer->add_text(" ");
212  printer->push_block();
213 
214  // function requires return variable declaration
215  if (node.is_function_block()) {
216  auto type = default_float_data_type();
217  printer->fmt_line("{} ret_{} = 0.0;", type, name);
218  } else {
219  printer->fmt_line("int ret_{} = 0;", name);
220  }
221 
222  print_statement_block(*node.get_statement_block(), false, false);
223  printer->fmt_line("return ret_{};", name);
224  printer->pop_block();
225 }
226 
227 
229  auto name = node.get_node_name();
230 
231  if (info.function_uses_table(name)) {
232  throw std::runtime_error("Function tables not implemented.");
233  } else {
234  print_function_or_procedure(node, name);
235  }
236 }
237 
238 
240  print_function_procedure_helper(node);
241 }
242 
243 
245  auto name = node.get_node_name();
246 
247  // name of return variable
248  std::string return_var;
249  if (info.function_uses_table(name)) {
250  throw std::runtime_error("Function tables not implemented.");
251  } else {
252  return_var = "ret_" + name;
253  }
254 
255  // first rename return variable name
256  auto block = node.get_statement_block().get();
257  RenameVisitor v(name, return_var);
258  block->accept(v);
259 
260  print_function_procedure_helper(node);
261 }
262 
264  const ast::Block* function_or_procedure_block,
265  InterpreterWrapper wrapper_type) {
266  if (info.point_process && wrapper_type == InterpreterWrapper::Python) {
267  return;
268  }
269  const auto block_name = function_or_procedure_block->get_node_name();
270  if (info.point_process) {
271  printer->fmt_push_block("static double _hoc_{}(void* _vptr)", block_name);
272  } else if (wrapper_type == InterpreterWrapper::HOC) {
273  printer->fmt_push_block("static void _hoc_{}(void)", block_name);
274  } else {
275  printer->fmt_push_block("static double _npy_{}(Prop* _prop)", block_name);
276  }
277  printer->add_multi_line(R"CODE(
278  double _r{};
279  Datum* _ppvar;
280  Datum* _thread;
281  NrnThread* _nt;
282  )CODE");
283  if (info.point_process) {
284  printer->add_multi_line(R"CODE(
285  auto* const _pnt = static_cast<Point_process*>(_vptr);
286  auto* const _p = _pnt->prop;
287  if (!_p) {
288  hoc_execerror("POINT_PROCESS data instance not valid", NULL);
289  }
290  _nrn_mechanism_cache_instance _ml_real{_p};
291  auto* const _ml = &_ml_real;
292  size_t const id{};
293  _ppvar = _nrn_mechanism_access_dparam(_p);
294  _thread = _extcall_thread.data();
295  _nt = static_cast<NrnThread*>(_pnt->_vnt);
296  )CODE");
297  } else if (wrapper_type == InterpreterWrapper::HOC) {
298  if (program_symtab->lookup(block_name)->has_all_properties(NmodlType::use_range_ptr_var)) {
299  printer->push_block("if (!_prop_id)");
300  printer->fmt_line(
301  "hoc_execerror(\"No data for {}_{}. Requires prior call to setdata_{} and that the "
302  "specified mechanism instance still be in existence.\", NULL);",
303  function_or_procedure_block->get_node_name(),
304  info.mod_suffix,
305  info.mod_suffix);
306  printer->pop_block();
307  printer->add_line("Prop* _local_prop = _extcall_prop;");
308  } else {
309  printer->add_line("Prop* _local_prop = _prop_id ? _extcall_prop : nullptr;");
310  }
311  printer->add_multi_line(R"CODE(
312  _nrn_mechanism_cache_instance _ml_real{_local_prop};
313  auto* const _ml = &_ml_real;
314  size_t const id{};
315  _ppvar = _local_prop ? _nrn_mechanism_access_dparam(_local_prop) : nullptr;
316  _thread = _extcall_thread.data();
317  _nt = nrn_threads;
318  )CODE");
319  } else { // wrapper_type == InterpreterWrapper::Python
320  printer->add_multi_line(R"CODE(
321  _nrn_mechanism_cache_instance _ml_real{_prop};
322  auto* const _ml = &_ml_real;
323  size_t const id{};
324  _ppvar = _nrn_mechanism_access_dparam(_prop);
325  _thread = _extcall_thread.data();
326  _nt = nrn_threads;
327  )CODE");
328  }
329  printer->fmt_line("auto inst = make_instance_{}(_ml_real);", info.mod_suffix);
330  if (info.function_uses_table(block_name)) {
331  printer->fmt_line("_check_{}({})", block_name, internal_method_arguments());
332  }
333  const auto get_func_call_str = [&]() {
334  const auto params = function_or_procedure_block->get_parameters();
335  const auto func_proc_name = block_name + "_" + info.mod_suffix;
336  auto func_call = fmt::format("{}({}", func_proc_name, internal_method_arguments());
337  for (int i = 0; i < params.size(); ++i) {
338  func_call.append(fmt::format(", *getarg({})", i + 1));
339  }
340  func_call.append(")");
341  return func_call;
342  };
343  if (function_or_procedure_block->is_function_block()) {
344  printer->add_indent();
345  printer->fmt_text("_r = {};", get_func_call_str());
346  printer->add_newline();
347  } else {
348  printer->add_line("_r = 1.;");
349  printer->fmt_line("{};", get_func_call_str());
350  }
351  if (info.point_process || wrapper_type != InterpreterWrapper::HOC) {
352  printer->add_line("return(_r);");
353  } else if (wrapper_type == InterpreterWrapper::HOC) {
354  printer->add_line("hoc_retpushx(_r);");
355  }
356  printer->pop_block();
357 }
358 
359 
361  for (const auto& procedure: info.procedures) {
362  print_hoc_py_wrapper_function_body(procedure, InterpreterWrapper::HOC);
363  print_hoc_py_wrapper_function_body(procedure, InterpreterWrapper::Python);
364  }
365  for (const auto& function: info.functions) {
366  print_hoc_py_wrapper_function_body(function, InterpreterWrapper::HOC);
367  print_hoc_py_wrapper_function_body(function, InterpreterWrapper::Python);
368  }
369 }
370 
371 
372 /****************************************************************************************/
373 /* Code-specific helper routines */
374 /****************************************************************************************/
375 
376 
378  return "_ml, inst, id, _ppvar, _thread, _nt";
379 }
380 
381 
383  ParamVector params;
384  params.emplace_back("", "_nrn_mechanism_cache_range*", "", "_ml");
385  params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst");
386  params.emplace_back("", "size_t", "", "id");
387  params.emplace_back("", "Datum*", "", "_ppvar");
388  params.emplace_back("", "Datum*", "", "_thread");
389  params.emplace_back("", "NrnThread*", "", "_nt");
390  return params;
391 }
392 
393 
394 /// TODO: Edit for NEURON
396  return {};
397 }
398 
399 
400 /// TODO: Edit for NEURON
401 const char* CodegenNeuronCppVisitor::external_method_parameters(bool table) noexcept {
402  return {};
403 }
404 
405 
406 /// TODO: Edit for NEURON
408  return {};
409 }
410 
411 
412 /// TODO: Edit for NEURON
414  return {};
415 }
416 
417 
418 /// TODO: Write for NEURON
419 std::string CodegenNeuronCppVisitor::process_verbatim_text(std::string const& text) {
420  return {};
421 }
422 
423 
424 /// TODO: Write for NEURON
426  return {};
427 };
428 
429 
431  const std::string& function_or_procedure_name) const {
432  return fmt::format("_hoc_{}", function_or_procedure_name);
433 }
434 
435 
437  const std::string& function_or_procedure_name) const {
438  return fmt::format("static {} {}(void{})",
439  info.point_process ? "double" : "void",
440  hoc_function_name(function_or_procedure_name),
441  info.point_process ? "*" : "");
442 }
443 
444 
446  const std::string& function_or_procedure_name) const {
447  return fmt::format("_npy_{}", function_or_procedure_name);
448 }
449 
450 
452  const std::string& function_or_procedure_name) const {
453  return fmt::format("static double {}(Prop*)", py_function_name(function_or_procedure_name));
454 }
455 
456 
457 /****************************************************************************************/
458 /* Code-specific printing routines for code generation */
459 /****************************************************************************************/
460 
461 
463  printer->add_newline(2);
464  printer->push_block("namespace neuron");
465 }
466 
467 
469  printer->pop_block();
470 }
471 
472 
473 std::string CodegenNeuronCppVisitor::conc_write_statement(const std::string& ion_name,
474  const std::string& concentration,
475  int index) {
476  // throw std::runtime_error("Not implemented.");
477  return "";
478 }
479 
480 /****************************************************************************************/
481 /* Routines for returning variable name */
482 /****************************************************************************************/
483 
484 
485 /// TODO: Edit for NEURON
487  bool use_instance) const {
488  auto name = symbol->get_name();
489  auto dimension = symbol->get_length();
490  // auto position = position_of_float_var(name);
491  if (symbol->is_array()) {
492  if (use_instance) {
493  return fmt::format("(inst.{}+id*{})", name, dimension);
494  }
495  throw std::runtime_error("Printing non-instance variables is not implemented.");
496  // return fmt::format("(data + {}*pnodecount + id*{})", position, dimension);
497  }
498  if (use_instance) {
499  return fmt::format("inst.{}[id]", name);
500  }
501  throw std::runtime_error("Not implemented.");
502  // return fmt::format("data[{}*pnodecount + id]", position);
503 }
504 
505 
506 /// TODO: Edit for NEURON
508  const std::string& name,
509  bool use_instance) const {
510  auto position = position_of_int_var(name);
511  if (symbol.is_index) {
512  if (use_instance) {
513  throw std::runtime_error("Not implemented. [wiejo]");
514  // return fmt::format("inst->{}[{}]", name, position);
515  }
516  throw std::runtime_error("Not implemented. [ncuwi]");
517  // return fmt::format("indexes[{}]", position);
518  }
519  if (symbol.is_integer) {
520  if (use_instance) {
521  throw std::runtime_error("Not implemented. [cnuoe]");
522  // return fmt::format("inst->{}[{}*pnodecount+id]", name, position);
523  }
524  throw std::runtime_error("Not implemented. [u32ow]");
525  // return fmt::format("indexes[{}*pnodecount+id]", position);
526  }
527  if (use_instance) {
528  return fmt::format("(*inst.{}[id])", name);
529  }
530 
531  throw std::runtime_error("Not implemented. [nvueir]");
532  // auto data = symbol.is_vdata ? "_vdata" : "_data";
533  // return fmt::format("nt->{}[indexes[{}*pnodecount + id]]", data, position);
534 }
535 
536 
538  bool use_instance) const {
539  if (use_instance) {
540  return fmt::format("inst.{}->{}", naming::INST_GLOBAL_MEMBER, symbol->get_name());
541  } else {
542  return fmt::format("{}.{}", global_struct_instance(), symbol->get_name());
543  }
544 }
545 
546 
547 std::string CodegenNeuronCppVisitor::get_variable_name(const std::string& name,
548  bool use_instance) const {
549  const std::string& varname = update_if_ion_variable_name(name);
550 
551  auto symbol_comparator = [&varname](const SymbolType& sym) {
552  return varname == sym->get_name();
553  };
554 
555  auto index_comparator = [&varname](const IndexVariableInfo& var) {
556  return varname == var.symbol->get_name();
557  };
558 
559  // float variable
560  auto f = std::find_if(codegen_float_variables.begin(),
561  codegen_float_variables.end(),
562  symbol_comparator);
563  if (f != codegen_float_variables.end()) {
564  return float_variable_name(*f, use_instance);
565  }
566 
567  // integer variable
568  auto i =
569  std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), index_comparator);
570  if (i != codegen_int_variables.end()) {
571  return int_variable_name(*i, varname, use_instance);
572  }
573 
574  // global variable
575  auto g = std::find_if(codegen_global_variables.begin(),
576  codegen_global_variables.end(),
577  symbol_comparator);
578  if (g != codegen_global_variables.end()) {
579  return global_variable_name(*g, use_instance);
580  }
581 
582  if (varname == naming::NTHREAD_DT_VARIABLE) {
583  return std::string("_nt->_") + naming::NTHREAD_DT_VARIABLE;
584  }
585 
586  // t in net_receive method is an argument to function and hence it should
587  // be used instead of nt->_t which is current time of thread
588  if (varname == naming::NTHREAD_T_VARIABLE && !printing_net_receive) {
589  return std::string("_nt->_") + naming::NTHREAD_T_VARIABLE;
590  }
591 
592  auto const iter =
593  std::find_if(info.neuron_global_variables.begin(),
594  info.neuron_global_variables.end(),
595  [&varname](auto const& entry) { return entry.first->get_name() == varname; });
596  if (iter != info.neuron_global_variables.end()) {
597  std::string ret;
598  if (use_instance) {
599  ret = "*(inst->";
600  }
601  ret.append(varname);
602  if (use_instance) {
603  ret.append(")");
604  }
605  return ret;
606  }
607 
608  // otherwise return original name
609  return varname;
610 }
611 
612 
613 /****************************************************************************************/
614 /* Main printing routines for code generation */
615 /****************************************************************************************/
616 
617 
619  time_t current_time{};
620  time(&current_time);
621  std::string data_time_str{std::ctime(&current_time)};
622  auto version = nmodl::Version::NMODL_VERSION + " [" + nmodl::Version::GIT_REVISION + "]";
623 
624  printer->add_line("/*********************************************************");
625  printer->add_line("Model Name : ", info.mod_suffix);
626  printer->add_line("Filename : ", info.mod_file, ".mod");
627  printer->add_line("NMODL Version : ", nmodl_version());
628  printer->fmt_line("Vectorized : {}", info.vectorize);
629  printer->fmt_line("Threadsafe : {}", info.thread_safe);
630  printer->add_line("Created : ", stringutils::trim(data_time_str));
631  printer->add_line("Simulator : ", simulator_name());
632  printer->add_line("Backend : ", backend_name());
633  printer->add_line("NMODL Compiler : ", version);
634  printer->add_line("*********************************************************/");
635 }
636 
637 
639  printer->add_newline();
640  printer->add_multi_line(R"CODE(
641  #include <math.h>
642  #include <stdio.h>
643  #include <stdlib.h>
644  )CODE");
645  if (!info.vectorize) {
646  printer->add_line("#include <vector>");
647  }
648 }
649 
650 
652  printer->add_newline();
653  printer->add_multi_line(R"CODE(
654  #include "mech_api.h"
655  #include "neuron/cache/mechanism_range.hpp"
656  #include "nrniv_mf.h"
657  #include "section_fwd.hpp"
658  )CODE");
659 }
660 
661 
662 void CodegenNeuronCppVisitor::print_sdlists_init([[maybe_unused]] bool print_initializers) {
663  /// _initlists() should only be called once by the mechanism registration function
664  /// (_<mod_file>_reg())
665  printer->add_newline(2);
666  printer->push_block("static void _initlists()");
667  for (auto i = 0; i < info.prime_variables_by_order.size(); ++i) {
668  const auto& prime_var = info.prime_variables_by_order[i];
669  /// TODO: Something similar needs to happen for slist/dlist2 but I don't know their usage at
670  // the moment
671  /// TODO: We have to do checks and add errors similar to nocmodl in the
672  // SemanticAnalysisVisitor
673  if (prime_var->is_array()) {
674  /// TODO: Needs a for loop here. Look at
675  // https://github.com/neuronsimulator/nrn/blob/df001a436bcb4e23d698afe66c2a513819a6bfe8/src/nmodl/deriv.cpp#L524
676  /// TODO: Also needs a test
677  printer->fmt_push_block("for (int _i = 0; _i < {}; ++_i)", prime_var->get_length());
678  printer->fmt_line("/* {}[{}] */", prime_var->get_name(), prime_var->get_length());
679  printer->fmt_line("_slist1[{}+_i] = {{{}, _i}};",
680  i,
681  position_of_float_var(prime_var->get_name()));
682  const auto prime_var_deriv_name = "D" + prime_var->get_name();
683  printer->fmt_line("/* {}[{}] */", prime_var_deriv_name, prime_var->get_length());
684  printer->fmt_line("_dlist1[{}+_i] = {{{}, _i}};",
685  i,
686  position_of_float_var(prime_var_deriv_name));
687  printer->pop_block();
688  } else {
689  printer->fmt_line("/* {} */", prime_var->get_name());
690  printer->fmt_line("_slist1[{}] = {{{}, 0}};",
691  i,
692  position_of_float_var(prime_var->get_name()));
693  const auto prime_var_deriv_name = "D" + prime_var->get_name();
694  printer->fmt_line("/* {} */", prime_var_deriv_name);
695  printer->fmt_line("_dlist1[{}] = {{{}, 0}};",
696  i,
697  position_of_float_var(prime_var_deriv_name));
698  }
699  }
700  printer->pop_block();
701 }
702 
703 
705  const auto value_initialize = print_initializers ? "{}" : "";
706 
707  /// TODO: Print only global variables printed in NEURON
708  printer->add_newline(2);
709  printer->add_line("/* NEURON global variables */");
710  if (info.primes_size != 0) {
711  printer->fmt_line("static neuron::container::field_index _slist1[{0}], _dlist1[{0}];",
712  info.primes_size);
713  }
714 
715  for (const auto& ion: info.ions) {
716  printer->fmt_line("static Symbol* _{}_sym;", ion.name);
717  }
718 
719  printer->add_line("static int mech_type;");
720 
721  if (info.point_process) {
722  printer->add_line("static int _pointtype;");
723  } else {
724  printer->add_multi_line(R"CODE(
725  static Prop* _extcall_prop;
726  /* _prop_id kind of shadows _extcall_prop to allow validity checking. */
727  static _nrn_non_owning_id_without_container _prop_id{};)CODE");
728  }
729 
730  printer->fmt_line("static int {} = {};",
732  info.pointer_variables.size() > 0
733  ? static_cast<int>(info.pointer_variables.size())
734  : -1);
735 
736  printer->add_line("static _nrn_mechanism_std_vector<Datum> _extcall_thread;");
737 
738  // Start printing the CNRN-style global variables.
739  auto float_type = default_float_data_type();
740  printer->add_newline(2);
741  printer->add_line("/** all global variables */");
742  printer->fmt_push_block("struct {}", global_struct());
743 
744  if (!info.ions.empty()) {
745  // TODO implement these when needed.
746  }
747 
748  if (!info.vectorize && !info.top_local_variables.empty()) {
749  throw std::runtime_error("Not implemented, global vectorize something.");
750  }
751 
752  if (!info.thread_variables.empty()) {
753  throw std::runtime_error("Not implemented, global thread variables.");
754  }
755 
756  if (info.table_count > 0) {
757  throw std::runtime_error("Not implemented, global table count.");
758  }
759 
760  for (const auto& var: info.state_vars) {
761  auto name = var->get_name() + "0";
762  auto symbol = program_symtab->lookup(name);
763  if (symbol == nullptr) {
764  printer->fmt_line("{} {}{};", float_type, name, value_initialize);
765  codegen_global_variables.push_back(make_symbol(name));
766  }
767  }
768 
769  for (const auto& var: info.global_variables) {
770  auto name = var->get_name();
771  auto length = var->get_length();
772  if (var->is_array()) {
773  printer->fmt_line("{} {}[{}] /* TODO init const-array */;", float_type, name, length);
774  } else {
775  double value{};
776  if (auto const& value_ptr = var->get_value()) {
777  value = *value_ptr;
778  }
779  printer->fmt_line("{} {}{};",
780  float_type,
781  name,
782  print_initializers ? fmt::format("{{{:g}}}", value) : std::string{});
783  }
784  codegen_global_variables.push_back(var);
785  }
786 
787 
788  for (const auto& f: info.function_tables) {
789  throw std::runtime_error("Not implemented, global function tables.");
790  }
791 
792  if (info.vectorize && info.thread_data_index) {
793  throw std::runtime_error("Not implemented, global vectorize something else.");
794  }
795 
796  printer->pop_block(";");
797 
798  print_global_var_struct_assertions();
799  print_global_var_struct_decl();
800 }
801 
802 /// TODO: Same as CoreNEURON?
804  /// TODO: Write HocParmLimits and other HOC global variables (delta_t)
805  // Probably needs more changes
806  auto variable_printer =
807  [&](const std::vector<SymbolType>& variables, bool if_array, bool if_vector) {
808  for (const auto& variable: variables) {
809  if (variable->is_array() == if_array) {
810  // false => do not use the instance struct, which is not
811  // defined in the global declaration that we are printing
812  auto name = get_variable_name(variable->get_name(), false);
813  auto ename = add_escape_quote(variable->get_name() + "_" + info.mod_suffix);
814  auto length = variable->get_length();
815  if (if_vector) {
816  printer->fmt_line("{{{}, {}, {}}},", ename, name, length);
817  } else {
818  printer->fmt_line("{{{}, &{}}},", ename, name);
819  }
820  }
821  }
822  };
823 
824  auto globals = info.global_variables;
825  auto thread_vars = info.thread_variables;
826 
827  if (info.table_count > 0) {
828  globals.push_back(make_symbol(naming::USE_TABLE_VARIABLE));
829  }
830 
831  printer->add_newline(2);
832  printer->add_line("/** connect global (scalar) variables to hoc -- */");
833  printer->add_line("static DoubScal hoc_scalar_double[] = {");
834  printer->increase_indent();
835  variable_printer(globals, false, false);
836  variable_printer(thread_vars, false, false);
837  printer->add_line("{nullptr, nullptr}");
838  printer->decrease_indent();
839  printer->add_line("};");
840 
841  printer->add_newline(2);
842  printer->add_line("/** connect global (array) variables to hoc -- */");
843  printer->add_line("static DoubVec hoc_vector_double[] = {");
844  printer->increase_indent();
845  variable_printer(globals, true, true);
846  variable_printer(thread_vars, true, true);
847  printer->add_line("{nullptr, nullptr, 0}");
848  printer->decrease_indent();
849  printer->add_line("};");
850 
851  printer->add_newline(2);
852  printer->add_line("/* declaration of user functions */");
853  for (const auto& procedure: info.procedures) {
854  const auto proc_name = procedure->get_node_name();
855  printer->fmt_line("{};", hoc_function_signature(proc_name));
856  }
857  for (const auto& function: info.functions) {
858  const auto func_name = function->get_node_name();
859  printer->fmt_line("{};", hoc_function_signature(func_name));
860  }
861  if (!info.point_process) {
862  for (const auto& procedure: info.procedures) {
863  const auto proc_name = procedure->get_node_name();
864  printer->fmt_line("{};", py_function_signature(proc_name));
865  }
866  for (const auto& function: info.functions) {
867  const auto func_name = function->get_node_name();
868  printer->fmt_line("{};", py_function_signature(func_name));
869  }
870  }
871 
872  printer->add_newline(2);
873  printer->add_line("/* connect user functions to hoc names */");
874  printer->add_line("static VoidFunc hoc_intfunc[] = {");
875  printer->increase_indent();
876  if (info.point_process) {
877  printer->add_line("{0, 0}");
878  printer->decrease_indent();
879  printer->add_line("};");
880  printer->add_line("static Member_func _member_func[] = {");
881  printer->increase_indent();
882  printer->add_multi_line(R"CODE(
883  {"loc", _hoc_loc_pnt},
884  {"has_loc", _hoc_has_loc},
885  {"get_loc", _hoc_get_loc_pnt},)CODE");
886  } else {
887  printer->fmt_line("{{\"setdata_{}\", _hoc_setdata}},", info.mod_suffix);
888  }
889 
890  for (const auto& procedure: info.procedures) {
891  const auto proc_name = procedure->get_node_name();
892  printer->fmt_line("{{\"{}{}\", {}}},",
893  proc_name,
894  info.rsuffix,
895  hoc_function_name(proc_name));
896  }
897  for (const auto& function: info.functions) {
898  const auto func_name = function->get_node_name();
899  printer->fmt_line("{{\"{}{}\", {}}},",
900  func_name,
901  info.rsuffix,
902  hoc_function_name(func_name));
903  }
904 
905  printer->add_line("{0, 0}");
906  printer->decrease_indent();
907  printer->add_line("};");
908  if (!info.point_process) {
909  printer->push_block("static NPyDirectMechFunc npy_direct_func_proc[] =");
910  for (const auto& procedure: info.procedures) {
911  const auto proc_name = procedure->get_node_name();
912  printer->fmt_line("{{\"{}\", {}}},", proc_name, py_function_name(proc_name));
913  }
914  for (const auto& function: info.functions) {
915  const auto func_name = function->get_node_name();
916  printer->fmt_line("{{\"{}\", {}}},", func_name, py_function_name(func_name));
917  }
918  printer->pop_block(";");
919  }
920 }
921 
923  /// TODO: Write this according to NEURON
924  printer->add_newline(2);
925  printer->add_line("/** register channel with the simulator */");
926  printer->fmt_push_block("extern \"C\" void _{}_reg()", info.mod_file);
927  printer->add_line("_initlists();");
928 
929  printer->add_newline();
930 
931  for (const auto& ion: info.ions) {
932  printer->fmt_line("ion_reg(\"{}\", {});", ion.name, "-10000.");
933  }
934  printer->add_newline();
935 
936  if (info.diam_used) {
937  printer->add_line("_morphology_sym = hoc_lookup(\"morphology\");");
938  printer->add_newline();
939  }
940 
941  for (const auto& ion: info.ions) {
942  printer->fmt_line("_{0}_sym = hoc_lookup(\"{0}_ion\");", ion.name);
943  }
944 
945  printer->add_newline();
946 
947  const auto compute_functions_parameters =
948  breakpoint_exist()
949  ? fmt::format("{}, {}, {}",
950  nrn_cur_required() ? method_name(naming::NRN_CUR_METHOD) : "nullptr",
951  method_name(naming::NRN_JACOB_METHOD),
952  nrn_state_required() ? method_name(naming::NRN_STATE_METHOD) : "nullptr")
953  : "nullptr, nullptr, nullptr";
954  const auto register_mech_args = fmt::format("{}, {}, {}, {}, {}, {}",
955  get_channel_info_var_name(),
956  method_name(naming::NRN_ALLOC_METHOD),
957  compute_functions_parameters,
958  method_name(naming::NRN_INIT_METHOD),
960  1 + info.thread_data_index);
961  if (info.point_process) {
962  printer->fmt_line(
963  "_pointtype = point_register_mech({}, _hoc_create_pnt, _hoc_destroy_pnt, "
964  "_member_func);",
965  register_mech_args);
966  } else {
967  printer->fmt_line("register_mech({});", register_mech_args);
968  }
969 
970  /// type related information
971  printer->add_newline();
972  printer->fmt_line("mech_type = nrn_get_mechtype({}[1]);", get_channel_info_var_name());
973 
974  /// Call _nrn_mechanism_register_data_fields() with the correct arguments
975  /// Geenerated code follows the style underneath
976  ///
977  /// _nrn_mechanism_register_data_fields(mech_type,
978  /// _nrn_mechanism_field<double>{"var_name"}, /* float var index 0 */
979  /// ...
980  /// );
981  ///
982  /// TODO: More things to add here
983  printer->add_line("_nrn_mechanism_register_data_fields(mech_type,");
984  printer->increase_indent();
985 
986  const auto codegen_float_variables_size = codegen_float_variables.size();
987  std::vector<std::string> mech_register_args;
988 
989  for (int i = 0; i < codegen_float_variables_size; ++i) {
990  const auto& float_var = codegen_float_variables[i];
991  if (float_var->is_array()) {
992  mech_register_args.push_back(
993  fmt::format("_nrn_mechanism_field<double>{{\"{}\", {}}} /* {} */",
994  float_var->get_name(),
995  float_var->get_length(),
996  i));
997  } else {
998  mech_register_args.push_back(fmt::format(
999  "_nrn_mechanism_field<double>{{\"{}\"}} /* {} */", float_var->get_name(), i));
1000  }
1001  }
1002 
1003  const auto codegen_int_variables_size = codegen_int_variables.size();
1004  for (int i = 0; i < codegen_int_variables_size; ++i) {
1005  const auto& int_var = codegen_int_variables[i];
1006  const auto& name = int_var.symbol->get_name();
1007  if (i != info.semantics[i].index) {
1008  throw std::runtime_error("Broken logic.");
1009  }
1010 
1011  auto type = (name == naming::POINT_PROCESS_VARIABLE) ? "Point_process*" : "double*";
1012  mech_register_args.push_back(
1013  fmt::format("_nrn_mechanism_field<{}>{{\"{}\", \"{}\"}} /* {} */",
1014  type,
1015  name,
1016  info.semantics[i].name,
1017  i));
1018  }
1019  if (info.emit_cvode) {
1020  mech_register_args.push_back(
1021  "_nrn_mechanism_field<int>{\"_cvode_ieq\", \"cvodeieq\"} /* 0 */");
1022  }
1023 
1024  printer->add_multi_line(fmt::format("{}", fmt::join(mech_register_args, ",\n")));
1025 
1026  printer->decrease_indent();
1027  printer->add_line(");");
1028  printer->add_newline();
1029 
1030  printer->fmt_line("hoc_register_prop_size(mech_type, {}, {});",
1031  codegen_float_variables_size,
1032  codegen_int_variables_size);
1033 
1034  for (int i = 0; i < codegen_int_variables_size; ++i) {
1035  const auto& int_var = codegen_int_variables[i];
1036  const auto& name = int_var.symbol->get_name();
1037  if (i != info.semantics[i].index) {
1038  throw std::runtime_error("Broken logic.");
1039  }
1040 
1041  printer->fmt_line("hoc_register_dparam_semantics(mech_type, {}, \"{}\");",
1042  i,
1043  info.semantics[i].name);
1044  }
1045 
1046  printer->add_line("hoc_register_var(hoc_scalar_double, hoc_vector_double, hoc_intfunc);");
1047  if (!info.point_process) {
1048  printer->add_line("hoc_register_npy_direct(mech_type, npy_direct_func_proc);");
1049  }
1050  printer->pop_block();
1051 }
1052 
1053 
1055  auto const value_initialize = print_initializers ? "{}" : "";
1056  auto int_type = default_int_data_type();
1057  printer->add_newline(2);
1058  printer->add_line("/** all mechanism instance variables and global variables */");
1059  printer->fmt_push_block("struct {} ", instance_struct());
1060 
1061  for (auto const& [var, type]: info.neuron_global_variables) {
1062  auto const name = var->get_name();
1063  printer->fmt_line("{}* {}{};",
1064  type,
1065  name,
1066  print_initializers ? fmt::format("{{&coreneuron::{}}}", name)
1067  : std::string{});
1068  }
1069  for (auto& var: codegen_float_variables) {
1070  const auto& name = var->get_name();
1071  printer->fmt_line("double* {}{};", name, value_initialize);
1072  }
1073  for (auto& var: codegen_int_variables) {
1074  const auto& name = var.symbol->get_name();
1075  if (name == naming::POINT_PROCESS_VARIABLE) {
1076  continue;
1077  } else if (var.is_index || var.is_integer) {
1078  auto qualifier = var.is_constant ? "const " : "";
1079  printer->fmt_line("{}{}* const* {}{};", qualifier, int_type, name, value_initialize);
1080  } else {
1081  auto qualifier = var.is_constant ? "const " : "";
1082  auto type = var.is_vdata ? "void*" : default_float_data_type();
1083  printer->fmt_line("{}{}* const* {}{};", qualifier, type, name, value_initialize);
1084  }
1085  }
1086 
1087  printer->fmt_line("{}* {}{};",
1088  global_struct(),
1090  print_initializers ? fmt::format("{{&{}}}", global_struct_instance())
1091  : std::string{});
1092  printer->pop_block(";");
1093 }
1094 
1096  printer->add_newline(2);
1097  printer->fmt_push_block("static {} make_instance_{}(_nrn_mechanism_cache_range& _ml)",
1098  instance_struct(),
1099  info.mod_suffix);
1100  printer->fmt_push_block("return {}", instance_struct());
1101 
1102  std::vector<std::string> make_instance_args;
1103 
1104  const auto codegen_float_variables_size = codegen_float_variables.size();
1105  for (int i = 0; i < codegen_float_variables_size; ++i) {
1106  const auto& float_var = codegen_float_variables[i];
1107  if (float_var->is_array()) {
1108  make_instance_args.push_back(
1109  fmt::format("_ml.template data_array_ptr<{}, {}>()", i, float_var->get_length()));
1110  } else {
1111  make_instance_args.push_back(fmt::format("_ml.template fpfield_ptr<{}>()", i));
1112  }
1113  }
1114 
1115  const auto codegen_int_variables_size = codegen_int_variables.size();
1116  for (size_t i = 0; i < codegen_int_variables_size; ++i) {
1117  const auto& var = codegen_int_variables[i];
1118  auto name = var.symbol->get_name();
1119  auto const variable = [&var, i]() -> std::string {
1120  if (var.is_index || var.is_integer) {
1121  return "";
1122  } else if (var.is_vdata) {
1123  return "";
1124  } else {
1125  return fmt::format("_ml.template dptr_field_ptr<{}>()", i);
1126  }
1127  }();
1128  if (variable != "") {
1129  make_instance_args.push_back(variable);
1130  }
1131  }
1132 
1133  printer->add_multi_line(fmt::format("{}", fmt::join(make_instance_args, ",\n")));
1134 
1135  printer->pop_block(";");
1136  printer->pop_block();
1137 }
1138 
1140  auto const value_initialize = print_initializers ? "{}" : "";
1141  printer->add_newline(2);
1142  printer->fmt_push_block("struct {} ", node_data_struct());
1143 
1144  // Pointers to node variables
1145  printer->add_line("int const * nodeindices;");
1146  printer->add_line("double const * node_voltages;");
1147  printer->add_line("double * node_rhs;");
1148  printer->add_line("int nodecount;");
1149 
1150  printer->pop_block(";");
1151 }
1152 
1154  printer->add_newline(2);
1155  printer->fmt_push_block("static {} make_node_data_{}(NrnThread& _nt, Memb_list& _ml_arg)",
1156  node_data_struct(),
1157  info.mod_suffix);
1158 
1159  std::vector<std::string> make_node_data_args;
1160  make_node_data_args.push_back("_ml_arg.nodeindices");
1161  make_node_data_args.push_back("_nt.node_voltage_storage()");
1162  make_node_data_args.push_back("_nt.node_rhs_storage()");
1163  make_node_data_args.push_back("_ml_arg.nodecount");
1164 
1165  printer->fmt_push_block("return {}", node_data_struct());
1166  printer->add_multi_line(fmt::format("{}", fmt::join(make_node_data_args, ",\n")));
1167 
1168  printer->pop_block(";");
1169  printer->pop_block();
1170 }
1171 
1172 
1174  // read ion statements
1175  auto read_statements = ion_read_statements(BlockType::Initial);
1176  for (auto& statement: read_statements) {
1177  printer->add_line(statement);
1178  }
1179 
1180  // initial block
1181  if (node != nullptr) {
1182  const auto& block = node->get_statement_block();
1183  print_statement_block(*block, false, false);
1184  }
1185 
1186  // write ion statements
1187  auto write_statements = ion_write_statements(BlockType::Initial);
1188  for (auto& statement: write_statements) {
1189  auto text = process_shadow_update_statement(statement, BlockType::Initial);
1190  printer->add_line(text);
1191  }
1192 }
1193 
1194 
1196  const std::string& function_name) {
1197  std::string method = function_name.empty() ? compute_method_name(type) : function_name;
1198  std::string args =
1199  "_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* _ml_arg, int "
1200  "_type";
1201  printer->fmt_push_block("void {}({})", method, args);
1202 
1203  printer->add_line("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};");
1204  printer->fmt_line("auto inst = make_instance_{}(_lmr);", info.mod_suffix);
1205  printer->fmt_line("auto node_data = make_node_data_{}(*_nt, *_ml_arg);", info.mod_suffix);
1206 
1207  printer->add_line("auto nodecount = _ml_arg->nodecount;");
1208 }
1209 
1210 
1211 void CodegenNeuronCppVisitor::print_nrn_init(bool skip_init_check) {
1212  printer->add_newline(2);
1213 
1214  print_global_function_common_code(BlockType::Initial);
1215 
1216  printer->push_block("for (int id = 0; id < nodecount; id++)");
1217  print_initial_block(info.initial_node);
1218  printer->pop_block();
1219 
1220  printer->pop_block();
1221 }
1222 
1224  printer->add_newline(2);
1225  printer->add_line("/** nrn_jacob function */");
1226 
1227  printer->fmt_line(
1228  "static void {}(_nrn_model_sorted_token const& _sorted_token, NrnThread* "
1229  "_nt, Memb_list* _ml_arg, int _type) {{}}",
1230  method_name(naming::NRN_JACOB_METHOD));
1231 }
1232 
1233 
1234 /// TODO: Edit for NEURON
1236  return;
1237 }
1238 
1239 
1240 /// TODO: Edit for NEURON
1242  return;
1243 }
1244 
1245 
1246 /// TODO: Print the equivalent of `nrn_alloc_<mech_name>`
1248  printer->add_newline(2);
1249 
1250  auto method = method_name(naming::NRN_ALLOC_METHOD);
1251  printer->fmt_push_block("static void {}(Prop* _prop)", method);
1252  printer->add_multi_line(R"CODE(
1253  Prop *prop_ion{};
1254  Datum *_ppvar{};
1255  )CODE");
1256 
1257  if (info.point_process) {
1258  printer->push_block("if (nrn_point_prop_)");
1259  printer->add_multi_line(R"CODE(
1260  _nrn_mechanism_access_alloc_seq(_prop) = _nrn_mechanism_access_alloc_seq(nrn_point_prop_);
1261  _ppvar = _nrn_mechanism_access_dparam(nrn_point_prop_);
1262  )CODE");
1263  printer->chain_block("else");
1264  }
1265  if (info.semantic_variable_count) {
1266  printer->fmt_line("_ppvar = nrn_prop_datum_alloc(mech_type, {}, _prop);",
1267  info.semantic_variable_count);
1268  printer->add_line("_nrn_mechanism_access_dparam(_prop) = _ppvar;");
1269  }
1270  printer->add_multi_line(R"CODE(
1271  _nrn_mechanism_cache_instance _ml_real{_prop};
1272  auto* const _ml = &_ml_real;
1273  size_t const _iml{};
1274  )CODE");
1275  printer->fmt_line("assert(_nrn_mechanism_get_num_vars(_prop) == {});",
1276  codegen_float_variables.size());
1277  if (float_variables_size()) {
1278  printer->add_line("/*initialize range parameters*/");
1279  for (const auto& var: info.range_parameter_vars) {
1280  if (var->is_array()) {
1281  continue;
1282  }
1283  const auto& var_name = var->get_name();
1284  printer->fmt_line("_ml->template fpfield<{}>(_iml) = {}; /* {} */",
1285  position_of_float_var(var_name),
1286  *var->get_value(),
1287  var_name);
1288  }
1289  }
1290  if (info.point_process) {
1291  printer->pop_block();
1292  }
1293 
1294  if (info.semantic_variable_count) {
1295  printer->add_line("_nrn_mechanism_access_dparam(_prop) = _ppvar;");
1296  }
1297 
1298  if (info.diam_used) {
1299  throw std::runtime_error("Diam allocation not implemented.");
1300  }
1301 
1302  if (info.area_used) {
1303  throw std::runtime_error("Area allocation not implemented.");
1304  }
1305 
1306  const auto codegen_int_variables_size = codegen_int_variables.size();
1307 
1308  for (const auto& ion: info.ions) {
1309  printer->fmt_line("Symbol * {}_sym = hoc_lookup(\"{}_ion\");", ion.name, ion.name);
1310  printer->fmt_line("Prop * {}_prop = need_memb({}_sym);", ion.name, ion.name);
1311 
1312  for (size_t i = 0; i < codegen_int_variables_size; ++i) {
1313  const auto& var = codegen_int_variables[i];
1314 
1315  // if(var.symbol->has_any_property(NmodlType::useion)) {
1316  const std::string& var_name = var.symbol->get_name();
1317  if (var_name.rfind("ion_", 0) != 0) {
1318  continue;
1319  }
1320 
1321  std::string ion_var_name = std::string(var_name.begin() + 4, var_name.end());
1322  if (ion.is_ionic_variable(ion_var_name)) {
1323  printer->fmt_line("_ppvar[{}] = _nrn_mechanism_get_param_handle({}_prop, {});",
1324  i,
1325  ion.name,
1326  ion.variable_index(ion_var_name));
1327  }
1328  //}
1329  }
1330  }
1331 
1332  /// TODO: CONSTRUCTOR call
1333 
1334  printer->pop_block();
1335 }
1336 
1337 
1338 /****************************************************************************************/
1339 /* Print nrn_state routine */
1340 /****************************************************************************************/
1341 
1342 
1343 /// TODO: Edit for NEURON
1345  if (!nrn_state_required()) {
1346  return;
1347  }
1348 
1349  printer->add_newline(2);
1350  print_global_function_common_code(BlockType::State);
1351 
1352  printer->push_block("for (int id = 0; id < nodecount; id++)");
1353 
1354  /**
1355  * \todo Eigen solver node also emits IonCurVar variable in the functor
1356  * but that shouldn't update ions in derivative block
1357  */
1358  if (ion_variable_struct_required()) {
1359  throw std::runtime_error("Not implemented.");
1360  }
1361 
1362  auto read_statements = ion_read_statements(BlockType::State);
1363  for (auto& statement: read_statements) {
1364  printer->add_line(statement);
1365  }
1366 
1367  if (info.nrn_state_block) {
1368  info.nrn_state_block->visit_children(*this);
1369  }
1370 
1371  if (info.currents.empty() && info.breakpoint_node != nullptr) {
1372  auto block = info.breakpoint_node->get_statement_block();
1373  print_statement_block(*block, false, false);
1374  }
1375 
1376  const auto& write_statements = ion_write_statements(BlockType::State);
1377  for (auto& statement: write_statements) {
1378  const auto& text = process_shadow_update_statement(statement, BlockType::State);
1379  printer->add_line(text);
1380  }
1381 
1382  printer->pop_block();
1383  printer->pop_block();
1384 }
1385 
1386 
1387 /****************************************************************************************/
1388 /* Print nrn_cur related routines */
1389 /****************************************************************************************/
1390 
1392  if (ion_variable_struct_required()) {
1393  throw std::runtime_error("Not implemented.");
1394  }
1395  return "id, inst, node_data, v";
1396 }
1397 
1398 
1400  if (ion_variable_struct_required()) {
1401  throw std::runtime_error("Not implemented.");
1402  }
1403 
1404  ParamVector params;
1405  params.emplace_back("", "size_t", "", "id");
1406  params.emplace_back("", fmt::format("{}&", instance_struct()), "", "inst");
1407  params.emplace_back("", fmt::format("{}&", node_data_struct()), "", "node_data");
1408  params.emplace_back("", "double", "", "v");
1409  return params;
1410 }
1411 
1412 
1413 /// TODO: Edit for NEURON
1415  const auto& args = nrn_current_parameters();
1416  const auto& block = node.get_statement_block();
1417  printer->add_newline(2);
1418  // print_device_method_annotation();
1419  printer->fmt_push_block("inline double nrn_current_{}({})",
1420  info.mod_suffix,
1421  get_parameter_str(args));
1422  printer->add_line("double current = 0.0;");
1423  print_statement_block(*block, false, false);
1424  for (auto& current: info.currents) {
1425  const auto& name = get_variable_name(current);
1426  printer->fmt_line("current += {};", name);
1427  }
1428  printer->add_line("return current;");
1429  printer->pop_block();
1430 }
1431 
1432 
1433 /// TODO: Edit for NEURON
1435  const auto& block = node.get_statement_block();
1436  print_statement_block(*block, false, false);
1437  if (!info.currents.empty()) {
1438  std::string sum;
1439  for (const auto& current: info.currents) {
1440  auto var = breakpoint_current(current);
1441  sum += get_variable_name(var);
1442  if (&current != &info.currents.back()) {
1443  sum += "+";
1444  }
1445  }
1446  printer->fmt_line("double rhs = {};", sum);
1447  }
1448 
1449  std::string sum;
1450  for (const auto& conductance: info.conductances) {
1451  auto var = breakpoint_current(conductance.variable);
1452  sum += get_variable_name(var);
1453  if (&conductance != &info.conductances.back()) {
1454  sum += "+";
1455  }
1456  }
1457  printer->fmt_line("double g = {};", sum);
1458 
1459  for (const auto& conductance: info.conductances) {
1460  if (!conductance.ion.empty()) {
1461  const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + conductance.ion +
1462  "dv";
1463  const auto& rhs = get_variable_name(conductance.variable);
1464  const ShadowUseStatement statement{lhs, "+=", rhs};
1465  const auto& text = process_shadow_update_statement(statement, BlockType::Equation);
1466  printer->add_line(text);
1467  }
1468  }
1469 }
1470 
1471 
1472 /// TODO: Edit for NEURON
1474  printer->fmt_line("double I1 = nrn_current_{}({}+0.001);",
1475  info.mod_suffix,
1476  nrn_current_arguments());
1477  for (auto& ion: info.ions) {
1478  for (auto& var: ion.writes) {
1479  if (ion.is_ionic_current(var)) {
1480  const auto& name = get_variable_name(var);
1481  printer->fmt_line("double di{} = {};", ion.name, name);
1482  }
1483  }
1484  }
1485  printer->fmt_line("double I0 = nrn_current_{}({});", info.mod_suffix, nrn_current_arguments());
1486  printer->add_line("double rhs = I0;");
1487 
1488  printer->add_line("double g = (I1-I0)/0.001;");
1489  for (auto& ion: info.ions) {
1490  for (auto& var: ion.writes) {
1491  if (ion.is_ionic_current(var)) {
1492  const auto& lhs = std::string(naming::ION_VARNAME_PREFIX) + "di" + ion.name + "dv";
1493  auto rhs = fmt::format("(di{}-{})/0.001", ion.name, get_variable_name(var));
1494  if (info.point_process) {
1495  auto area = get_variable_name(naming::NODE_AREA_VARIABLE);
1496  rhs += fmt::format("*1.e2/{}", area);
1497  }
1498  const ShadowUseStatement statement{lhs, "+=", rhs};
1499  const auto& text = process_shadow_update_statement(statement, BlockType::Equation);
1500  printer->add_line(text);
1501  }
1502  }
1503  }
1504 }
1505 
1506 
1507 /// TODO: Edit for NEURON
1509  printer->add_line("int node_id = node_data.nodeindices[id];");
1510  printer->add_line("double v = node_data.node_voltages[node_id];");
1511 
1512  const auto& read_statements = ion_read_statements(BlockType::Equation);
1513  for (auto& statement: read_statements) {
1514  printer->add_line(statement);
1515  }
1516 
1517  if (info.conductances.empty()) {
1518  print_nrn_cur_non_conductance_kernel();
1519  } else {
1520  print_nrn_cur_conductance_kernel(node);
1521  }
1522 
1523  const auto& write_statements = ion_write_statements(BlockType::Equation);
1524  for (auto& statement: write_statements) {
1525  auto text = process_shadow_update_statement(statement, BlockType::Equation);
1526  printer->add_line(text);
1527  }
1528 
1529  if (info.point_process) {
1530  const auto& area = get_variable_name(naming::NODE_AREA_VARIABLE);
1531  printer->fmt_line("double mfactor = 1.e2/{};", area);
1532  printer->add_line("g = g*mfactor;");
1533  printer->add_line("rhs = rhs*mfactor;");
1534  }
1535 
1536  // print_g_unused();
1537 }
1538 
1539 
1540 /// TODO: Edit for NEURON
1542  return;
1543 }
1544 
1545 
1546 /// TODO: Edit for NEURON
1548  if (!nrn_cur_required()) {
1549  return;
1550  }
1551 
1552  if (info.conductances.empty()) {
1553  print_nrn_current(*info.breakpoint_node);
1554  }
1555 
1556  printer->add_newline(2);
1557  printer->add_line("/** update current */");
1558  print_global_function_common_code(BlockType::Equation);
1559  // print_channel_iteration_block_parallel_hint(BlockType::Equation, info.breakpoint_node);
1560  printer->push_block("for (int id = 0; id < nodecount; id++)");
1561  print_nrn_cur_kernel(*info.breakpoint_node);
1562  // print_nrn_cur_matrix_shadow_update();
1563  // if (!nrn_cur_reduction_loop_required()) {
1564  // print_fast_imem_calculation();
1565  // }
1566 
1567 
1568  printer->add_line("node_data.node_rhs[node_id] -= rhs;");
1569 
1570 
1571  printer->pop_block();
1572 
1573  // if (nrn_cur_reduction_loop_required()) {
1574  // printer->push_block("for (int id = 0; id < nodecount; id++)");
1575  // print_nrn_cur_matrix_shadow_reduction();
1576  // printer->pop_block();
1577  // print_fast_imem_calculation();
1578  // }
1579 
1580  // print_kernel_data_present_annotation_block_end();
1581  printer->pop_block();
1582 }
1583 
1584 
1585 /****************************************************************************************/
1586 /* Main code printing entry points */
1587 /****************************************************************************************/
1588 
1590  print_standard_includes();
1591  print_neuron_includes();
1592 }
1593 
1594 
1596  print_global_macros();
1597  print_mechanism_variables_macros();
1598 }
1599 
1600 
1602  printer->add_newline();
1603  printer->add_line("/* NEURON global macro definitions */");
1604  if (info.vectorize) {
1605  printer->add_multi_line(R"CODE(
1606  /* VECTORIZED */
1607  #define NRN_VECTORIZED 1
1608  )CODE");
1609  } else {
1610  printer->add_multi_line(R"CODE(
1611  /* NOT VECTORIZED */
1612  #define NRN_VECTORIZED 0
1613  )CODE");
1614  }
1615 }
1616 
1617 
1619  printer->add_newline();
1620  printer->add_line("static constexpr auto number_of_datum_variables = ",
1621  std::to_string(int_variables_size()),
1622  ";");
1623  printer->add_line("static constexpr auto number_of_floating_point_variables = ",
1624  std::to_string(float_variables_size()),
1625  ";");
1626  printer->add_newline();
1627  printer->add_multi_line(R"CODE(
1628  namespace {
1629  template <typename T>
1630  using _nrn_mechanism_std_vector = std::vector<T>;
1631  using _nrn_model_sorted_token = neuron::model_sorted_token;
1632  using _nrn_mechanism_cache_range = neuron::cache::MechanismRange<number_of_floating_point_variables, number_of_datum_variables>;
1633  using _nrn_mechanism_cache_instance = neuron::cache::MechanismInstance<number_of_floating_point_variables, number_of_datum_variables>;
1634  using _nrn_non_owning_id_without_container = neuron::container::non_owning_identifier_without_container;
1635  template <typename T>
1636  using _nrn_mechanism_field = neuron::mechanism::field<T>;
1637  template <typename... Args>
1638  void _nrn_mechanism_register_data_fields(Args&&... args) {
1639  neuron::mechanism::register_data_fields(std::forward<Args>(args)...);
1640  }
1641  } // namespace
1642  )CODE");
1643 
1644  if (info.point_process) {
1645  printer->add_line("extern Prop* nrn_point_prop_;");
1646  } else {
1647  printer->add_line("Prop* hoc_getdata_range(int type);");
1648  }
1649  /// TODO: More prints here?
1650 }
1651 
1652 
1654  print_namespace_start();
1655 }
1656 
1657 
1659  print_namespace_stop();
1660 }
1661 
1662 
1663 void CodegenNeuronCppVisitor::print_data_structures(bool print_initializers) {
1664  print_mechanism_global_var_structure(print_initializers);
1665  print_mechanism_range_var_structure(print_initializers);
1666  print_node_data_structure(print_initializers);
1667  print_make_instance();
1668  print_make_node_data();
1669 }
1670 
1671 
1673  if (!info.vectorize) {
1674  return;
1675  }
1676  printer->add_multi_line(R"CODE(
1677  #if NRN_PRCELLSTATE
1678  inst->v_unused[id] = v;
1679  #endif
1680  )CODE");
1681 }
1682 
1683 
1685  printer->add_multi_line(R"CODE(
1686  #if NRN_PRCELLSTATE
1687  inst->g_unused[id] = g;
1688  #endif
1689  )CODE");
1690 }
1691 
1692 
1693 /// TODO: Edit for NEURON
1695  print_hoc_py_wrapper_function_definitions();
1696  for (const auto& procedure: info.procedures) {
1697  print_procedure(*procedure);
1698  }
1699  for (const auto& function: info.functions) {
1700  print_function(*function);
1701  }
1702  print_nrn_init();
1703  print_nrn_cur();
1704  print_nrn_state();
1705  print_nrn_jacob();
1706 }
1707 
1708 
1709 /// TODO: Edit for NEURON
1711  print_backend_info();
1712  print_headers_include();
1713  print_macro_definitions();
1714  print_namespace_begin();
1715  print_nmodl_constants();
1716  print_prcellstate_macros();
1717  print_mechanism_info();
1718  print_data_structures(true);
1719  print_nrn_alloc();
1720  print_function_prototypes();
1721  print_global_variables_for_hoc();
1722  print_compute_functions(); // only nrn_cur and nrn_state
1723  print_sdlists_init(true);
1724  print_mechanism_register();
1725  print_namespace_end();
1726 }
1727 
1729  throw std::runtime_error("Not implemented.");
1730 }
1731 
1733  throw std::runtime_error("Not implemented.");
1734 }
1735 
1737  throw std::runtime_error("Not implemented.");
1738 }
1739 
1740 
1741 /****************************************************************************************/
1742 /* Overloaded visitor routines */
1743 /****************************************************************************************/
1744 
1745 /// TODO: Edit for NEURON
1747  return;
1748 }
1749 
1750 
1751 } // namespace codegen
1752 } // namespace nmodl
nmodl::codegen::CodegenNeuronCppVisitor::external_method_parameters
const char * 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:401
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_destructor
void print_nrn_destructor() override
Print nrn_destructor function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1241
nmodl::codegen::IndexVariableInfo::is_index
bool is_index
if this is pure index (e.g.
Definition: codegen_cpp_visitor.hpp:121
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:1473
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:451
nmodl::codegen::IndexVariableInfo
Helper to represent information about index/int variables.
Definition: codegen_cpp_visitor.hpp:111
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_cur
void print_nrn_cur() override
Print nrn_cur / current update function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1547
nmodl::codegen::CodegenNeuronCppVisitor::print_macro_definitions
void print_macro_definitions()
Print all NEURON macros.
Definition: codegen_neuron_cpp_visitor.cpp:1595
nmodl::ast::FunctionBlock
TODO.
Definition: function_block.hpp:39
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:1736
nmodl::codegen::naming::POINT_PROCESS_VARIABLE
static constexpr char POINT_PROCESS_VARIABLE[]
inbuilt neuron variable for point process
Definition: codegen_naming.hpp:63
nmodl::codegen::CodegenNeuronCppVisitor::print_neuron_includes
void print_neuron_includes()
Print includes from NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:651
nmodl::codegen::naming::NRN_JACOB_METHOD
static constexpr char NRN_JACOB_METHOD[]
nrn_jacob method in generated code
Definition: codegen_naming.hpp:159
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:1211
nmodl::codegen::CodegenNeuronCppVisitor::print_hoc_py_wrapper_function_body
void print_hoc_py_wrapper_function_body(const ast::Block *function_or_procedure_block, InterpreterWrapper wrapper_type)
Definition: codegen_neuron_cpp_visitor.cpp:263
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:377
nmodl::codegen::CodegenCppVisitor::SymbolType
std::shared_ptr< symtab::Symbol > SymbolType
Definition: codegen_cpp_visitor.hpp:238
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_alloc
void print_nrn_alloc() override
Print nrn_alloc function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1247
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:425
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:65
nmodl::codegen::CodegenNeuronCppVisitor::nrn_current_arguments
std::string nrn_current_arguments()
Definition: codegen_neuron_cpp_visitor.cpp:1391
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:89
nmodl::codegen::CodegenNeuronCppVisitor::internal_method_parameters
ParamVector internal_method_parameters() override
Parameters for internally defined functions.
Definition: codegen_neuron_cpp_visitor.cpp:382
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:430
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:537
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:413
codegen_neuron_cpp_visitor.hpp
Visitor for printing C++ code compatible with legacy api of NEURON
nmodl::codegen::CodegenNeuronCppVisitor::backend_name
virtual std::string backend_name() const override
Name of the code generation backend.
Definition: codegen_neuron_cpp_visitor.cpp:43
nmodl::codegen::CodegenNeuronCppVisitor::process_verbatim_text
std::string process_verbatim_text(std::string const &text) override
Process a verbatim block for possible variable renaming.
Definition: codegen_neuron_cpp_visitor.cpp:419
nmodl::codegen::CodegenNeuronCppVisitor::nrn_current_parameters
ParamVector nrn_current_parameters()
Definition: codegen_neuron_cpp_visitor.cpp:1399
nmodl::codegen::naming::NTHREAD_DT_VARIABLE
static constexpr char NTHREAD_DT_VARIABLE[]
dt variable in neuron thread structure
Definition: codegen_naming.hpp:99
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:1684
nmodl::codegen::CodegenNeuronCppVisitor::visit_watch_statement
virtual void visit_watch_statement(const ast::WatchStatement &node) override
TODO: Edit for NEURON.
Definition: codegen_neuron_cpp_visitor.cpp:1746
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:1728
string_utils.hpp
Implement string manipulation functions.
nmodl::codegen::CodegenNeuronCppVisitor::print_namespace_end
void print_namespace_end() override
Print end of namespaces.
Definition: codegen_neuron_cpp_visitor.cpp:1658
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:1732
nmodl::codegen::naming::NODE_AREA_VARIABLE
static constexpr char NODE_AREA_VARIABLE[]
inbuilt neuron variable for area of the compartment
Definition: codegen_naming.hpp:57
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_state
void print_nrn_state() override
Print nrn_state / state update function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1344
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:150
nmodl::Version::GIT_REVISION
static const std::string GIT_REVISION
git revision id
Definition: config.h:33
nmodl::codegen::CodegenNeuronCppVisitor::print_initial_block
void print_initial_block(const ast::InitialBlock *node)
Print the initial block.
Definition: codegen_neuron_cpp_visitor.cpp:1173
nmodl::codegen::IndexVariableInfo::is_integer
bool is_integer
if this is an integer (e.g.
Definition: codegen_cpp_visitor.hpp:125
nmodl::codegen::CodegenNeuronCppVisitor::print_global_function_common_code
virtual 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:1195
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:486
nmodl::codegen::CodegenNeuronCppVisitor::print_function
void print_function(const ast::FunctionBlock &node) override
Print NMODL function in target backend code.
Definition: codegen_neuron_cpp_visitor.cpp:244
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:360
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:1672
nmodl::ast::Block
Base class for all block scoped nodes.
Definition: block.hpp:41
nmodl::ast::InitialBlock
Represents a INITIAL block in the NMODL.
Definition: initial_block.hpp:49
nmodl::stringutils::trim
static std::string trim(std::string text)
Definition: string_utils.hpp:63
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:102
visitor_utils.hpp
Utility functions for visitors implementation.
nmodl::codegen::BlockType::Equation
@ Equation
breakpoint block
nmodl::codegen::naming::USE_TABLE_VARIABLE
static constexpr char USE_TABLE_VARIABLE[]
global variable to indicate if table is used
Definition: codegen_naming.hpp:72
nmodl::ast::WatchStatement
Represent WATCH statement in NMODL.
Definition: watch_statement.hpp:39
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:1434
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:507
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:50
nmodl::codegen::CodegenNeuronCppVisitor::print_namespace_begin
void print_namespace_begin() override
Print start of namespaces.
Definition: codegen_neuron_cpp_visitor.cpp:1653
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:803
nmodl::codegen::CodegenNeuronCppVisitor::print_standard_includes
void print_standard_includes() override
Print standard C/C++ includes.
Definition: codegen_neuron_cpp_visitor.cpp:638
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:1054
nmodl::codegen::CodegenNeuronCppVisitor::print_procedure
virtual void print_procedure(const ast::ProcedureBlock &node) override
Print NMODL procedure in target backend code.
Definition: codegen_neuron_cpp_visitor.cpp:239
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:436
nmodl::codegen::CodegenNeuronCppVisitor::print_namespace_start
void print_namespace_start() override
Prints the start of the neuron namespace.
Definition: codegen_neuron_cpp_visitor.cpp:462
nmodl::codegen::CodegenNeuronCppVisitor::print_backend_info
void print_backend_info() override
Print top file header printed in generated code.
Definition: codegen_neuron_cpp_visitor.cpp:618
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:279
nmodl::codegen::CodegenNeuronCppVisitor::print_compute_functions
virtual void print_compute_functions() override
Print all compute functions for every backend.
Definition: codegen_neuron_cpp_visitor.cpp:1694
nmodl::codegen::naming::NRN_INIT_METHOD
static constexpr char NRN_INIT_METHOD[]
nrn_init method in generated code
Definition: codegen_naming.hpp:135
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:1508
nmodl::visitor::RenameVisitor
Blindly rename given variable to new name
Definition: rename_visitor.hpp:43
nmodl::codegen::naming::NRN_CUR_METHOD
static constexpr char NRN_CUR_METHOD[]
nrn_cur method in generated code
Definition: codegen_naming.hpp:156
nmodl::codegen::CodegenNeuronCppVisitor::conc_write_statement
std::string conc_write_statement(const std::string &ion_name, const std::string &concentration, int index) override
Generate Function call statement for nrn_wrote_conc.
Definition: codegen_neuron_cpp_visitor.cpp:473
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_register
void print_mechanism_register() override
Print the mechanism registration function.
Definition: codegen_neuron_cpp_visitor.cpp:922
codegen_utils.hpp
Implement utility functions for codegen visitors.
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_jacob
void print_nrn_jacob()
Print nrn_jacob function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1223
nmodl::codegen::HOC
@ HOC
Definition: codegen_neuron_cpp_visitor.hpp:50
nmodl::codegen::CodegenNeuronCppVisitor::print_fast_imem_calculation
virtual void print_fast_imem_calculation() override
Print fast membrane current calculation code.
Definition: codegen_neuron_cpp_visitor.cpp:1541
nmodl::codegen::CodegenNeuronCppVisitor::print_data_structures
void print_data_structures(bool print_initializers) override
Print all classes.
Definition: codegen_neuron_cpp_visitor.cpp:1663
nmodl::ast::FunctionBlock::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:3963
nmodl::codegen::CodegenNeuronCppVisitor::print_sdlists_init
void print_sdlists_init(bool print_initializers) override
Definition: codegen_neuron_cpp_visitor.cpp:662
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:445
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:1139
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:93
nmodl::codegen::CodegenNeuronCppVisitor::print_make_instance
void print_make_instance() const
Print make_*_instance.
Definition: codegen_neuron_cpp_visitor.cpp:1095
nmodl::codegen::CodegenNeuronCppVisitor::print_atomic_reduction_pragma
virtual void print_atomic_reduction_pragma() override
Print atomic update pragma for reduction statements.
Definition: codegen_neuron_cpp_visitor.cpp:85
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::codegen::CodegenNeuronCppVisitor::print_namespace_stop
void print_namespace_stop() override
Prints the end of the neuron namespace.
Definition: codegen_neuron_cpp_visitor.cpp:468
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:147
nmodl::codegen::ShadowUseStatement
Represents ion write statement during code generation.
Definition: codegen_cpp_visitor.hpp:150
nmodl::ast::ProcedureBlock
TODO.
Definition: procedure_block.hpp:39
nmodl::codegen::CodegenNeuronCppVisitor::print_mechanism_variables_macros
void print_mechanism_variables_macros()
Print mechanism variables' related macros.
Definition: codegen_neuron_cpp_visitor.cpp:1618
nmodl::codegen::CodegenNeuronCppVisitor::print_nrn_constructor
void print_nrn_constructor() override
Print nrn_constructor function definition.
Definition: codegen_neuron_cpp_visitor.cpp:1235
nmodl::Version::NMODL_VERSION
static const std::string NMODL_VERSION
project tagged version in the cmake
Definition: config.h:36
nmodl::ast::FunctionBlock::get_statement_block
std::shared_ptr< StatementBlock > get_statement_block() const noexcept override
Getter for member variable FunctionBlock::statement_block.
Definition: function_block.hpp:219
nmodl::codegen::BlockType
BlockType
Helper to represent various block types.
Definition: codegen_cpp_visitor.hpp:56
nmodl::codegen::CodegenNeuronCppVisitor::print_function_or_procedure
void print_function_or_procedure(const ast::Block &node, const std::string &name) override
Print nmodl function or procedure (common code)
Definition: codegen_neuron_cpp_visitor.cpp:207
nmodl::codegen::CodegenNeuronCppVisitor::print_headers_include
void print_headers_include() override
Print all includes.
Definition: codegen_neuron_cpp_visitor.cpp:1589
nmodl::codegen::naming::NRN_STATE_METHOD
static constexpr char NRN_STATE_METHOD[]
nrn_state method in generated code
Definition: codegen_naming.hpp:153
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:1414
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:53
nmodl::codegen::CodegenNeuronCppVisitor::get_variable_name
std::string get_variable_name(const std::string &name, bool use_instance=true) const override
Determine variable name in the structure of mechanism properties.
Definition: codegen_neuron_cpp_visitor.cpp:547
nmodl::codegen::CodegenNeuronCppVisitor::print_make_node_data
void print_make_node_data() const
Print make_*_node_data.
Definition: codegen_neuron_cpp_visitor.cpp:1153
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:38
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:228
nmodl::codegen::naming::NTHREAD_T_VARIABLE
static constexpr char NTHREAD_T_VARIABLE[]
t variable in neuron thread structure
Definition: codegen_naming.hpp:96
rename_visitor.hpp
Blindly rename given variable to new name
nmodl::codegen::CodegenNeuronCppVisitor::external_method_arguments
const char * external_method_arguments() noexcept override
Arguments for external functions called from generated code.
Definition: codegen_neuron_cpp_visitor.cpp:395
nmodl::codegen::BlockType::State
@ State
derivative block
nmodl::ast::Block::get_parameters
virtual const ArgumentVector & get_parameters() const
Definition: block.hpp:50
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:407
nmodl::codegen::Python
@ Python
Definition: codegen_neuron_cpp_visitor.hpp:50
nmodl::codegen::CodegenNeuronCppVisitor::print_codegen_routines
void print_codegen_routines() override
Print entry point to code generation.
Definition: codegen_neuron_cpp_visitor.cpp:1710
nmodl::codegen::BlockType::Initial
@ Initial
initial block
nmodl::codegen::naming::NRN_POINTERINDEX
static constexpr char NRN_POINTERINDEX[]
hoc_nrnpointerindex name
Definition: codegen_naming.hpp:174
nmodl::ast::Ast::get_node_name
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
all.hpp
Auto generated AST classes declaration.
nmodl::codegen::CodegenNeuronCppVisitor::print_function_prototypes
void print_function_prototypes() override
Print function and procedures prototype declaration.
Definition: codegen_neuron_cpp_visitor.cpp:197
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:704
nmodl::codegen::CodegenNeuronCppVisitor::print_global_macros
void print_global_macros()
Print NEURON global variable macros.
Definition: codegen_neuron_cpp_visitor.cpp:1601
nmodl::codegen::CodegenCppVisitor::ParamVector
std::vector< std::tuple< std::string, std::string, std::string, std::string > > ParamVector
A vector of parameters represented by a 4-tuple of strings:
Definition: codegen_cpp_visitor.hpp:250
nmodl::codegen::naming::ION_VARNAME_PREFIX
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
Definition: codegen_naming.hpp:171