8 #include <catch2/catch_test_macros.hpp> 
    9 #include <catch2/matchers/catch_matchers_string.hpp> 
   20 using namespace nmodl;
 
   21 using namespace visitor;
 
   23 using namespace test_utils;
 
   25 using Catch::Matchers::Equals;
 
   36     SymtabVisitor().visit_program(*ast);
 
   37     InlineVisitor().visit_program(*ast);
 
   38     std::stringstream stream;
 
   39     NmodlPrintVisitor(stream).visit_program(*ast);
 
   43     CheckParentVisitor().check_ast(*ast);
 
   48 SCENARIO(
"Inlining of external procedure calls", 
"[visitor][inline]") {
 
   49     GIVEN(
"Procedures with external procedure call") {
 
   50         std::string nmodl_text = R
"( 
   60         THEN("nothing gets inlined") {
 
   63             REQUIRE(result == input);
 
   68 SCENARIO(
"Inlining of function call as argument in external function", 
"[visitor][inline]") {
 
   69     GIVEN(
"An external function calling a function") {
 
   70         std::string input_nmodl = R
"( 
   76                 net_send(rates_1(), 0) 
   80         std::string output_nmodl = R"( 
   90                 net_send(rates_1_in_0, 0) 
   93         THEN("External function doesn't get inlined") {
 
   97             REQUIRE(result == expected_result);
 
  102 SCENARIO(
"Inlining of simple, one level procedure call", 
"[visitor][inline]") {
 
  103     GIVEN(
"A procedure calling another procedure") {
 
  104         std::string input_nmodl = R
"( 
  105             PROCEDURE rates_1() { 
  110             PROCEDURE rates_2(y) { 
  116         std::string output_nmodl = R"( 
  117             PROCEDURE rates_1() { 
  126             PROCEDURE rates_2(y) { 
  131         THEN("Procedure body gets inlined") {
 
  135             REQUIRE(result == expected_result);
 
  140 SCENARIO(
"Inlining of nested procedure call", 
"[visitor][inline]") {
 
  141     GIVEN(
"A procedure with nested call chain and arguments") {
 
  142         std::string input_nmodl = R
"( 
  143             PROCEDURE rates_1() { 
  149             PROCEDURE rates_2() { 
  151                 x = 21.1*v + rates_3(x, x+1.1) 
  154             PROCEDURE rates_3(a, b) { 
  160         std::string output_nmodl = R"( 
  161             PROCEDURE rates_1() { 
  164                     LOCAL x, rates_3_in_0 
  166                         LOCAL c, a_in_0, b_in_0 
  169                         c = 21.1*v+a_in_0*b_in_0 
  172                     x = 21.1*v+rates_3_in_0 
  175                     LOCAL c, a_in_1, b_in_1 
  178                     c = 21.1*v+a_in_1*b_in_1 
  182             PROCEDURE rates_2() { 
  183                 LOCAL x, rates_3_in_0 
  185                     LOCAL c, a_in_0, b_in_0 
  188                     c = 21.1*v+a_in_0*b_in_0 
  191                 x = 21.1*v+rates_3_in_0 
  194             PROCEDURE rates_3(a, b) { 
  199         THEN("Nested procedure gets inlined with variables renaming") {
 
  203             REQUIRE(result == expected_result);
 
  208 SCENARIO(
"Inline function call in procedure", 
"[visitor][inline]") {
 
  209     GIVEN(
"A procedure with function call") {
 
  210         std::string input_nmodl = R
"( 
  211             PROCEDURE rates_1() { 
  223         std::string output_nmodl = R"( 
  224             PROCEDURE rates_1() { 
  225                 LOCAL x, rates_2_in_0 
  231                 x = 12.1+rates_2_in_0 
  240         THEN("Procedure body gets inlined") {
 
  244             REQUIRE(result == expected_result);
 
  249 SCENARIO(
"Inling function call within conditional statement", 
"[visitor][inline]") {
 
  250     GIVEN(
"A procedure with function call in if statement") {
 
  251         std::string input_nmodl = R
"( 
  265         std::string output_nmodl = R"( 
  283         THEN("Procedure body gets inlined and return value is used in if condition") {
 
  287             REQUIRE(result == expected_result);
 
  292 SCENARIO(
"Inline multiple function calls in same statement", 
"[visitor][inline]") {
 
  293     GIVEN(
"A procedure with two function calls in binary expression") {
 
  294         std::string input_nmodl = R
"( 
  296                 IF (rates_2()-rates_2()) { 
  306         std::string output_nmodl = R"( 
  308                 LOCAL rates_2_in_0, rates_2_in_1 
  315                 IF (rates_2_in_0-rates_2_in_1) { 
  325         THEN("Procedure body gets inlined") {
 
  329             REQUIRE(result == expected_result);
 
  333     GIVEN(
"A procedure with multiple function calls in an expression") {
 
  334         std::string input_nmodl = R
"( 
  337                 x = (rates_2()+(rates_2()/rates_2())) 
  345         std::string output_nmodl = R"( 
  347                 LOCAL x, rates_2_in_0, rates_2_in_1, rates_2_in_2 
  357                 x = (rates_2_in_0+(rates_2_in_1/rates_2_in_2)) 
  365         THEN("Procedure body gets inlined and return values are used in an expression") {
 
  369             REQUIRE(result == expected_result);
 
  374 SCENARIO(
"Inline nested function calls withing arguments", 
"[visitor][inline]") {
 
  375     GIVEN(
"A procedure with function call") {
 
  376         std::string input_nmodl = R
"( 
  378                 IF (rates_3(11,21)) { 
  381                 rates_2 = rates_3(12,22) 
  385                 rates_1 = 12.1+rates_2()+exp(12.1) 
  388             FUNCTION rates_3(x, y) { 
  393         std::string output_nmodl = R"( 
  395                 LOCAL rates_3_in_0, rates_3_in_1 
  400                     rates_3_in_0 = x_in_0+y_in_0 
  409                     rates_3_in_1 = x_in_1+y_in_1 
  411                 rates_2 = rates_3_in_1 
  417                     LOCAL rates_3_in_0, rates_3_in_1 
  422                         rates_3_in_0 = x_in_0+y_in_0 
  431                         rates_3_in_1 = x_in_1+y_in_1 
  433                     rates_2_in_0 = rates_3_in_1 
  435                 rates_1 = 12.1+rates_2_in_0+exp(12.1) 
  438             FUNCTION rates_3(x, y) { 
  443         THEN("Procedure body gets inlined") {
 
  447             REQUIRE(result == expected_result);
 
  452 SCENARIO(
"Inline function call in non-binary expression", 
"[visitor][inline]") {
 
  453     GIVEN(
"A function call in unary expression") {
 
  454         std::string input_nmodl = R
"( 
  455             PROCEDURE rates_1() { 
  460             FUNCTION rates_2(y) { 
  465         std::string output_nmodl = R"( 
  466             PROCEDURE rates_1() { 
  467                 LOCAL x, rates_2_in_0 
  471                     rates_2_in_0 = 21.1*v+y_in_0 
  476             FUNCTION rates_2(y) { 
  480         THEN("Function gets inlined in the unary expression") {
 
  484             REQUIRE(result == expected_result);
 
  488     GIVEN(
"A function call as part of function argument itself") {
 
  489         std::string input_nmodl = R
"( 
  491                 rates_1 = 10 + rates_2( rates_2(11) ) 
  494             FUNCTION rates_2(x) { 
  499         std::string output_nmodl = R"( 
  501                 LOCAL rates_2_in_0, rates_2_in_1 
  505                     rates_2_in_0 = 10+x_in_0 
  509                     x_in_1 = rates_2_in_0 
  510                     rates_2_in_1 = 10+x_in_1 
  512                 rates_1 = 10+rates_2_in_1 
  515             FUNCTION rates_2(x) { 
  519         THEN("Function and it's arguments gets inlined recursively") {
 
  523             REQUIRE(result == expected_result);
 
  529 SCENARIO(
"Inline function call as standalone expression", 
"[visitor][inline]") {
 
  530     GIVEN(
"Function call as a statement") {
 
  531         std::string input_nmodl = R
"( 
  532             PROCEDURE rates_1() { 
  537             FUNCTION rates_2(y) { 
  542         std::string output_nmodl = R"( 
  543             PROCEDURE rates_1() { 
  544                 LOCAL x, rates_2_in_0 
  548                     rates_2_in_0 = 21.1*v+y_in_0 
  552             FUNCTION rates_2(y) { 
  556         THEN("Function gets inlined but it's value is not used") {
 
  560             REQUIRE(result == expected_result);
 
  565 SCENARIO(
"Inline procedure call as standalone statement as well as part of expression",
 
  566          "[visitor][inline]") {
 
  567     GIVEN(
"A procedure call in expression and statement") {
 
  568         std::string input_nmodl = R
"( 
  569             PROCEDURE rates_1() { 
  575             PROCEDURE rates_2() { 
  579         std::string output_nmodl = R"( 
  580             PROCEDURE rates_1() { 
  581                 LOCAL x, rates_2_in_0 
  590             PROCEDURE rates_2() { 
  593         THEN("Return statement from procedure (with zero value) is used") {
 
  597             REQUIRE(result == expected_result);
 
  602 SCENARIO(
"Inlining pass handles local-global name conflict", 
"[visitor][inline]") {
 
  603     GIVEN(
"A procedure with local variable that exist in global scope") {
 
  605         std::string input_nmodl = R
"( 
  610             PROCEDURE rates_1() { 
  617             PROCEDURE rates_2(y) { 
  622         std::string output_nmodl = R"( 
  627             PROCEDURE rates_1() { 
  638             PROCEDURE rates_2(y) { 
  643         THEN("Caller variables get renamed first and then inlining is done") {
 
  647             REQUIRE(result == expected_result);
 
  652 SCENARIO(
"Trying to inline a function with VERBATIM block") {
 
  653     GIVEN(
"A VERBATIM block without a return inside") {
 
  654         std::string input_nmodl = R
"( 
  666         std::string output_nmodl = R"( 
  681         THEN("It gets inlined") {
 
  685             REQUIRE(expected_result == result);
 
  688     GIVEN(
"A VERBATIM block with a return value") {
 
  689         std::string nmodl_text = R
"( 
  701         THEN("It is not inlined") {
 
  704             REQUIRE(result == input);