From fad89723117d9ebcd44adc1ccd99fab78c920c35 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 30 Jul 2024 15:08:35 +0200 Subject: [PATCH 01/23] Implement VERBATIM (NEURON version). --- .../codegen_coreneuron_cpp_visitor.hpp | 1 - src/codegen/codegen_cpp_visitor.cpp | 1 + src/codegen/codegen_cpp_visitor.hpp | 4 + src/codegen/codegen_neuron_cpp_visitor.cpp | 89 ++++++++++++++++++- src/codegen/codegen_neuron_cpp_visitor.hpp | 28 +++++- src/main.cpp | 1 + 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/src/codegen/codegen_coreneuron_cpp_visitor.hpp b/src/codegen/codegen_coreneuron_cpp_visitor.hpp index fefd60df5..c43c2516f 100644 --- a/src/codegen/codegen_coreneuron_cpp_visitor.hpp +++ b/src/codegen/codegen_coreneuron_cpp_visitor.hpp @@ -123,7 +123,6 @@ class CodegenCoreneuronCppVisitor: public CodegenCppVisitor { */ std::string process_verbatim_token(const std::string& token); - /** * Check if variable is qualified as constant * \param name The name of variable diff --git a/src/codegen/codegen_cpp_visitor.cpp b/src/codegen/codegen_cpp_visitor.cpp index 50f9d950c..2217b449a 100644 --- a/src/codegen/codegen_cpp_visitor.cpp +++ b/src/codegen/codegen_cpp_visitor.cpp @@ -13,6 +13,7 @@ #include "ast/all.hpp" #include "codegen/codegen_helper_visitor.hpp" #include "codegen/codegen_utils.hpp" +#include "utils/string_utils.hpp" #include "visitors/defuse_analyze_visitor.hpp" #include "visitors/rename_visitor.hpp" #include "visitors/symtab_visitor.hpp" diff --git a/src/codegen/codegen_cpp_visitor.hpp b/src/codegen/codegen_cpp_visitor.hpp index b492d75ec..fc5cf8972 100644 --- a/src/codegen/codegen_cpp_visitor.hpp +++ b/src/codegen/codegen_cpp_visitor.hpp @@ -169,6 +169,10 @@ struct ShadowUseStatement { std::string rhs; }; +inline std::string get_name(ast::Ast const* sym) { + return sym->get_node_name(); +} + inline std::string get_name(const std::shared_ptr& sym) { return sym->get_name(); } diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index a7e280705..b0cb9b352 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -631,9 +631,77 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock return {params, {}}; } +std::vector CodegenNeuronCppVisitor::print_verbatim_setup( + const std::string& verbatim) { + // Note, the logic for reducing the number of macros printed, is aims to + // improve legibility of the generated code by reducing number of lines of + // code. It would be correct to print all macros, because that's essentially + // what NOCMODL does. Therefore, the logic isn't sharp. + + std::vector macros_defined; + auto print_macro = [this, &verbatim, ¯os_defined](const std::string& macro_name, + const std::string& macro_value) { + if (verbatim.find(macro_name) != std::string::npos) { + printer->fmt_line("#define {} {}", macro_name, macro_value); + macros_defined.push_back(macro_name); + } + }; + + printer->add_line("// Setup for VERBATIM"); + for (const auto& var: codegen_float_variables) { + auto name = get_name(var); + print_macro(name, get_variable_name(name)); + } + + for (const auto& var: codegen_int_variables) { + auto name = get_name(var); + print_macro(name, get_variable_name(name)); + if (verbatim.find("_p_" + name) != std::string::npos) { + print_macro("_p_" + name, get_pointer_name(name)); + } + } + + for (const auto& func: info.functions) { + auto name = get_name(func); + print_macro(name, "::neuron::" + method_name(name)); + } + + for (const auto& proc: info.procedures) { + auto name = get_name(proc); + print_macro(name, "::neuron::" + method_name(name)); + } + + if (verbatim.find("_nt") != std::string::npos) { + print_macro("_nt", "nt"); + } + + if (verbatim.find("_tqitem") != std::string::npos) { + print_macro("_tqitem", "tqitem"); + } + + return macros_defined; +} + +void CodegenNeuronCppVisitor::print_verbatim_cleanup( + const std::vector& macros_defined) { + for (const auto& macro: macros_defined) { + printer->fmt_line("#undef {}", macro); + } + printer->add_line("// End of cleanup for VERBATIM"); +} + void CodegenNeuronCppVisitor::visit_verbatim(const Verbatim& node) { - // Not implemented yet. + const auto& verbatim_code = node.get_statement()->eval(); + + auto macros_defined = print_verbatim_setup(verbatim_code); + printer->add_line("// Begin VERBATIM"); + const auto& lines = stringutils::split_string(verbatim_code, '\n'); + for (const auto& line: lines) { + printer->add_line(line); + } + printer->add_line("// End VERBATIM"); + print_verbatim_cleanup(macros_defined); } @@ -793,6 +861,25 @@ std::string CodegenNeuronCppVisitor::global_variable_name(const SymbolType& symb } +std::string CodegenNeuronCppVisitor::get_pointer_name(const std::string& name) const { + auto name_comparator = [&name](const auto& sym) { return name == get_name(sym); }; + + auto var = + std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), name_comparator); + + if (var == codegen_int_variables.end()) { + throw std::runtime_error("Only integer variables have a 'pointer name'."); + } + auto position = position_of_int_var(name); + + if (info.semantics[position].name == naming::RANDOM_SEMANTIC) { + return fmt::format("_ppvar[{}].literal_value()", position); + } + + throw std::runtime_error(fmt::format("Unsupported variable: {}. [loicw]", name)); +} + + std::string CodegenNeuronCppVisitor::get_variable_name(const std::string& name, bool use_instance) const { std::string varname = update_if_ion_variable_name(name); diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 823055b30..59e005070 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -358,6 +358,17 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { const ast::FunctionTableBlock& /* node */) override; + /** Print compatibility macros required for VERBATIM blocks. + * + * Returns the names of all macros introduced. + */ + std::vector print_verbatim_setup(const std::string& verbatim); + + /** Print `#undef`s to erase all compatibility macros. + */ + void print_verbatim_cleanup(const std::vector& macros_defined); + + /** * Arguments for register_mech or point_register_mech function */ @@ -462,7 +473,10 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { /** - * Determine variable name in the structure of mechanism properties + * Determine the C++ string to replace variable names with. + * + * Given a variable name such as `ion_cai` or `v`, return the C++ code + * required to get the value. * * \param name Variable name that is being printed * \param use_instance Should the variable be accessed via instance or data array @@ -471,6 +485,18 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { */ std::string get_variable_name(const std::string& name, bool use_instance = true) const override; + /** + * Determine the C++ string to replace pointer names with. + * + * Given a variable name such as `_p_ptr` or `_p_rng`, return the C++ code + * required to get a pointer to `ptr` (or `rng`). + * + * \param name Variable name that is being printed + * \return The C++ string representing the variable. + * thread structure + */ + std::string get_pointer_name(const std::string& name) const; + /****************************************************************************************/ /* Main printing routines for code generation */ diff --git a/src/main.cpp b/src/main.cpp index b63b7b0c7..3eabb7e75 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -294,6 +294,7 @@ int run_nmodl(int argc, const char* argv[]) { CLI11_PARSE(app, argc, argv); std::string simulator_name = neuron_code ? "neuron" : "coreneuron"; + verbatim_rename = neuron_code ? false : verbatim_rename; fs::create_directories(output_dir); fs::create_directories(scratch_dir); From ba86d6f54ca9021c1b7f8993435a96e000d723c4 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 30 Jul 2024 15:47:33 +0200 Subject: [PATCH 02/23] Fixups. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index b0cb9b352..45db7e087 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -671,6 +671,10 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( print_macro(name, "::neuron::" + method_name(name)); } + if (verbatim.find("t") != std::string::npos) { + print_macro("t", "nt->_t"); + } + if (verbatim.find("_nt") != std::string::npos) { print_macro("_nt", "nt"); } @@ -871,12 +875,7 @@ std::string CodegenNeuronCppVisitor::get_pointer_name(const std::string& name) c throw std::runtime_error("Only integer variables have a 'pointer name'."); } auto position = position_of_int_var(name); - - if (info.semantics[position].name == naming::RANDOM_SEMANTIC) { - return fmt::format("_ppvar[{}].literal_value()", position); - } - - throw std::runtime_error(fmt::format("Unsupported variable: {}. [loicw]", name)); + return fmt::format("_ppvar[{}].literal_value()", position); } From 7b7ddc56ee909f964a8d6145f4098b8c09b07fe6 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 30 Jul 2024 16:42:50 +0200 Subject: [PATCH 03/23] Print top-level VERBATIM. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 45db7e087..c0c4dde62 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -2546,6 +2546,7 @@ void CodegenNeuronCppVisitor::print_codegen_routines_regular() { print_point_process_function_definitions(); print_setdata_functions(); print_check_table_entrypoint(); + print_top_verbatim_blocks(); print_functors_definitions(); print_global_variables_for_hoc(); print_thread_memory_callbacks(); From 3d1ce91de95b525585c3b6b469cbcae06d532ae1 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 31 Jul 2024 10:58:52 +0200 Subject: [PATCH 04/23] Support `_threadargs_`. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 80 +++++++++++++++---- src/codegen/codegen_neuron_cpp_visitor.hpp | 17 ++++ test/usecases/CMakeLists.txt | 3 +- test/usecases/verbatim/internal_function.mod | 14 ++++ .../verbatim/test_internal_function.py | 11 +++ 5 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 test/usecases/verbatim/internal_function.mod create mode 100644 test/usecases/verbatim/test_internal_function.py diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index c0c4dde62..b6101e8c8 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -16,10 +16,12 @@ #include #include "ast/all.hpp" +#include "ast/procedure_block.hpp" #include "codegen/codegen_cpp_visitor.hpp" #include "codegen/codegen_utils.hpp" #include "codegen_naming.hpp" #include "config/config.h" +#include "parser/c11_driver.hpp" #include "solver/solver.hpp" #include "utils/string_utils.hpp" #include "visitors/rename_visitor.hpp" @@ -610,6 +612,19 @@ const CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::external_method_pa } +CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::internalthreadargs_parameters() { + return internal_method_parameters(); +} + +CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::threadargs_parameters() { + return {{"", "Memb_list*", "", "_ml"}, + {"", "size_t", "", "_iml"}, + {"", "Datum*", "", "_ppvar"}, + {"", "Datum*", "", "_thread"}, + {"", "double*", "", "_globals"}, + {"", "NrnThread*", "", "_nt"}}; +} + /// TODO: Edit for NEURON std::string CodegenNeuronCppVisitor::nrn_thread_arguments() const { return {}; @@ -633,10 +648,11 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock std::vector CodegenNeuronCppVisitor::print_verbatim_setup( const std::string& verbatim) { - // Note, the logic for reducing the number of macros printed, is aims to + // Note, the logic for reducing the number of macros printed, aims to // improve legibility of the generated code by reducing number of lines of - // code. It would be correct to print all macros, because that's essentially - // what NOCMODL does. Therefore, the logic isn't sharp. + // code. It would be correct to print all macros, because that's + // essentially what NOCMODL does. Therefore, the logic isn't sharp (and + // doesn't have to be). std::vector macros_defined; auto print_macro = [this, &verbatim, ¯os_defined](const std::string& macro_name, @@ -663,25 +679,28 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( for (const auto& func: info.functions) { auto name = get_name(func); - print_macro(name, "::neuron::" + method_name(name)); + print_macro(name, method_name(name)); } for (const auto& proc: info.procedures) { auto name = get_name(proc); - print_macro(name, "::neuron::" + method_name(name)); + print_macro(name, method_name(name)); } - if (verbatim.find("t") != std::string::npos) { - print_macro("t", "nt->_t"); - } + print_macro("t", "nt->_t"); + print_macro("_nt", "nt"); + print_macro("_tqitem", "tqitem"); - if (verbatim.find("_nt") != std::string::npos) { - print_macro("_nt", "nt"); - } + auto print_args_macro = [this, print_macro](const std::string& macro_basename, + const ParamVector& params) { + print_macro("_" + macro_basename + "_", get_arg_str(params)); + print_macro("_" + macro_basename + "comma_", get_arg_str(params) + ","); + print_macro("_" + macro_basename + "proto_", get_parameter_str(params)); + print_macro("_" + macro_basename + "protocomma_", get_parameter_str(params) + ","); + }; - if (verbatim.find("_tqitem") != std::string::npos) { - print_macro("_tqitem", "tqitem"); - } + print_args_macro("internalthreadargs", internalthreadargs_parameters()); + print_args_macro("threadargs", threadargs_parameters()); return macros_defined; } @@ -694,13 +713,42 @@ void CodegenNeuronCppVisitor::print_verbatim_cleanup( printer->add_line("// End of cleanup for VERBATIM"); } +std::string CodegenNeuronCppVisitor::process_verbatim_text(const std::string& verbatim) { + parser::CDriver driver; + driver.scan_string(verbatim); + auto tokens = driver.all_tokens(); + std::string result; + for (size_t i = 0; i < tokens.size(); i++) { + auto token = tokens[i]; + + // check if we have function call in the verbatim block where + // function is defined in the same mod file + if (program_symtab->is_method_defined(token) && tokens[i + 1] == "(") { + result += token + "("; + if (tokens[i + 2] == "_threadargs_") { + result += "_internalthreadargs_"; + } else if (tokens[i + 2] == "_threadargscomma_") { + result += "_internalthreadargscomma_"; + } else { + result += tokens[i + 2]; + } + + i += 2; + } else { + result += token; + } + } + return result; +} + void CodegenNeuronCppVisitor::visit_verbatim(const Verbatim& node) { const auto& verbatim_code = node.get_statement()->eval(); + auto massaged_verbatim = process_verbatim_text(verbatim_code); - auto macros_defined = print_verbatim_setup(verbatim_code); + auto macros_defined = print_verbatim_setup(massaged_verbatim); printer->add_line("// Begin VERBATIM"); - const auto& lines = stringutils::split_string(verbatim_code, '\n'); + const auto& lines = stringutils::split_string(massaged_verbatim, '\n'); for (const auto& line: lines) { printer->add_line(line); } diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 59e005070..a17a672e7 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -24,6 +24,8 @@ #include #include +#include "ast/function_block.hpp" +#include "ast/procedure_block.hpp" #include "codegen/codegen_cpp_visitor.hpp" #include "codegen/codegen_info.hpp" #include "codegen/codegen_naming.hpp" @@ -343,6 +345,14 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { const ParamVector external_method_parameters(bool table = false) noexcept override; + /** The parameters for the four macros `_internalthreadargs*_`. */ + ParamVector internalthreadargs_parameters(); + + + /** The parameters for the four macros `_threadargs*_`. */ + ParamVector threadargs_parameters(); + + /** * Arguments for "_threadargs_" macro in neuron implementation */ @@ -358,12 +368,18 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { const ast::FunctionTableBlock& /* node */) override; + void print_verbatim_overload(const std::string& return_type, const ast::Ast& node); + void print_procedure_verbatim_overload(const ast::ProcedureBlock& procedure); + void print_function_verbatim_overload(const ast::FunctionBlock& function); + + /** Print compatibility macros required for VERBATIM blocks. * * Returns the names of all macros introduced. */ std::vector print_verbatim_setup(const std::string& verbatim); + /** Print `#undef`s to erase all compatibility macros. */ void print_verbatim_cleanup(const std::vector& macros_defined); @@ -786,6 +802,7 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { /* Overloaded visitor routines */ /****************************************************************************************/ + std::string process_verbatim_text(const std::string& verbatim); void visit_verbatim(const ast::Verbatim& node) override; void visit_watch_statement(const ast::WatchStatement& node) override; void visit_for_netcon(const ast::ForNetcon& node) override; diff --git a/test/usecases/CMakeLists.txt b/test/usecases/CMakeLists.txt index 22a806a1c..dce927a0c 100644 --- a/test/usecases/CMakeLists.txt +++ b/test/usecases/CMakeLists.txt @@ -30,7 +30,8 @@ set(NMODL_USECASE_DIRS steady_state suffix table - useion) + useion + verbatim) foreach(usecase ${NMODL_USECASE_DIRS}) add_test(NAME usecase_${usecase} diff --git a/test/usecases/verbatim/internal_function.mod b/test/usecases/verbatim/internal_function.mod new file mode 100644 index 000000000..c5042a9d4 --- /dev/null +++ b/test/usecases/verbatim/internal_function.mod @@ -0,0 +1,14 @@ +NEURON { + SUFFIX internal_function + THREADSAFE +} + +FUNCTION f() { +VERBATIM + return g(_threadargs_); +ENDVERBATIM +} + +FUNCTION g() { + g = 42.0 +} diff --git a/test/usecases/verbatim/test_internal_function.py b/test/usecases/verbatim/test_internal_function.py new file mode 100644 index 000000000..b75e9a555 --- /dev/null +++ b/test/usecases/verbatim/test_internal_function.py @@ -0,0 +1,11 @@ +from neuron import h + + +def test_internal_function(): + s = h.Section() + s.nseg = 4 + + s.insert("internal_function") + + assert s.internal_function.g() == 42.0 + assert s.internal_function.f() == 42.0 From be30aad3b25f0cbbbd5a5a9ab3051066de52d54d Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 30 Oct 2024 13:59:58 +0100 Subject: [PATCH 05/23] random verbatim --- src/codegen/codegen_neuron_cpp_visitor.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index b6101e8c8..0c9157079 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -669,9 +669,11 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( print_macro(name, get_variable_name(name)); } - for (const auto& var: codegen_int_variables) { + for (size_t i = 0; i < codegen_int_variables.size(); ++i) { + const auto& var = codegen_int_variables[i]; auto name = get_name(var); - print_macro(name, get_variable_name(name)); + std::string macro_value = get_variable_name(name); + print_macro(name, macro_value); if (verbatim.find("_p_" + name) != std::string::npos) { print_macro("_p_" + name, get_pointer_name(name)); } @@ -680,6 +682,7 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( for (const auto& func: info.functions) { auto name = get_name(func); print_macro(name, method_name(name)); + print_macro(fmt::format("_l{}", name), fmt::format("ret_{}", name)); } for (const auto& proc: info.procedures) { From cb06b79917b619ad621f0a543fb0589a1ce62ddf Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 9 Sep 2024 14:01:42 +0200 Subject: [PATCH 06/23] Test RANGE variables used as pointers. --- test/usecases/verbatim/internal_function.mod | 2 +- test/usecases/verbatim/pointer_in_double.mod | 36 +++++++++++++++++++ .../verbatim/test_pointer_in_double.py | 22 ++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/usecases/verbatim/pointer_in_double.mod create mode 100644 test/usecases/verbatim/test_pointer_in_double.py diff --git a/test/usecases/verbatim/internal_function.mod b/test/usecases/verbatim/internal_function.mod index c5042a9d4..eff6756c8 100644 --- a/test/usecases/verbatim/internal_function.mod +++ b/test/usecases/verbatim/internal_function.mod @@ -1,4 +1,4 @@ -NEURON { +NEURON { SUFFIX internal_function THREADSAFE } diff --git a/test/usecases/verbatim/pointer_in_double.mod b/test/usecases/verbatim/pointer_in_double.mod new file mode 100644 index 000000000..033f84077 --- /dev/null +++ b/test/usecases/verbatim/pointer_in_double.mod @@ -0,0 +1,36 @@ +NEURON { + SUFFIX pointer_in_double + THREADSAFE +} + +ASSIGNED { + ptr +} + +VERBATIM +struct SomeDouble { + SomeDouble(double _value) : _value(_value) {} + + double value() const { + return _value; + } + + double _value; +}; + +static std::vector some_doubles; +ENDVERBATIM + +INITIAL { +VERBATIM + some_doubles.reserve(10); + some_doubles.push_back(SomeDouble(double(some_doubles.size()))); + *reinterpret_cast(&ptr) = &some_doubles.back(); +ENDVERBATIM +} + +FUNCTION use_pointer() { +VERBATIM + return (*reinterpret_cast(&ptr))->value(); +ENDVERBATIM +} diff --git a/test/usecases/verbatim/test_pointer_in_double.py b/test/usecases/verbatim/test_pointer_in_double.py new file mode 100644 index 000000000..f03d30e46 --- /dev/null +++ b/test/usecases/verbatim/test_pointer_in_double.py @@ -0,0 +1,22 @@ +from neuron import h, gui + +# Since a double is 64-bits and a pointer is also 32 or 64-bits, we can store +# the bits of a pointer in the memory that was allocated for use as doubles. +# Concretely, we, using VERBATIM, safe pointers in ASSIGNED or RANGE variables. +# +# The pattern is found in the builtin mod file: `apcount.mod`. + +def test_pointer_in_double(): + s = h.Section() + s.nseg = 3 + s.insert("pointer_in_double") + + h.finitialize() + for i, x in enumerate([0.25, 0.5, 0.75]): + actual = s(x).pointer_in_double.use_pointer() + expected = i + assert actual == expected, f"{actual} != {expected}" + + +if __name__ == "__main__": + test_pointer_in_double() From b12d9c95eae691b9e6f1c9eb575f07b2c7ab4844 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 11 Sep 2024 16:35:23 +0200 Subject: [PATCH 07/23] formatting --- test/usecases/verbatim/test_pointer_in_double.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/usecases/verbatim/test_pointer_in_double.py b/test/usecases/verbatim/test_pointer_in_double.py index f03d30e46..3bf76f490 100644 --- a/test/usecases/verbatim/test_pointer_in_double.py +++ b/test/usecases/verbatim/test_pointer_in_double.py @@ -6,6 +6,7 @@ # # The pattern is found in the builtin mod file: `apcount.mod`. + def test_pointer_in_double(): s = h.Section() s.nseg = 3 From 389fda69f3bc7dd242f4f412fb2eeb9ff203d268 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 16 Sep 2024 14:23:07 +0200 Subject: [PATCH 08/23] Modernize for-loop. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 0c9157079..5d754d1e6 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -669,8 +669,7 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( print_macro(name, get_variable_name(name)); } - for (size_t i = 0; i < codegen_int_variables.size(); ++i) { - const auto& var = codegen_int_variables[i]; + for (const auto& var: codegen_int_variables) { auto name = get_name(var); std::string macro_value = get_variable_name(name); print_macro(name, macro_value); From 554cdf8b210cab3179f3c0fbb8209d6c2c06fc3b Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 16 Sep 2024 14:23:19 +0200 Subject: [PATCH 09/23] Print macros for global and thread variables. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 5d754d1e6..e6e7e7ba7 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -678,6 +678,16 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( } } + for (const auto& var : codegen_global_variables) { + auto name = get_name(var); + print_macro(name, get_variable_name(name)); + } + + for (const auto& var : codegen_thread_variables) { + auto name = get_name(var); + print_macro(name, get_variable_name(name)); + } + for (const auto& func: info.functions) { auto name = get_name(func); print_macro(name, method_name(name)); From 24c5ffe8aa841a879171a2bcd61974c3dc87c911 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 16 Sep 2024 14:38:37 +0200 Subject: [PATCH 10/23] Test VERBATIM globals. --- test/usecases/verbatim/globals.mod | 14 ++++++++++++++ test/usecases/verbatim/test_globals.py | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/usecases/verbatim/globals.mod create mode 100644 test/usecases/verbatim/test_globals.py diff --git a/test/usecases/verbatim/globals.mod b/test/usecases/verbatim/globals.mod new file mode 100644 index 000000000..7d7293217 --- /dev/null +++ b/test/usecases/verbatim/globals.mod @@ -0,0 +1,14 @@ +NEURON { + SUFFIX globals + GLOBAL gbl +} + +ASSIGNED { + gbl +} + +FUNCTION get_gbl() { +VERBATIM +_lget_gbl = gbl; +ENDVERBATIM +} diff --git a/test/usecases/verbatim/test_globals.py b/test/usecases/verbatim/test_globals.py new file mode 100644 index 000000000..c6bc2427a --- /dev/null +++ b/test/usecases/verbatim/test_globals.py @@ -0,0 +1,13 @@ +from neuron import h, gui + +def test_globals(): + s = h.Section() + s.insert("globals") + + h.gbl_globals = 654.0 + + assert h.globals.get_gbl() == h.gbl + + +if __name__ == "__main__": + test_globals() From 1fa3cb47e7e84c21afe25de592978cff12efe250 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 24 Sep 2024 09:07:09 +0200 Subject: [PATCH 11/23] fixup: test globals --- test/usecases/verbatim/test_globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/usecases/verbatim/test_globals.py b/test/usecases/verbatim/test_globals.py index c6bc2427a..86c74df2c 100644 --- a/test/usecases/verbatim/test_globals.py +++ b/test/usecases/verbatim/test_globals.py @@ -6,7 +6,7 @@ def test_globals(): h.gbl_globals = 654.0 - assert h.globals.get_gbl() == h.gbl + assert s(0.5).globals.get_gbl() == h.gbl_globals if __name__ == "__main__": From c79187220d85e7da22d38ff869f9f6d7da456cd3 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 8 Oct 2024 13:54:39 +0200 Subject: [PATCH 12/23] pointless changes --- src/codegen/codegen_neuron_cpp_visitor.cpp | 5 ++++- src/codegen/codegen_neuron_cpp_visitor.hpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index e6e7e7ba7..26d07d986 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -647,6 +647,7 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock } std::vector CodegenNeuronCppVisitor::print_verbatim_setup( + const ast::Verbatim& node, const std::string& verbatim) { // Note, the logic for reducing the number of macros printed, aims to // improve legibility of the generated code by reducing number of lines of @@ -654,6 +655,8 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( // essentially what NOCMODL does. Therefore, the logic isn't sharp (and // doesn't have to be). + auto symtab = node.get_symbol_table(); + std::vector macros_defined; auto print_macro = [this, &verbatim, ¯os_defined](const std::string& macro_name, const std::string& macro_value) { @@ -758,7 +761,7 @@ void CodegenNeuronCppVisitor::visit_verbatim(const Verbatim& node) { const auto& verbatim_code = node.get_statement()->eval(); auto massaged_verbatim = process_verbatim_text(verbatim_code); - auto macros_defined = print_verbatim_setup(massaged_verbatim); + auto macros_defined = print_verbatim_setup(node, massaged_verbatim); printer->add_line("// Begin VERBATIM"); const auto& lines = stringutils::split_string(massaged_verbatim, '\n'); for (const auto& line: lines) { diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index a17a672e7..8a762b8f2 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -377,7 +377,7 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { * * Returns the names of all macros introduced. */ - std::vector print_verbatim_setup(const std::string& verbatim); + std::vector print_verbatim_setup(const ast::Verbatim& node, const std::string& verbatim); /** Print `#undef`s to erase all compatibility macros. From 0c9d9869f5fc199418781b33daa0bbec5ef65523 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 8 Oct 2024 14:48:54 +0200 Subject: [PATCH 13/23] macros for locals. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 26d07d986..a87f16d0b 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -655,8 +655,6 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( // essentially what NOCMODL does. Therefore, the logic isn't sharp (and // doesn't have to be). - auto symtab = node.get_symbol_table(); - std::vector macros_defined; auto print_macro = [this, &verbatim, ¯os_defined](const std::string& macro_name, const std::string& macro_value) { @@ -702,6 +700,15 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( print_macro(name, method_name(name)); } + + auto symtab = node.get_parent()->get_symbol_table(); + auto locals = symtab->get_variables(/* with= */ NmodlType::local_var); + for (const auto& local: locals) { + std::string name = local->get_name(); + print_macro(fmt::format("_l{}", name), get_variable_name(name)); + } + + print_macro("t", "nt->_t"); print_macro("_nt", "nt"); print_macro("_tqitem", "tqitem"); From 81ceeeb1d986680072c2c98727567cc047b818bc Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 9 Oct 2024 10:31:47 +0200 Subject: [PATCH 14/23] better macros for locals --- src/codegen/codegen_neuron_cpp_visitor.cpp | 36 +++++++++++++++++++--- src/symtab/symbol_table.cpp | 1 - 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index a87f16d0b..a473d7d07 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -646,6 +646,34 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock return {params, {}}; } + +std::unordered_map get_nonglobal_local_variable_names(const symtab::SymbolTable& symtab) { + if(symtab.global_scope()) { + return {}; + } + + auto local_variables = symtab.get_variables(NmodlType::local_var); + auto parent_symtab = symtab.get_parent_table(); + if(parent_symtab == nullptr) { + throw std::runtime_error("Internal NMODL error: non top-level symbol table doesn't have a parent."); + } + + auto variable_names = get_nonglobal_local_variable_names(*parent_symtab); + + for(const auto& symbol : local_variables) { + auto status = symbol->get_status(); + bool is_renamed = (status & symtab::syminfo::Status::renamed) != symtab::syminfo::Status::empty; + auto current_name = symbol->get_name(); + auto mod_name = is_renamed ? symbol->get_original_name() : current_name; + + variable_names[mod_name] = current_name; + } + + return variable_names; +} + + + std::vector CodegenNeuronCppVisitor::print_verbatim_setup( const ast::Verbatim& node, const std::string& verbatim) { @@ -702,13 +730,11 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( auto symtab = node.get_parent()->get_symbol_table(); - auto locals = symtab->get_variables(/* with= */ NmodlType::local_var); - for (const auto& local: locals) { - std::string name = local->get_name(); - print_macro(fmt::format("_l{}", name), get_variable_name(name)); + auto locals = get_nonglobal_local_variable_names(*symtab); + for (const auto& [mod_name, current_name]: locals) { + print_macro(fmt::format("_l{}", mod_name), get_variable_name(current_name)); } - print_macro("t", "nt->_t"); print_macro("_nt", "nt"); print_macro("_tqitem", "tqitem"); diff --git a/src/symtab/symbol_table.cpp b/src/symtab/symbol_table.cpp index 06dfab5a5..c313672c0 100644 --- a/src/symtab/symbol_table.cpp +++ b/src/symtab/symbol_table.cpp @@ -116,7 +116,6 @@ std::vector> SymbolTable::get_variables(NmodlType with, return result; } - std::vector> SymbolTable::get_variables_with_status(Status status, bool all) const { std::vector> variables; From 5768faa6c72c87149d40827fbf0d08bd4b9ca669 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 9 Oct 2024 10:31:54 +0200 Subject: [PATCH 15/23] Tests for locals. --- test/usecases/verbatim/locals.mod | 26 ++++++++++++++++++++++++++ test/usecases/verbatim/test_locals.py | 12 ++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 test/usecases/verbatim/locals.mod create mode 100644 test/usecases/verbatim/test_locals.py diff --git a/test/usecases/verbatim/locals.mod b/test/usecases/verbatim/locals.mod new file mode 100644 index 000000000..c5fd8b29b --- /dev/null +++ b/test/usecases/verbatim/locals.mod @@ -0,0 +1,26 @@ +NEURON { + SUFFIX locals +} + +PARAMETER { + a = -1.0 +} + +FUNCTION get_a() { LOCAL a + a = 32.0 +VERBATIM + _lget_a = _la; +ENDVERBATIM +} + +FUNCTION get_b() { LOCAL a, b + a = -1.0 + b = 32.0 + { LOCAL a + a = 100.0 + b = b + a + VERBATIM + _lget_b = _lb; + ENDVERBATIM + } +} diff --git a/test/usecases/verbatim/test_locals.py b/test/usecases/verbatim/test_locals.py new file mode 100644 index 000000000..c89fc1277 --- /dev/null +++ b/test/usecases/verbatim/test_locals.py @@ -0,0 +1,12 @@ +from neuron import h, gui + +def test_locals(): + s = h.Section() + s.insert("locals") + + assert s(0.5).locals.get_a() == 32.0 + assert s(0.5).locals.get_b() == 132.0 + + +if __name__ == "__main__": + test_locals() From d8a9144d9039fa18392f9dc79db4339e9ddd20c4 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 30 Oct 2024 09:32:01 +0100 Subject: [PATCH 16/23] formatting --- src/codegen/codegen_neuron_cpp_visitor.cpp | 20 +++++++++++--------- src/codegen/codegen_neuron_cpp_visitor.hpp | 3 ++- test/usecases/verbatim/test_globals.py | 1 + test/usecases/verbatim/test_locals.py | 1 + 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index a473d7d07..1984e75a9 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -647,22 +647,25 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock } -std::unordered_map get_nonglobal_local_variable_names(const symtab::SymbolTable& symtab) { - if(symtab.global_scope()) { +std::unordered_map get_nonglobal_local_variable_names( + const symtab::SymbolTable& symtab) { + if (symtab.global_scope()) { return {}; } auto local_variables = symtab.get_variables(NmodlType::local_var); auto parent_symtab = symtab.get_parent_table(); - if(parent_symtab == nullptr) { - throw std::runtime_error("Internal NMODL error: non top-level symbol table doesn't have a parent."); + if (parent_symtab == nullptr) { + throw std::runtime_error( + "Internal NMODL error: non top-level symbol table doesn't have a parent."); } auto variable_names = get_nonglobal_local_variable_names(*parent_symtab); - for(const auto& symbol : local_variables) { + for (const auto& symbol: local_variables) { auto status = symbol->get_status(); - bool is_renamed = (status & symtab::syminfo::Status::renamed) != symtab::syminfo::Status::empty; + bool is_renamed = (status & symtab::syminfo::Status::renamed) != + symtab::syminfo::Status::empty; auto current_name = symbol->get_name(); auto mod_name = is_renamed ? symbol->get_original_name() : current_name; @@ -673,7 +676,6 @@ std::unordered_map get_nonglobal_local_variable_names( } - std::vector CodegenNeuronCppVisitor::print_verbatim_setup( const ast::Verbatim& node, const std::string& verbatim) { @@ -707,12 +709,12 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( } } - for (const auto& var : codegen_global_variables) { + for (const auto& var: codegen_global_variables) { auto name = get_name(var); print_macro(name, get_variable_name(name)); } - for (const auto& var : codegen_thread_variables) { + for (const auto& var: codegen_thread_variables) { auto name = get_name(var); print_macro(name, get_variable_name(name)); } diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 8a762b8f2..82c4e1ec4 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -377,7 +377,8 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { * * Returns the names of all macros introduced. */ - std::vector print_verbatim_setup(const ast::Verbatim& node, const std::string& verbatim); + std::vector print_verbatim_setup(const ast::Verbatim& node, + const std::string& verbatim); /** Print `#undef`s to erase all compatibility macros. diff --git a/test/usecases/verbatim/test_globals.py b/test/usecases/verbatim/test_globals.py index 86c74df2c..d9f530da9 100644 --- a/test/usecases/verbatim/test_globals.py +++ b/test/usecases/verbatim/test_globals.py @@ -1,5 +1,6 @@ from neuron import h, gui + def test_globals(): s = h.Section() s.insert("globals") diff --git a/test/usecases/verbatim/test_locals.py b/test/usecases/verbatim/test_locals.py index c89fc1277..b0c673052 100644 --- a/test/usecases/verbatim/test_locals.py +++ b/test/usecases/verbatim/test_locals.py @@ -1,5 +1,6 @@ from neuron import h, gui + def test_locals(): s = h.Section() s.insert("locals") From 9f3f497be437910f0ec9dd131ebef492976f1ced Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 30 Oct 2024 15:12:53 +0100 Subject: [PATCH 17/23] essential whitespace. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 1984e75a9..2afc86f9f 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -616,6 +616,7 @@ CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::internalthreadargs_param return internal_method_parameters(); } + CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::threadargs_parameters() { return {{"", "Memb_list*", "", "_ml"}, {"", "size_t", "", "_iml"}, @@ -625,6 +626,7 @@ CodegenCppVisitor::ParamVector CodegenNeuronCppVisitor::threadargs_parameters() {"", "NrnThread*", "", "_nt"}}; } + /// TODO: Edit for NEURON std::string CodegenNeuronCppVisitor::nrn_thread_arguments() const { return {}; @@ -755,6 +757,7 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( return macros_defined; } + void CodegenNeuronCppVisitor::print_verbatim_cleanup( const std::vector& macros_defined) { for (const auto& macro: macros_defined) { @@ -763,6 +766,7 @@ void CodegenNeuronCppVisitor::print_verbatim_cleanup( printer->add_line("// End of cleanup for VERBATIM"); } + std::string CodegenNeuronCppVisitor::process_verbatim_text(const std::string& verbatim) { parser::CDriver driver; driver.scan_string(verbatim); From 6dca96b43a081787e1549e44a95c73010551ae2a Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 30 Oct 2024 15:46:27 +0100 Subject: [PATCH 18/23] Remove: `*_overload` functions. --- src/codegen/codegen_neuron_cpp_visitor.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 82c4e1ec4..b51cce96c 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -368,11 +368,6 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { const ast::FunctionTableBlock& /* node */) override; - void print_verbatim_overload(const std::string& return_type, const ast::Ast& node); - void print_procedure_verbatim_overload(const ast::ProcedureBlock& procedure); - void print_function_verbatim_overload(const ast::FunctionBlock& function); - - /** Print compatibility macros required for VERBATIM blocks. * * Returns the names of all macros introduced. From 62bcbb88826bcb5647646e2ef621b06f8a8757b6 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 30 Oct 2024 15:57:23 +0100 Subject: [PATCH 19/23] Use a constant for a constant. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 2afc86f9f..48595e94f 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -739,7 +739,7 @@ std::vector CodegenNeuronCppVisitor::print_verbatim_setup( print_macro(fmt::format("_l{}", mod_name), get_variable_name(current_name)); } - print_macro("t", "nt->_t"); + print_macro(naming::NTHREAD_T_VARIABLE, "nt->_t"); print_macro("_nt", "nt"); print_macro("_tqitem", "tqitem"); From 08e92aa92c75958bd1324d8bb203e8157a3b6bcc Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 31 Oct 2024 07:34:45 +0100 Subject: [PATCH 20/23] Introduce more names. --- src/codegen/codegen_naming.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/codegen/codegen_naming.hpp b/src/codegen/codegen_naming.hpp index cd0403c22..78e484c43 100644 --- a/src/codegen/codegen_naming.hpp +++ b/src/codegen/codegen_naming.hpp @@ -176,9 +176,27 @@ static constexpr char NRN_WATCH_CHECK_METHOD[] = "nrn_watch_check"; /// verbatim name of the variable for nrn thread arguments static constexpr char THREAD_ARGS[] = "_threadargs_"; +/// verbatim name of the variable for nrn thread arguments, sometimes with trailing comma +static constexpr char THREAD_ARGS_COMMA[] = "_threadargscomma_"; + /// verbatim name of the variable for nrn thread arguments in prototype static constexpr char THREAD_ARGS_PROTO[] = "_threadargsproto_"; +/// verbatim name of the variable for nrn thread arguments in prototype and a comma +static constexpr char THREAD_ARGS_PROTO_COMMA[] = "_threadargsprotocomma_"; + +/// variation of `_threadargs_` for "internal" functions. +static constexpr char INTERNAL_THREAD_ARGS[] = "_internalthreadargs_"; + +/// variation of `_threadargs_` for "internal" functions, with comma (maybe). +static constexpr char INTERNAL_THREAD_ARGS_COMMA[] = "_internalthreadargscomma_"; + +/// variation of `_threadargsproto_` for "internal" functions. +static constexpr char INTERNAL_THREAD_ARGS_PROTO[] = "_internalthreadargsproto_"; + +/// variation of `_threadargsproto_` for "internal" functions, possibly with comma. +static constexpr char INTERNAL_THREAD_ARGS_PROTO_COMMA[] = "_internalthreadargsprotocomma_"; + /// prefix for ion variable static constexpr char ION_VARNAME_PREFIX[] = "ion_"; From 3b5f00d73083955fac9053d626421f11e13bd7f0 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 31 Oct 2024 07:52:10 +0100 Subject: [PATCH 21/23] Use some more `naming::`. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 48595e94f..06aa65601 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -779,10 +779,10 @@ std::string CodegenNeuronCppVisitor::process_verbatim_text(const std::string& ve // function is defined in the same mod file if (program_symtab->is_method_defined(token) && tokens[i + 1] == "(") { result += token + "("; - if (tokens[i + 2] == "_threadargs_") { - result += "_internalthreadargs_"; - } else if (tokens[i + 2] == "_threadargscomma_") { - result += "_internalthreadargscomma_"; + if (tokens[i + 2] == naming::THREAD_ARGS) { + result += naming::INTERNAL_THREAD_ARGS; + } else if (tokens[i + 2] == naming::THREAD_ARGS_COMMA) { + result += naming::INTERNAL_THREAD_ARGS_COMMA; } else { result += tokens[i + 2]; } From 220712eb104c254ea981574d2f31d6fbb1e16316 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 31 Oct 2024 09:17:49 +0100 Subject: [PATCH 22/23] Comment `get_nonglobal_local_variable_name`. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 06aa65601..a6fcce801 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -649,6 +649,17 @@ CodegenNeuronCppVisitor::function_table_parameters(const ast::FunctionTableBlock } +/** Map of the non-(global/top-local) LOCAL variables. + * + * The map associates the name in the MOD file, e.g. `a` with + * the current name of that LOCAL variable, e.g. `a_r_4`. + * + * auto map = get_nonglobal_local_variable_names(); + * assert map["a"] == "a_r_4"; + * + * The two names can differ, because an early pass makes all + * names unique by renaming local variables. + */ std::unordered_map get_nonglobal_local_variable_names( const symtab::SymbolTable& symtab) { if (symtab.global_scope()) { From 3f272a5b7dec8fa2405311a5de913f506a4b0f8f Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Thu, 31 Oct 2024 15:08:55 +0100 Subject: [PATCH 23/23] Check top-level VERBATIM in `SUFFIX nothing`. --- src/codegen/codegen_neuron_cpp_visitor.cpp | 1 + test/usecases/verbatim/nothing.mod | 11 +++++++++++ test/usecases/verbatim/test_nothing.py | 9 +++++++++ 3 files changed, 21 insertions(+) create mode 100644 test/usecases/verbatim/nothing.mod create mode 100644 test/usecases/verbatim/test_nothing.py diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index a6fcce801..49f345367 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -2677,6 +2677,7 @@ void CodegenNeuronCppVisitor::print_codegen_routines_nothing() { print_headers_include(); print_namespace_start(); print_function_prototypes(); + print_top_verbatim_blocks(); print_global_variables_for_hoc(); print_function_definitions(); print_mechanism_register(); diff --git a/test/usecases/verbatim/nothing.mod b/test/usecases/verbatim/nothing.mod new file mode 100644 index 000000000..e100e9ddb --- /dev/null +++ b/test/usecases/verbatim/nothing.mod @@ -0,0 +1,11 @@ +NEURON { SUFFIX nothing } + +VERBATIM +double foo = 42.0; +ENDVERBATIM + +FUNCTION get_foo() { +VERBATIM + return foo; +ENDVERBATIM +} diff --git a/test/usecases/verbatim/test_nothing.py b/test/usecases/verbatim/test_nothing.py new file mode 100644 index 000000000..207d38cbd --- /dev/null +++ b/test/usecases/verbatim/test_nothing.py @@ -0,0 +1,9 @@ +from neuron import h, gui + + +def test_nothing(): + assert h.get_foo() == 42.0 + + +if __name__ == "__main__": + test_nothing()