From cba38a3503a6b402dcf9e618abe64520fcccb4a2 Mon Sep 17 00:00:00 2001 From: Nora Abi Akar <nora.abiakar@gmail.com> Date: Wed, 17 Feb 2021 16:59:06 +0100 Subject: [PATCH] Modcc: solve statement (#1373) - Allow SOLVE statement anywhere in the BREAKPOINT block. - Add unit test. Fixes #1384. --- modcc/module.cpp | 29 +++++++++++--------- test/unit-modcc/mod_files/test8.mod | 42 +++++++++++++++++++++++++++++ test/unit-modcc/test_module.cpp | 11 ++++++++ 3 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 test/unit-modcc/mod_files/test8.mod diff --git a/modcc/module.cpp b/modcc/module.cpp index b13b5cb1..4bc7a565 100644 --- a/modcc/module.cpp +++ b/modcc/module.cpp @@ -182,6 +182,23 @@ bool Module::semantic() { // move functions and procedures to the symbol table if(!move_symbols(callables_)) return false; + // Before starting the inlining process, look for the BREAKPOINT block: + // if it includes a SOLVE statement, check that it is the first statement + // in the block. + if (has_symbol("breakpoint", symbolKind::procedure)) { + bool found_non_solve = false; + auto breakpoint = symbols_["breakpoint"]->is_procedure(); + for (const auto& s: breakpoint->body()->statements()) { + if(!s->is_solve_statement()) { + found_non_solve = true; + } + else if (found_non_solve) { + error("SOLVE statements must come first in BREAKPOINT block", s->location()); + return false; + } + } + } + // perform semantic analysis and inlining on function and procedure bodies if(auto errors = semantic_func_proc()) { error("There were "+std::to_string(errors)+" errors in the semantic analysis"); @@ -360,25 +377,13 @@ bool Module::semantic() { // Grab SOLVE statements, put them in `nrn_state` after translation. bool found_solve = false; - bool found_non_solve = false; std::set<std::string> solved_ids; for(auto& e: (breakpoint->body()->statements())) { SolveExpression* solve_expression = e->is_solve_statement(); - LocalDeclaration* local_expression = e->is_local_declaration(); - if(local_expression) { - continue; - } if(!solve_expression) { - found_non_solve = true; continue; } - if(found_non_solve) { - error("SOLVE statements must come first in BREAKPOINT block", - e->location()); - return false; - } - found_solve = true; std::unique_ptr<SolverVisitorBase> solver; diff --git a/test/unit-modcc/mod_files/test8.mod b/test/unit-modcc/mod_files/test8.mod new file mode 100644 index 00000000..cbf21748 --- /dev/null +++ b/test/unit-modcc/mod_files/test8.mod @@ -0,0 +1,42 @@ +NEURON { +POINT_PROCESS expsyn +RANGE tau, e +NONSPECIFIC_CURRENT i +} + +UNITS { +(mV) = (millivolt) +} + +PARAMETER { +tau = 2.0 (ms) : the default for Neuron is 0.1 +e = 0 (mV) +} + +ASSIGNED {} + +STATE { +g +} + +INITIAL { +g=0 +} + +BREAKPOINT { +SOLVE state METHOD cnexp +i = foo(g)*(v - e) +} + +DERIVATIVE state { +g' = -g/tau + tau +} + +NET_RECEIVE(weight) { +g = g * weight +} + +FUNCTION foo(g) { +foo = exp(g) + 5 +} + diff --git a/test/unit-modcc/test_module.cpp b/test/unit-modcc/test_module.cpp index 74040532..f708fc91 100644 --- a/test/unit-modcc/test_module.cpp +++ b/test/unit-modcc/test_module.cpp @@ -102,3 +102,14 @@ TEST(Module, linear_mechanisms) { } } } + +TEST(Module, breakpoint) { + // Test function call in BREAKPOINT block + Module m(io::read_all(DATADIR "/mod_files/test8.mod"), "test8.mod"); + EXPECT_NE(m.buffer().size(), 0); + + Parser p(m, false); + EXPECT_TRUE(p.parse()); + + EXPECT_TRUE(m.semantic()); +} -- GitLab