11 #include "config/config.h"
27 using visitor::DefUseAnalyzeVisitor;
29 using visitor::RenameVisitor;
30 using visitor::SymtabVisitor;
40 return optimize_ion_variable_copies() &&
info.ion_has_write_variable();
44 std::vector<std::string> variables;
45 for (
const auto&
param: params) {
46 variables.push_back(std::get<3>(
param));
48 return fmt::format(
"{}", fmt::join(variables,
", "));
53 std::vector<std::string> variables;
54 for (
const auto&
param: params) {
55 variables.push_back(fmt::format(
"{}{} {}{}",
61 return fmt::format(
"{}", fmt::join(variables,
", "));
67 auto parameters =
node->get_parameters();
68 return std::any_of(parameters.begin(),
70 [&
name](
const decltype(*parameters.begin()) arg) {
71 return arg->get_node_name() == name;
77 return "update_table_" + method_name(block_name);
89 if (
node.is_unit_state()
90 ||
node.is_line_comment()
91 ||
node.is_block_comment()
92 ||
node.is_solve_block()
93 ||
node.is_conductance_hint()
94 ||
node.is_table_statement()) {
98 if (
node.is_expression_statement()) {
100 if (expression->is_solve_block()) {
103 if (expression->is_initial_block()) {
112 if (net_receive_required() && !
info.artificial_cell) {
113 if (
info.net_event_used ||
info.net_send_used ||
info.is_watch_used()) {
122 return info.point_process && !
info.artificial_cell &&
info.net_receive_node !=
nullptr;
127 if (
info.artificial_cell) {
130 return info.nrn_state_block !=
nullptr || breakpoint_exist();
135 return info.breakpoint_node !=
nullptr && !
info.currents.empty();
140 return info.net_receive_node !=
nullptr;
145 return info.breakpoint_node !=
nullptr;
150 return net_receive_exist();
165 const auto&
function = program_symtab->lookup(
name);
166 auto properties = NmodlType::function_block | NmodlType::procedure_block;
167 return function &&
function->has_any_property(properties);
171 auto it = std::find_if(
info.function_tables.begin(),
172 info.function_tables.end(),
173 [
name](
const auto&
node) { return node->get_node_name() == name; });
174 return it !=
info.function_tables.end();
179 for (
const auto&
var: codegen_float_variables) {
180 n_floats +=
var->get_length();
188 const auto count_semantics = [](
int sum,
const IndexSemantics& sem) {
return sum += sem.size; };
189 return std::accumulate(
info.semantics.begin(),
info.semantics.end(), 0, count_semantics);
219 if (
node.is_if_statement()
220 ||
node.is_else_if_statement()
221 ||
node.is_else_statement()
222 ||
node.is_from_statement()
223 ||
node.is_verbatim()
224 ||
node.is_conductance_hint()
225 ||
node.is_while_statement()
226 ||
node.is_protect_statement()
227 ||
node.is_mutex_lock()
228 ||
node.is_mutex_unlock()) {
231 if (
node.is_expression_statement()) {
233 if (expression->is_statement_block()
234 || expression->is_eigen_newton_solver_block()
235 || expression->is_eigen_linear_solver_block()
236 || expression->is_solution_expression()
237 || expression->is_for_netcon()) {
253 if (optimize_ion_variable_copies()) {
254 return ion_read_statements_optimized(
type);
256 std::vector<std::string> statements;
257 for (
const auto& ion:
info.ions) {
258 auto name = ion.name;
259 for (
const auto&
var: ion.reads) {
260 auto const iter =
std::find(ion.implicit_reads.begin(), ion.implicit_reads.end(),
var);
261 if (iter != ion.implicit_reads.end()) {
264 auto variable_names = read_ion_variable_name(
var);
265 auto first = get_variable_name(variable_names.first);
266 auto second = get_variable_name(variable_names.second);
267 statements.push_back(fmt::format(
"{} = {};", first, second));
269 for (
const auto&
var: ion.writes) {
270 if (ion.is_ionic_conc(
var)) {
271 auto variables = read_ion_variable_name(
var);
272 auto first = get_variable_name(variables.first);
273 auto second = get_variable_name(variables.second);
274 statements.push_back(fmt::format(
"{} = {};", first, second));
283 std::vector<std::string> statements;
284 for (
const auto& ion:
info.ions) {
285 for (
const auto&
var: ion.writes) {
286 if (ion.is_ionic_conc(
var)) {
287 auto variables = read_ion_variable_name(
var);
288 auto first =
"ionvar." + variables.first;
289 const auto& second = get_variable_name(variables.second);
290 statements.push_back(fmt::format(
"{} = {};", first, second));
299 std::vector<ShadowUseStatement> statements;
300 for (
const auto& ion:
info.ions) {
301 std::string concentration;
302 for (
const auto&
var: ion.writes) {
303 auto variable_names = write_ion_variable_name(
var);
304 if (ion.is_ionic_current(
var)) {
307 auto lhs = variable_names.first;
310 if (
info.point_process) {
312 rhs += fmt::format(
"*(1.e2/{})",
area);
317 if (!ion.is_rev_potential(
var)) {
320 auto lhs = variable_names.first;
322 auto rhs = get_variable_name(variable_names.second);
328 append_conc_write_statements(statements, ion, concentration);
343 if (statement.
op.empty() && statement.
rhs.empty()) {
344 auto text = statement.
lhs +
";";
349 auto lhs = get_variable_name(statement.
lhs);
350 auto text = fmt::format(
"{} {} {};", lhs, statement.
op, statement.
rhs);
364 auto breakpoint =
info.breakpoint_node;
365 if (breakpoint ==
nullptr) {
368 auto symtab = breakpoint->get_statement_block()->get_symbol_table();
369 auto variables = symtab->get_variables_with_properties(NmodlType::local_var);
370 for (
const auto&
var: variables) {
371 auto renamed_name =
var->get_name();
372 auto original_name =
var->get_original_name();
373 if (
current == original_name) {
402 std::vector<std::shared_ptr<const ast::Ast>> nodes;
410 printer->add_line(
"#pragma omp simd");
411 printer->add_line(
"#pragma ivdep");
422 if (ion_variable_struct_required()) {
423 if (
info.is_ion_read_variable(
name)) {
426 if (
info.is_ion_write_variable(
name)) {
438 const std::string&
name) {
444 const std::string&
name) {
460 time_t current_time{};
462 std::string data_time_str{std::ctime(¤t_time)};
465 printer->add_line(
"/*********************************************************");
466 printer->add_line(
"Model Name : ",
info.mod_suffix);
467 printer->add_line(
"Filename : ",
info.mod_file,
".mod");
468 printer->add_line(
"NMODL Version : ", nmodl_version());
469 printer->fmt_line(
"Vectorized : {}",
info.vectorize);
470 printer->fmt_line(
"Threadsafe : {}",
info.thread_safe);
472 printer->add_line(
"Simulator : ", simulator_name());
473 printer->add_line(
"Backend : ", backend_name());
474 printer->add_line(
"NMODL Compiler : ", version);
475 printer->add_line(
"*********************************************************/");
480 for (
const auto& f:
info.function_tables) {
481 printer->fmt_line(
"void* _ptable_{}{{}};", f->get_node_name());
482 codegen_global_variables.push_back(make_symbol(
"_ptable_" + f->get_node_name()));
490 printer->fmt_line(
"static_assert(std::is_trivially_copy_constructible_v<{}>);",
492 printer->fmt_line(
"static_assert(std::is_trivially_move_constructible_v<{}>);",
494 printer->fmt_line(
"static_assert(std::is_trivially_copy_assignable_v<{}>);", global_struct());
495 printer->fmt_line(
"static_assert(std::is_trivially_move_assignable_v<{}>);", global_struct());
496 printer->fmt_line(
"static_assert(std::is_trivially_destructible_v<{}>);", global_struct());
501 printer->fmt_line(
"static {} {};", global_struct(), global_struct_instance());
506 const auto&
name =
node.get_node_name();
510 auto get_renamed_random_function =
511 [&](
const std::string&
name) -> std::pair<std::string, bool> {
515 return {
name,
false};
517 auto [function_name, is_random_function] = get_renamed_random_function(
name);
519 if (defined_method(
name)) {
520 function_name = method_name(
name);
524 print_nrn_pointing(
node);
528 if (is_net_send(
name)) {
529 print_net_send_call(
node);
533 if (is_net_move(
name)) {
534 print_net_move_call(
node);
538 if (is_net_event(
name)) {
539 print_net_event_call(
node);
543 if (is_function_table_call(
name)) {
544 print_function_table_call(
node);
548 const auto& arguments =
node.get_arguments();
549 printer->add_text(function_name,
'(');
551 if (defined_method(
name)) {
552 auto internal_args = internal_method_arguments();
553 printer->add_text(internal_args);
554 if (!arguments.empty() && !internal_args.empty()) {
555 printer->add_text(
", ");
559 print_vector_elements(arguments,
", ");
560 printer->add_text(
')');
564 printer->add_text(
"nrn_pointing(&");
565 print_vector_elements(
node.get_arguments(),
", ");
566 printer->add_text(
")");
570 print_function_procedure_helper(
node);
578 std::string return_var;
579 if (
info.function_uses_table(
name)) {
580 return_var =
"ret_f_" +
name;
582 return_var =
"ret_" +
name;
586 auto block =
node.get_statement_block().get();
590 print_function_procedure_helper(
node);
596 const auto&
p =
node.get_parameters();
597 auto [params, table_params] = function_table_parameters(
node);
598 printer->fmt_push_block(
"double {}({})", method_name(
name), get_parameter_str(params));
599 printer->fmt_line(
"double _arg[{}];",
p.size());
600 for (
size_t i = 0;
i <
p.size(); ++
i) {
601 printer->fmt_line(
"_arg[{}] = {};",
i,
p[
i]->get_node_name());
603 printer->fmt_line(
"return hoc_func_table({}, {}, _arg);",
604 get_variable_name(std::string(
"_ptable_" +
name),
true),
606 printer->pop_block();
608 printer->fmt_push_block(
"double table_{}({})",
610 get_parameter_str(table_params));
611 printer->fmt_line(
"hoc_spec_table(&{}, {});",
612 get_variable_name(std::string(
"_ptable_" +
name)),
614 printer->add_line(
"return 0.;");
615 printer->pop_block();
620 printer->add_line(
"#ifndef NRN_PRCELLSTATE");
621 printer->add_line(
"#define NRN_PRCELLSTATE 0");
622 printer->add_line(
"#endif");
627 auto variable_printer = [&](
const std::vector<SymbolType>& variables) {
628 for (
const auto&
v: variables) {
629 auto name =
v->get_name();
630 if (!
info.point_process) {
634 name += fmt::format(
"[{}]",
v->get_length());
636 printer->add_line(add_escape_quote(
name),
",");
640 printer->add_newline(2);
641 printer->add_line(
"/** channel information */");
642 printer->fmt_line(
"static const char *{}[] = {{", get_channel_info_var_name());
643 printer->increase_indent();
644 printer->add_line(add_escape_quote(nmodl_version()),
",");
645 printer->add_line(add_escape_quote(
info.mod_suffix),
",");
646 variable_printer(
info.range_parameter_vars);
647 printer->add_line(
"0,");
648 variable_printer(
info.range_assigned_vars);
649 printer->add_line(
"0,");
650 variable_printer(
info.range_state_vars);
651 printer->add_line(
"0,");
652 variable_printer(
info.pointer_variables);
653 printer->add_line(
"0");
654 printer->decrease_indent();
655 printer->add_line(
"};");
659 printer->fmt_line(
"using namespace {};", namespace_name());
663 printer->add_newline(2);
664 printer->fmt_push_block(
"namespace {}", namespace_name());
669 printer->pop_block();
674 if (
info.top_verbatim_blocks.empty()) {
677 print_namespace_stop();
679 printer->add_newline(2);
680 print_using_namespace();
682 printing_top_verbatim_blocks =
true;
684 for (
const auto& block:
info.top_verbatim_blocks) {
685 printer->add_newline(2);
686 block->accept(*
this);
689 printing_top_verbatim_blocks =
false;
691 print_namespace_start();
704 printer->push_block();
707 const auto& statements =
node.get_statements();
708 for (
const auto& statement: statements) {
709 if (statement_to_skip(*statement)) {
713 if (!statement->is_verbatim() && !statement->is_mutex_lock() &&
714 !statement->is_mutex_unlock() && !statement->is_protect_statement()) {
715 printer->add_indent();
717 statement->accept(*
this);
718 if (need_semicolon(*statement)) {
719 printer->add_text(
';');
721 if (!statement->is_mutex_lock() && !statement->is_mutex_unlock()) {
722 printer->add_newline();
727 printer->pop_block_nl(0);
745 auto model_symbol_table = std::make_shared<symtab::ModelSymbolTable>();
753 auto is_functor_const =
true;
755 for (
const auto& variable: variables) {
756 const auto& chain =
v.analyze(complete_block, variable->get_node_name());
757 is_functor_const = !(chain.eval() ==
DUState::D || chain.eval() == DUState::LD ||
758 chain.eval() == DUState::CD);
759 if (!is_functor_const) {
764 return is_functor_const;
769 for (
const auto& functor_name:
info.functor_names) {
770 printer->add_newline(2);
771 print_functor_definition(*functor_name.first);
778 auto float_type = default_float_data_type();
779 int N =
node.get_n_state_vars()->get_value();
781 const auto functor_name =
info.functor_names[&
node];
782 printer->fmt_push_block(
"struct {}", functor_name);
784 auto params = functor_params();
785 for (
const auto&
param: params) {
786 printer->fmt_line(
"{}{} {};", std::get<0>(
param), std::get<1>(
param), std::get<3>(
param));
789 if (ion_variable_struct_required()) {
790 print_ion_variable();
793 print_statement_block(*
node.get_variable_block(),
false,
false);
794 printer->add_newline();
796 printer->push_block(
"void initialize()");
797 print_statement_block(*
node.get_initialize_block(),
false,
false);
798 printer->pop_block();
799 printer->add_newline();
801 printer->fmt_line(
"{}({})", functor_name, get_parameter_str(params));
802 printer->increase_indent();
803 auto initializers = std::vector<std::string>();
804 for (
const auto&
param: params) {
805 initializers.push_back(fmt::format(
"{0}({0})", std::get<3>(
param)));
808 printer->add_multi_line(
": " + fmt::format(
"{}", fmt::join(initializers,
", ")));
809 printer->decrease_indent();
810 printer->add_line(
"{}");
812 printer->add_indent();
814 const auto& variable_block = *
node.get_variable_block();
815 const auto& functor_block = *
node.get_functor_block();
818 "void operator()(const Eigen::Matrix<{0}, {1}, 1>& nmodl_eigen_xm, Eigen::Matrix<{0}, {1}, "
819 "1>& nmodl_eigen_dxm, Eigen::Matrix<{0}, {1}, "
820 "1>& nmodl_eigen_fm, "
821 "Eigen::Matrix<{0}, {1}, {1}>& nmodl_eigen_jm) {2}",
824 is_functor_const(variable_block, functor_block) ?
"const " :
"");
825 printer->push_block();
826 printer->fmt_line(
"const {}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
827 printer->fmt_line(
"{}* nmodl_eigen_dx = nmodl_eigen_dxm.data();", float_type);
828 printer->fmt_line(
"{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
829 printer->fmt_line(
"{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
831 for (
size_t i = 0;
i < N; ++
i) {
833 "nmodl_eigen_dx[{0}] = std::max(1e-6, 0.02*std::fabs(nmodl_eigen_x[{0}]));",
i);
836 print_statement_block(functor_block,
false,
false);
837 printer->pop_block();
838 printer->add_newline();
841 printer->push_block(
"void finalize()");
842 print_statement_block(*
node.get_finalize_block(),
false,
false);
843 printer->pop_block();
845 printer->pop_block(
";");
852 printer->add_multi_line(R
"CODE(
854 nmodl_eigen_jm.computeInverseWithCheck(nmodl_eigen_jm_inv,invertible);
855 nmodl_eigen_xm = nmodl_eigen_jm_inv*nmodl_eigen_fm;
856 if (!invertible) assert(false && "Singular or ill-conditioned matrix (Eigen::inverse)!");
863 printer->add_line(
"if (!nmodl_eigen_jm.IsRowMajor) nmodl_eigen_jm.transposeInPlace();");
866 printer->fmt_line(
"Eigen::Matrix<int, {}, 1> pivot;", N);
867 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, 1> rowmax;", float_type, N);
871 "if (nmodl::crout::Crout<{0}>({1}, nmodl_eigen_jm.data(), pivot.data(), rowmax.data()) "
872 "< 0) assert(false && \"Singular or ill-conditioned matrix (nmodl::crout)!\");",
878 "nmodl::crout::solveCrout<{0}>({1}, nmodl_eigen_jm.data(), nmodl_eigen_fm.data(), "
879 "nmodl_eigen_xm.data(), pivot.data());",
896 if (!
info.factor_definitions.empty()) {
897 printer->add_newline(2);
898 printer->add_line(
"/** constants used in nmodl from UNITS */");
899 for (
const auto& it:
info.factor_definitions) {
900 const std::string format_string =
"static const double {} = {};";
901 printer->fmt_line(format_string, it->get_node_name(), it->get_value()->get_value());
917 if (enable_variable_name_lookup) {
920 printer->add_text(
name);
946 node.visit_children(*
this);
956 throw std::runtime_error(
"PRIME encountered during code generation, ODEs not solved?");
965 const auto& at_index =
node.get_at();
969 printer->add_text(
"@");
970 at_index->accept(*
this);
973 printer->add_text(
"[");
974 printer->add_text(
"static_cast<int>(");
975 index->accept(*
this);
976 printer->add_text(
")");
977 printer->add_text(
"]");
983 node.get_name()->accept(*
this);
984 printer->add_text(
"[");
985 printer->add_text(
"static_cast<int>(");
986 node.get_length()->accept(*
this);
987 printer->add_text(
")");
988 printer->add_text(
"]");
993 printer->add_text(local_var_type(),
' ');
994 print_vector_elements(
node.get_variables(),
", ");
999 printer->add_text(
"if (");
1000 node.get_condition()->accept(*
this);
1001 printer->add_text(
") ");
1002 node.get_statement_block()->accept(*
this);
1003 print_vector_elements(
node.get_elseifs(),
"");
1004 const auto& elses =
node.get_elses();
1006 elses->accept(*
this);
1012 printer->add_text(
" else if (");
1013 node.get_condition()->accept(*
this);
1014 printer->add_text(
") ");
1015 node.get_statement_block()->accept(*
this);
1020 printer->add_text(
" else ");
1021 node.visit_children(*
this);
1026 printer->add_text(
"while (");
1027 node.get_condition()->accept(*
this);
1028 printer->add_text(
") ");
1029 node.get_statement_block()->accept(*
this);
1035 const auto& from =
node.get_from();
1036 const auto& to =
node.get_to();
1037 const auto& inc =
node.get_increment();
1038 const auto& block =
node.get_statement_block();
1039 printer->fmt_text(
"for (int {} = ",
name);
1040 from->accept(*
this);
1041 printer->fmt_text(
"; {} <= ",
name);
1044 printer->fmt_text(
"; {} += ",
name);
1047 printer->fmt_text(
"; {}++",
name);
1049 printer->add_text(
") ");
1050 block->accept(*
this);
1055 printer->add_text(
"(");
1056 node.get_expression()->accept(*
this);
1057 printer->add_text(
")");
1062 auto op =
node.get_op().eval();
1063 const auto& lhs =
node.get_lhs();
1064 const auto&
rhs =
node.get_rhs();
1066 printer->add_text(
"pow(");
1068 printer->add_text(
", ");
1070 printer->add_text(
")");
1073 printer->add_text(
" " + op +
" ");
1080 printer->add_text(
node.eval());
1085 printer->add_text(
" " +
node.eval());
1095 print_statement_block(
node);
1100 print_function_call(
node);
1110 printer->fmt_line(
"#pragma omp critical ({})",
info.mod_suffix);
1111 printer->add_indent();
1112 printer->push_block();
1117 printer->pop_block();
1122 auto block =
node.get_node_to_solve().get();
1123 if (block->is_statement_block()) {
1125 print_statement_block(*statement_block,
false,
false);
1127 block->accept(*
this);
1134 printer->add_newline();
1136 auto float_type = default_float_data_type();
1137 int N =
node.get_n_state_vars()->get_value();
1138 printer->fmt_line(
"Eigen::Matrix<{}, {}, 1> nmodl_eigen_xm;", float_type, N);
1139 printer->fmt_line(
"{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1141 print_statement_block(*
node.get_setup_x_block(),
false,
false);
1144 printer->add_line(
"// call newton solver");
1145 printer->fmt_line(
"{} newton_functor({});",
1147 get_arg_str(functor_params()));
1148 printer->add_line(
"newton_functor.initialize();");
1150 "int newton_iterations = nmodl::newton::newton_solver(nmodl_eigen_xm, newton_functor);");
1152 "if (newton_iterations < 0) assert(false && \"Newton solver did not converge!\");");
1155 print_statement_block(*
node.get_update_states_block(),
false,
false);
1156 printer->add_line(
"newton_functor.initialize(); // TODO mimic calling F again.");
1157 printer->add_line(
"newton_functor.finalize();");
1162 printer->add_newline();
1164 const std::string float_type = default_float_data_type();
1165 int N =
node.get_n_state_vars()->get_value();
1166 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, 1> nmodl_eigen_xm, nmodl_eigen_fm;", float_type, N);
1167 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm;", float_type, N);
1169 printer->fmt_line(
"Eigen::Matrix<{0}, {1}, {1}> nmodl_eigen_jm_inv;", float_type, N);
1171 printer->fmt_line(
"{}* nmodl_eigen_x = nmodl_eigen_xm.data();", float_type);
1172 printer->fmt_line(
"{}* nmodl_eigen_j = nmodl_eigen_jm.data();", float_type);
1173 printer->fmt_line(
"{}* nmodl_eigen_f = nmodl_eigen_fm.data();", float_type);
1174 print_statement_block(*
node.get_variable_block(),
false,
false);
1175 print_statement_block(*
node.get_initialize_block(),
false,
false);
1176 print_statement_block(*
node.get_setup_x_block(),
false,
false);
1178 printer->add_newline();
1179 print_eigen_linear_solver(float_type, N);
1180 printer->add_newline();
1182 print_statement_block(*
node.get_update_states_block(),
false,
false);
1183 print_statement_block(*
node.get_finalize_block(),
false,
false);
1193 info.semantics.clear();
1195 if (
info.point_process) {
1199 for (
const auto& ion:
info.ions) {
1200 for (
auto i = 0;
i < ion.reads.size(); ++
i) {
1201 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1203 for (
const auto&
var: ion.writes) {
1205 if (
std::find(ion.reads.begin(), ion.reads.end(),
var) == ion.reads.end()) {
1206 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1208 if (ion.is_ionic_current(
var)) {
1209 info.semantics.emplace_back(
index++, ion.name +
"_ion", 1);
1212 if (ion.need_style) {
1213 info.semantics.emplace_back(
index++, fmt::format(
"{}_ion", ion.name), 1);
1214 info.semantics.emplace_back(
index++, fmt::format(
"#{}_ion", ion.name), 1);
1217 for (
auto&
var:
info.pointer_variables) {
1218 if (
info.first_pointer_var_index == -1) {
1221 int size =
var->get_length();
1222 if (
var->has_any_property(NmodlType::pointer_var)) {
1230 for (
auto&
var:
info.random_variables) {
1231 if (
info.first_random_var_index == -1) {
1234 int size =
var->get_length();
1239 if (
info.diam_used) {
1243 if (
info.area_used) {
1247 if (
info.net_send_used) {
1255 if (!
info.watch_statements.empty()) {
1256 for (
int i = 0;
i <
info.watch_statements.size() + 1;
i++) {
1261 if (
info.for_netcon_used) {
1270 return first->get_definition_order() < second->get_definition_order();
1273 auto assigned =
info.assigned_vars;
1277 for (
const auto& state:
states) {
1278 auto name =
"D" + state->get_name();
1279 auto symbol = make_symbol(
name);
1280 if (state->is_array()) {
1281 symbol->set_as_array(state->get_length());
1283 symbol->set_definition_order(state->get_definition_order());
1284 assigned.push_back(symbol);
1286 std::sort(assigned.begin(), assigned.end(), comparator);
1288 auto variables =
info.range_parameter_vars;
1289 variables.insert(variables.end(),
1290 info.range_assigned_vars.begin(),
1291 info.range_assigned_vars.end());
1292 variables.insert(variables.end(),
info.range_state_vars.begin(),
info.range_state_vars.end());
1294 for (
const auto&
v: assigned) {
1295 auto it = std::find_if(
info.external_variables.begin(),
1296 info.external_variables.end(),
1297 [&
v](
auto it) { return it->get_name() == get_name(v); });
1299 if (it ==
info.external_variables.end()) {
1300 variables.push_back(
v);
1304 if (needs_v_unused()) {
1308 if (breakpoint_exist()) {
1313 if (
auto r = std::find_if(variables.cbegin(),
1315 [&](
const auto&
s) { return name == s->get_name(); });
1316 r == variables.cend()) {
1317 variables.push_back(make_symbol(
name));
1321 if (net_receive_exist()) {
1344 std::vector<IndexVariableInfo> variables;
1345 if (
info.point_process) {
1347 variables.back().is_constant =
true;
1349 add_variable_point_process(variables);
1352 for (
auto& ion:
info.ions) {
1353 bool need_style =
false;
1354 std::unordered_map<std::string, int> ion_vars;
1358 auto const has_var = [&ion](
const char*
suffix) ->
bool {
1359 auto const pred = [
name = ion.name +
suffix](
auto const& x) {
return x ==
name; };
1360 return std::any_of(ion.reads.begin(), ion.reads.end(), pred) ||
1361 std::any_of(ion.writes.begin(), ion.writes.end(), pred);
1363 auto const add_implicit_read = [&ion](
const char*
suffix) {
1365 ion.reads.push_back(
name);
1368 bool const have_ionin{has_var(
"i")}, have_ionout{has_var(
"o")};
1369 if (have_ionin && !have_ionout) {
1370 add_implicit_read(
"o");
1371 }
else if (have_ionout && !have_ionin) {
1372 add_implicit_read(
"i");
1374 for (
const auto&
var: ion.reads) {
1376 variables.emplace_back(make_symbol(
name));
1377 variables.back().is_constant =
true;
1378 ion_vars[
name] =
static_cast<int>(variables.size() - 1);
1382 std::shared_ptr<symtab::Symbol> ion_di_dv_var =
nullptr;
1384 for (
const auto&
var: ion.writes) {
1387 const auto ion_vars_it = ion_vars.find(
name);
1388 if (ion_vars_it != ion_vars.end()) {
1389 variables[ion_vars_it->second].is_constant =
false;
1393 if (ion.is_ionic_current(
var)) {
1397 if (ion.is_intra_cell_conc(
var) || ion.is_extra_cell_conc(
var)) {
1403 if (ion_di_dv_var !=
nullptr) {
1404 variables.emplace_back(ion_di_dv_var);
1409 variables.emplace_back(make_symbol(
"style_" + ion.name),
false,
true);
1410 variables.back().is_constant =
true;
1414 for (
const auto&
var:
info.pointer_variables) {
1416 if (
var->has_any_property(NmodlType::pointer_var)) {
1417 variables.emplace_back(make_symbol(
name));
1419 variables.emplace_back(make_symbol(
name),
true);
1423 for (
const auto&
var:
info.random_variables) {
1425 variables.emplace_back(make_symbol(
name),
true);
1426 variables.back().symbol->add_properties(NmodlType::random_var);
1429 if (
info.diam_used) {
1433 if (
info.area_used) {
1437 add_variable_tqitem(variables);
1444 if (!
info.watch_statements.empty()) {
1445 for (
int i = 0;
i <
info.watch_statements.size() + 1;
i++) {
1446 variables.emplace_back(make_symbol(fmt::format(
"watch{}",
i)),
false,
false,
true);
1450 if (
info.for_netcon_used) {
1458 program_symtab =
node.get_symbol_table();
1462 info.mod_file = mod_filename;
1464 if (
info.mod_suffix ==
"") {
1465 info.mod_suffix = std::filesystem::path(mod_filename).stem().string();
1467 info.rsuffix =
info.point_process ?
"" :
"_" +
info.mod_suffix;
1468 if (
info.mod_suffix ==
"nothing") {
1472 if (!
info.vectorize) {
1473 logger->warn(
"CodegenCppVisitor : MOD file uses non-thread safe constructs of NMODL");
1476 codegen_float_variables = get_float_variables();
1477 codegen_int_variables = get_int_variables();
1479 update_index_semantics();
1481 info.semantic_variable_count = int_variables_size();
1504 throw std::logic_error(
"compute_method_name not implemented");
1510 print_codegen_routines();
1516 auto statement = get_table_statement(
node);
1517 auto table_variables = statement->get_table_vars();
1518 auto with = statement->get_with()->eval();
1520 auto tmin_name = get_variable_name(
"tmin_" +
name);
1521 auto mfac_name = get_variable_name(
"mfac_" +
name);
1522 auto function_name = method_name(
"f_" +
name);
1524 printer->add_newline(2);
1525 print_function_declaration(
node,
name);
1526 printer->push_block();
1528 const auto& params =
node.get_parameters();
1529 printer->fmt_push_block(
"if ({} == 0)", use_table_var);
1530 if (
node.is_procedure_block()) {
1531 printer->fmt_line(
"{}({}, {});",
1533 internal_method_arguments(),
1534 params[0].
get()->get_node_name());
1535 printer->add_line(
"return 0;");
1537 printer->fmt_line(
"return {}({}, {});",
1539 internal_method_arguments(),
1540 params[0].
get()->get_node_name());
1542 printer->pop_block();
1544 printer->fmt_line(
"double xi = {} * ({} - {});",
1546 params[0].
get()->get_node_name(),
1548 printer->push_block(
"if (isnan(xi))");
1549 if (
node.is_procedure_block()) {
1550 for (
const auto&
var: table_variables) {
1551 auto var_name = get_variable_name(
var->get_node_name());
1552 auto [
is_array, array_length] = check_if_var_is_array(
var->get_node_name());
1554 for (
int j = 0;
j < array_length;
j++) {
1555 printer->fmt_line(
"{}[{}] = xi;", var_name,
j);
1558 printer->fmt_line(
"{} = xi;", var_name);
1561 printer->add_line(
"return 0;");
1563 printer->add_line(
"return xi;");
1565 printer->pop_block();
1567 printer->fmt_push_block(
"if (xi <= 0. || xi >= {}.)", with);
1568 printer->fmt_line(
"int index = (xi <= 0.) ? 0 : {};", with);
1569 if (
node.is_procedure_block()) {
1570 for (
const auto& variable: table_variables) {
1571 auto var_name = variable->get_node_name();
1572 auto instance_name = get_variable_name(var_name);
1573 auto table_name = get_variable_name(
"t_" + var_name);
1574 auto [
is_array, array_length] = check_if_var_is_array(var_name);
1576 for (
int j = 0;
j < array_length;
j++) {
1578 "{}[{}] = {}[{}][index];", instance_name,
j, table_name,
j);
1581 printer->fmt_line(
"{} = {}[index];", instance_name, table_name);
1584 printer->add_line(
"return 0;");
1586 auto table_name = get_variable_name(
"t_" +
name);
1587 printer->fmt_line(
"return {}[index];", table_name);
1589 printer->pop_block();
1591 printer->add_line(
"int i = int(xi);");
1592 printer->add_line(
"double theta = xi - double(i);");
1593 if (
node.is_procedure_block()) {
1594 for (
const auto&
var: table_variables) {
1595 auto var_name =
var->get_node_name();
1596 auto instance_name = get_variable_name(var_name);
1597 auto table_name = get_variable_name(
"t_" + var_name);
1598 auto [
is_array, array_length] = check_if_var_is_array(
var->get_node_name());
1600 for (
size_t j = 0;
j < array_length;
j++) {
1602 "{0}[{1}] = {2}[{1}][i] + theta*({2}[{1}][i+1]-{2}[{1}][i]);",
1608 printer->fmt_line(
"{0} = {1}[i] + theta*({1}[i+1]-{1}[i]);",
1613 printer->add_line(
"return 0;");
1615 auto table_name = get_variable_name(
"t_" +
name);
1616 printer->fmt_line(
"return {0}[i] + theta * ({0}[i+1] - {0}[i]);", table_name);
1619 printer->pop_block();
1624 auto statement = get_table_statement(
node);
1625 auto table_variables = statement->get_table_vars();
1626 auto depend_variables = statement->get_depend_vars();
1627 const auto& from = statement->get_from();
1628 const auto& to = statement->get_to();
1630 auto internal_params = internal_method_parameters();
1631 auto with = statement->get_with()->eval();
1633 auto tmin_name = get_variable_name(
"tmin_" +
name);
1634 auto mfac_name = get_variable_name(
"mfac_" +
name);
1635 auto float_type = default_float_data_type();
1637 printer->add_newline(2);
1638 printer->fmt_push_block(
"void {}({})",
1639 table_update_function_name(
name),
1640 get_parameter_str(internal_params));
1642 printer->fmt_push_block(
"if ({} == 0)", use_table_var);
1643 printer->add_line(
"return;");
1644 printer->pop_block();
1646 printer->add_line(
"static bool make_table = true;");
1647 for (
const auto& variable: depend_variables) {
1648 printer->fmt_line(
"static {} save_{};", float_type, variable->get_node_name());
1651 for (
const auto& variable: depend_variables) {
1652 const auto& var_name = variable->get_node_name();
1653 const auto& instance_name = get_variable_name(var_name);
1654 printer->fmt_push_block(
"if (save_{} != {})", var_name, instance_name);
1655 printer->add_line(
"make_table = true;");
1656 printer->pop_block();
1659 printer->push_block(
"if (make_table)");
1661 printer->add_line(
"make_table = false;");
1663 printer->add_indent();
1664 printer->add_text(tmin_name,
" = ");
1665 from->accept(*
this);
1666 printer->add_text(
';');
1667 printer->add_newline();
1669 printer->add_indent();
1670 printer->add_text(
"double tmax = ");
1672 printer->add_text(
';');
1673 printer->add_newline();
1676 printer->fmt_line(
"double dx = (tmax-{}) / {}.;", tmin_name, with);
1677 printer->fmt_line(
"{} = 1./dx;", mfac_name);
1679 printer->fmt_line(
"double x = {};", tmin_name);
1680 printer->fmt_push_block(
"for (std::size_t i = 0; i < {}; x += dx, i++)", with + 1);
1681 auto function = method_name(
"f_" +
name);
1682 if (
node.is_procedure_block()) {
1683 printer->fmt_line(
"{}({}, x);",
function, internal_method_arguments());
1684 for (
const auto& variable: table_variables) {
1685 auto var_name = variable->get_node_name();
1686 auto instance_name = get_variable_name(var_name);
1687 auto table_name = get_variable_name(
"t_" + var_name);
1688 auto [
is_array, array_length] = check_if_var_is_array(var_name);
1690 for (
int j = 0;
j < array_length;
j++) {
1692 "{}[{}][i] = {}[{}];", table_name,
j, instance_name,
j);
1695 printer->fmt_line(
"{}[i] = {};", table_name, instance_name);
1699 auto table_name = get_variable_name(
"t_" +
name);
1700 printer->fmt_line(
"{}[i] = {}({}, x);",
1703 internal_method_arguments());
1705 printer->pop_block();
1707 for (
const auto& variable: depend_variables) {
1708 auto var_name = variable->get_node_name();
1709 auto instance_name = get_variable_name(var_name);
1710 printer->fmt_line(
"save_{} = {};", var_name, instance_name);
1713 printer->pop_block();
1715 printer->pop_block();
1720 const std::unordered_set<CppObjectSpecifier>& specifiers) {
1722 for (
const auto& specifier: specifiers) {
1726 result += object_specifier_map[specifier];
1733 const auto& table_statements =
collect_nodes(
node, {AstNodeType::TABLE_STATEMENT});
1735 if (table_statements.size() != 1) {
1736 auto message = fmt::format(
"One table statement expected in {} found {}",
1737 node.get_node_name(),
1738 table_statements.size());
1739 throw std::runtime_error(message);
1746 auto symbol = program_symtab->lookup_in_scope(
name);
1748 throw std::runtime_error(
1749 fmt::format(
"CodegenCppVisitor:: {} not found in symbol table!",
name));
1751 if (symbol->is_array()) {
1752 return {
true, symbol->get_length()};
1760 for (
const auto& state:
info.state_vars) {
1761 auto state_name = state->get_name();
1762 if (!
info.is_ionic_conc(state_name)) {
1763 auto lhs = get_variable_name(state_name);
1764 auto rhs = get_variable_name(state_name +
"0");
1766 if (state->is_array()) {
1767 for (
int i = 0;
i < state->get_length(); ++
i) {
1768 printer->fmt_line(
"{}[{}] = {};", lhs,
i,
rhs);
1771 printer->fmt_line(
"{} = {};", lhs,
rhs);
Auto generated AST classes declaration.
Represents binary expression in the NMODL.
Operator used in ast::BinaryExpression.
Base class for all block scoped nodes.
Represents a boolean variable.
Represents a double variable.
Represent linear solver solution block based on Eigen.
Represent newton solver solution block based on Eigen.
Represents a float variable.
Represents specific element of an array variable.
Represents an integer variable.
Represent MUTEXLOCK statement in NMODL.
Represent MUTEXUNLOCK statement in NMODL.
Represents a prime variable (for ODE)
Represents top level AST node for whole NMODL input.
Represent solution of a block in the AST.
Represents block encapsulating list of statements.
const StatementVector & get_statements() const noexcept
Getter for member variable StatementBlock::statements.
StatementVector::const_iterator insert_statement(StatementVector::const_iterator position, const std::shared_ptr< Statement > &n)
Insert member to statements.
symtab::SymbolTable * get_symbol_table() const override
Return associated symbol table for the current ast node.
Represents TABLE statement in NMODL.
Statement to indicate a change in timestep in a given block.
std::vector< SymbolType > get_float_variables() const
Determine all float variables required during code generation.
bool nrn_cur_required() const noexcept
Check if nrn_cur function is required.
void visit_prime_name(const ast::PrimeName &node) override
visit node of type ast::PrimeName
virtual void print_nrn_pointing(const ast::FunctionCall &node)
Print nrn_pointing.
void print_functors_definitions()
Print all Newton functor structs.
bool range_variable_setup_required() const noexcept
Check if setup_range_variable function is required.
void visit_from_statement(const ast::FromStatement &node) override
visit node of type ast::FromStatement
void print_top_verbatim_blocks()
Print top level (global scope) verbatim blocks.
void visit_unit(const ast::Unit &node) override
visit node of type ast::Unit
void visit_binary_operator(const ast::BinaryOperator &node) override
visit node of type ast::BinaryOperator
std::vector< std::string > ion_read_statements_optimized(BlockType type) const
For a given output block type, return minimal statements for all read ion variables.
bool net_receive_buffering_required() const noexcept
Check if net receive/send buffering kernels required.
bool is_function_table_call(const std::string &name) const
std::string format_float_string(const std::string &value)
Convert a given float value to its string representation.
void print_namespace_start()
Prints the start of the simulator namespace.
std::vector< ShadowUseStatement > ion_write_statements(BlockType type)
For a given output block type, return statements for writing back ion variables.
bool defined_method(const std::string &name) const
Check if given method is defined in this model.
void visit_integer(const ast::Integer &node) override
visit node of type ast::Integer
bool nrn_state_required() const noexcept
Check if nrn_state function is required.
virtual void print_parallel_iteration_hint(BlockType type, const ast::Block *block)
Print pragma annotations for channel iterations.
bool net_receive_exist() const noexcept
Check if net_receive node exist.
void visit_function_call(const ast::FunctionCall &node) override
visit node of type ast::FunctionCall
void visit_eigen_linear_solver_block(const ast::EigenLinearSolverBlock &node) override
visit node of type ast::EigenLinearSolverBlock
void visit_if_statement(const ast::IfStatement &node) override
visit node of type ast::IfStatement
static std::pair< std::string, std::string > read_ion_variable_name(const std::string &name)
Return ion variable name and corresponding ion read variable name.
void visit_solution_expression(const ast::SolutionExpression &node) override
visit node of type ast::SolutionExpression
void visit_else_statement(const ast::ElseStatement &node) override
visit node of type ast::ElseStatement
std::string get_object_specifiers(const std::unordered_set< CppObjectSpecifier > &)
std::tuple< bool, int > check_if_var_is_array(const std::string &name)
Check if the given name exist in the symbol.
void visit_program(const ast::Program &program) override
Main and only member function to call after creating an instance of this class.
virtual void print_global_var_struct_assertions() const
Print static assertions about the global variable struct.
void print_namespace_stop()
Prints the end of the simulator namespace.
void visit_var_name(const ast::VarName &node) override
void visit_string(const ast::String &node) override
visit node of type ast::String
static std::string get_parameter_str(const ParamVector ¶ms)
Generate the string representing the procedure parameter declaration.
void print_prcellstate_macros() const
Print declaration of macro NRN_PRCELLSTATE for debugging.
void visit_float(const ast::Float &node) override
visit node of type ast::Float
bool breakpoint_exist() const noexcept
Check if breakpoint node exist.
bool net_receive_required() const noexcept
Check if net_receive function is required.
void print_procedure(const ast::ProcedureBlock &node)
Print NMODL procedure in target backend code.
void print_using_namespace()
Prints f"using namespace {namespace_name()}".
virtual void print_global_struct_function_table_ptrs()
Print the entries of for FUNCTION_TABLEs in the global struct.
static std::string get_arg_str(const ParamVector ¶ms)
Generate the string representing the parameters in a function call.
void visit_update_dt(const ast::UpdateDt &node) override
visit node of type ast::UpdateDt
std::vector< std::string > ion_read_statements(BlockType type) const
For a given output block type, return statements for all read ion variables.
bool ion_variable_struct_required() const
Check if a structure for ion variables is required.
void visit_unary_operator(const ast::UnaryOperator &node) override
visit node of type ast::UnaryOperator
const ast::TableStatement * get_table_statement(const ast::Block &)
std::vector< std::tuple< std::string, std::string, std::string, std::string > > ParamVector
A vector of parameters represented by a 4-tuple of strings:
void print_eigen_linear_solver(const std::string &float_type, int N)
Print linear solver using Eigen.
static bool statement_to_skip(const ast::Statement &node)
Check if given statement should be skipped during code generation.
void visit_else_if_statement(const ast::ElseIfStatement &node) override
visit node of type ast::ElseIfStatement
void visit_name(const ast::Name &node) override
visit node of type ast::Name
std::shared_ptr< symtab::Symbol > SymbolType
void print_statement_block(const ast::StatementBlock &node, bool open_brace=true, bool close_brace=true)
Print any statement block in nmodl with option to (not) print braces.
static std::pair< std::string, std::string > write_ion_variable_name(const std::string &name)
Return ion variable name and corresponding ion write variable name.
void print_nmodl_constants()
Print the nmodl constants used in backend code.
void visit_statement_block(const ast::StatementBlock &node) override
void visit_mutex_lock(const ast::MutexLock &node) override
visit node of type ast::MutexLock
int float_variables_size() const
Number of float variables in the model.
std::string table_update_function_name(const std::string &block_name) const
The name of the function that updates the table value if the parameters changed.
void visit_boolean(const ast::Boolean &node) override
visit node of type ast::Boolean
void visit_paren_expression(const ast::ParenExpression &node) override
visit node of type ast::ParenExpression
void visit_double(const ast::Double &node) override
visit node of type ast::Double
void print_table_replacement_function(const ast::Block &)
Print replacement function for function or procedure using table.
std::vector< IndexVariableInfo > get_int_variables()
Determine all int variables required during code generation.
void print_table_check_function(const ast::Block &)
Print check_function() for functions or procedure using table.
std::string format_double_string(const std::string &value)
Convert a given double value to its string representation.
std::string process_shadow_update_statement(const ShadowUseStatement &statement, BlockType type)
Process shadow update statement.
int int_variables_size() const
Number of integer variables in the model.
std::string breakpoint_current(std::string current) const
Determine the variable name for the "current" used in breakpoint block taking into account intermedia...
virtual void print_global_var_struct_decl()
Instantiate global var instance.
bool is_functor_const(const ast::StatementBlock &variable_block, const ast::StatementBlock &functor_block)
Checks whether the functor_block generated by sympy solver modifies any variable outside its scope.
std::string update_if_ion_variable_name(const std::string &name) const
Determine the updated name if the ion variable has been optimized.
void visit_indexed_name(const ast::IndexedName &node) override
visit node of type ast::IndexedName
void visit_mutex_unlock(const ast::MutexUnlock &node) override
visit node of type ast::MutexUnlock
bool has_parameter_of_name(const T &node, const std::string &name)
Check if function or procedure node has parameter with given name.
void visit_local_list_statement(const ast::LocalListStatement &node) override
visit node of type ast::LocalListStatement
void visit_while_statement(const ast::WhileStatement &node) override
visit node of type ast::WhileStatement
bool net_send_buffer_required() const noexcept
Check if net_send_buffer is required.
void print_rename_state_vars() const
virtual void print_function_call(const ast::FunctionCall &node)
Print call to internal or external function.
void visit_eigen_newton_solver_block(const ast::EigenNewtonSolverBlock &node) override
visit node of type ast::EigenNewtonSolverBlock
void visit_binary_expression(const ast::BinaryExpression &node) override
visit node of type ast::BinaryExpression
std::string compute_method_name(BlockType type) const
int get_int_variable_index(const std::string &var_name)
void update_index_semantics()
populate all index semantics needed for registration with coreneuron
void print_mechanism_info()
Print backend code for byte array that has mechanism information (to be registered with NEURON/CoreNE...
virtual void setup(const ast::Program &node)
void print_function(const ast::FunctionBlock &node)
Print NMODL function in target backend code.
void print_function_tables(const ast::FunctionTableBlock &node)
Print the internal function for FUNCTION_TABLES.
void print_functor_definition(const ast::EigenNewtonSolverBlock &node)
Based on the EigenNewtonSolverBlock passed print the definition needed for its functor.
void print_backend_info()
Print top file header printed in generated code.
static bool need_semicolon(const ast::Statement &node)
Check if a semicolon is required at the end of given statement.
Helper visitor to gather AST information to help code generation.
Visitor to return Def-Use chain for a given variable in the block/node
Blindly rename given variable to new name
Concrete visitor for constructing symbol table from AST.
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
Visitor for printing C++ code compatible with legacy api of CoreNEURON
Helper visitor to gather AST information to help code generation.
Implement utility functions for codegen visitors.
Visitor to return Def-Use chain for a given variable in the block/node
@ MUTEX_UNLOCK
type of ast::MutexUnlock
@ MUTEX_LOCK
type of ast::MutexLock
@ PROTECT_STATEMENT
type of ast::ProtectStatement
@ LOCAL_VAR
type of ast::LocalVar
int get_index_from_name(const std::vector< T > &variables, const std::string &name)
BlockType
Helper to represent various block types.
@ Destructor
destructor block
@ Constructor
constructor block
@ Equation
breakpoint block
static std::string trim(std::string text)
bool is_array(const Symbol &sym)
double var(InputIterator begin, InputIterator end)
void move(Item *q1, Item *q2, Item *q3)
static constexpr char POINT_PROCESS_SEMANTIC[]
semantic type for point process variable
static constexpr char AREA_VARIABLE[]
similar to node_area but user can explicitly declare it as area
static constexpr char NRN_CONSTRUCTOR_METHOD[]
nrn_constructor method in generated code
static constexpr char NET_SEND_SEMANTIC[]
semantic type for net send call
static constexpr char NRN_INIT_METHOD[]
nrn_init method in generated code
static constexpr char T_SAVE_VARIABLE[]
variable t indicating last execution time of net receive block
static constexpr char CONDUCTANCE_UNUSED_VARIABLE[]
range variable when conductance is not used (for vectorized model)
static constexpr char NRN_STATE_METHOD[]
nrn_state method in generated code
static constexpr char CORE_POINTER_SEMANTIC[]
semantic type for core pointer variable
static constexpr char USE_TABLE_VARIABLE[]
global variable to indicate if table is used
static constexpr char WATCH_SEMANTIC[]
semantic type for watch statement
static constexpr char CONDUCTANCE_VARIABLE[]
range variable for conductance
static constexpr char FOR_NETCON_SEMANTIC[]
semantic type for for_netcon statement
static constexpr char DEFAULT_FLOAT_TYPE[]
default float variable type
static constexpr char NRN_CUR_METHOD[]
nrn_cur method in generated code
static constexpr char FOR_NETCON_VARIABLE[]
name of the integer variabe to store FOR_NETCON info.
static constexpr char NRN_DESTRUCTOR_METHOD[]
nrn_destructor method in generated code
static constexpr char DIAM_VARIABLE[]
inbuilt neuron variable for diameter of the compartment
static std::unordered_map< std::string, std::string > RANDOM_FUNCTIONS_MAPPING
static constexpr char RANDOM_SEMANTIC[]
semantic type for RANDOM variable
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
static constexpr char POINTER_SEMANTIC[]
semantic type for pointer variable
static constexpr char NRN_WATCH_CHECK_METHOD[]
nrn_watch_check method in generated c++ file
static constexpr char AREA_SEMANTIC[]
semantic type for area variable
static constexpr char VOLTAGE_UNUSED_VARIABLE[]
range variable for voltage when unused (for vectorized model)
static constexpr char NODE_AREA_VARIABLE[]
inbuilt neuron variable for area of the compartment
std::string format_float_string(const std::string &s_value)
Handles the float constants format being printed in the generated code.
std::string format_double_string(const std::string &s_value)
Handles the double constants format being printed in the generated code.
const std::regex regex_special_chars
std::string to_string(const T &obj)
NmodlType
NMODL variable properties.
DUState
Represent a state in Def-Use chain.
encapsulates code generation backend implementations
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
bool is_nrn_pointing(const std::string &name)
Is given name nrn_pointing.
Symbol * breakpoint_current(Symbol *s)
static Node * node(Object *)
static double param[NPARAM]
Blindly rename given variable to new name
int find(const int, const int, const int, const int, const int)
Implement string manipulation functions.
static const std::string NMODL_VERSION
project tagged version in the cmake
static const std::string GIT_REVISION
git revision id
Represent semantic information for index variable.
Represents ion write statement during code generation.
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
Utility functions for visitors implementation.