User Guide
defuse_analyze.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_session.hpp>
9 #include <catch2/catch_test_macros.hpp>
10 
12 #include "ast/program.hpp"
13 #include "parser/nmodl_driver.hpp"
19 
20 using namespace nmodl;
21 using namespace visitor;
22 using namespace test;
23 using namespace test_utils;
24 
25 using ast::AstNodeType;
27 
28 //=============================================================================
29 // DefUseAnalyze visitor tests
30 //=============================================================================
31 
32 std::vector<DUChain> run_defuse_visitor(const std::string& text, const std::string& variable) {
34  const auto& ast = driver.parse_string(text);
35 
36  SymtabVisitor().visit_program(*ast);
37  InlineVisitor().visit_program(*ast);
38 
39  std::vector<DUChain> chains;
40  DefUseAnalyzeVisitor v(*ast->get_symbol_table());
41 
42  /// analyse only derivative blocks in this test
43  const auto& blocks = nmodl::collect_nodes(*ast, {AstNodeType::DERIVATIVE_BLOCK});
44  chains.reserve(blocks.size());
45  for (const auto& block: blocks) {
46  chains.push_back(v.analyze(*block, variable));
47  }
48 
49  // check that, after visitor rearrangement, parents are still up-to-date
50  CheckParentVisitor().check_ast(*ast);
51 
52  return chains;
53 }
54 
55 SCENARIO("Perform DefUse analysis on NMODL constructs") {
56  GIVEN("global variable usage in assignment statements") {
57  std::string nmodl_text = R"(
58  NEURON {
59  RANGE tau, beta
60  }
61 
62  DERIVATIVE states {
63  tau = 1
64  tau = 1 + tau
65  }
66  )";
67 
68  std::string expected_text =
69  R"({"DerivativeBlock":[{"name":"D"},{"name":"U"},{"name":"D"}]})";
70 
71  THEN("Def-Use chains for individual usage is printed") {
72  std::string input = reindent_text(nmodl_text);
73  auto chains = run_defuse_visitor(input, "tau");
74 
75  REQUIRE(chains[0].to_string(true) == expected_text);
76  REQUIRE(chains[0].eval() == DUState::D);
77 
78  REQUIRE(to_nmodl(*chains[0].chain[0].binary_expression) == "tau = 1");
79  REQUIRE(to_nmodl(*chains[0].chain[1].binary_expression) == "tau = 1+tau");
80  REQUIRE(to_nmodl(*chains[0].chain[2].binary_expression) == "tau = 1+tau");
81  }
82  }
83 
84  GIVEN("block with use of verbatim block") {
85  std::string nmodl_text = R"(
86  NEURON {
87  RANGE tau, beta
88  }
89 
90  DERIVATIVE states {
91  VERBATIM ENDVERBATIM
92  tau = 1
93  VERBATIM ENDVERBATIM
94  }
95  )";
96 
97  std::string expected_text =
98  R"({"DerivativeBlock":[{"name":"U"},{"name":"D"},{"name":"U"}]})";
99 
100  THEN("Verbatim block is considered as use of the variable") {
101  std::string input = reindent_text(nmodl_text);
102  auto chains = run_defuse_visitor(input, "tau");
103  REQUIRE(chains[0].to_string(true) == expected_text);
104  REQUIRE(chains[0].eval() == DUState::U);
105 
106  REQUIRE(chains[0].chain[0].binary_expression == nullptr); // verbatim begin
107  REQUIRE(to_nmodl(*chains[0].chain[1].binary_expression) == "tau = 1");
108  REQUIRE(chains[0].chain[2].binary_expression == nullptr); // verbatim end
109  }
110  }
111 
112  GIVEN("use of array variables") {
113  std::string nmodl_text = R"(
114  DEFINE N 3
115  STATE {
116  m[N]
117  h[N]
118  n[N]
119  o[N]
120  }
121  DERIVATIVE states {
122  LOCAL tau[N]
123  tau[0] = 1 : tau[0] is defined
124  tau[2] = 1 + tau[1] + tau[2] : tau[1] is used; tau[2] is defined as well as used
125  m[0] = m[1] : m[0] is defined and used on next line; m[1] is used
126  h[1] = m[0] + h[0] : h[0] is used; h[1] is defined
127  o[i] = 1 : o[i] is defined for any i
128  n[i+1] = 1 + n[i] : n[i] is used as well as defined for any i
129  }
130  )";
131 
132  THEN("Def-Use analyser distinguishes variables by array index") {
133  std::string input = reindent_text(nmodl_text);
134  {
135  auto m0 = run_defuse_visitor(input, "m[0]");
136  auto m1 = run_defuse_visitor(input, "m[1]");
137  auto h1 = run_defuse_visitor(input, "h[1]");
138  auto tau0 = run_defuse_visitor(input, "tau[0]");
139  auto tau1 = run_defuse_visitor(input, "tau[1]");
140  auto tau2 = run_defuse_visitor(input, "tau[2]");
141  auto n0 = run_defuse_visitor(input, "n[0]");
142  auto n1 = run_defuse_visitor(input, "n[1]");
143  auto o0 = run_defuse_visitor(input, "o[0]");
144 
145  REQUIRE(m0[0].to_string() == R"({"DerivativeBlock":[{"name":"D"},{"name":"U"}]})");
146  REQUIRE(to_nmodl(*m0[0].chain[0].binary_expression) == "m[0] = m[1]");
147  REQUIRE(to_nmodl(*m0[0].chain[1].binary_expression) == "h[1] = m[0]+h[0]");
148  REQUIRE(m1[0].to_string() == R"({"DerivativeBlock":[{"name":"U"}]})");
149  REQUIRE(to_nmodl(*m1[0].chain[0].binary_expression) == "m[0] = m[1]");
150  REQUIRE(h1[0].to_string() == R"({"DerivativeBlock":[{"name":"D"}]})");
151  REQUIRE(to_nmodl(*h1[0].chain[0].binary_expression) == "h[1] = m[0]+h[0]");
152  REQUIRE(tau0[0].to_string() == R"({"DerivativeBlock":[{"name":"LD"}]})");
153  REQUIRE(to_nmodl(*tau0[0].chain[0].binary_expression) == "tau[0] = 1");
154  REQUIRE(tau1[0].to_string() == R"({"DerivativeBlock":[{"name":"LU"}]})");
155  REQUIRE(to_nmodl(*tau1[0].chain[0].binary_expression) ==
156  "tau[2] = 1+tau[1]+tau[2]");
157  REQUIRE(tau2[0].to_string() ==
158  R"({"DerivativeBlock":[{"name":"LU"},{"name":"LD"}]})");
159  REQUIRE(to_nmodl(*tau2[0].chain[0].binary_expression) ==
160  "tau[2] = 1+tau[1]+tau[2]");
161  REQUIRE(to_nmodl(*tau2[0].chain[1].binary_expression) ==
162  "tau[2] = 1+tau[1]+tau[2]");
163  REQUIRE(n0[0].to_string() == R"({"DerivativeBlock":[{"name":"U"},{"name":"D"}]})");
164  REQUIRE(to_nmodl(*n0[0].chain[0].binary_expression) == "n[i+1] = 1+n[i]");
165  REQUIRE(to_nmodl(*n0[0].chain[1].binary_expression) == "n[i+1] = 1+n[i]");
166  REQUIRE(n1[0].to_string() == R"({"DerivativeBlock":[{"name":"U"},{"name":"D"}]})");
167  REQUIRE(to_nmodl(*n1[0].chain[0].binary_expression) == "n[i+1] = 1+n[i]");
168  REQUIRE(to_nmodl(*n1[0].chain[1].binary_expression) == "n[i+1] = 1+n[i]");
169  REQUIRE(o0[0].to_string() == R"({"DerivativeBlock":[{"name":"D"}]})");
170  REQUIRE(to_nmodl(*o0[0].chain[0].binary_expression) == "o[i] = 1");
171  }
172  }
173  }
174 
175  GIVEN("global variable used in if statement (lhs)") {
176  std::string nmodl_text = R"(
177  NEURON {
178  RANGE tau
179  }
180 
181  DERIVATIVE states {
182  IF (tau == 0) {
183  }
184  }
185  )";
186 
187  std::string expected_text =
188  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"U"}]}]}]})";
189 
190  THEN("tau is used") {
191  std::string input = reindent_text(nmodl_text);
192  auto chains = run_defuse_visitor(input, "tau");
193  REQUIRE(chains[0].to_string() == expected_text);
194  REQUIRE(chains[0].eval() == DUState::U);
195  REQUIRE(chains[0].chain[0].binary_expression == nullptr);
196  REQUIRE(chains[0].chain[0].children[0].binary_expression == nullptr);
197  REQUIRE(to_nmodl(*chains[0].chain[0].children[0].children[0].binary_expression) ==
198  "tau == 0");
199  }
200  }
201 
202  GIVEN("global variable used in if statement (rhs)") {
203  std::string nmodl_text = R"(
204  NEURON {
205  RANGE tau
206  }
207 
208  DERIVATIVE states {
209  IF (0 == tau) {
210  }
211  }
212  )";
213 
214  std::string expected_text =
215  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"U"}]}]}]})";
216 
217  THEN("tau is used") {
218  std::string input = reindent_text(nmodl_text);
219  auto chains = run_defuse_visitor(input, "tau");
220  REQUIRE(chains[0].to_string() == expected_text);
221  REQUIRE(chains[0].eval() == DUState::U);
222  REQUIRE(chains[0].chain[0].binary_expression == nullptr);
223  REQUIRE(chains[0].chain[0].children[0].binary_expression == nullptr);
224  REQUIRE(to_nmodl(*chains[0].chain[0].children[0].children[0].binary_expression) ==
225  "0 == tau");
226  }
227  }
228 
229  GIVEN("global variable definition in else block") {
230  std::string nmodl_text = R"(
231  NEURON {
232  RANGE tau, beta
233  }
234 
235  DERIVATIVE states {
236  IF (1) {
237  LOCAL tau
238  tau = 1
239  } ELSE {
240  tau = 1
241  }
242  }
243  )";
244 
245  std::string expected_text =
246  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"LD"}]},{"ELSE":[{"name":"D"}]}]}]})";
247 
248  THEN("Def-Use chains should return CD") {
249  std::string input = reindent_text(nmodl_text);
250  auto chains = run_defuse_visitor(input, "tau");
251  REQUIRE(chains[0].to_string() == expected_text);
252  REQUIRE(chains[0].eval() == DUState::CD);
253  }
254  }
255 
256  GIVEN("global variable use in if statement + definition and use in if and else blocks") {
257  std::string nmodl_text = R"(
258  NEURON {
259  RANGE tau
260  }
261 
262  DERIVATIVE states {
263  IF (tau == 0) {
264  tau = 1 + tau
265  } ELSE {
266  tau = 2 + tau
267  }
268  }
269  )";
270 
271  std::string expected_text =
272  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"U"},{"name":"U"},{"name":"D"}]},{"ELSE":[{"name":"U"},{"name":"D"}]}]}]})";
273 
274  THEN("tau is used and then used in its definitions") {
275  std::string input = reindent_text(nmodl_text);
276  auto chains = run_defuse_visitor(input, "tau");
277  REQUIRE(chains[0].to_string() == expected_text);
278  REQUIRE(chains[0].chain[0].binary_expression == nullptr); // CONDITIONAL_BLOCK
279  REQUIRE(chains[0].chain[0].children[0].binary_expression == nullptr); // IF
280  REQUIRE(to_nmodl(*chains[0].chain[0].children[0].children[0].binary_expression) ==
281  "tau == 0");
282  REQUIRE(to_nmodl(*chains[0].chain[0].children[0].children[1].binary_expression) ==
283  "tau = 1+tau");
284  REQUIRE(to_nmodl(*chains[0].chain[0].children[0].children[2].binary_expression) ==
285  "tau = 1+tau");
286  REQUIRE(chains[0].chain[0].children[1].binary_expression == nullptr); // ELSE
287  REQUIRE(to_nmodl(*chains[0].chain[0].children[1].children[0].binary_expression) ==
288  "tau = 2+tau");
289  REQUIRE(to_nmodl(*chains[0].chain[0].children[1].children[1].binary_expression) ==
290  "tau = 2+tau");
291  }
292  }
293 
294  GIVEN("global variable usage in else block") {
295  std::string nmodl_text = R"(
296  NEURON {
297  RANGE tau, beta
298  }
299 
300  DERIVATIVE states {
301  IF (1) {
302  } ELSE {
303  tau = 1 + tau
304  }
305  }
306  )";
307 
308  std::string expected_text =
309  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"name":"IF"},{"ELSE":[{"name":"U"},{"name":"D"}]}]}]})";
310 
311  THEN("Def-Use chains should return USE") {
312  std::string input = reindent_text(nmodl_text);
313  auto chains = run_defuse_visitor(input, "tau");
314  REQUIRE(chains[0].to_string() == expected_text);
315  REQUIRE(chains[0].eval() == DUState::U);
316  }
317  }
318 
319  GIVEN("local variable usage in else block") {
320  std::string nmodl_text = R"(
321  NEURON {
322  RANGE tau
323  }
324 
325  DERIVATIVE states {
326  IF (tau == 1) {
327  } ELSE {
328  LOCAL tau
329  tau = 1 + tau
330  }
331  }
332  )";
333 
334  std::string expected_text =
335  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"U"}]},{"ELSE":[{"name":"LU"},{"name":"LD"}]}]}]})";
336 
337  THEN("Def-Use chains should return USE because global variables have precedence in eval") {
338  std::string input = reindent_text(nmodl_text);
339  auto chains = run_defuse_visitor(input, "tau");
340  REQUIRE(chains[0].to_string() == expected_text);
341  REQUIRE(chains[0].eval() == DUState::U);
342  }
343  }
344 
345  GIVEN("local variable conditional definition") {
346  std::string nmodl_text = R"(
347  NEURON {
348  RANGE beta
349  }
350 
351  DERIVATIVE states {
352  LOCAL tau
353  IF (beta == 0) {
354  tau = 1
355  }
356  }
357  )";
358 
359  std::string expected_text =
360  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"LD"}]}]}]})";
361 
362  THEN("Def-Use chains should return USE because global variables have precedence in eval") {
363  std::string input = reindent_text(nmodl_text);
364  auto chains = run_defuse_visitor(input, "tau");
365  REQUIRE(chains[0].to_string() == expected_text);
366  REQUIRE(chains[0].eval() == DUState::CD);
367  }
368  }
369 
370  GIVEN("local and range variables usage and definitions") {
371  std::string nmodl_text = R"(
372  NEURON {
373  RANGE beta
374  }
375 
376  DERIVATIVE states {
377  LOCAL tau
378  IF (beta == 0) {
379  tau = 1
380  } ELSE {
381  beta = 0
382  }
383  }
384  )";
385 
386  std::string expected_text =
387  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"name":"IF"},{"name":"ELSE"}]}]})";
388 
389  THEN(
390  "Def-Use chains should return NONE because the variable we look for is not one of "
391  "them") {
392  std::string input = reindent_text(nmodl_text);
393  auto chains = run_defuse_visitor(input, "alpha");
394  REQUIRE(chains[0].to_string() == expected_text);
395  REQUIRE(chains[0].eval() == DUState::NONE);
396  }
397  }
398 
399  GIVEN("Simple check of local and global variables") {
400  std::string nmodl_text = R"(
401  NEURON {
402  GLOBAL x
403  }
404 
405  DERIVATIVE states {
406  LOCAL a, b
407  a = 1
408  IF (x == 1) {
409  LOCAL c
410  c = 1
411  }
412  }
413  )";
414 
415  std::string expected_text_x =
416  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"U"}]}]}]})";
417  std::string expected_text_a =
418  R"({"DerivativeBlock":[{"name":"LD"},{"CONDITIONAL_BLOCK":[{"name":"IF"}]}]})";
419  std::string expected_text_b =
420  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"name":"IF"}]}]})";
421  std::string expected_text_c =
422  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"LD"}]}]}]})";
423 
424  THEN("local and global variables are correctly analyzed") {
425  std::string input = reindent_text(nmodl_text);
426  auto chains_x = run_defuse_visitor(input, "x");
427  // Global variable "x" should be U as it's only used in the IF-ELSE statement
428  REQUIRE(chains_x[0].to_string() == expected_text_x);
429  REQUIRE(chains_x[0].eval() == DUState::U);
430 
431  auto chains_a = run_defuse_visitor(input, "a");
432  // Local variable "a" should be LD as it's local and defined
433  REQUIRE(chains_a[0].to_string() == expected_text_a);
434  REQUIRE(chains_a[0].eval() == DUState::LD);
435 
436  auto chains_b = run_defuse_visitor(input, "b");
437  // Local variable "b" should be NONE as it's not used
438  REQUIRE(chains_b[0].to_string() == expected_text_b);
439  REQUIRE(chains_b[0].eval() == DUState::NONE);
440 
441  auto chains_c = run_defuse_visitor(input, "c");
442  // Local variable "c" should be CD as it's conditionally defined
443  REQUIRE(chains_c[0].to_string() == expected_text_c);
444  REQUIRE(chains_c[0].eval() == DUState::CD);
445  }
446  }
447 
448  GIVEN("Simple check of assigned variables") {
449  const std::string nmodl_text = R"(
450  NEURON {
451  SUFFIX foo
452  }
453 
454  ASSIGNED {
455  y
456  }
457 
458  DERIVATIVE states {
459  y = 1
460  y = y + 2
461  }
462  )";
463 
464  const std::string expected_text_y =
465  R"({"DerivativeBlock":[{"name":"D"},{"name":"U"},{"name":"D"}]})";
466 
467  THEN("assigned variables are correctly analyzed") {
468  const std::string input = reindent_text(nmodl_text);
469  // Assigned variable "y" should be DU as it's defined and used as well
470  const auto& chains_y = run_defuse_visitor(input, "y");
471  REQUIRE(chains_y[0].to_string() == expected_text_y);
472  REQUIRE(chains_y[0].eval() == DUState::D);
473  }
474  }
475 
476 
477  GIVEN("global variable definition in if-else block") {
478  std::string nmodl_text = R"(
479  NEURON {
480  RANGE tau
481  }
482 
483  DERIVATIVE states {
484  IF (1) {
485  tau = 11.1
486  exp(tau)
487  } ELSE {
488  tau = 1
489  }
490  }
491  )";
492 
493  std::string expected_text =
494  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"D"},{"name":"U"}]},{"ELSE":[{"name":"D"}]}]}]})";
495 
496  THEN("Def-Use chains should return DEF") {
497  std::string input = reindent_text(nmodl_text);
498  auto chains = run_defuse_visitor(input, "tau");
499  REQUIRE(chains[0].to_string() == expected_text);
500  REQUIRE(chains[0].eval() == DUState::D);
501  }
502  }
503 
504  GIVEN("conditional definition in nested block") {
505  std::string nmodl_text = R"(
506  NEURON {
507  RANGE tau, beta
508  }
509 
510  DERIVATIVE states {
511  IF (1) {
512  IF(11) {
513  tau = 11.1
514  exp(tau)
515  }
516  } ELSE IF(1) {
517  tau = 1
518  }
519  }
520  )";
521 
522  std::string expected_text =
523  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"D"},{"name":"U"}]}]}]},{"ELSEIF":[{"name":"D"}]}]}]})";
524 
525  THEN("Def-Use chains should return DEF") {
526  std::string input = reindent_text(nmodl_text);
527  auto chains = run_defuse_visitor(input, "tau");
528  REQUIRE(chains[0].to_string() == expected_text);
529  REQUIRE(chains[0].eval() == DUState::CD);
530  }
531  }
532 
533  GIVEN("global variable usage in if-elseif-else block") {
534  std::string nmodl_text = R"(
535  NEURON {
536  RANGE tau, beta
537  }
538 
539  DERIVATIVE states {
540  IF (1) {
541  tau = 1
542  }
543  tau = 1 + tau
544  IF (0) {
545  beta = 1
546  } ELSE IF (2) {
547  tau = 1
548  }
549  }
550 
551  )";
552 
553  std::string expected_text =
554  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"D"}]}]},{"name":"U"},{"name":"D"},{"CONDITIONAL_BLOCK":[{"name":"IF"},{"ELSEIF":[{"name":"D"}]}]}]})";
555 
556  THEN("Def-Use chains for individual usage is printed") {
557  std::string input = reindent_text(nmodl_text);
558  auto chains = run_defuse_visitor(input, "tau");
559  REQUIRE(chains[0].to_string() == expected_text);
560  REQUIRE(chains[0].eval() == DUState::U);
561  }
562  }
563 
564  GIVEN("global variable used in nested if-elseif-else block") {
565  std::string nmodl_text = R"(
566  NEURON {
567  RANGE tau, beta
568  }
569 
570  DERIVATIVE states {
571  IF (1) {
572  LOCAL tau
573  tau = 1
574  }
575  IF (0) {
576  IF (1) {
577  beta = 1
578  } ELSE {
579  tau = 1
580  }
581  } ELSE IF (2) {
582  IF (1) {
583  beta = 1
584  IF (0) {
585  } ELSE {
586  beta = 1 + exp(tau)
587  }
588  }
589  tau = 1
590  }
591  }
592  )";
593 
594  std::string expected_text =
595  R"({"DerivativeBlock":[{"CONDITIONAL_BLOCK":[{"IF":[{"name":"LD"}]}]},{"CONDITIONAL_BLOCK":[{"IF":[{"CONDITIONAL_BLOCK":[{"name":"IF"},{"ELSE":[{"name":"D"}]}]}]},{"ELSEIF":[{"CONDITIONAL_BLOCK":[{"IF":[{"CONDITIONAL_BLOCK":[{"name":"IF"},{"ELSE":[{"name":"U"}]}]}]}]},{"name":"D"}]}]}]})";
596 
597  THEN("Def-Use chains for nested statements calculated") {
598  std::string input = reindent_text(nmodl_text);
599  auto chains = run_defuse_visitor(input, "tau");
600  REQUIRE(chains[0].to_string() == expected_text);
601  REQUIRE(chains[0].eval() == DUState::U);
602  }
603  }
604 }
test_utils.hpp
SCENARIO
SCENARIO("Perform DefUse analysis on NMODL constructs")
Definition: defuse_analyze.cpp:55
nmodl::parser::NmodlDriver
Class that binds all pieces together for parsing nmodl file.
Definition: nmodl_driver.hpp:67
nmodl::to_nmodl
std::string to_nmodl(const ast::Ast &node, const std::set< ast::AstNodeType > &exclude_types)
Given AST node, return the NMODL string representation.
Definition: visitor_utils.cpp:234
nmodl::test_utils::reindent_text
std::string reindent_text(const std::string &text, int indent_level)
Reindent nmodl text for text-to-text comparison.
Definition: test_utils.cpp:53
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::visitor::DUState::LD
@ LD
local variable is defined
nmodl::visitor::DUState::D
@ D
global variable is defined
nmodl::ast::AstNodeType
AstNodeType
Enum type for every AST node type.
Definition: ast_decl.hpp:166
nmodl::visitor::DUState::U
@ U
global variable is used
run_defuse_visitor
std::vector< DUChain > run_defuse_visitor(const std::string &text, const std::string &variable)
Definition: defuse_analyze.cpp:32
binary_expression.hpp
Auto generated AST classes declaration.
program.hpp
Auto generated AST classes declaration.
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::visitor::DUState::NONE
@ NONE
variable is not used
nmodl::parser::UnitDriver::parse_string
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
Definition: unit_driver.cpp:40
nmodl::visitor::to_string
std::string to_string(DUState state)
DUState to string conversion for pretty-printing.
Definition: defuse_analyze_visitor.cpp:23
nmodl::collect_nodes
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
Definition: visitor_utils.cpp:206
defuse_analyze_visitor.hpp
Visitor to return Def-Use chain for a given variable in the block/node
checkparent_visitor.hpp
Visitor for checking parents of ast nodes
inline_visitor.hpp
Visitor to inline local procedure and function calls
nmodl_driver.hpp
nmodl::visitor::DUState::CD
@ CD
global or local variable is conditionally defined
symtab_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.