8 #include <catch2/catch_test_macros.hpp> 
    9 #include <catch2/matchers/catch_matchers_string.hpp> 
   16 using namespace nmodl;
 
   17 using namespace visitor;
 
   27 SCENARIO(
"Symbol table generation with Perf stat visitor", 
"[visitor][performance]") {
 
   28     GIVEN(
"A mod file and associated ast") {
 
   29         std::string nmodl_text = R
"( 
   32                 USEION na READ ena WRITE ina 
   33                 RANGE gNaTs2_tbar, A_AMPA_step  : range + anything = range (2) 
   34                 GLOBAL Rstate                   : global + anything = global 
   35                 POINTER rng                     : pointer = global 
   36                 BBCOREPOINTER coreRng           : pointer + assigned = range 
   40                 gNaTs2_tbar = 0.00001 (S/cm2)   : range + parameter = range already 
   41                 tau_r = 0.2 (ms)                : parameter = global 
   42                 tau_d_AMPA = 1.0                : parameter = global 
   43                 tsyn_fac = 11.1                 : parameter + assigned = range 
   47                 v   (mV)        : only assigned = range 
   48                 ena (mV)        : only assigned = range 
   49                 tsyn_fac        : parameter + assigned = range already 
   50                 A_AMPA_step     : range + assigned = range already 
   51                 AmState         : only assigned = range 
   52                 Rstate          : global + assigned == global already 
   53                 coreRng         : pointer + assigned = range already 
   62                 CONDUCTANCE gNaTs2_t USEION na 
   63                 SOLVE states METHOD cnexp 
   67                         gNaTs2_t = gNaTs2_tbar*m*m*m*h 
   69                     ina = gNaTs2_t*(v-ena) 
   76                     gNaTs2_tbar = gNaTs2_tbar*gNaTs2_tbar + 11.0 
   82                 hBetaf = (-0.015 * (-v -60))/(1-(exp((-v -60)/6))) 
   89         WHEN(
"Symbol table generator pass runs") {
 
   91             v.visit_program(*ast);
 
   92             auto symtab = ast->get_model_symbol_table();
 
   94             THEN(
"Can lookup for defined variables") {
 
   95                 auto symbol = symtab->lookup(
"m");
 
   96                 REQUIRE(symbol->has_any_property(NmodlType::assigned_definition));
 
   97                 REQUIRE_FALSE(symbol->has_any_property(NmodlType::local_var));
 
   99                 symbol = symtab->lookup(
"gNaTs2_tbar");
 
  100                 REQUIRE(symbol->has_any_property(NmodlType::param_assign));
 
  101                 REQUIRE(symbol->has_any_property(NmodlType::range_var));
 
  103                 symbol = symtab->lookup(
"ena");
 
  104                 REQUIRE(symbol->has_any_property(NmodlType::read_ion_var));
 
  106             THEN(
"Can lookup for defined functions") {
 
  107                 auto symbol = symtab->lookup(
"hBetaf");
 
  108                 REQUIRE(symbol->has_any_property(NmodlType::function_block));
 
  110             THEN(
"Non existent variable lookup returns nullptr") {
 
  111                 REQUIRE(symtab->lookup(
"xyz") == 
nullptr);
 
  114             WHEN(
"Perf visitor pass runs after symtab visitor") {
 
  116                 v.visit_program(*ast);
 
  118                 auto result = v.get_total_perfstat();
 
  119                 auto num_instance_var = v.get_instance_variable_count();
 
  120                 auto num_global_var = v.get_global_variable_count();
 
  121                 auto num_state_var = v.get_state_variable_count();
 
  122                 auto num_const_instance_var = v.get_const_instance_variable_count();
 
  123                 auto num_const_global_var = v.get_const_global_variable_count();
 
  125                 THEN(
"Performance counters are updated") {
 
  126                     REQUIRE(result.n_add == 2);
 
  127                     REQUIRE(result.n_sub == 4);
 
  128                     REQUIRE(result.n_mul == 7);
 
  129                     REQUIRE(result.n_div == 3);
 
  130                     REQUIRE(result.n_exp == 1);
 
  131                     REQUIRE(result.n_global_read == 7);
 
  132                     REQUIRE(result.n_unique_global_read == 4);
 
  133                     REQUIRE(result.n_global_write == 3);
 
  134                     REQUIRE(result.n_unique_global_write == 2);
 
  135                     REQUIRE(result.n_constant_read == 4);
 
  136                     REQUIRE(result.n_unique_constant_read == 1);
 
  137                     REQUIRE(result.n_constant_write == 2);
 
  138                     REQUIRE(result.n_unique_constant_write == 1);
 
  139                     REQUIRE(result.n_local_read == 3);
 
  140                     REQUIRE(result.n_local_write == 2);
 
  141                     REQUIRE(result.n_ext_func_call == 1);
 
  142                     REQUIRE(result.n_int_func_call == 1);
 
  143                     REQUIRE(result.n_neg == 3);
 
  144                     REQUIRE(num_instance_var == 9);
 
  145                     REQUIRE(num_global_var == 4);
 
  146                     REQUIRE(num_state_var == 2);
 
  147                     REQUIRE(num_const_instance_var == 2);
 
  148                     REQUIRE(num_const_global_var == 2);
 
  153         WHEN(
"Perf visitor pass runs before symtab visitor") {
 
  155             THEN(
"exception is thrown") {
 
  156                 REQUIRE_THROWS_WITH(v.visit_program(*ast),
 
  157                                     Catch::Matchers::ContainsSubstring(
"table not setup"));