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);