NEURON
semantic_analysis.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <catch2/catch_test_macros.hpp>
9 #include <catch2/matchers/catch_matchers_string.hpp>
10 
11 #include "ast/program.hpp"
12 #include "parser/nmodl_driver.hpp"
13 #include "utils/test_utils.hpp"
16 
17 
18 using namespace nmodl;
19 using namespace visitor;
20 using namespace test_utils;
21 
23 
24 //=============================================================================
25 // Procedure/Function inlining tests
26 //=============================================================================
27 
28 bool run_semantic_analysis_visitor(const std::string& text) {
30  const auto& ast = driver.parse_string(text);
32  return SemanticAnalysisVisitor{}.check(*ast);
33 }
34 
35 SCENARIO("TABLE stmt", "[visitor][semantic_analysis]") {
36  GIVEN("Procedure with more than one argument") {
37  std::string nmodl_text = R"(
38  PROCEDURE rates_1(a, b) {
39  TABLE ainf FROM 0 TO 1 WITH 1
40  ainf = 1
41  }
42  )";
43  THEN("fail") {
45  }
46  }
47  GIVEN("Procedure with exactly one argument") {
48  std::string nmodl_text = R"(
49  PROCEDURE rates_1(a) {
50  TABLE ainf FROM 0 TO 1 WITH 1
51  ainf = 1
52  }
53  )";
54  THEN("pass") {
56  }
57  }
58  GIVEN("Procedure with less than one argument") {
59  std::string nmodl_text = R"(
60  PROCEDURE rates_1() {
61  TABLE ainf FROM 0 TO 1 WITH 1
62  ainf = 1
63  }
64  )";
65  THEN("fail") {
67  }
68  }
69  GIVEN("Two procedures which use a table and have the same variable") {
70  std::string nmodl_text = R"(
71  PROCEDURE p1(arg) {
72  TABLE var FROM 0 TO 1 WITH 10
73  var = arg
74  }
75  PROCEDURE p2(arg) {
76  TABLE var FROM 0 TO 1 WITH 10
77  var = 2 * arg
78  }
79  )";
80  THEN("fail") {
81  // This is asserted because `nocmodl` generated code fails to
82  // compile in these cases, not because it must not work.
84  }
85  }
86 }
87 
88 SCENARIO("Destructor block", "[visitor][semantic_analysis]") {
89  GIVEN("A point-process mod file, with a destructor") {
90  std::string nmodl_text = R"(
91  DESTRUCTOR { : Destructor is before
92  }
93 
94  NEURON {
95  POINT_PROCESS test
96  }
97  )";
98  THEN("pass") {
100  }
101  }
102  GIVEN("A artifial-cell mod file, with a destructor") {
103  std::string nmodl_text = R"(
104  NEURON {
105  ARTIFICIAL_CELL test
106  }
107 
108  DESTRUCTOR {
109  }
110  )";
111  THEN("pass") {
113  }
114  }
115  GIVEN("A non point-process mod file, with a destructor") {
116  std::string nmodl_text = R"(
117  NEURON {
118  }
119 
120  DESTRUCTOR {
121  }
122  )";
123  THEN("fail") {
125  }
126  }
127 }
128 
129 SCENARIO("Ion variable in CONSTANT block", "[visitor][semantic_analysis]") {
130  GIVEN("A mod file with ion variable redeclared in a CONSTANT block") {
131  std::string nmodl_text = R"(
132  NEURON {
133  SUFFIX cdp4Nsp
134  USEION ca READ cao, cai, ica WRITE cai
135  }
136  CONSTANT { cao = 2 (mM) }
137  )";
138  THEN("Semantic analysis fails") {
140  }
141  }
142 }
143 
144 SCENARIO("INDEPENDENT block", "[visitor][semantic_analysis]") {
145  GIVEN("A mod file with Independent block with only t") {
146  std::string nmodl_text = R"(
147  INDEPENDENT {
148  t FROM 0 TO 1 WITH 100
149  }
150  )";
151  THEN("Semantic analysis succeed") {
153  }
154  }
155  GIVEN("A mod file with Independent block with something else than t") {
156  std::string nmodl_text = R"(
157  INDEPENDENT {
158  t FROM 0 TO 1 WITH 100
159  u FROM 0 TO 1 WITH 100
160  }
161  )";
162  THEN("Semantic analysis fails") {
164  }
165  }
166 }
167 
168 SCENARIO("FUNCTION_TABLE block", "[visitor][semantic_analysis]") {
169  GIVEN("A mod file with FUNCTION_TABLE without argument") {
170  std::string nmodl_text = R"(
171  FUNCTION_TABLE ttt()
172  )";
173  THEN("Semantic analysis should fail") {
175  }
176  }
177  GIVEN("A mod file with FUNCTION_TABLE with at least one argument") {
178  std::string nmodl_text = R"(
179  FUNCTION_TABLE ttt(w (mV))
180  )";
181  THEN("Semantic analysis should success") {
183  }
184  }
185 }
186 
187 
188 SCENARIO("At most one DERIVATIVE block", "[visitor][semantic_analysis]") {
189  GIVEN("Only one DERIVATIVE block") {
190  std::string nmodl_text = R"(
191  DERIVATIVE states {
192  m' = m/mTau
193  }
194  )";
195  THEN("Semantic analysis should success") {
197  }
198  }
199  GIVEN("2 DERIVATIVE blocks") {
200  std::string nmodl_text = R"(
201  DERIVATIVE states1 {
202  m' = m/mTau
203  }
204  DERIVATIVE states2 {
205  h' = h/hTau
206  }
207  )";
208  THEN("Semantic analysis should failed") {
210  }
211  }
212 }
213 
214 SCENARIO("RANDOM Construct", "[visitor][semantic_analysis]") {
215  GIVEN("A mod file with correct RANDOM variable usage") {
216  std::string nmodl_text = R"(
217  NEURON {
218  RANDOM r
219  }
220  PROCEDURE rates() {
221  LOCAL x
222  random_setseq(r, 1)
223  x = 1 + random_negexp(r)
224  x = x + exp(random_negexp(r))
225  }
226  FUNCTION erand() {
227  erand = random_negexp(r)
228  }
229  )";
230  THEN("Semantic analysis should pass") {
232  }
233  }
234 
235  GIVEN("A mod file with incorrect usage of RANDOM variable as function arguments") {
236  std::string nmodl_text = R"(
237  NEURON {
238  RANDOM r
239  }
240  PROCEDURE rates() {
241  random_setseq(1, r)
242  }
243  )";
244  THEN("Semantic analysis should faial") {
246  }
247  }
248 
249  GIVEN("A mod file with incorrect usage of RANDOM variable in an expression") {
250  std::string nmodl_text = R"(
251  NEURON {
252  RANDOM r
253  }
254  PROCEDURE rates() {
255  LOCAL x
256  x = r + 1
257  }
258  )";
259  THEN("Semantic analysis should fail") {
261  }
262  }
263 
264  GIVEN("A mod file with incorrect usage of RANDOM variable in non-random function") {
265  std::string nmodl_text = R"(
266  NEURON {
267  RANDOM r
268  }
269  PROCEDURE rates() {
270  LOCAL x
271  x = exp(r) + 1
272  }
273  )";
274  THEN("Semantic analysis should fail") {
276  }
277  }
278 }
279 
280 SCENARIO("RANGE and FUNCTION/PROCEDURE block", "[visitor][semantic_analysis]") {
281  GIVEN("A mod file with same RANGE var name and a FUNCTION name") {
282  std::string nmodl_text = R"(
283  NEURON {
284  RANGE f
285  }
286  FUNCTION f(arg) {
287  f = 1
288  }
289  )";
290  THEN("Semantic analysis should fail") {
292  }
293  }
294  GIVEN("A mod file with same RANGE var name and a PROCEDURE name") {
295  std::string nmodl_text = R"(
296  NEURON {
297  RANGE f
298  }
299  PROCEDURE f(arg) {
300  }
301  )";
302  THEN("Semantic analysis should fail") {
304  }
305  }
306 }
307 
308 SCENARIO("FUNCTION block that does not return anything must raise a warning",
309  "[visitor][semantic_analysis]") {
310  GIVEN("A mod file with a FUNCTION that does not return anything") {
311  std::string nmodl_text = R"(
312  FUNCTION asdf() {
313  }
314  )";
315  THEN("Semantic analysis should raise a warning") {
316  auto capture = test_utils::LoggerCapture();
318  REQUIRE_THAT(capture.output(),
319  Catch::Matchers::ContainsSubstring("does not have a return statement"));
320  }
321  }
322  GIVEN("A mod file with a FUNCTION that does not return anything and VERBATIM block") {
323  std::string nmodl_text = R"(
324  FUNCTION asdf() {
325  VERBATIM
326  _lasdf = 1;
327  ENDVERBATIM
328  }
329  )";
330  THEN("Semantic analysis should raise a warning") {
331  auto capture = test_utils::LoggerCapture();
333  REQUIRE_THAT(capture.output(),
334  Catch::Matchers::ContainsSubstring(
335  "possible return statement in VERBATIM block"));
336  }
337  }
338 }
Class that binds all pieces together for parsing nmodl file.
Visitor to check some semantic rules on the AST
Concrete visitor for constructing symbol table from AST.
void visit_program(ast::Program &node) override
visit node of type ast::Program
int nmodl_text
Definition: modl.cpp:58
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
Definition: unit_driver.cpp:40
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
#define text
Definition: plot.cpp:60
Auto generated AST classes declaration.
bool run_semantic_analysis_visitor(const std::string &text)
SCENARIO("TABLE stmt", "[visitor][semantic_analysis]")
Visitor to check some semantic rules on the AST
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28