diff --git a/modcc/module.cpp b/modcc/module.cpp index b13b5cb1f3f69aa9418104c1ea8f28ed28f420b5..4bc7a56516269c86100f175e6702388737e2711c 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 0000000000000000000000000000000000000000..cbf21748e543ed413f8f73f27cd02d8f1f410386 --- /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 74040532615d59ffa7a38c354d3289e250f9aa1e..f708fc91d5af3b4b6d283a4fcb038c3bb21d281f 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()); +}