Skip to content

Commit

Permalink
Semantic: check there is at most one DERIVATIVE block
Browse files Browse the repository at this point in the history
This is not forbidden to have more, but due to a bug this fail in nrn.
  • Loading branch information
Nicolas Cornu committed Nov 21, 2023
1 parent f57d0d7 commit 2dea9aa
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 49 deletions.
31 changes: 11 additions & 20 deletions src/visitors/semantic_analysis_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ bool SemanticAnalysisVisitor::check(const ast::Program& node) {
return check_fail;
}

void SemanticAnalysisVisitor::visit_program(const ast::Program& node) {
/// <-- This code is for check 8
const auto& derivative_block_nodes = collect_nodes(node, {ast::AstNodeType::DERIVATIVE_BLOCK});
if (derivative_block_nodes.size() > 1) {
logger->critical("It is not supported to have several DERIVATIVE blocks");
check_fail = true;
}
/// -->
node.visit_children(*this);
}

void SemanticAnalysisVisitor::visit_procedure_block(const ast::ProcedureBlock& node) {
/// <-- This code is for check 1
in_procedure = true;
Expand Down Expand Up @@ -171,25 +182,5 @@ void SemanticAnalysisVisitor::visit_mutex_unlock(const ast::MutexUnlock& /* node
/// -->
}

void SemanticAnalysisVisitor::visit_breakpoint_block(const ast::BreakpointBlock& node) {
/// <-- This code is for check 8
solve_block_found_in_this_breakpoint_block = false;
node.visit_children(*this);
solve_block_found_in_this_breakpoint_block = false;
/// -->
}

void SemanticAnalysisVisitor::visit_solve_block(const ast::SolveBlock& /* node */) {
/// <-- This code is for check 8
if (solve_block_found_in_this_breakpoint_block) {
logger->critical(
"It is not allowed to have several solve blocks in the same breakpoint block");
check_fail = true;
} else {
solve_block_found_in_this_breakpoint_block = true;
}
/// -->
}

} // namespace visitor
} // namespace nmodl
12 changes: 4 additions & 8 deletions src/visitors/semantic_analysis_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* 5. Check if an independent variable is not 't'.
* 6. Check that mutex are not badly use
* 7. Check than function table got at least one argument.
* 8. Check that at most one solve block is present per breakpoint block.
* 8. Check that at most one derivative block is present.
*/
#include "ast/ast.hpp"
#include "visitors/ast_visitor.hpp"
Expand All @@ -55,8 +55,9 @@ class SemanticAnalysisVisitor: public ConstAstVisitor {
bool is_point_process = false;
/// true if we are inside a mutex locked part
bool in_mutex = false;
/// true if we already found a solve block
bool solve_block_found_in_this_breakpoint_block = false;

/// Check number of DERIVATIVE blocks
void visit_program(const ast::Program& node) override;

/// Store if we are in a procedure and if the arity of this is 1
void visit_procedure_block(const ast::ProcedureBlock& node) override;
Expand Down Expand Up @@ -85,11 +86,6 @@ class SemanticAnalysisVisitor: public ConstAstVisitor {
/// Look if MUTEXUNLOCK is outside a locked block
void visit_mutex_unlock(const ast::MutexUnlock& node) override;

void visit_breakpoint_block(const ast::BreakpointBlock& node) override;

/// Check how many solve block we got
void visit_solve_block(const ast::SolveBlock& node) override;

public:
SemanticAnalysisVisitor(bool accel_backend = false)
: accel_backend(accel_backend) {}
Expand Down
31 changes: 10 additions & 21 deletions test/unit/visitor/semantic_analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,38 +167,27 @@ SCENARIO("FUNCTION_TABLE block", "[visitor][semantic_analysis]") {
}


SCENARIO("At most one solve block per breakpoint block", "[visitor][semantic_analysis]") {
GIVEN("A breakpoint block with only one solve block") {
SCENARIO("At most one DERIVATIVE block", "[visitor][semantic_analysis]") {
GIVEN("Only one DERIVATIVE block") {
std::string nmodl_text = R"(
BREAKPOINT {
SOLVE dX METHOD cnexp
DERIVATIVE states {
m' = m/mTau
}
)";
THEN("Semantic analysis should success") {
REQUIRE_FALSE(run_semantic_analysis_visitor(nmodl_text));
}
}
GIVEN("2 breakpoints block with one solve block each") {
GIVEN("2 DERIVATIVE blocks") {
std::string nmodl_text = R"(
PROCEDURE foo() {
SOLVE dX METHOD cnexp
DERIVATIVE states1 {
m' = m/mTau
}
BREAKPOINT {
SOLVE dY METHOD cnexp
DERIVATIVE states2 {
h' = h/hTau
}
)";
THEN("Semantic analysis should success") {
REQUIRE_FALSE(run_semantic_analysis_visitor(nmodl_text));
}
}
GIVEN("A breakpoint block with two solve blocks") {
std::string nmodl_text = R"(
BREAKPOINT {
SOLVE dX METHOD cnexp
SOLVE dY METHOD cnexp
}
)";
THEN("Semantic analysis should fail") {
THEN("Semantic analysis should failed") {
REQUIRE(run_semantic_analysis_visitor(nmodl_text));
}
}
Expand Down

0 comments on commit 2dea9aa

Please sign in to comment.