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;
38 std::stringstream stream;
48 SCENARIO(
"Inlining of external procedure calls",
"[visitor][inline]") {
49 GIVEN(
"Procedures with external procedure call") {
60 THEN("nothing gets inlined") {
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") {
701 THEN("It is not inlined") {
Visitor for checking parents of ast nodes
Class that binds all pieces together for parsing nmodl file.
Visitor to inline local procedure and function calls
void visit_program(ast::Program &node) override
visit node of type ast::Program
Visitor for printing AST back to NMODL
void visit_program(const ast::Program &node) override
visit node of type ast::Program
Concrete visitor for constructing symbol table from AST.
void visit_program(ast::Program &node) override
visit node of type ast::Program
Visitor for checking parents of ast nodes
int check_ast(const ast::Ast &node)
A small wrapper to have a nicer call in parser.cpp.
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
std::string run_inline_visitor(const std::string &text)
SCENARIO("Inlining of external procedure calls", "[visitor][inline]")
Visitor to inline local procedure and function calls
std::string reindent_text(const std::string &text, int indent_level)
Reindent nmodl text for text-to-text comparison.
encapsulates code generation backend implementations
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
Auto generated AST classes declaration.
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
nmodl::parser::UnitDriver driver