github.com/gotranspile/cxgo@v0.3.7/flow_test.go (about) 1 package cxgo 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/gotranspile/cxgo/libs" 13 "github.com/gotranspile/cxgo/types" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func numStmt(n int) CStmt { 18 return NewCExprStmt1(&CallExpr{ 19 Fun: FuncIdent{types.NewIdent("foo", types.UnkT(1))}, 20 Args: []Expr{cIntLit(int64(n))}, 21 }) 22 } 23 24 func varDecl(n int) CStmt { 25 return &CDeclStmt{&CVarDecl{ 26 CVarSpec: CVarSpec{ 27 Type: types.NamedT("bar", types.UnkT(1)), 28 Names: []*types.Ident{ 29 types.NewIdent(fmt.Sprintf("foo%d", n), types.UnkT(1)), 30 }, 31 Inits: []Expr{ 32 cIntLit(int64(n)), 33 }, 34 }, 35 }} 36 } 37 38 func numCond(n int) BoolExpr { 39 return BoolIdent{types.NewIdent(fmt.Sprintf("%d", n), types.BoolT())} 40 } 41 42 func ret(n int) CStmt { 43 return &CReturnStmt{Expr: cIntLit(int64(n))} 44 } 45 46 func newBlock(stmts ...CStmt) *BlockStmt { 47 return &BlockStmt{Stmts: stmts} 48 } 49 50 var casesControlFlow = []struct { 51 name string 52 tree []CStmt 53 exp string 54 dom string 55 flat string 56 }{ 57 { 58 name: "return", 59 tree: []CStmt{ 60 ret(1), 61 }, 62 exp: ` 63 n2[label="return 1",shape="box"]; 64 n1->n2; 65 `, 66 dom: ` 67 n2[label="return 1",shape="box"]; 68 n1->n2; 69 `, 70 flat: ` 71 return 1 72 `, 73 }, 74 { 75 name: "no return", 76 tree: []CStmt{ 77 numStmt(1), 78 }, 79 exp: ` 80 n2[label="foo(1)",shape="box"]; 81 n3[label="return",shape="box"]; 82 n1->n2; 83 n2->n3; 84 n3->n2[color="#99999955"]; 85 `, 86 dom: ` 87 n2[label="foo(1)",shape="box"]; 88 n3[label="return",shape="box"]; 89 n1->n2; 90 n2->n3; 91 `, 92 flat: ` 93 foo(1) 94 goto L_1 95 L_1: 96 return 97 `, 98 }, 99 { 100 name: "code and return", 101 tree: []CStmt{ 102 numStmt(1), 103 ret(2), 104 }, 105 exp: ` 106 n2[label="foo(1)",shape="box"]; 107 n3[label="return 2",shape="box"]; 108 n1->n2; 109 n2->n3; 110 n3->n2[color="#99999955"]; 111 `, 112 dom: ` 113 n2[label="foo(1)",shape="box"]; 114 n3[label="return 2",shape="box"]; 115 n1->n2; 116 n2->n3; 117 `, 118 flat: ` 119 foo(1) 120 goto L_1 121 L_1: 122 return 2 123 `, 124 }, 125 { 126 name: "code and return 2", 127 tree: []CStmt{ 128 numStmt(1), 129 numStmt(2), 130 ret(3), 131 }, 132 exp: ` 133 n2[label="foo(1)\nfoo(2)",shape="box"]; 134 n3[label="return 3",shape="box"]; 135 n1->n2; 136 n2->n3; 137 n3->n2[color="#99999955"]; 138 `, 139 dom: ` 140 n2[label="foo(1)\nfoo(2)",shape="box"]; 141 n3[label="return 3",shape="box"]; 142 n1->n2; 143 n2->n3; 144 `, 145 flat: ` 146 foo(1) 147 foo(2) 148 goto L_1 149 L_1: 150 return 3 151 `, 152 }, 153 { 154 name: "code with decls", 155 tree: []CStmt{ 156 &CIfStmt{Cond: numCond(1), Then: newBlock(varDecl(1))}, 157 varDecl(2), 158 ret(1), 159 }, 160 exp: ` 161 n2[label="if 1",shape="hexagon"]; 162 n3[label="var foo1 bar = 1",shape="box"]; 163 n4[label="var foo2 bar = 2",shape="box"]; 164 n5[label="return 1",shape="box"]; 165 n1->n2; 166 n2->n3[color="#00aa00"]; 167 n2->n4[color="#aa0000"]; 168 n3->n2[color="#99999955"]; 169 n3->n4; 170 n4->n3[color="#99999955"]; 171 n4->n2[color="#99999955"]; 172 n4->n5; 173 n5->n4[color="#99999955"]; 174 `, 175 dom: ` 176 n2[label="if 1",shape="hexagon"]; 177 n3[label="var foo1 bar = 1",shape="box"]; 178 n4[label="var foo2 bar = 2",shape="box"]; 179 n5[label="return 1",shape="box"]; 180 n1->n2; 181 n2->n3; 182 n2->n4; 183 n4->n5; 184 `, 185 flat: ` 186 var foo1 bar 187 var foo2 bar 188 if 1 { 189 goto L_1 190 } else { 191 goto L_2 192 } 193 L_1: 194 foo1 = 1 195 goto L_2 196 L_2: 197 foo2 = 2 198 goto L_3 199 L_3: 200 return 1 201 `, 202 }, 203 { 204 name: "if", 205 tree: []CStmt{ 206 &CIfStmt{Cond: numCond(1), Then: newBlock(numStmt(2))}, 207 numStmt(3), 208 numStmt(4), 209 ret(5), 210 }, 211 exp: ` 212 n2[label="if 1",shape="hexagon"]; 213 n3[label="foo(2)",shape="box"]; 214 n4[label="foo(3)\nfoo(4)",shape="box"]; 215 n5[label="return 5",shape="box"]; 216 n1->n2; 217 n2->n3[color="#00aa00"]; 218 n2->n4[color="#aa0000"]; 219 n3->n2[color="#99999955"]; 220 n3->n4; 221 n4->n3[color="#99999955"]; 222 n4->n2[color="#99999955"]; 223 n4->n5; 224 n5->n4[color="#99999955"]; 225 `, 226 dom: ` 227 n2[label="if 1",shape="hexagon"]; 228 n3[label="foo(2)",shape="box"]; 229 n4[label="foo(3)\nfoo(4)",shape="box"]; 230 n5[label="return 5",shape="box"]; 231 n1->n2; 232 n2->n3; 233 n2->n4; 234 n4->n5; 235 `, 236 flat: ` 237 if 1 { 238 goto L_1 239 } else { 240 goto L_2 241 } 242 L_1: 243 foo(2) 244 goto L_2 245 L_2: 246 foo(3) 247 foo(4) 248 goto L_3 249 L_3: 250 return 5 251 `, 252 }, 253 { 254 name: "if else", 255 tree: []CStmt{ 256 &CIfStmt{Cond: numCond(1), Then: newBlock(numStmt(2)), Else: newBlock(numStmt(3))}, 257 ret(4), 258 }, 259 exp: ` 260 n2[label="if 1",shape="hexagon"]; 261 n3[label="foo(2)",shape="box"]; 262 n4[label="return 4",shape="box"]; 263 n5[label="foo(3)",shape="box"]; 264 n1->n2; 265 n2->n3[color="#00aa00"]; 266 n2->n5[color="#aa0000"]; 267 n3->n2[color="#99999955"]; 268 n3->n4; 269 n4->n3[color="#99999955"]; 270 n4->n5[color="#99999955"]; 271 n5->n2[color="#99999955"]; 272 n5->n4; 273 `, 274 dom: ` 275 n2[label="if 1",shape="hexagon"]; 276 n3[label="foo(2)",shape="box"]; 277 n4[label="return 4",shape="box"]; 278 n5[label="foo(3)",shape="box"]; 279 n1->n2; 280 n2->n3; 281 n2->n4; 282 n2->n5; 283 `, 284 flat: ` 285 if 1 { 286 goto L_1 287 } else { 288 goto L_3 289 } 290 L_1: 291 foo(2) 292 goto L_2 293 L_2: 294 return 4 295 L_3: 296 foo(3) 297 goto L_2 298 `, 299 }, 300 { 301 name: "if return else", 302 tree: []CStmt{ 303 &CIfStmt{Cond: numCond(1), Then: newBlock(ret(2)), Else: newBlock(numStmt(3))}, 304 ret(4), 305 }, 306 exp: ` 307 n2[label="if 1",shape="hexagon"]; 308 n3[label="return 2",shape="box"]; 309 n4[label="foo(3)",shape="box"]; 310 n5[label="return 4",shape="box"]; 311 n1->n2; 312 n2->n3[color="#00aa00"]; 313 n2->n4[color="#aa0000"]; 314 n3->n2[color="#99999955"]; 315 n4->n2[color="#99999955"]; 316 n4->n5; 317 n5->n4[color="#99999955"]; 318 `, 319 dom: ` 320 n2[label="if 1",shape="hexagon"]; 321 n3[label="return 2",shape="box"]; 322 n4[label="foo(3)",shape="box"]; 323 n5[label="return 4",shape="box"]; 324 n1->n2; 325 n2->n3; 326 n2->n4; 327 n4->n5; 328 `, 329 flat: ` 330 if 1 { 331 goto L_1 332 } else { 333 goto L_2 334 } 335 L_1: 336 return 2 337 L_2: 338 foo(3) 339 goto L_3 340 L_3: 341 return 4 342 `, 343 }, 344 { 345 name: "if else return", 346 tree: []CStmt{ 347 &CIfStmt{Cond: numCond(1), Then: newBlock(numStmt(2)), Else: newBlock(ret(3))}, 348 ret(4), 349 }, 350 exp: ` 351 n2[label="if 1",shape="hexagon"]; 352 n3[label="foo(2)",shape="box"]; 353 n4[label="return 4",shape="box"]; 354 n5[label="return 3",shape="box"]; 355 n1->n2; 356 n2->n3[color="#00aa00"]; 357 n2->n5[color="#aa0000"]; 358 n3->n2[color="#99999955"]; 359 n3->n4; 360 n4->n3[color="#99999955"]; 361 n5->n2[color="#99999955"]; 362 `, 363 dom: ` 364 n2[label="if 1",shape="hexagon"]; 365 n3[label="foo(2)",shape="box"]; 366 n4[label="return 4",shape="box"]; 367 n5[label="return 3",shape="box"]; 368 n1->n2; 369 n2->n3; 370 n2->n5; 371 n3->n4; 372 `, 373 flat: ` 374 if 1 { 375 goto L_1 376 } else { 377 goto L_3 378 } 379 L_1: 380 foo(2) 381 goto L_2 382 L_2: 383 return 4 384 L_3: 385 return 3 386 `, 387 }, 388 { 389 name: "if all return", 390 tree: []CStmt{ 391 &CIfStmt{Cond: numCond(1), Then: newBlock(ret(2)), Else: newBlock(ret(3))}, 392 }, 393 exp: ` 394 n2[label="if 1",shape="hexagon"]; 395 n3[label="return 2",shape="box"]; 396 n4[label="return 3",shape="box"]; 397 n1->n2; 398 n2->n3[color="#00aa00"]; 399 n2->n4[color="#aa0000"]; 400 n3->n2[color="#99999955"]; 401 n4->n2[color="#99999955"]; 402 `, 403 dom: ` 404 n2[label="if 1",shape="hexagon"]; 405 n3[label="return 2",shape="box"]; 406 n4[label="return 3",shape="box"]; 407 n1->n2; 408 n2->n3; 409 n2->n4; 410 `, 411 flat: ` 412 if 1 { 413 goto L_1 414 } else { 415 goto L_2 416 } 417 L_1: 418 return 2 419 L_2: 420 return 3 421 `, 422 }, 423 { 424 name: "if all return unreachable", 425 tree: []CStmt{ 426 &CIfStmt{Cond: numCond(1), Then: newBlock(ret(2)), Else: newBlock(ret(3))}, 427 ret(4), 428 }, 429 exp: ` 430 n2[label="if 1",shape="hexagon"]; 431 n3[label="return 2",shape="box"]; 432 n4[label="return 3",shape="box"]; 433 n1->n2; 434 n2->n3[color="#00aa00"]; 435 n2->n4[color="#aa0000"]; 436 n3->n2[color="#99999955"]; 437 n4->n2[color="#99999955"]; 438 `, 439 dom: ` 440 n2[label="if 1",shape="hexagon"]; 441 n3[label="return 2",shape="box"]; 442 n4[label="return 3",shape="box"]; 443 n1->n2; 444 n2->n3; 445 n2->n4; 446 `, 447 flat: ` 448 if 1 { 449 goto L_1 450 } else { 451 goto L_2 452 } 453 L_1: 454 return 2 455 L_2: 456 return 3 457 `, 458 }, 459 { 460 name: "switch", 461 tree: []CStmt{ 462 &CSwitchStmt{ 463 Cond: cIntLit(1), 464 Cases: []*CCaseStmt{ 465 {Expr: cIntLit(1), Stmts: []CStmt{numStmt(1)}}, 466 {Expr: cIntLit(2), Stmts: []CStmt{numStmt(2)}}, 467 {Expr: cIntLit(3), Stmts: []CStmt{numStmt(3), &CBreakStmt{}}}, 468 {Stmts: []CStmt{numStmt(4)}}, 469 }, 470 }, 471 ret(1), 472 }, 473 exp: ` 474 n2[label="switch 1",shape="trapezium"]; 475 n3[label="foo(1)",shape="box"]; 476 n4[label="foo(2)",shape="box"]; 477 n5[label="foo(3)",shape="box"]; 478 n6[label="return 1",shape="box"]; 479 n7[label="foo(4)",shape="box"]; 480 n1->n2; 481 n2->n3[label="1"]; 482 n2->n4[label="2"]; 483 n2->n5[label="3"]; 484 n2->n7[color="#aa0000"]; 485 n3->n2[color="#99999955"]; 486 n3->n4; 487 n4->n2[color="#99999955"]; 488 n4->n3[color="#99999955"]; 489 n4->n5; 490 n5->n2[color="#99999955"]; 491 n5->n4[color="#99999955"]; 492 n5->n6; 493 n6->n7[color="#99999955"]; 494 n6->n5[color="#99999955"]; 495 n7->n2[color="#99999955"]; 496 n7->n6; 497 `, 498 dom: ` 499 n2[label="switch 1",shape="trapezium"]; 500 n3[label="foo(1)",shape="box"]; 501 n4[label="foo(2)",shape="box"]; 502 n5[label="foo(3)",shape="box"]; 503 n6[label="return 1",shape="box"]; 504 n7[label="foo(4)",shape="box"]; 505 n1->n2; 506 n2->n3; 507 n2->n4; 508 n2->n5; 509 n2->n6; 510 n2->n7; 511 `, 512 flat: ` 513 switch 1 { 514 case 1: 515 goto L_1 516 case 2: 517 goto L_2 518 case 3: 519 goto L_3 520 default: 521 goto L_5 522 } 523 L_1: 524 foo(1) 525 goto L_2 526 L_2: 527 foo(2) 528 goto L_3 529 L_3: 530 foo(3) 531 goto L_4 532 L_4: 533 return 1 534 L_5: 535 foo(4) 536 goto L_4 537 `, 538 }, 539 { 540 name: "switch no default", 541 tree: []CStmt{ 542 &CSwitchStmt{ 543 Cond: cIntLit(1), 544 Cases: []*CCaseStmt{ 545 {Expr: cIntLit(1), Stmts: []CStmt{numStmt(1)}}, 546 {Expr: cIntLit(2), Stmts: []CStmt{&CBreakStmt{}}}, 547 {Expr: cIntLit(3), Stmts: []CStmt{numStmt(3), &CBreakStmt{}}}, 548 }, 549 }, 550 ret(1), 551 }, 552 exp: ` 553 n2[label="switch 1",shape="trapezium"]; 554 n3[label="foo(1)",shape="box"]; 555 n4[label="return 1",shape="box"]; 556 n5[label="foo(3)",shape="box"]; 557 n1->n2; 558 n2->n3[label="1"]; 559 n2->n4[label="2"]; 560 n2->n5[label="3"]; 561 n2->n4[color="#aa0000"]; 562 n3->n2[color="#99999955"]; 563 n3->n4; 564 n4->n5[color="#99999955"]; 565 n4->n2[color="#99999955"]; 566 n4->n3[color="#99999955"]; 567 n5->n2[color="#99999955"]; 568 n5->n4; 569 `, 570 dom: ` 571 n2[label="switch 1",shape="trapezium"]; 572 n3[label="foo(1)",shape="box"]; 573 n4[label="return 1",shape="box"]; 574 n5[label="foo(3)",shape="box"]; 575 n1->n2; 576 n2->n3; 577 n2->n4; 578 n2->n5; 579 `, 580 flat: ` 581 switch 1 { 582 case 1: 583 goto L_1 584 case 2: 585 goto L_2 586 case 3: 587 goto L_3 588 default: 589 goto L_2 590 } 591 L_1: 592 foo(1) 593 goto L_2 594 L_2: 595 return 1 596 L_3: 597 foo(3) 598 goto L_2 599 `, 600 }, 601 { 602 name: "goto", 603 tree: []CStmt{ 604 numStmt(1), 605 &CIfStmt{ 606 Cond: numCond(1), 607 Then: newBlock( 608 numStmt(2), 609 &CGotoStmt{Label: "L1"}, 610 ), 611 }, 612 &CLabelStmt{Label: "L1"}, 613 ret(3), 614 }, 615 exp: ` 616 n2[label="foo(1)",shape="box"]; 617 n3[label="if 1",shape="hexagon"]; 618 n4[label="foo(2)",shape="box"]; 619 n5[label="return 3",shape="box"]; 620 n1->n2; 621 n2->n3; 622 n3->n2[color="#99999955"]; 623 n3->n4[color="#00aa00"]; 624 n3->n5[color="#aa0000"]; 625 n4->n3[color="#99999955"]; 626 n4->n5; 627 n5->n4[color="#99999955"]; 628 n5->n3[color="#99999955"]; 629 `, 630 dom: ` 631 n2[label="foo(1)",shape="box"]; 632 n3[label="if 1",shape="hexagon"]; 633 n4[label="foo(2)",shape="box"]; 634 n5[label="return 3",shape="box"]; 635 n1->n2; 636 n2->n3; 637 n3->n4; 638 n3->n5; 639 `, 640 flat: ` 641 foo(1) 642 goto L_1 643 L_1: 644 if 1 { 645 goto L_2 646 } else { 647 goto L_3 648 } 649 L_2: 650 foo(2) 651 goto L_3 652 L_3: 653 return 3 654 `, 655 }, 656 { 657 name: "goto loop", 658 tree: []CStmt{ 659 numStmt(0), 660 &CLabelStmt{Label: "L1"}, 661 &CIfStmt{ 662 Cond: numCond(1), 663 Then: newBlock( 664 numStmt(1), 665 &CGotoStmt{Label: "L1"}, 666 ), 667 }, 668 ret(3), 669 }, 670 exp: ` 671 n2[label="foo(0)",shape="box"]; 672 n3[label="if 1",shape="hexagon"]; 673 n4[label="foo(1)",shape="box"]; 674 n5[label="return 3",shape="box"]; 675 n1->n2; 676 n2->n3; 677 n3->n4[color="#99999955"]; 678 n3->n2[color="#99999955"]; 679 n3->n4[color="#00aa00"]; 680 n3->n5[color="#aa0000"]; 681 n4->n3[color="#99999955"]; 682 n4->n3; 683 n5->n3[color="#99999955"]; 684 `, 685 dom: ` 686 n2[label="foo(0)",shape="box"]; 687 n3[label="if 1",shape="hexagon"]; 688 n4[label="foo(1)",shape="box"]; 689 n5[label="return 3",shape="box"]; 690 n1->n2; 691 n2->n3; 692 n3->n4; 693 n3->n5; 694 `, 695 flat: ` 696 foo(0) 697 goto L_1 698 L_1: 699 if 1 { 700 goto L_2 701 } else { 702 goto L_3 703 } 704 L_2: 705 foo(1) 706 goto L_1 707 L_3: 708 return 3 709 `, 710 }, 711 { 712 name: "for infinite empty", 713 tree: []CStmt{ 714 &CForStmt{}, 715 ret(2), 716 }, 717 exp: ` 718 n2[label="",shape="box"]; 719 n1->n2; 720 n2->n2[color="#99999955"]; 721 n2->n2; 722 `, 723 dom: ` 724 n2[label="",shape="box"]; 725 n1->n2; 726 `, 727 flat: ` 728 L_1: 729 goto L_1 730 `, 731 }, 732 { 733 name: "for infinite", 734 tree: []CStmt{ 735 &CForStmt{Body: *newBlock(numStmt(1))}, 736 ret(2), 737 }, 738 exp: ` 739 n2[label="foo(1)",shape="box"]; 740 n1->n2; 741 n2->n2[color="#99999955"]; 742 n2->n2; 743 `, 744 dom: ` 745 n2[label="foo(1)",shape="box"]; 746 n1->n2; 747 `, 748 flat: ` 749 L_1: 750 foo(1) 751 goto L_1 752 `, 753 }, 754 { 755 name: "for infinite break", 756 tree: []CStmt{ 757 &CForStmt{Body: *newBlock( 758 numStmt(1), 759 &CBreakStmt{}, 760 )}, 761 ret(2), 762 }, 763 exp: ` 764 n2[label="foo(1)",shape="box"]; 765 n3[label="return 2",shape="box"]; 766 n1->n2; 767 n2->n3; 768 n3->n2[color="#99999955"]; 769 `, 770 dom: ` 771 n2[label="foo(1)",shape="box"]; 772 n3[label="return 2",shape="box"]; 773 n1->n2; 774 n2->n3; 775 `, 776 flat: ` 777 foo(1) 778 goto L_1 779 L_1: 780 return 2 781 `, 782 }, 783 { 784 name: "for infinite continue", 785 tree: []CStmt{ 786 &CForStmt{Body: *newBlock( 787 numStmt(1), 788 &CContinueStmt{}, 789 )}, 790 ret(2), 791 }, 792 exp: ` 793 n2[label="foo(1)",shape="box"]; 794 n1->n2; 795 n2->n2[color="#99999955"]; 796 n2->n2; 797 `, 798 dom: ` 799 n2[label="foo(1)",shape="box"]; 800 n1->n2; 801 `, 802 flat: ` 803 L_1: 804 foo(1) 805 goto L_1 806 `, 807 }, 808 { 809 name: "for cond", 810 tree: []CStmt{ 811 &CForStmt{Cond: cIntLit(1), Body: *newBlock( 812 numStmt(1), 813 )}, 814 ret(2), 815 }, 816 exp: ` 817 n2[label="if false",shape="hexagon"]; 818 n3[label="foo(1)",shape="box"]; 819 n4[label="return 2",shape="box"]; 820 n1->n2; 821 n2->n3[color="#99999955"]; 822 n2->n4[color="#00aa00"]; 823 n2->n3[color="#aa0000"]; 824 n3->n2[color="#99999955"]; 825 n3->n2; 826 n4->n2[color="#99999955"]; 827 `, 828 dom: ` 829 n2[label="if false",shape="hexagon"]; 830 n3[label="return 2",shape="box"]; 831 n4[label="foo(1)",shape="box"]; 832 n1->n2; 833 n2->n3; 834 n2->n4; 835 `, 836 flat: ` 837 L_1: 838 if false { 839 goto L_2 840 } else { 841 goto L_3 842 } 843 L_2: 844 return 2 845 L_3: 846 foo(1) 847 goto L_1 848 `, 849 }, 850 { 851 name: "for cond break", 852 tree: []CStmt{ 853 &CForStmt{ 854 Cond: cIntLit(1), 855 Body: *newBlock( 856 &CIfStmt{ 857 Cond: numCond(2), 858 Then: newBlock( 859 numStmt(3), 860 &CBreakStmt{}, 861 ), 862 }, 863 numStmt(4), 864 ), 865 }, 866 ret(5), 867 }, 868 exp: ` 869 n2[label="if false",shape="hexagon"]; 870 n3[label="foo(4)",shape="box"]; 871 n4[label="if 2",shape="hexagon"]; 872 n5[label="foo(3)",shape="box"]; 873 n6[label="return 5",shape="box"]; 874 n1->n2; 875 n2->n3[color="#99999955"]; 876 n2->n6[color="#00aa00"]; 877 n2->n4[color="#aa0000"]; 878 n3->n4[color="#99999955"]; 879 n3->n2; 880 n4->n2[color="#99999955"]; 881 n4->n5[color="#00aa00"]; 882 n4->n3[color="#aa0000"]; 883 n5->n4[color="#99999955"]; 884 n5->n6; 885 n6->n5[color="#99999955"]; 886 n6->n2[color="#99999955"]; 887 `, 888 dom: ` 889 n2[label="if false",shape="hexagon"]; 890 n3[label="return 5",shape="box"]; 891 n4[label="if 2",shape="hexagon"]; 892 n5[label="foo(3)",shape="box"]; 893 n6[label="foo(4)",shape="box"]; 894 n1->n2; 895 n2->n3; 896 n2->n4; 897 n4->n5; 898 n4->n6; 899 `, 900 flat: ` 901 L_1: 902 if false { 903 goto L_2 904 } else { 905 goto L_3 906 } 907 L_2: 908 return 5 909 L_3: 910 if 2 { 911 goto L_4 912 } else { 913 goto L_5 914 } 915 L_4: 916 foo(3) 917 goto L_2 918 L_5: 919 foo(4) 920 goto L_1 921 `, 922 }, 923 { 924 name: "for cond nested", 925 tree: []CStmt{ 926 &CForStmt{Cond: cIntLit(2), Body: *newBlock( 927 numStmt(2), 928 &CForStmt{Cond: cIntLit(3), Body: *newBlock( 929 numStmt(3), 930 )}, 931 )}, 932 ret(1), 933 }, 934 exp: ` 935 n2[label="if 2 == 0",shape="hexagon"]; 936 n3[label="if 3 == 0",shape="hexagon"]; 937 n4[label="foo(3)",shape="box"]; 938 n5[label="foo(2)",shape="box"]; 939 n6[label="return 1",shape="box"]; 940 n1->n2; 941 n2->n3[color="#99999955"]; 942 n2->n6[color="#00aa00"]; 943 n2->n5[color="#aa0000"]; 944 n3->n4[color="#99999955"]; 945 n3->n5[color="#99999955"]; 946 n3->n2[color="#00aa00"]; 947 n3->n4[color="#aa0000"]; 948 n4->n3[color="#99999955"]; 949 n4->n3; 950 n5->n2[color="#99999955"]; 951 n5->n3; 952 n6->n2[color="#99999955"]; 953 `, 954 dom: ` 955 n2[label="if 2 == 0",shape="hexagon"]; 956 n3[label="return 1",shape="box"]; 957 n4[label="foo(2)",shape="box"]; 958 n5[label="if 3 == 0",shape="hexagon"]; 959 n6[label="foo(3)",shape="box"]; 960 n1->n2; 961 n2->n3; 962 n2->n4; 963 n4->n5; 964 n5->n6; 965 `, 966 flat: ` 967 L_1: 968 if 2 == 0 { 969 goto L_2 970 } else { 971 goto L_3 972 } 973 L_2: 974 return 1 975 L_3: 976 foo(2) 977 goto L_4 978 L_4: 979 if 3 == 0 { 980 goto L_1 981 } else { 982 goto L_5 983 } 984 L_5: 985 foo(3) 986 goto L_4 987 `, 988 }, 989 { 990 name: "for cond nested 2", 991 tree: []CStmt{ 992 &CForStmt{Cond: cIntLit(2), Body: *newBlock( 993 numStmt(2), 994 &CForStmt{Cond: cIntLit(3), Body: *newBlock( 995 numStmt(3), 996 )}, 997 numStmt(4), 998 )}, 999 ret(1), 1000 }, 1001 exp: ` 1002 n2[label="if 2 == 0",shape="hexagon"]; 1003 n3[label="foo(4)",shape="box"]; 1004 n4[label="if 3 == 0",shape="hexagon"]; 1005 n5[label="foo(3)",shape="box"]; 1006 n6[label="foo(2)",shape="box"]; 1007 n7[label="return 1",shape="box"]; 1008 n1->n2; 1009 n2->n3[color="#99999955"]; 1010 n2->n7[color="#00aa00"]; 1011 n2->n6[color="#aa0000"]; 1012 n3->n4[color="#99999955"]; 1013 n3->n2; 1014 n4->n5[color="#99999955"]; 1015 n4->n6[color="#99999955"]; 1016 n4->n3[color="#00aa00"]; 1017 n4->n5[color="#aa0000"]; 1018 n5->n4[color="#99999955"]; 1019 n5->n4; 1020 n6->n2[color="#99999955"]; 1021 n6->n4; 1022 n7->n2[color="#99999955"]; 1023 `, 1024 dom: ` 1025 n2[label="if 2 == 0",shape="hexagon"]; 1026 n3[label="return 1",shape="box"]; 1027 n4[label="foo(2)",shape="box"]; 1028 n5[label="if 3 == 0",shape="hexagon"]; 1029 n6[label="foo(4)",shape="box"]; 1030 n7[label="foo(3)",shape="box"]; 1031 n1->n2; 1032 n2->n3; 1033 n2->n4; 1034 n4->n5; 1035 n5->n6; 1036 n5->n7; 1037 `, 1038 flat: ` 1039 L_1: 1040 if 2 == 0 { 1041 goto L_2 1042 } else { 1043 goto L_3 1044 } 1045 L_2: 1046 return 1 1047 L_3: 1048 foo(2) 1049 goto L_4 1050 L_4: 1051 if 3 == 0 { 1052 goto L_5 1053 } else { 1054 goto L_6 1055 } 1056 L_5: 1057 foo(4) 1058 goto L_1 1059 L_6: 1060 foo(3) 1061 goto L_4 1062 `, 1063 }, 1064 { 1065 name: "for full", 1066 tree: []CStmt{ 1067 &CForStmt{ 1068 Init: numStmt(1), Cond: cIntLit(1), Iter: numStmt(2), 1069 Body: *newBlock( 1070 numStmt(3), 1071 ), 1072 }, 1073 ret(4), 1074 }, 1075 exp: ` 1076 n2[label="foo(1)",shape="box"]; 1077 n3[label="if false",shape="hexagon"]; 1078 n4[label="foo(2)",shape="box"]; 1079 n5[label="foo(3)",shape="box"]; 1080 n6[label="return 4",shape="box"]; 1081 n1->n2; 1082 n2->n3; 1083 n3->n4[color="#99999955"]; 1084 n3->n2[color="#99999955"]; 1085 n3->n6[color="#00aa00"]; 1086 n3->n5[color="#aa0000"]; 1087 n4->n5[color="#99999955"]; 1088 n4->n3; 1089 n5->n3[color="#99999955"]; 1090 n5->n4; 1091 n6->n3[color="#99999955"]; 1092 `, 1093 dom: ` 1094 n2[label="foo(1)",shape="box"]; 1095 n3[label="if false",shape="hexagon"]; 1096 n4[label="return 4",shape="box"]; 1097 n5[label="foo(3)",shape="box"]; 1098 n6[label="foo(2)",shape="box"]; 1099 n1->n2; 1100 n2->n3; 1101 n3->n4; 1102 n3->n5; 1103 n5->n6; 1104 `, 1105 flat: ` 1106 foo(1) 1107 goto L_1 1108 L_1: 1109 if false { 1110 goto L_2 1111 } else { 1112 goto L_3 1113 } 1114 L_2: 1115 return 4 1116 L_3: 1117 foo(3) 1118 goto L_4 1119 L_4: 1120 foo(2) 1121 goto L_1 1122 `, 1123 }, 1124 { 1125 name: "for full break", 1126 tree: []CStmt{ 1127 &CForStmt{ 1128 Init: numStmt(1), Cond: cIntLit(1), Iter: numStmt(2), 1129 Body: *newBlock( 1130 &CIfStmt{ 1131 Cond: numCond(2), 1132 Then: newBlock( 1133 numStmt(3), 1134 &CBreakStmt{}, 1135 ), 1136 }, 1137 numStmt(4), 1138 ), 1139 }, 1140 ret(5), 1141 }, 1142 exp: ` 1143 n2[label="foo(1)",shape="box"]; 1144 n3[label="if false",shape="hexagon"]; 1145 n4[label="foo(2)",shape="box"]; 1146 n5[label="foo(4)",shape="box"]; 1147 n6[label="if 2",shape="hexagon"]; 1148 n7[label="foo(3)",shape="box"]; 1149 n8[label="return 5",shape="box"]; 1150 n1->n2; 1151 n2->n3; 1152 n3->n4[color="#99999955"]; 1153 n3->n2[color="#99999955"]; 1154 n3->n8[color="#00aa00"]; 1155 n3->n6[color="#aa0000"]; 1156 n4->n5[color="#99999955"]; 1157 n4->n3; 1158 n5->n6[color="#99999955"]; 1159 n5->n4; 1160 n6->n3[color="#99999955"]; 1161 n6->n7[color="#00aa00"]; 1162 n6->n5[color="#aa0000"]; 1163 n7->n6[color="#99999955"]; 1164 n7->n8; 1165 n8->n7[color="#99999955"]; 1166 n8->n3[color="#99999955"]; 1167 `, 1168 dom: ` 1169 n2[label="foo(1)",shape="box"]; 1170 n3[label="if false",shape="hexagon"]; 1171 n4[label="return 5",shape="box"]; 1172 n5[label="if 2",shape="hexagon"]; 1173 n6[label="foo(3)",shape="box"]; 1174 n7[label="foo(4)",shape="box"]; 1175 n8[label="foo(2)",shape="box"]; 1176 n1->n2; 1177 n2->n3; 1178 n3->n4; 1179 n3->n5; 1180 n5->n6; 1181 n5->n7; 1182 n7->n8; 1183 `, 1184 flat: ` 1185 foo(1) 1186 goto L_1 1187 L_1: 1188 if false { 1189 goto L_2 1190 } else { 1191 goto L_3 1192 } 1193 L_2: 1194 return 5 1195 L_3: 1196 if 2 { 1197 goto L_4 1198 } else { 1199 goto L_5 1200 } 1201 L_4: 1202 foo(3) 1203 goto L_2 1204 L_5: 1205 foo(4) 1206 goto L_6 1207 L_6: 1208 foo(2) 1209 goto L_1 1210 `, 1211 }, 1212 } 1213 1214 func writeDotFile(name string, data []byte) { 1215 name = strings.ReplaceAll(name, " ", "_") 1216 fname := name + ".dot" 1217 _ = ioutil.WriteFile(fname, data, 0644) 1218 sdata, _ := exec.Command("dot", "-Tsvg", fname).Output() 1219 _ = ioutil.WriteFile(name+".svg", sdata, 0644) 1220 _ = os.Remove(fname) 1221 } 1222 1223 func cleanDot(s string) string { 1224 s = strings.TrimPrefix(s, `digraph {`) 1225 s = strings.TrimSpace(s) 1226 s = strings.TrimPrefix(s, `n1[label="begin"];`) 1227 s = strings.TrimSuffix(s, `}`) 1228 s = strings.TrimSpace(s) 1229 return s 1230 } 1231 1232 func TestControlFlow(t *testing.T) { 1233 const dir = "testout" 1234 _ = os.MkdirAll(dir, 0755) 1235 for _, c := range casesControlFlow { 1236 t.Run(c.name, func(t *testing.T) { 1237 tr := newTranslator(libs.NewEnv(types.Config32()), Config{}) 1238 var fixer Visitor 1239 fixer = func(n Node) { 1240 switch n := n.(type) { 1241 case nil: 1242 return 1243 case *CVarDecl: 1244 n.g = tr 1245 case *CVarSpec: 1246 n.g = tr 1247 } 1248 n.Visit(fixer) 1249 } 1250 1251 for _, st := range c.tree { 1252 st.Visit(fixer) 1253 } 1254 1255 cf := tr.NewControlFlow(c.tree) 1256 1257 got := cf.dumpDot() 1258 writeDotFile(filepath.Join(dir, c.name), []byte(got)) 1259 got = cleanDot(got) 1260 require.Equal(t, strings.TrimSpace(c.exp), got) 1261 1262 got = cf.dumpDomDot() 1263 writeDotFile(filepath.Join(dir, c.name+"_dom"), []byte(got)) 1264 got = cleanDot(got) 1265 require.Equal(t, strings.TrimSpace(c.dom), got) 1266 1267 stmts := cf.Flatten() 1268 got = printStmts(stmts) 1269 got = strings.ReplaceAll(got, "\t", "") 1270 require.Equal(t, strings.TrimSpace(c.flat), got) 1271 }) 1272 } 1273 }