From 1bd6043a42a17de4188c5f256cf5fe2d357ecbc8 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Fri, 19 Jul 2024 10:00:20 +0200 Subject: [PATCH] Initial attempt at implementing VERBATIM. --- .../codegen_coreneuron_cpp_visitor.cpp | 13 ++++ .../codegen_coreneuron_cpp_visitor.hpp | 2 +- src/codegen/codegen_cpp_visitor.cpp | 16 +---- src/codegen/codegen_cpp_visitor.hpp | 2 - src/codegen/codegen_neuron_cpp_visitor.cpp | 59 ++++++++++++++++++- src/codegen/codegen_neuron_cpp_visitor.hpp | 8 +-- 6 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/codegen/codegen_coreneuron_cpp_visitor.cpp b/src/codegen/codegen_coreneuron_cpp_visitor.cpp index 323ecb119..a08483909 100644 --- a/src/codegen/codegen_coreneuron_cpp_visitor.cpp +++ b/src/codegen/codegen_coreneuron_cpp_visitor.cpp @@ -109,6 +109,19 @@ std::string CodegenCoreneuronCppVisitor::process_verbatim_token(const std::strin return get_variable_name(token, use_instance); } +void CodegenCoreneuronCppVisitor::visit_verbatim(const Verbatim& node) { + const auto& text = node.get_statement()->eval(); + const auto& result = process_verbatim_text(text); + + const auto& statements = stringutils::split_string(result, '\n'); + for (const auto& statement: statements) { + const auto& trimed_stmt = stringutils::trim_newline(statement); + if (trimed_stmt.find_first_not_of(' ') != std::string::npos) { + printer->add_line(trimed_stmt); + } + } +} + /** * \details This can be override in the backend. For example, parameters can be constant diff --git a/src/codegen/codegen_coreneuron_cpp_visitor.hpp b/src/codegen/codegen_coreneuron_cpp_visitor.hpp index 33c4e311d..12feb3003 100644 --- a/src/codegen/codegen_coreneuron_cpp_visitor.hpp +++ b/src/codegen/codegen_coreneuron_cpp_visitor.hpp @@ -122,7 +122,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 @@ -1017,6 +1016,7 @@ class CodegenCoreneuronCppVisitor: public CodegenCppVisitor { void visit_derivimplicit_callback(const ast::DerivimplicitCallback& node) override; void visit_for_netcon(const ast::ForNetcon& node) override; + void visit_verbatim(const ast::Verbatim& node) override; void visit_watch_statement(const ast::WatchStatement& node) override; ParamVector functor_params() override; diff --git a/src/codegen/codegen_cpp_visitor.cpp b/src/codegen/codegen_cpp_visitor.cpp index 5dd659846..cecd29c97 100644 --- a/src/codegen/codegen_cpp_visitor.cpp +++ b/src/codegen/codegen_cpp_visitor.cpp @@ -8,11 +8,13 @@ #include +#include "codegen/codegen_coreneuron_cpp_visitor.hpp" #include "config/config.h" #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" @@ -966,20 +968,6 @@ void CodegenCppVisitor::visit_function_call(const FunctionCall& node) { } -void CodegenCppVisitor::visit_verbatim(const Verbatim& node) { - const auto& text = node.get_statement()->eval(); - const auto& result = process_verbatim_text(text); - - const auto& statements = stringutils::split_string(result, '\n'); - for (const auto& statement: statements) { - const auto& trimed_stmt = stringutils::trim_newline(statement); - if (trimed_stmt.find_first_not_of(' ') != std::string::npos) { - printer->add_line(trimed_stmt); - } - } -} - - void CodegenCppVisitor::visit_update_dt(const ast::UpdateDt& node) { // dt change statement should be pulled outside already } diff --git a/src/codegen/codegen_cpp_visitor.hpp b/src/codegen/codegen_cpp_visitor.hpp index 7c24a3f6d..0d942410f 100644 --- a/src/codegen/codegen_cpp_visitor.hpp +++ b/src/codegen/codegen_cpp_visitor.hpp @@ -1013,7 +1013,6 @@ class CodegenCppVisitor: public visitor::ConstAstVisitor { */ virtual std::string process_verbatim_text(std::string const& text) = 0; - /** * Arguments for register_mech or point_register_mech function */ @@ -1452,7 +1451,6 @@ class CodegenCppVisitor: public visitor::ConstAstVisitor { void visit_unary_operator(const ast::UnaryOperator& node) override; void visit_unit(const ast::Unit& node) override; void visit_var_name(const ast::VarName& node) override; - void visit_verbatim(const ast::Verbatim& node) override; void visit_while_statement(const ast::WhileStatement& node) override; void visit_update_dt(const ast::UpdateDt& node) override; void visit_protect_statement(const ast::ProtectStatement& node) override; diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 0163d2c87..d332bb2a6 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -491,10 +491,65 @@ std::string CodegenNeuronCppVisitor::nrn_thread_internal_arguments() { return {}; } +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("_nt") != std::string::npos) { + print_macro("_nt", "nt"); + } + + 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"); +} + -/// TODO: Write for NEURON std::string CodegenNeuronCppVisitor::process_verbatim_text(std::string const& text) { - return {}; + return text; +} + + +void CodegenNeuronCppVisitor::visit_verbatim(const Verbatim& node) { + 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); } diff --git a/src/codegen/codegen_neuron_cpp_visitor.hpp b/src/codegen/codegen_neuron_cpp_visitor.hpp index 66270573f..7bc507650 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.hpp +++ b/src/codegen/codegen_neuron_cpp_visitor.hpp @@ -310,6 +310,9 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { */ std::string process_verbatim_text(std::string const& text) override; + std::vector print_verbatim_setup(const std::string& verbatim); + void print_verbatim_cleanup(const std::vector& macros_defined); + /** * Arguments for register_mech or point_register_mech function @@ -698,12 +701,9 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor { /* Overloaded visitor routines */ /****************************************************************************************/ - + void visit_verbatim(const ast::Verbatim& node) override; void visit_watch_statement(const ast::WatchStatement& node) override; - - - public: /****************************************************************************************/ /* Public printing routines for code generation for use in unit tests */