github.com/cilki/sh@v2.6.4+incompatible/syntax/filetests_test.go (about) 1 // Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc> 2 // See LICENSE for licensing information 3 4 package syntax 5 6 import ( 7 "reflect" 8 "strings" 9 "testing" 10 ) 11 12 func prepareTest(c *testCase) { 13 c.common = fullProg(c.common) 14 c.bash = fullProg(c.bash) 15 c.posix = fullProg(c.posix) 16 c.mksh = fullProg(c.mksh) 17 c.bsmk = fullProg(c.bsmk) // bash AND mksh 18 if f, ok := c.common.(*File); ok && f != nil { 19 c.All = append(c.All, f) 20 c.Bash = f 21 c.Posix = f 22 c.MirBSDKorn = f 23 } 24 if f, ok := c.bash.(*File); ok && f != nil { 25 c.All = append(c.All, f) 26 c.Bash = f 27 } 28 if f, ok := c.posix.(*File); ok && f != nil { 29 c.All = append(c.All, f) 30 c.Posix = f 31 } 32 if f, ok := c.mksh.(*File); ok && f != nil { 33 c.All = append(c.All, f) 34 c.MirBSDKorn = f 35 } 36 if f, ok := c.bsmk.(*File); ok && f != nil { 37 c.All = append(c.All, f) 38 c.Bash = f 39 c.MirBSDKorn = f 40 } 41 } 42 43 func init() { 44 for i := range fileTests { 45 prepareTest(&fileTests[i]) 46 } 47 for i := range fileTestsNoPrint { 48 prepareTest(&fileTestsNoPrint[i]) 49 } 50 } 51 52 func lit(s string) *Lit { return &Lit{Value: s} } 53 func word(ps ...WordPart) *Word { return &Word{Parts: ps} } 54 func litWord(s string) *Word { return word(lit(s)) } 55 func litWords(strs ...string) []*Word { 56 l := make([]*Word, 0, len(strs)) 57 for _, s := range strs { 58 l = append(l, litWord(s)) 59 } 60 return l 61 } 62 63 func call(words ...*Word) *CallExpr { return &CallExpr{Args: words} } 64 func litCall(strs ...string) *CallExpr { return call(litWords(strs...)...) } 65 66 func stmt(cmd Command) *Stmt { return &Stmt{Cmd: cmd} } 67 func stmtList(sts ...*Stmt) StmtList { return StmtList{Stmts: sts} } 68 func stmts(cmds ...Command) StmtList { 69 l := make([]*Stmt, len(cmds)) 70 for i, cmd := range cmds { 71 l[i] = stmt(cmd) 72 } 73 return stmtList(l...) 74 } 75 76 func litStmt(strs ...string) *Stmt { return stmt(litCall(strs...)) } 77 func litStmts(strs ...string) StmtList { 78 l := make([]*Stmt, len(strs)) 79 for i, s := range strs { 80 l[i] = litStmt(s) 81 } 82 return stmtList(l...) 83 } 84 85 func sglQuoted(s string) *SglQuoted { return &SglQuoted{Value: s} } 86 func sglDQuoted(s string) *SglQuoted { return &SglQuoted{Dollar: true, Value: s} } 87 func dblQuoted(ps ...WordPart) *DblQuoted { return &DblQuoted{Parts: ps} } 88 func dblDQuoted(ps ...WordPart) *DblQuoted { return &DblQuoted{Dollar: true, Parts: ps} } 89 func block(sts ...*Stmt) *Block { return &Block{StmtList: stmtList(sts...)} } 90 func subshell(sts ...*Stmt) *Subshell { return &Subshell{StmtList: stmtList(sts...)} } 91 func arithmExp(e ArithmExpr) *ArithmExp { return &ArithmExp{X: e} } 92 func arithmExpBr(e ArithmExpr) *ArithmExp { return &ArithmExp{Bracket: true, X: e} } 93 func arithmCmd(e ArithmExpr) *ArithmCmd { return &ArithmCmd{X: e} } 94 func parenArit(e ArithmExpr) *ParenArithm { return &ParenArithm{X: e} } 95 func parenTest(e TestExpr) *ParenTest { return &ParenTest{X: e} } 96 97 func cmdSubst(sts ...*Stmt) *CmdSubst { return &CmdSubst{StmtList: stmtList(sts...)} } 98 func litParamExp(s string) *ParamExp { 99 return &ParamExp{Short: true, Param: lit(s)} 100 } 101 func letClause(exps ...ArithmExpr) *LetClause { 102 return &LetClause{Exprs: exps} 103 } 104 105 func arrValues(words ...*Word) *ArrayExpr { 106 ae := &ArrayExpr{} 107 for _, w := range words { 108 ae.Elems = append(ae.Elems, &ArrayElem{Value: w}) 109 } 110 return ae 111 } 112 113 type testCase struct { 114 Strs []string 115 common interface{} 116 bash, posix interface{} 117 bsmk, mksh interface{} 118 All []*File 119 Bash, Posix *File 120 MirBSDKorn *File 121 } 122 123 var fileTests = []testCase{ 124 { 125 Strs: []string{"", " ", "\t", "\n \n", "\r \r\n"}, 126 common: &File{}, 127 }, 128 { 129 Strs: []string{"", "# foo", "# foo ( bar", "# foo'bar"}, 130 common: &File{}, 131 }, 132 { 133 Strs: []string{"foo", "foo ", " foo", "foo # bar"}, 134 common: litWord("foo"), 135 }, 136 { 137 Strs: []string{`\`}, 138 common: litWord(`\`), 139 }, 140 { 141 Strs: []string{`foo\`, "f\\\noo\\"}, 142 common: litWord(`foo\`), 143 }, 144 { 145 Strs: []string{`foo\a`, "f\\\noo\\a"}, 146 common: litWord(`foo\a`), 147 }, 148 { 149 Strs: []string{ 150 "foo\nbar", 151 "foo; bar;", 152 "foo;bar;", 153 "\nfoo\nbar\n", 154 "foo\r\nbar\r\n", 155 }, 156 common: litStmts("foo", "bar"), 157 }, 158 { 159 Strs: []string{"foo a b", " foo a b ", "foo \\\n a b"}, 160 common: litCall("foo", "a", "b"), 161 }, 162 { 163 Strs: []string{"foobar", "foo\\\nbar", "foo\\\nba\\\nr"}, 164 common: litWord("foobar"), 165 }, 166 { 167 Strs: []string{"foo", "foo \\\n"}, 168 common: litWord("foo"), 169 }, 170 { 171 Strs: []string{"foo'bar'"}, 172 common: word(lit("foo"), sglQuoted("bar")), 173 }, 174 { 175 Strs: []string{"(foo)", "(foo;)", "(\nfoo\n)"}, 176 common: subshell(litStmt("foo")), 177 }, 178 { 179 Strs: []string{"(\n\tfoo\n\tbar\n)", "(foo; bar)"}, 180 common: subshell(litStmt("foo"), litStmt("bar")), 181 }, 182 { 183 Strs: []string{"{ foo; }", "{\nfoo\n}"}, 184 common: block(litStmt("foo")), 185 }, 186 { 187 Strs: []string{ 188 "{ if a; then b; fi; }", 189 "{ if a; then b; fi }", 190 }, 191 common: block(stmt(&IfClause{ 192 Cond: litStmts("a"), 193 Then: litStmts("b"), 194 })), 195 }, 196 { 197 Strs: []string{ 198 "if a; then b; fi", 199 "if a\nthen\nb\nfi", 200 "if a;\nthen\nb\nfi", 201 "if a \nthen\nb\nfi", 202 }, 203 common: &IfClause{ 204 Cond: litStmts("a"), 205 Then: litStmts("b"), 206 }, 207 }, 208 { 209 Strs: []string{ 210 "if a; then b; else c; fi", 211 "if a\nthen b\nelse\nc\nfi", 212 }, 213 common: &IfClause{ 214 Cond: litStmts("a"), 215 Then: litStmts("b"), 216 Else: litStmts("c"), 217 }, 218 }, 219 { 220 Strs: []string{ 221 "if a; then a; elif b; then b; else c; fi", 222 }, 223 common: &IfClause{ 224 Cond: litStmts("a"), 225 Then: litStmts("a"), 226 Else: stmtList(stmt(&IfClause{ 227 Elif: true, 228 Cond: litStmts("b"), 229 Then: litStmts("b"), 230 Else: litStmts("c"), 231 })), 232 }, 233 }, 234 { 235 Strs: []string{ 236 "if a; then a; elif b; then b; elif c; then c; else d; fi", 237 "if a\nthen a\nelif b\nthen b\nelif c\nthen c\nelse\nd\nfi", 238 }, 239 common: &IfClause{ 240 Cond: litStmts("a"), 241 Then: litStmts("a"), 242 Else: stmtList(stmt(&IfClause{ 243 Elif: true, 244 Cond: litStmts("b"), 245 Then: litStmts("b"), 246 Else: stmtList(stmt(&IfClause{ 247 Elif: true, 248 Cond: litStmts("c"), 249 Then: litStmts("c"), 250 Else: litStmts("d"), 251 })), 252 })), 253 }, 254 }, 255 { 256 Strs: []string{ 257 "if\n\ta1\n\ta2 foo\n\ta3 bar\nthen b; fi", 258 "if a1; a2 foo; a3 bar; then b; fi", 259 }, 260 common: &IfClause{ 261 Cond: stmtList( 262 litStmt("a1"), 263 litStmt("a2", "foo"), 264 litStmt("a3", "bar"), 265 ), 266 Then: litStmts("b"), 267 }, 268 }, 269 { 270 Strs: []string{`((a == 2))`}, 271 bsmk: stmt(arithmCmd(&BinaryArithm{ 272 Op: Eql, 273 X: litWord("a"), 274 Y: litWord("2"), 275 })), 276 posix: subshell(stmt(subshell(litStmt("a", "==", "2")))), 277 }, 278 { 279 Strs: []string{"if (($# > 2)); then b; fi"}, 280 bsmk: &IfClause{ 281 Cond: stmts(arithmCmd(&BinaryArithm{ 282 Op: Gtr, 283 X: word(litParamExp("#")), 284 Y: litWord("2"), 285 })), 286 Then: litStmts("b"), 287 }, 288 }, 289 { 290 Strs: []string{ 291 "(($(date -u) > DATE))", 292 "((`date -u` > DATE))", 293 }, 294 bsmk: arithmCmd(&BinaryArithm{ 295 Op: Gtr, 296 X: word(cmdSubst(litStmt("date", "-u"))), 297 Y: litWord("DATE"), 298 }), 299 }, 300 { 301 Strs: []string{": $((0x$foo == 10))"}, 302 common: call( 303 litWord(":"), 304 word(arithmExp(&BinaryArithm{ 305 Op: Eql, 306 X: word(lit("0x"), litParamExp("foo")), 307 Y: litWord("10"), 308 })), 309 ), 310 }, 311 { 312 Strs: []string{"((# 1 + 2))", "(( # 1 + 2 ))"}, 313 mksh: &ArithmCmd{ 314 X: &BinaryArithm{ 315 Op: Add, 316 X: litWord("1"), 317 Y: litWord("2"), 318 }, 319 Unsigned: true, 320 }, 321 }, 322 { 323 Strs: []string{"$((# 1 + 2))", "$(( # 1 + 2 ))"}, 324 mksh: &ArithmExp{ 325 X: &BinaryArithm{ 326 Op: Add, 327 X: litWord("1"), 328 Y: litWord("2"), 329 }, 330 Unsigned: true, 331 }, 332 }, 333 { 334 Strs: []string{"((3#20))"}, 335 bsmk: arithmCmd(litWord("3#20")), 336 }, 337 { 338 Strs: []string{ 339 "while a; do b; done", 340 "wh\\\nile a; do b; done", 341 "while a\ndo\nb\ndone", 342 "while a;\ndo\nb\ndone", 343 }, 344 common: &WhileClause{ 345 Cond: litStmts("a"), 346 Do: litStmts("b"), 347 }, 348 }, 349 { 350 Strs: []string{"while { a; }; do b; done", "while { a; } do b; done"}, 351 common: &WhileClause{ 352 Cond: stmts(block(litStmt("a"))), 353 Do: litStmts("b"), 354 }, 355 }, 356 { 357 Strs: []string{"while (a); do b; done", "while (a) do b; done"}, 358 common: &WhileClause{ 359 Cond: stmts(subshell(litStmt("a"))), 360 Do: litStmts("b"), 361 }, 362 }, 363 { 364 Strs: []string{"while ((1 > 2)); do b; done"}, 365 bsmk: &WhileClause{ 366 Cond: stmts(arithmCmd(&BinaryArithm{ 367 Op: Gtr, 368 X: litWord("1"), 369 Y: litWord("2"), 370 })), 371 Do: litStmts("b"), 372 }, 373 }, 374 { 375 Strs: []string{"until a; do b; done", "until a\ndo\nb\ndone"}, 376 common: &WhileClause{ 377 Until: true, 378 Cond: litStmts("a"), 379 Do: litStmts("b"), 380 }, 381 }, 382 { 383 Strs: []string{ 384 "for i; do foo; done", 385 "for i do foo; done", 386 "for i\ndo foo\ndone", 387 "for i;\ndo foo\ndone", 388 "for i in; do foo; done", 389 }, 390 common: &ForClause{ 391 Loop: &WordIter{Name: lit("i")}, 392 Do: litStmts("foo"), 393 }, 394 }, 395 { 396 Strs: []string{ 397 "for i in 1 2 3; do echo $i; done", 398 "for i in 1 2 3\ndo echo $i\ndone", 399 "for i in 1 2 3;\ndo echo $i\ndone", 400 "for i in 1 2 3 #foo\ndo echo $i\ndone", 401 }, 402 common: &ForClause{ 403 Loop: &WordIter{ 404 Name: lit("i"), 405 Items: litWords("1", "2", "3"), 406 }, 407 Do: stmts(call( 408 litWord("echo"), 409 word(litParamExp("i")), 410 )), 411 }, 412 }, 413 { 414 Strs: []string{ 415 "for i in \\\n\t1 2 3; do #foo\n\techo $i\ndone", 416 "for i #foo\n\tin 1 2 3; do\n\techo $i\ndone", 417 }, 418 common: &ForClause{ 419 Loop: &WordIter{ 420 Name: lit("i"), 421 Items: litWords("1", "2", "3"), 422 }, 423 Do: stmts(call( 424 litWord("echo"), 425 word(litParamExp("i")), 426 )), 427 }, 428 }, 429 { 430 Strs: []string{ 431 "for ((i = 0; i < 10; i++)); do echo $i; done", 432 "for ((i=0;i<10;i++)) do echo $i; done", 433 "for (( i = 0 ; i < 10 ; i++ ))\ndo echo $i\ndone", 434 "for (( i = 0 ; i < 10 ; i++ ));\ndo echo $i\ndone", 435 }, 436 bash: &ForClause{ 437 Loop: &CStyleLoop{ 438 Init: &BinaryArithm{ 439 Op: Assgn, 440 X: litWord("i"), 441 Y: litWord("0"), 442 }, 443 Cond: &BinaryArithm{ 444 Op: Lss, 445 X: litWord("i"), 446 Y: litWord("10"), 447 }, 448 Post: &UnaryArithm{ 449 Op: Inc, 450 Post: true, 451 X: litWord("i"), 452 }, 453 }, 454 Do: stmts(call( 455 litWord("echo"), 456 word(litParamExp("i")), 457 )), 458 }, 459 }, 460 { 461 Strs: []string{ 462 "for (( ; ; )); do foo; done", 463 "for ((;;)); do foo; done", 464 }, 465 bash: &ForClause{ 466 Loop: &CStyleLoop{}, 467 Do: litStmts("foo"), 468 }, 469 }, 470 { 471 Strs: []string{ 472 "for ((i = 0; ; )); do foo; done", 473 "for ((i = 0;;)); do foo; done", 474 }, 475 bash: &ForClause{ 476 Loop: &CStyleLoop{ 477 Init: &BinaryArithm{ 478 Op: Assgn, 479 X: litWord("i"), 480 Y: litWord("0"), 481 }, 482 }, 483 Do: litStmts("foo"), 484 }, 485 }, 486 { 487 Strs: []string{ 488 "select i; do foo; done", 489 // TODO: bash won't allow this - bug? 490 //"select i in; do foo; done", 491 }, 492 bsmk: &ForClause{ 493 Select: true, 494 Loop: &WordIter{Name: lit("i")}, 495 Do: litStmts("foo"), 496 }, 497 }, 498 { 499 Strs: []string{ 500 "select i in 1 2 3; do echo $i; done", 501 "select i in 1 2 3\ndo echo $i\ndone", 502 "select i in 1 2 3 #foo\ndo echo $i\ndone", 503 }, 504 bsmk: &ForClause{ 505 Select: true, 506 Loop: &WordIter{ 507 Name: lit("i"), 508 Items: litWords("1", "2", "3"), 509 }, 510 Do: stmts(call( 511 litWord("echo"), 512 word(litParamExp("i")), 513 )), 514 }, 515 }, 516 { 517 Strs: []string{"select foo bar"}, 518 posix: litStmt("select", "foo", "bar"), 519 }, 520 { 521 Strs: []string{`' ' "foo bar"`}, 522 common: call( 523 word(sglQuoted(" ")), 524 word(dblQuoted(lit("foo bar"))), 525 ), 526 }, 527 { 528 Strs: []string{`"foo \" bar"`}, 529 common: word(dblQuoted(lit(`foo \" bar`))), 530 }, 531 { 532 Strs: []string{"\">foo\" \"\nbar\""}, 533 common: call( 534 word(dblQuoted(lit(">foo"))), 535 word(dblQuoted(lit("\nbar"))), 536 ), 537 }, 538 { 539 Strs: []string{`foo \" bar`}, 540 common: litCall(`foo`, `\"`, `bar`), 541 }, 542 { 543 Strs: []string{`'"'`}, 544 common: sglQuoted(`"`), 545 }, 546 { 547 Strs: []string{"'`'"}, 548 common: sglQuoted("`"), 549 }, 550 { 551 Strs: []string{`"'"`}, 552 common: dblQuoted(lit("'")), 553 }, 554 { 555 Strs: []string{`""`}, 556 common: dblQuoted(), 557 }, 558 { 559 Strs: []string{"=a s{s s=s"}, 560 common: litCall("=a", "s{s", "s=s"), 561 }, 562 { 563 Strs: []string{"foo && bar", "foo&&bar", "foo &&\nbar"}, 564 common: &BinaryCmd{ 565 Op: AndStmt, 566 X: litStmt("foo"), 567 Y: litStmt("bar"), 568 }, 569 }, 570 { 571 Strs: []string{"foo &&\n\tbar"}, 572 common: &BinaryCmd{ 573 Op: AndStmt, 574 X: litStmt("foo"), 575 Y: litStmt("bar"), 576 }, 577 }, 578 { 579 Strs: []string{"foo || bar", "foo||bar", "foo ||\nbar"}, 580 common: &BinaryCmd{ 581 Op: OrStmt, 582 X: litStmt("foo"), 583 Y: litStmt("bar"), 584 }, 585 }, 586 { 587 Strs: []string{"if a; then b; fi || while a; do b; done"}, 588 common: &BinaryCmd{ 589 Op: OrStmt, 590 X: stmt(&IfClause{ 591 Cond: litStmts("a"), 592 Then: litStmts("b"), 593 }), 594 Y: stmt(&WhileClause{ 595 Cond: litStmts("a"), 596 Do: litStmts("b"), 597 }), 598 }, 599 }, 600 { 601 Strs: []string{"foo && bar1 || bar2"}, 602 common: &BinaryCmd{ 603 Op: OrStmt, 604 X: stmt(&BinaryCmd{ 605 Op: AndStmt, 606 X: litStmt("foo"), 607 Y: litStmt("bar1"), 608 }), 609 Y: litStmt("bar2"), 610 }, 611 }, 612 { 613 Strs: []string{"a || b || c || d"}, 614 common: &BinaryCmd{ 615 Op: OrStmt, 616 X: stmt(&BinaryCmd{ 617 Op: OrStmt, 618 X: stmt(&BinaryCmd{ 619 Op: OrStmt, 620 X: litStmt("a"), 621 Y: litStmt("b"), 622 }), 623 Y: litStmt("c"), 624 }), 625 Y: litStmt("d"), 626 }, 627 }, 628 { 629 Strs: []string{"foo | bar", "foo|bar", "foo |\n#etc\nbar"}, 630 common: &BinaryCmd{ 631 Op: Pipe, 632 X: litStmt("foo"), 633 Y: litStmt("bar"), 634 }, 635 }, 636 { 637 Strs: []string{"foo | bar | extra"}, 638 common: &BinaryCmd{ 639 Op: Pipe, 640 X: litStmt("foo"), 641 Y: stmt(&BinaryCmd{ 642 Op: Pipe, 643 X: litStmt("bar"), 644 Y: litStmt("extra"), 645 }), 646 }, 647 }, 648 { 649 Strs: []string{"foo | a=b bar"}, 650 common: &BinaryCmd{ 651 Op: Pipe, 652 X: litStmt("foo"), 653 Y: stmt(&CallExpr{ 654 Assigns: []*Assign{{ 655 Name: lit("a"), 656 Value: litWord("b"), 657 }}, 658 Args: litWords("bar"), 659 }), 660 }, 661 }, 662 { 663 Strs: []string{"foo |&"}, 664 mksh: &Stmt{Cmd: litCall("foo"), Coprocess: true}, 665 }, 666 { 667 Strs: []string{"foo |& bar", "foo|&bar"}, 668 bash: &BinaryCmd{ 669 Op: PipeAll, 670 X: litStmt("foo"), 671 Y: litStmt("bar"), 672 }, 673 mksh: []*Stmt{ 674 {Cmd: litCall("foo"), Coprocess: true}, 675 litStmt("bar"), 676 }, 677 }, 678 { 679 Strs: []string{ 680 "foo() {\n\ta\n\tb\n}", 681 "foo() { a; b; }", 682 "foo ( ) {\na\nb\n}", 683 "foo()\n{\na\nb\n}", 684 }, 685 common: &FuncDecl{ 686 Name: lit("foo"), 687 Body: stmt(block(litStmt("a"), litStmt("b"))), 688 }, 689 }, 690 { 691 Strs: []string{"foo() { a; }\nbar", "foo() {\na\n}; bar"}, 692 common: []Command{ 693 &FuncDecl{ 694 Name: lit("foo"), 695 Body: stmt(block(litStmt("a"))), 696 }, 697 litCall("bar"), 698 }, 699 }, 700 { 701 Strs: []string{"foO_123() { a; }"}, 702 common: &FuncDecl{ 703 Name: lit("foO_123"), 704 Body: stmt(block(litStmt("a"))), 705 }, 706 }, 707 { 708 Strs: []string{"-foo_.,+-bar() { a; }"}, 709 bsmk: &FuncDecl{ 710 Name: lit("-foo_.,+-bar"), 711 Body: stmt(block(litStmt("a"))), 712 }, 713 }, 714 { 715 Strs: []string{ 716 "function foo() {\n\ta\n\tb\n}", 717 "function foo {\n\ta\n\tb\n}", 718 "function foo() { a; b; }", 719 }, 720 bsmk: &FuncDecl{ 721 RsrvWord: true, 722 Name: lit("foo"), 723 Body: stmt(block(litStmt("a"), litStmt("b"))), 724 }, 725 }, 726 { 727 Strs: []string{"function foo() (a)"}, 728 bash: &FuncDecl{ 729 RsrvWord: true, 730 Name: lit("foo"), 731 Body: stmt(subshell(litStmt("a"))), 732 }, 733 }, 734 { 735 Strs: []string{"a=b foo=$bar foo=start$bar"}, 736 common: &CallExpr{ 737 Assigns: []*Assign{ 738 {Name: lit("a"), Value: litWord("b")}, 739 {Name: lit("foo"), Value: word(litParamExp("bar"))}, 740 {Name: lit("foo"), Value: word( 741 lit("start"), 742 litParamExp("bar"), 743 )}, 744 }, 745 }, 746 }, 747 { 748 Strs: []string{"a=\"\nbar\""}, 749 common: &CallExpr{ 750 Assigns: []*Assign{{ 751 Name: lit("a"), 752 Value: word(dblQuoted(lit("\nbar"))), 753 }}, 754 }, 755 }, 756 { 757 Strs: []string{"A_3a= foo"}, 758 common: &CallExpr{ 759 Assigns: []*Assign{{Name: lit("A_3a")}}, 760 Args: litWords("foo"), 761 }, 762 }, 763 { 764 Strs: []string{"a=b=c"}, 765 common: &CallExpr{ 766 Assigns: []*Assign{{Name: lit("a"), Value: litWord("b=c")}}, 767 }, 768 }, 769 { 770 Strs: []string{"à=b foo"}, 771 common: litStmt("à=b", "foo"), 772 }, 773 { 774 Strs: []string{ 775 "foo >a >>b <c", 776 "foo > a >> b < c", 777 ">a >>b <c foo", 778 }, 779 common: &Stmt{ 780 Cmd: litCall("foo"), 781 Redirs: []*Redirect{ 782 {Op: RdrOut, Word: litWord("a")}, 783 {Op: AppOut, Word: litWord("b")}, 784 {Op: RdrIn, Word: litWord("c")}, 785 }, 786 }, 787 }, 788 { 789 Strs: []string{ 790 "foo bar >a", 791 "foo >a bar", 792 }, 793 common: &Stmt{ 794 Cmd: litCall("foo", "bar"), 795 Redirs: []*Redirect{ 796 {Op: RdrOut, Word: litWord("a")}, 797 }, 798 }, 799 }, 800 { 801 Strs: []string{`>a >\b`}, 802 common: &Stmt{ 803 Redirs: []*Redirect{ 804 {Op: RdrOut, Word: litWord("a")}, 805 {Op: RdrOut, Word: litWord(`\b`)}, 806 }, 807 }, 808 }, 809 { 810 Strs: []string{">a\n>b", ">a; >b"}, 811 common: []*Stmt{ 812 {Redirs: []*Redirect{ 813 {Op: RdrOut, Word: litWord("a")}, 814 }}, 815 {Redirs: []*Redirect{ 816 {Op: RdrOut, Word: litWord("b")}, 817 }}, 818 }, 819 }, 820 { 821 Strs: []string{"foo1\nfoo2 >r2", "foo1; >r2 foo2"}, 822 common: []*Stmt{ 823 litStmt("foo1"), 824 { 825 Cmd: litCall("foo2"), 826 Redirs: []*Redirect{ 827 {Op: RdrOut, Word: litWord("r2")}, 828 }, 829 }, 830 }, 831 }, 832 { 833 Strs: []string{"foo >bar$(etc)", "foo >b\\\nar`etc`"}, 834 common: &Stmt{ 835 Cmd: litCall("foo"), 836 Redirs: []*Redirect{ 837 {Op: RdrOut, Word: word( 838 lit("bar"), 839 cmdSubst(litStmt("etc")), 840 )}, 841 }, 842 }, 843 }, 844 { 845 Strs: []string{ 846 "a=b c=d foo >x <y", 847 "a=b c=d >x <y foo", 848 ">x a=b c=d <y foo", 849 ">x <y a=b c=d foo", 850 "a=b >x c=d foo <y", 851 }, 852 common: &Stmt{ 853 Cmd: &CallExpr{ 854 Assigns: []*Assign{ 855 {Name: lit("a"), Value: litWord("b")}, 856 {Name: lit("c"), Value: litWord("d")}, 857 }, 858 Args: litWords("foo"), 859 }, 860 Redirs: []*Redirect{ 861 {Op: RdrOut, Word: litWord("x")}, 862 {Op: RdrIn, Word: litWord("y")}, 863 }, 864 }, 865 }, 866 { 867 Strs: []string{ 868 "foo <<EOF\nbar\nEOF", 869 "foo <<EOF \nbar\nEOF", 870 "foo <<EOF\t\nbar\nEOF", 871 }, 872 common: &Stmt{ 873 Cmd: litCall("foo"), 874 Redirs: []*Redirect{{ 875 Op: Hdoc, 876 Word: litWord("EOF"), 877 Hdoc: litWord("bar\n"), 878 }}, 879 }, 880 }, 881 { 882 Strs: []string{"foo <<EOF\n\nbar\nEOF"}, 883 common: &Stmt{ 884 Cmd: litCall("foo"), 885 Redirs: []*Redirect{{ 886 Op: Hdoc, 887 Word: litWord("EOF"), 888 Hdoc: litWord("\nbar\n"), 889 }}, 890 }, 891 }, 892 { 893 Strs: []string{"foo <<EOF\nbar\n\nEOF"}, 894 common: &Stmt{ 895 Cmd: litCall("foo"), 896 Redirs: []*Redirect{{ 897 Op: Hdoc, 898 Word: litWord("EOF"), 899 Hdoc: litWord("bar\n\n"), 900 }}, 901 }, 902 }, 903 { 904 Strs: []string{"foo <<EOF\n1\n2\n3\nEOF"}, 905 common: &Stmt{ 906 Cmd: litCall("foo"), 907 Redirs: []*Redirect{{ 908 Op: Hdoc, 909 Word: litWord("EOF"), 910 Hdoc: litWord("1\n2\n3\n"), 911 }}, 912 }, 913 }, 914 { 915 Strs: []string{"a <<EOF\nfoo$bar\nEOF"}, 916 common: &Stmt{ 917 Cmd: litCall("a"), 918 Redirs: []*Redirect{{ 919 Op: Hdoc, 920 Word: litWord("EOF"), 921 Hdoc: word( 922 lit("foo"), 923 litParamExp("bar"), 924 lit("\n"), 925 ), 926 }}, 927 }, 928 }, 929 { 930 Strs: []string{"a <<EOF\n\"$bar\"\nEOF"}, 931 common: &Stmt{ 932 Cmd: litCall("a"), 933 Redirs: []*Redirect{{ 934 Op: Hdoc, 935 Word: litWord("EOF"), 936 Hdoc: word( 937 lit(`"`), 938 litParamExp("bar"), 939 lit("\"\n"), 940 ), 941 }}, 942 }, 943 }, 944 { 945 Strs: []string{"a <<EOF\n$''$bar\nEOF"}, 946 bash: &Stmt{ 947 Cmd: litCall("a"), 948 Redirs: []*Redirect{{ 949 Op: Hdoc, 950 Word: litWord("EOF"), 951 Hdoc: word( 952 lit("$"), 953 lit("''"), 954 litParamExp("bar"), 955 lit("\n"), 956 ), 957 }}, 958 }, 959 }, 960 { 961 Strs: []string{ 962 "a <<EOF\n$(b)\nc\nEOF", 963 "a <<EOF\n`b`\nc\nEOF", 964 }, 965 common: &Stmt{ 966 Cmd: litCall("a"), 967 Redirs: []*Redirect{{ 968 Op: Hdoc, 969 Word: litWord("EOF"), 970 Hdoc: word( 971 cmdSubst(litStmt("b")), 972 lit("\nc\n"), 973 ), 974 }}, 975 }, 976 }, 977 { 978 Strs: []string{"a <<EOF\n\\${\nEOF"}, 979 common: &Stmt{ 980 Cmd: litCall("a"), 981 Redirs: []*Redirect{{ 982 Op: Hdoc, 983 Word: litWord("EOF"), 984 Hdoc: litWord("\\${\n"), 985 }}, 986 }, 987 }, 988 { 989 Strs: []string{ 990 "{\n\tfoo <<EOF\nbar\nEOF\n}", 991 "{ foo <<EOF\nbar\nEOF\n}", 992 }, 993 common: block(&Stmt{ 994 Cmd: litCall("foo"), 995 Redirs: []*Redirect{{ 996 Op: Hdoc, 997 Word: litWord("EOF"), 998 Hdoc: litWord("bar\n"), 999 }}, 1000 }), 1001 }, 1002 { 1003 Strs: []string{ 1004 "$(\n\tfoo <<EOF\nbar\nEOF\n)", 1005 "$(foo <<EOF\nbar\nEOF\n)", 1006 }, 1007 common: cmdSubst(&Stmt{ 1008 Cmd: litCall("foo"), 1009 Redirs: []*Redirect{{ 1010 Op: Hdoc, 1011 Word: litWord("EOF"), 1012 Hdoc: litWord("bar\n"), 1013 }}, 1014 }), 1015 }, 1016 { 1017 Strs: []string{"$(<foo)", "`<foo`"}, 1018 common: cmdSubst(&Stmt{ 1019 Redirs: []*Redirect{{ 1020 Op: RdrIn, 1021 Word: litWord("foo"), 1022 }}, 1023 }), 1024 }, 1025 { 1026 Strs: []string{"foo <<EOF >f\nbar\nEOF"}, 1027 common: &Stmt{ 1028 Cmd: litCall("foo"), 1029 Redirs: []*Redirect{ 1030 { 1031 Op: Hdoc, 1032 Word: litWord("EOF"), 1033 Hdoc: litWord("bar\n"), 1034 }, 1035 {Op: RdrOut, Word: litWord("f")}, 1036 }, 1037 }, 1038 }, 1039 { 1040 Strs: []string{"foo <<EOF && {\nbar\nEOF\n\tetc\n}"}, 1041 common: &BinaryCmd{ 1042 Op: AndStmt, 1043 X: &Stmt{ 1044 Cmd: litCall("foo"), 1045 Redirs: []*Redirect{{ 1046 Op: Hdoc, 1047 Word: litWord("EOF"), 1048 Hdoc: litWord("bar\n"), 1049 }}, 1050 }, 1051 Y: stmt(block(litStmt("etc"))), 1052 }, 1053 }, 1054 { 1055 Strs: []string{ 1056 "$(\n\tfoo\n) <<EOF\nbar\nEOF", 1057 "<<EOF $(\n\tfoo\n)\nbar\nEOF", 1058 }, 1059 // note that dash won't accept the second one 1060 bsmk: &Stmt{ 1061 Cmd: call(word(cmdSubst(litStmt("foo")))), 1062 Redirs: []*Redirect{{ 1063 Op: Hdoc, 1064 Word: litWord("EOF"), 1065 Hdoc: litWord("bar\n"), 1066 }}, 1067 }, 1068 }, 1069 { 1070 Strs: []string{ 1071 "$(\n\tfoo\n) <<EOF\nbar\nEOF", 1072 "`\n\tfoo\n` <<EOF\nbar\nEOF", 1073 "<<EOF `\n\tfoo\n`\nbar\nEOF", 1074 }, 1075 common: &Stmt{ 1076 Cmd: call(word(cmdSubst(litStmt("foo")))), 1077 Redirs: []*Redirect{{ 1078 Op: Hdoc, 1079 Word: litWord("EOF"), 1080 Hdoc: litWord("bar\n"), 1081 }}, 1082 }, 1083 }, 1084 { 1085 Strs: []string{ 1086 "$((foo)) <<EOF\nbar\nEOF", 1087 "<<EOF $((\n\tfoo\n))\nbar\nEOF", 1088 }, 1089 common: &Stmt{ 1090 Cmd: call(word(arithmExp(litWord("foo")))), 1091 Redirs: []*Redirect{{ 1092 Op: Hdoc, 1093 Word: litWord("EOF"), 1094 Hdoc: litWord("bar\n"), 1095 }}, 1096 }, 1097 }, 1098 { 1099 Strs: []string{"if true; then\n\tfoo <<-EOF\n\t\tbar\n\tEOF\nfi"}, 1100 common: &IfClause{ 1101 Cond: litStmts("true"), 1102 Then: stmtList(&Stmt{ 1103 Cmd: litCall("foo"), 1104 Redirs: []*Redirect{{ 1105 Op: DashHdoc, 1106 Word: litWord("EOF"), 1107 Hdoc: litWord("\t\tbar\n\t"), 1108 }}, 1109 }), 1110 }, 1111 }, 1112 { 1113 Strs: []string{"if true; then\n\tfoo <<-EOF\n\tEOF\nfi"}, 1114 common: &IfClause{ 1115 Cond: litStmts("true"), 1116 Then: stmtList(&Stmt{ 1117 Cmd: litCall("foo"), 1118 Redirs: []*Redirect{{ 1119 Op: DashHdoc, 1120 Word: litWord("EOF"), 1121 Hdoc: litWord("\t"), 1122 }}, 1123 }), 1124 }, 1125 }, 1126 { 1127 Strs: []string{"foo <<EOF\nbar\nEOF\nfoo2"}, 1128 common: []*Stmt{ 1129 { 1130 Cmd: litCall("foo"), 1131 Redirs: []*Redirect{{ 1132 Op: Hdoc, 1133 Word: litWord("EOF"), 1134 Hdoc: litWord("bar\n"), 1135 }}, 1136 }, 1137 litStmt("foo2"), 1138 }, 1139 }, 1140 { 1141 Strs: []string{"foo <<FOOBAR\nbar\nFOOBAR"}, 1142 common: &Stmt{ 1143 Cmd: litCall("foo"), 1144 Redirs: []*Redirect{{ 1145 Op: Hdoc, 1146 Word: litWord("FOOBAR"), 1147 Hdoc: litWord("bar\n"), 1148 }}, 1149 }, 1150 }, 1151 { 1152 Strs: []string{"foo <<\"EOF\"\nbar\nEOF"}, 1153 common: &Stmt{ 1154 Cmd: litCall("foo"), 1155 Redirs: []*Redirect{{ 1156 Op: Hdoc, 1157 Word: word(dblQuoted(lit("EOF"))), 1158 Hdoc: litWord("bar\n"), 1159 }}, 1160 }, 1161 }, 1162 { 1163 Strs: []string{"foo <<'EOF'\n${\nEOF"}, 1164 common: &Stmt{ 1165 Cmd: litCall("foo"), 1166 Redirs: []*Redirect{{ 1167 Op: Hdoc, 1168 Word: word(sglQuoted("EOF")), 1169 Hdoc: litWord("${\n"), 1170 }}, 1171 }, 1172 }, 1173 { 1174 Strs: []string{"foo <<'EOF'\nEOF"}, 1175 common: &Stmt{ 1176 Cmd: litCall("foo"), 1177 Redirs: []*Redirect{{ 1178 Op: Hdoc, 1179 Word: word(sglQuoted("EOF")), 1180 }}, 1181 }, 1182 }, 1183 { 1184 Strs: []string{"foo <<\"EOF\"2\nbar\nEOF2"}, 1185 common: &Stmt{ 1186 Cmd: litCall("foo"), 1187 Redirs: []*Redirect{{ 1188 Op: Hdoc, 1189 Word: word(dblQuoted(lit("EOF")), lit("2")), 1190 Hdoc: litWord("bar\n"), 1191 }}, 1192 }, 1193 }, 1194 { 1195 Strs: []string{"foo <<\\EOF\nbar\nEOF"}, 1196 common: &Stmt{ 1197 Cmd: litCall("foo"), 1198 Redirs: []*Redirect{{ 1199 Op: Hdoc, 1200 Word: litWord("\\EOF"), 1201 Hdoc: litWord("bar\n"), 1202 }}, 1203 }, 1204 }, 1205 { 1206 Strs: []string{"foo <<-EOF\n\tbar\nEOF"}, 1207 common: &Stmt{ 1208 Cmd: litCall("foo"), 1209 Redirs: []*Redirect{{ 1210 Op: DashHdoc, 1211 Word: litWord("EOF"), 1212 Hdoc: litWord("\tbar\n"), 1213 }}, 1214 }, 1215 }, 1216 { 1217 Strs: []string{"foo <<EOF\nEOF"}, 1218 common: &Stmt{ 1219 Cmd: litCall("foo"), 1220 Redirs: []*Redirect{{ 1221 Op: Hdoc, 1222 Word: litWord("EOF"), 1223 }}, 1224 }, 1225 }, 1226 { 1227 Strs: []string{"foo <<-EOF\nEOF"}, 1228 common: &Stmt{ 1229 Cmd: litCall("foo"), 1230 Redirs: []*Redirect{{ 1231 Op: DashHdoc, 1232 Word: litWord("EOF"), 1233 }}, 1234 }, 1235 }, 1236 { 1237 Strs: []string{"foo <<-EOF\n\tbar\nEOF"}, 1238 common: &Stmt{ 1239 Cmd: litCall("foo"), 1240 Redirs: []*Redirect{{ 1241 Op: DashHdoc, 1242 Word: litWord("EOF"), 1243 Hdoc: litWord("\tbar\n"), 1244 }}, 1245 }, 1246 }, 1247 { 1248 Strs: []string{"foo <<-'EOF'\n\tbar\nEOF"}, 1249 common: &Stmt{ 1250 Cmd: litCall("foo"), 1251 Redirs: []*Redirect{{ 1252 Op: DashHdoc, 1253 Word: word(sglQuoted("EOF")), 1254 Hdoc: litWord("\tbar\n"), 1255 }}, 1256 }, 1257 }, 1258 { 1259 Strs: []string{ 1260 "f1 <<EOF1\nh1\nEOF1\nf2 <<EOF2\nh2\nEOF2", 1261 "f1 <<EOF1; f2 <<EOF2\nh1\nEOF1\nh2\nEOF2", 1262 }, 1263 common: []*Stmt{ 1264 { 1265 Cmd: litCall("f1"), 1266 Redirs: []*Redirect{{ 1267 Op: Hdoc, 1268 Word: litWord("EOF1"), 1269 Hdoc: litWord("h1\n"), 1270 }}, 1271 }, 1272 { 1273 Cmd: litCall("f2"), 1274 Redirs: []*Redirect{{ 1275 Op: Hdoc, 1276 Word: litWord("EOF2"), 1277 Hdoc: litWord("h2\n"), 1278 }}, 1279 }, 1280 }, 1281 }, 1282 { 1283 Strs: []string{ 1284 "a <<EOF\nfoo\nEOF\nb\nb\nb\nb\nb\nb\nb\nb\nb", 1285 "a <<EOF;b;b;b;b;b;b;b;b;b\nfoo\nEOF", 1286 }, 1287 common: []*Stmt{ 1288 { 1289 Cmd: litCall("a"), 1290 Redirs: []*Redirect{{ 1291 Op: Hdoc, 1292 Word: litWord("EOF"), 1293 Hdoc: litWord("foo\n"), 1294 }}, 1295 }, 1296 litStmt("b"), litStmt("b"), litStmt("b"), 1297 litStmt("b"), litStmt("b"), litStmt("b"), 1298 litStmt("b"), litStmt("b"), litStmt("b"), 1299 }, 1300 }, 1301 { 1302 Strs: []string{ 1303 "foo \"\narg\" <<EOF\nbar\nEOF", 1304 "foo <<EOF \"\narg\"\nbar\nEOF", 1305 }, 1306 common: &Stmt{ 1307 Cmd: call( 1308 litWord("foo"), 1309 word(dblQuoted(lit("\narg"))), 1310 ), 1311 Redirs: []*Redirect{{ 1312 Op: Hdoc, 1313 Word: litWord("EOF"), 1314 Hdoc: litWord("bar\n"), 1315 }}, 1316 }, 1317 }, 1318 { 1319 Strs: []string{"foo >&2 <&0 2>file 345>file <>f2"}, 1320 common: &Stmt{ 1321 Cmd: litCall("foo"), 1322 Redirs: []*Redirect{ 1323 {Op: DplOut, Word: litWord("2")}, 1324 {Op: DplIn, Word: litWord("0")}, 1325 {Op: RdrOut, N: lit("2"), Word: litWord("file")}, 1326 {Op: RdrOut, N: lit("345"), Word: litWord("file")}, 1327 {Op: RdrInOut, Word: litWord("f2")}, 1328 }, 1329 }, 1330 }, 1331 { 1332 Strs: []string{ 1333 "foo bar >file", 1334 "foo bar>file", 1335 }, 1336 common: &Stmt{ 1337 Cmd: litCall("foo", "bar"), 1338 Redirs: []*Redirect{ 1339 {Op: RdrOut, Word: litWord("file")}, 1340 }, 1341 }, 1342 }, 1343 { 1344 Strs: []string{"foo &>a &>>b"}, 1345 bsmk: &Stmt{ 1346 Cmd: litCall("foo"), 1347 Redirs: []*Redirect{ 1348 {Op: RdrAll, Word: litWord("a")}, 1349 {Op: AppAll, Word: litWord("b")}, 1350 }, 1351 }, 1352 posix: []*Stmt{ 1353 {Cmd: litCall("foo"), Background: true}, 1354 {Redirs: []*Redirect{ 1355 {Op: RdrOut, Word: litWord("a")}, 1356 }, Background: true}, 1357 {Redirs: []*Redirect{ 1358 {Op: AppOut, Word: litWord("b")}, 1359 }}, 1360 }, 1361 }, 1362 { 1363 Strs: []string{"foo 2>file bar", "2>file foo bar"}, 1364 common: &Stmt{ 1365 Cmd: litCall("foo", "bar"), 1366 Redirs: []*Redirect{ 1367 {Op: RdrOut, N: lit("2"), Word: litWord("file")}, 1368 }, 1369 }, 1370 }, 1371 { 1372 Strs: []string{"a >f1\nb >f2", "a >f1; b >f2"}, 1373 common: []*Stmt{ 1374 { 1375 Cmd: litCall("a"), 1376 Redirs: []*Redirect{{Op: RdrOut, Word: litWord("f1")}}, 1377 }, 1378 { 1379 Cmd: litCall("b"), 1380 Redirs: []*Redirect{{Op: RdrOut, Word: litWord("f2")}}, 1381 }, 1382 }, 1383 }, 1384 { 1385 Strs: []string{"foo >|bar"}, 1386 common: &Stmt{ 1387 Cmd: litCall("foo"), 1388 Redirs: []*Redirect{ 1389 {Op: ClbOut, Word: litWord("bar")}, 1390 }, 1391 }, 1392 }, 1393 { 1394 Strs: []string{ 1395 "foo <<<input", 1396 "foo <<< input", 1397 }, 1398 bsmk: &Stmt{ 1399 Cmd: litCall("foo"), 1400 Redirs: []*Redirect{{ 1401 Op: WordHdoc, 1402 Word: litWord("input"), 1403 }}, 1404 }, 1405 }, 1406 { 1407 Strs: []string{ 1408 `foo <<<"spaced input"`, 1409 `foo <<< "spaced input"`, 1410 }, 1411 bsmk: &Stmt{ 1412 Cmd: litCall("foo"), 1413 Redirs: []*Redirect{{ 1414 Op: WordHdoc, 1415 Word: word(dblQuoted(lit("spaced input"))), 1416 }}, 1417 }, 1418 }, 1419 { 1420 Strs: []string{"foo >(foo)"}, 1421 bash: call( 1422 litWord("foo"), 1423 word(&ProcSubst{ 1424 Op: CmdOut, 1425 StmtList: litStmts("foo"), 1426 }), 1427 ), 1428 }, 1429 { 1430 Strs: []string{"foo < <(foo)"}, 1431 bash: &Stmt{ 1432 Cmd: litCall("foo"), 1433 Redirs: []*Redirect{{ 1434 Op: RdrIn, 1435 Word: word(&ProcSubst{ 1436 Op: CmdIn, 1437 StmtList: litStmts("foo"), 1438 }), 1439 }}, 1440 }, 1441 }, 1442 { 1443 Strs: []string{"a<(b) c>(d)"}, 1444 bash: call( 1445 word(lit("a"), &ProcSubst{ 1446 Op: CmdIn, 1447 StmtList: litStmts("b"), 1448 }), 1449 word(lit("c"), &ProcSubst{ 1450 Op: CmdOut, 1451 StmtList: litStmts("d"), 1452 }), 1453 ), 1454 }, 1455 { 1456 Strs: []string{"foo {fd}<f"}, 1457 bash: &Stmt{ 1458 Cmd: litCall("foo"), 1459 Redirs: []*Redirect{ 1460 {Op: RdrIn, N: lit("{fd}"), Word: litWord("f")}, 1461 }, 1462 }, 1463 }, 1464 { 1465 Strs: []string{"! foo"}, 1466 common: &Stmt{ 1467 Negated: true, 1468 Cmd: litCall("foo"), 1469 }, 1470 }, 1471 { 1472 Strs: []string{"foo &\nbar", "foo & bar", "foo&bar"}, 1473 common: []*Stmt{ 1474 {Cmd: litCall("foo"), Background: true}, 1475 litStmt("bar"), 1476 }, 1477 }, 1478 { 1479 Strs: []string{"! if foo; then bar; fi >/dev/null &"}, 1480 common: &Stmt{ 1481 Negated: true, 1482 Cmd: &IfClause{ 1483 Cond: litStmts("foo"), 1484 Then: litStmts("bar"), 1485 }, 1486 Redirs: []*Redirect{ 1487 {Op: RdrOut, Word: litWord("/dev/null")}, 1488 }, 1489 Background: true, 1490 }, 1491 }, 1492 { 1493 Strs: []string{"! foo && bar"}, 1494 common: &BinaryCmd{ 1495 Op: AndStmt, 1496 X: &Stmt{ 1497 Cmd: litCall("foo"), 1498 Negated: true, 1499 }, 1500 Y: litStmt("bar"), 1501 }, 1502 }, 1503 { 1504 Strs: []string{"! foo | bar"}, 1505 common: &Stmt{ 1506 Cmd: &BinaryCmd{ 1507 Op: Pipe, 1508 X: litStmt("foo"), 1509 Y: litStmt("bar"), 1510 }, 1511 Negated: true, 1512 }, 1513 }, 1514 { 1515 Strs: []string{ 1516 "a && b &\nc", 1517 "a && b & c", 1518 }, 1519 common: []*Stmt{ 1520 { 1521 Cmd: &BinaryCmd{ 1522 Op: AndStmt, 1523 X: litStmt("a"), 1524 Y: litStmt("b"), 1525 }, 1526 Background: true, 1527 }, 1528 litStmt("c"), 1529 }, 1530 }, 1531 { 1532 Strs: []string{"a | b &"}, 1533 common: &Stmt{ 1534 Cmd: &BinaryCmd{ 1535 Op: Pipe, 1536 X: litStmt("a"), 1537 Y: litStmt("b"), 1538 }, 1539 Background: true, 1540 }, 1541 }, 1542 { 1543 Strs: []string{"foo#bar"}, 1544 common: litWord("foo#bar"), 1545 }, 1546 { 1547 Strs: []string{"{ echo } }; }"}, 1548 common: block(litStmt("echo", "}", "}")), 1549 }, 1550 { 1551 Strs: []string{"$({ echo; })"}, 1552 common: cmdSubst(stmt( 1553 block(litStmt("echo")), 1554 )), 1555 }, 1556 { 1557 Strs: []string{ 1558 "$( (echo foo bar))", 1559 "$( (echo foo bar) )", 1560 "`(echo foo bar)`", 1561 }, 1562 common: cmdSubst(stmt( 1563 subshell(litStmt("echo", "foo", "bar")), 1564 )), 1565 }, 1566 { 1567 Strs: []string{"$()"}, 1568 common: cmdSubst(), 1569 }, 1570 { 1571 Strs: []string{"()"}, 1572 mksh: subshell(), // not common, as dash/bash wrongly error 1573 }, 1574 { 1575 Strs: []string{ 1576 "$(\n\t(a)\n\tb\n)", 1577 "$( (a); b)", 1578 "`(a); b`", 1579 }, 1580 common: cmdSubst( 1581 stmt(subshell(litStmt("a"))), 1582 litStmt("b"), 1583 ), 1584 }, 1585 { 1586 Strs: []string{ 1587 `$(echo \')`, 1588 "`" + `echo \\'` + "`", 1589 }, 1590 common: cmdSubst(litStmt("echo", `\'`)), 1591 }, 1592 { 1593 Strs: []string{ 1594 `$(echo \\)`, 1595 "`" + `echo \\\\` + "`", 1596 }, 1597 common: cmdSubst(litStmt("echo", `\\`)), 1598 }, 1599 { 1600 Strs: []string{ 1601 `$(echo '\' 'a\b' "\\" "a\a")`, 1602 "`" + `echo '\' 'a\b' "\\\\" "a\a"` + "`", 1603 }, 1604 common: cmdSubst(stmt(call( 1605 litWord("echo"), 1606 word(sglQuoted(`\`)), 1607 word(sglQuoted(`a\b`)), 1608 word(dblQuoted(lit(`\\`))), 1609 word(dblQuoted(lit(`a\a`))), 1610 ))), 1611 }, 1612 { 1613 Strs: []string{ 1614 "$(echo $(x))", 1615 "`echo \\`x\\``", 1616 }, 1617 common: cmdSubst(stmt(call( 1618 litWord("echo"), 1619 word(cmdSubst(litStmt("x"))), 1620 ))), 1621 }, 1622 { 1623 Strs: []string{ 1624 "$($(foo bar))", 1625 "`\\`foo bar\\``", 1626 }, 1627 common: cmdSubst(stmt(call( 1628 word(cmdSubst(litStmt("foo", "bar"))), 1629 ))), 1630 }, 1631 { 1632 Strs: []string{"$( (a) | b)"}, 1633 common: cmdSubst( 1634 stmt(&BinaryCmd{ 1635 Op: Pipe, 1636 X: stmt(subshell(litStmt("a"))), 1637 Y: litStmt("b"), 1638 }), 1639 ), 1640 }, 1641 { 1642 Strs: []string{`"$( (foo))"`}, 1643 common: dblQuoted(cmdSubst(stmt( 1644 subshell(litStmt("foo")), 1645 ))), 1646 }, 1647 { 1648 Strs: []string{"$({ echo; })", "`{ echo; }`"}, 1649 common: cmdSubst(stmt( 1650 block(litStmt("echo")), 1651 )), 1652 }, 1653 { 1654 Strs: []string{`{foo}`}, 1655 common: litWord(`{foo}`), 1656 }, 1657 { 1658 Strs: []string{`{"foo"`}, 1659 common: word(lit("{"), dblQuoted(lit("foo"))), 1660 }, 1661 { 1662 Strs: []string{`foo"bar"`, "fo\\\no\"bar\""}, 1663 common: word(lit("foo"), dblQuoted(lit("bar"))), 1664 }, 1665 { 1666 Strs: []string{`!foo`}, 1667 common: litWord(`!foo`), 1668 }, 1669 { 1670 Strs: []string{"$(foo bar)", "`foo bar`"}, 1671 common: cmdSubst(litStmt("foo", "bar")), 1672 }, 1673 { 1674 Strs: []string{"$(foo | bar)", "`foo | bar`"}, 1675 common: cmdSubst( 1676 stmt(&BinaryCmd{ 1677 Op: Pipe, 1678 X: litStmt("foo"), 1679 Y: litStmt("bar"), 1680 }), 1681 ), 1682 }, 1683 { 1684 Strs: []string{"$(foo | >f)", "`foo | >f`"}, 1685 common: cmdSubst( 1686 stmt(&BinaryCmd{ 1687 Op: Pipe, 1688 X: litStmt("foo"), 1689 Y: &Stmt{Redirs: []*Redirect{{ 1690 Op: RdrOut, 1691 Word: litWord("f"), 1692 }}}, 1693 }), 1694 ), 1695 }, 1696 { 1697 Strs: []string{"$(foo $(b1 b2))"}, 1698 common: cmdSubst(stmt(call( 1699 litWord("foo"), 1700 word(cmdSubst(litStmt("b1", "b2"))), 1701 ))), 1702 }, 1703 { 1704 Strs: []string{`"$(foo "bar")"`}, 1705 common: dblQuoted(cmdSubst(stmt(call( 1706 litWord("foo"), 1707 word(dblQuoted(lit("bar"))), 1708 )))), 1709 }, 1710 { 1711 Strs: []string{"$(foo)", "`fo\\\no`"}, 1712 common: cmdSubst(litStmt("foo")), 1713 }, 1714 { 1715 Strs: []string{"foo $(bar)", "foo `bar`"}, 1716 common: call( 1717 litWord("foo"), 1718 word(cmdSubst(litStmt("bar"))), 1719 ), 1720 }, 1721 { 1722 Strs: []string{"$(foo 'bar')", "`foo 'bar'`"}, 1723 common: cmdSubst(stmt(call( 1724 litWord("foo"), 1725 word(sglQuoted("bar")), 1726 ))), 1727 }, 1728 { 1729 Strs: []string{`$(foo "bar")`, "`foo \"bar\"`"}, 1730 common: cmdSubst(stmt(call( 1731 litWord("foo"), 1732 word(dblQuoted(lit("bar"))), 1733 ))), 1734 }, 1735 { 1736 Strs: []string{`"$(foo "bar")"`, "\"`foo \"bar\"`\""}, 1737 common: dblQuoted(cmdSubst(stmt(call( 1738 litWord("foo"), 1739 word(dblQuoted(lit("bar"))), 1740 )))), 1741 }, 1742 { 1743 Strs: []string{"${ foo;}", "${\n\tfoo; }", "${\tfoo;}"}, 1744 mksh: &CmdSubst{ 1745 StmtList: litStmts("foo"), 1746 TempFile: true, 1747 }, 1748 }, 1749 { 1750 Strs: []string{"${\n\tfoo\n\tbar\n}", "${ foo; bar;}"}, 1751 mksh: &CmdSubst{ 1752 StmtList: litStmts("foo", "bar"), 1753 TempFile: true, 1754 }, 1755 }, 1756 { 1757 Strs: []string{"${|foo;}", "${| foo; }"}, 1758 mksh: &CmdSubst{ 1759 StmtList: litStmts("foo"), 1760 ReplyVar: true, 1761 }, 1762 }, 1763 { 1764 Strs: []string{"${|\n\tfoo\n\tbar\n}", "${|foo; bar;}"}, 1765 mksh: &CmdSubst{ 1766 StmtList: litStmts("foo", "bar"), 1767 ReplyVar: true, 1768 }, 1769 }, 1770 { 1771 Strs: []string{`"$foo"`}, 1772 common: dblQuoted(litParamExp("foo")), 1773 }, 1774 { 1775 Strs: []string{`"#foo"`}, 1776 common: dblQuoted(lit("#foo")), 1777 }, 1778 { 1779 Strs: []string{`$@a $*a $#a $$a $?a $!a $-a $0a $30a $_a`}, 1780 common: call( 1781 word(litParamExp("@"), lit("a")), 1782 word(litParamExp("*"), lit("a")), 1783 word(litParamExp("#"), lit("a")), 1784 word(litParamExp("$"), lit("a")), 1785 word(litParamExp("?"), lit("a")), 1786 word(litParamExp("!"), lit("a")), 1787 word(litParamExp("-"), lit("a")), 1788 word(litParamExp("0"), lit("a")), 1789 word(litParamExp("3"), lit("0a")), 1790 word(litParamExp("_a")), 1791 ), 1792 }, 1793 { 1794 Strs: []string{`$`, `$ #`}, 1795 common: litWord("$"), 1796 }, 1797 { 1798 Strs: []string{`${@} ${*} ${#} ${$} ${?} ${!} ${0} ${29} ${-}`}, 1799 common: call( 1800 word(&ParamExp{Param: lit("@")}), 1801 word(&ParamExp{Param: lit("*")}), 1802 word(&ParamExp{Param: lit("#")}), 1803 word(&ParamExp{Param: lit("$")}), 1804 word(&ParamExp{Param: lit("?")}), 1805 word(&ParamExp{Param: lit("!")}), 1806 word(&ParamExp{Param: lit("0")}), 1807 word(&ParamExp{Param: lit("29")}), 1808 word(&ParamExp{Param: lit("-")}), 1809 ), 1810 }, 1811 { 1812 Strs: []string{`${#$} ${#@} ${#*} ${##}`}, 1813 common: call( 1814 word(&ParamExp{Length: true, Param: lit("$")}), 1815 word(&ParamExp{Length: true, Param: lit("@")}), 1816 word(&ParamExp{Length: true, Param: lit("*")}), 1817 word(&ParamExp{Length: true, Param: lit("#")}), 1818 ), 1819 }, 1820 { 1821 Strs: []string{`${foo}`}, 1822 common: &ParamExp{Param: lit("foo")}, 1823 }, 1824 { 1825 Strs: []string{`${foo}"bar"`}, 1826 common: word( 1827 &ParamExp{Param: lit("foo")}, 1828 dblQuoted(lit("bar")), 1829 ), 1830 }, 1831 { 1832 Strs: []string{`$a/b $a-b $a:b $a}b $a]b $a.b $a,b $a*b $a_b $a2b`}, 1833 common: call( 1834 word(litParamExp("a"), lit("/b")), 1835 word(litParamExp("a"), lit("-b")), 1836 word(litParamExp("a"), lit(":b")), 1837 word(litParamExp("a"), lit("}b")), 1838 word(litParamExp("a"), lit("]b")), 1839 word(litParamExp("a"), lit(".b")), 1840 word(litParamExp("a"), lit(",b")), 1841 word(litParamExp("a"), lit("*b")), 1842 word(litParamExp("a_b")), 1843 word(litParamExp("a2b")), 1844 ), 1845 }, 1846 { 1847 Strs: []string{`$aàb $àb $,b`}, 1848 common: call( 1849 word(litParamExp("a"), lit("àb")), 1850 word(lit("$"), lit("àb")), 1851 word(lit("$"), lit(",b")), 1852 ), 1853 }, 1854 { 1855 Strs: []string{"$à", "$\\\nà"}, 1856 common: word(lit("$"), lit("à")), 1857 }, 1858 { 1859 Strs: []string{"$foobar", "$foo\\\nbar"}, 1860 common: call( 1861 word(litParamExp("foobar")), 1862 ), 1863 }, 1864 { 1865 Strs: []string{"$foo\\bar"}, 1866 common: call( 1867 word(litParamExp("foo"), lit("\\bar")), 1868 ), 1869 }, 1870 { 1871 Strs: []string{`echo -e "$foo\nbar"`}, 1872 common: call( 1873 litWord("echo"), litWord("-e"), 1874 word(dblQuoted( 1875 litParamExp("foo"), lit(`\nbar`), 1876 )), 1877 ), 1878 }, 1879 { 1880 Strs: []string{`${foo-bar}`}, 1881 common: &ParamExp{ 1882 Param: lit("foo"), 1883 Exp: &Expansion{ 1884 Op: SubstMinus, 1885 Word: litWord("bar"), 1886 }, 1887 }, 1888 }, 1889 { 1890 Strs: []string{`${foo+}"bar"`}, 1891 common: word( 1892 &ParamExp{ 1893 Param: lit("foo"), 1894 Exp: &Expansion{Op: SubstPlus}, 1895 }, 1896 dblQuoted(lit("bar")), 1897 ), 1898 }, 1899 { 1900 Strs: []string{`${foo:=<"bar"}`}, 1901 common: &ParamExp{ 1902 Param: lit("foo"), 1903 Exp: &Expansion{ 1904 Op: SubstColAssgn, 1905 Word: word(lit("<"), dblQuoted(lit("bar"))), 1906 }, 1907 }, 1908 }, 1909 { 1910 Strs: []string{ 1911 "${foo:=b${c}$(d)}", 1912 "${foo:=b${c}`d`}", 1913 }, 1914 common: &ParamExp{ 1915 Param: lit("foo"), 1916 Exp: &Expansion{ 1917 Op: SubstColAssgn, 1918 Word: word( 1919 lit("b"), 1920 &ParamExp{Param: lit("c")}, 1921 cmdSubst(litStmt("d")), 1922 ), 1923 }, 1924 }, 1925 }, 1926 { 1927 Strs: []string{`${foo?"${bar}"}`}, 1928 common: &ParamExp{ 1929 Param: lit("foo"), 1930 Exp: &Expansion{ 1931 Op: SubstQuest, 1932 Word: word(dblQuoted( 1933 &ParamExp{Param: lit("bar")}, 1934 )), 1935 }, 1936 }, 1937 }, 1938 { 1939 Strs: []string{`${foo:?bar1 bar2}`}, 1940 common: &ParamExp{ 1941 Param: lit("foo"), 1942 Exp: &Expansion{ 1943 Op: SubstColQuest, 1944 Word: litWord("bar1 bar2"), 1945 }, 1946 }, 1947 }, 1948 { 1949 Strs: []string{`${a:+b}${a:-b}${a=b}`}, 1950 common: word( 1951 &ParamExp{ 1952 Param: lit("a"), 1953 Exp: &Expansion{ 1954 Op: SubstColPlus, 1955 Word: litWord("b"), 1956 }, 1957 }, 1958 &ParamExp{ 1959 Param: lit("a"), 1960 Exp: &Expansion{ 1961 Op: SubstColMinus, 1962 Word: litWord("b"), 1963 }, 1964 }, 1965 &ParamExp{ 1966 Param: lit("a"), 1967 Exp: &Expansion{ 1968 Op: SubstAssgn, 1969 Word: litWord("b"), 1970 }, 1971 }, 1972 ), 1973 }, 1974 { 1975 Strs: []string{`${3:-'$x'}`}, 1976 common: &ParamExp{ 1977 Param: lit("3"), 1978 Exp: &Expansion{ 1979 Op: SubstColMinus, 1980 Word: word(sglQuoted("$x")), 1981 }, 1982 }, 1983 }, 1984 { 1985 Strs: []string{`${@:-$x}`}, 1986 common: &ParamExp{ 1987 Param: lit("@"), 1988 Exp: &Expansion{ 1989 Op: SubstColMinus, 1990 Word: word(litParamExp("x")), 1991 }, 1992 }, 1993 }, 1994 { 1995 Strs: []string{`${foo%bar}${foo%%bar*}`}, 1996 common: word( 1997 &ParamExp{ 1998 Param: lit("foo"), 1999 Exp: &Expansion{ 2000 Op: RemSmallSuffix, 2001 Word: litWord("bar"), 2002 }, 2003 }, 2004 &ParamExp{ 2005 Param: lit("foo"), 2006 Exp: &Expansion{ 2007 Op: RemLargeSuffix, 2008 Word: litWord("bar*"), 2009 }, 2010 }, 2011 ), 2012 }, 2013 { 2014 Strs: []string{`${3#bar}${-##bar*}`}, 2015 common: word( 2016 &ParamExp{ 2017 Param: lit("3"), 2018 Exp: &Expansion{ 2019 Op: RemSmallPrefix, 2020 Word: litWord("bar"), 2021 }, 2022 }, 2023 &ParamExp{ 2024 Param: lit("-"), 2025 Exp: &Expansion{ 2026 Op: RemLargePrefix, 2027 Word: litWord("bar*"), 2028 }, 2029 }, 2030 ), 2031 }, 2032 { 2033 Strs: []string{`${foo%?}`}, 2034 common: &ParamExp{ 2035 Param: lit("foo"), 2036 Exp: &Expansion{ 2037 Op: RemSmallSuffix, 2038 Word: litWord("?"), 2039 }, 2040 }, 2041 }, 2042 { 2043 Strs: []string{ 2044 `${foo[1]}`, 2045 `${foo[ 1 ]}`, 2046 }, 2047 bsmk: &ParamExp{ 2048 Param: lit("foo"), 2049 Index: litWord("1"), 2050 }, 2051 }, 2052 { 2053 Strs: []string{`${foo[-1]}`}, 2054 bsmk: &ParamExp{ 2055 Param: lit("foo"), 2056 Index: &UnaryArithm{ 2057 Op: Minus, 2058 X: litWord("1"), 2059 }, 2060 }, 2061 }, 2062 { 2063 Strs: []string{`${foo[@]}`}, 2064 bsmk: &ParamExp{ 2065 Param: lit("foo"), 2066 Index: litWord("@"), 2067 }, 2068 }, 2069 { 2070 Strs: []string{`${foo[*]-etc}`}, 2071 bsmk: &ParamExp{ 2072 Param: lit("foo"), 2073 Index: litWord("*"), 2074 Exp: &Expansion{ 2075 Op: SubstMinus, 2076 Word: litWord("etc"), 2077 }, 2078 }, 2079 }, 2080 { 2081 Strs: []string{`${foo[bar]}`}, 2082 bsmk: &ParamExp{ 2083 Param: lit("foo"), 2084 Index: litWord("bar"), 2085 }, 2086 }, 2087 { 2088 Strs: []string{`${foo[$bar]}`}, 2089 bsmk: &ParamExp{ 2090 Param: lit("foo"), 2091 Index: word(litParamExp("bar")), 2092 }, 2093 }, 2094 { 2095 Strs: []string{`${foo[${bar}]}`}, 2096 bsmk: &ParamExp{ 2097 Param: lit("foo"), 2098 Index: word(&ParamExp{Param: lit("bar")}), 2099 }, 2100 }, 2101 { 2102 Strs: []string{`${foo:1}`, `${foo: 1 }`}, 2103 bsmk: &ParamExp{ 2104 Param: lit("foo"), 2105 Slice: &Slice{Offset: litWord("1")}, 2106 }, 2107 }, 2108 { 2109 Strs: []string{`${foo:1:2}`, `${foo: 1 : 2 }`}, 2110 bsmk: &ParamExp{ 2111 Param: lit("foo"), 2112 Slice: &Slice{ 2113 Offset: litWord("1"), 2114 Length: litWord("2"), 2115 }, 2116 }, 2117 }, 2118 { 2119 Strs: []string{`${foo:a:b}`}, 2120 bsmk: &ParamExp{ 2121 Param: lit("foo"), 2122 Slice: &Slice{ 2123 Offset: litWord("a"), 2124 Length: litWord("b"), 2125 }, 2126 }, 2127 }, 2128 { 2129 Strs: []string{`${foo:1:-2}`}, 2130 bsmk: &ParamExp{ 2131 Param: lit("foo"), 2132 Slice: &Slice{ 2133 Offset: litWord("1"), 2134 Length: &UnaryArithm{Op: Minus, X: litWord("2")}, 2135 }, 2136 }, 2137 }, 2138 { 2139 Strs: []string{`${foo::+3}`}, 2140 bsmk: &ParamExp{ 2141 Param: lit("foo"), 2142 Slice: &Slice{ 2143 Length: &UnaryArithm{Op: Plus, X: litWord("3")}, 2144 }, 2145 }, 2146 }, 2147 { 2148 Strs: []string{`${foo: -1}`}, 2149 bsmk: &ParamExp{ 2150 Param: lit("foo"), 2151 Slice: &Slice{ 2152 Offset: &UnaryArithm{Op: Minus, X: litWord("1")}, 2153 }, 2154 }, 2155 }, 2156 { 2157 Strs: []string{`${foo: +2+3}`}, 2158 bsmk: &ParamExp{ 2159 Param: lit("foo"), 2160 Slice: &Slice{ 2161 Offset: &BinaryArithm{ 2162 Op: Add, 2163 X: &UnaryArithm{Op: Plus, X: litWord("2")}, 2164 Y: litWord("3"), 2165 }, 2166 }, 2167 }, 2168 }, 2169 { 2170 Strs: []string{`${foo:a?1:2:3}`}, 2171 bsmk: &ParamExp{ 2172 Param: lit("foo"), 2173 Slice: &Slice{ 2174 Offset: &BinaryArithm{ 2175 Op: Quest, 2176 X: litWord("a"), 2177 Y: &BinaryArithm{ 2178 Op: Colon, 2179 X: litWord("1"), 2180 Y: litWord("2"), 2181 }, 2182 }, 2183 Length: litWord("3"), 2184 }, 2185 }, 2186 }, 2187 { 2188 Strs: []string{`${foo/a/b}`}, 2189 bsmk: &ParamExp{ 2190 Param: lit("foo"), 2191 Repl: &Replace{Orig: litWord("a"), With: litWord("b")}, 2192 }, 2193 }, 2194 { 2195 Strs: []string{"${foo/ /\t}"}, 2196 bsmk: &ParamExp{ 2197 Param: lit("foo"), 2198 Repl: &Replace{Orig: litWord(" "), With: litWord("\t")}, 2199 }, 2200 }, 2201 { 2202 Strs: []string{`${foo/[/]-}`}, 2203 bsmk: &ParamExp{ 2204 Param: lit("foo"), 2205 Repl: &Replace{Orig: litWord("["), With: litWord("]-")}, 2206 }, 2207 }, 2208 { 2209 Strs: []string{`${foo/bar/b/a/r}`}, 2210 bsmk: &ParamExp{ 2211 Param: lit("foo"), 2212 Repl: &Replace{ 2213 Orig: litWord("bar"), 2214 With: litWord("b/a/r"), 2215 }, 2216 }, 2217 }, 2218 { 2219 Strs: []string{`${foo/$a/$'\''}`}, 2220 bsmk: &ParamExp{ 2221 Param: lit("foo"), 2222 Repl: &Replace{ 2223 Orig: word(litParamExp("a")), 2224 With: word(sglDQuoted(`\'`)), 2225 }, 2226 }, 2227 }, 2228 { 2229 Strs: []string{`${foo//b1/b2}`}, 2230 bsmk: &ParamExp{ 2231 Param: lit("foo"), 2232 Repl: &Replace{ 2233 All: true, 2234 Orig: litWord("b1"), 2235 With: litWord("b2"), 2236 }, 2237 }, 2238 }, 2239 { 2240 Strs: []string{`${foo///}`, `${foo//}`}, 2241 bsmk: &ParamExp{ 2242 Param: lit("foo"), 2243 Repl: &Replace{All: true}, 2244 }, 2245 }, 2246 { 2247 Strs: []string{`${foo/-//}`}, 2248 bsmk: &ParamExp{ 2249 Param: lit("foo"), 2250 Repl: &Replace{Orig: litWord("-"), With: litWord("/")}, 2251 }, 2252 }, 2253 { 2254 Strs: []string{`${foo//#/}`, `${foo//#}`}, 2255 bsmk: &ParamExp{ 2256 Param: lit("foo"), 2257 Repl: &Replace{All: true, Orig: litWord("#")}, 2258 }, 2259 }, 2260 { 2261 Strs: []string{`${foo//[42]/}`}, 2262 bsmk: &ParamExp{ 2263 Param: lit("foo"), 2264 Repl: &Replace{All: true, Orig: litWord("[42]")}, 2265 }, 2266 }, 2267 { 2268 Strs: []string{`${a^b} ${a^^b} ${a,b} ${a,,b}`}, 2269 bash: call( 2270 word(&ParamExp{Param: lit("a"), 2271 Exp: &Expansion{ 2272 Op: UpperFirst, 2273 Word: litWord("b"), 2274 }, 2275 }), 2276 word(&ParamExp{Param: lit("a"), 2277 Exp: &Expansion{ 2278 Op: UpperAll, 2279 Word: litWord("b"), 2280 }, 2281 }), 2282 word(&ParamExp{Param: lit("a"), 2283 Exp: &Expansion{ 2284 Op: LowerFirst, 2285 Word: litWord("b"), 2286 }, 2287 }), 2288 word(&ParamExp{Param: lit("a"), 2289 Exp: &Expansion{ 2290 Op: LowerAll, 2291 Word: litWord("b"), 2292 }, 2293 }), 2294 ), 2295 }, 2296 { 2297 Strs: []string{`${a@E} ${b@a} ${@@Q}`}, 2298 bsmk: call( 2299 word(&ParamExp{Param: lit("a"), 2300 Exp: &Expansion{ 2301 Op: OtherParamOps, 2302 Word: litWord("E"), 2303 }, 2304 }), 2305 word(&ParamExp{Param: lit("b"), 2306 Exp: &Expansion{ 2307 Op: OtherParamOps, 2308 Word: litWord("a"), 2309 }, 2310 }), 2311 word(&ParamExp{Param: lit("@"), 2312 Exp: &Expansion{ 2313 Op: OtherParamOps, 2314 Word: litWord("Q"), 2315 }, 2316 }), 2317 ), 2318 }, 2319 { 2320 Strs: []string{`${#foo}`}, 2321 common: &ParamExp{ 2322 Length: true, 2323 Param: lit("foo"), 2324 }, 2325 }, 2326 { 2327 Strs: []string{`${%foo}`}, 2328 mksh: &ParamExp{ 2329 Width: true, 2330 Param: lit("foo"), 2331 }, 2332 }, 2333 { 2334 Strs: []string{`${!foo} ${!bar[@]}`}, 2335 bsmk: call( 2336 word(&ParamExp{ 2337 Excl: true, 2338 Param: lit("foo"), 2339 }), 2340 word(&ParamExp{ 2341 Excl: true, 2342 Param: lit("bar"), 2343 Index: litWord("@"), 2344 }), 2345 ), 2346 }, 2347 { 2348 Strs: []string{`${!foo*} ${!bar@}`}, 2349 bsmk: call( 2350 word(&ParamExp{ 2351 Excl: true, 2352 Param: lit("foo"), 2353 Names: NamesPrefix, 2354 }), 2355 word(&ParamExp{ 2356 Excl: true, 2357 Param: lit("bar"), 2358 Names: NamesPrefixWords, 2359 }), 2360 ), 2361 }, 2362 { 2363 Strs: []string{`${#?}`}, 2364 common: call( 2365 word(&ParamExp{Length: true, Param: lit("?")}), 2366 ), 2367 }, 2368 { 2369 Strs: []string{`"${foo}"`}, 2370 common: dblQuoted(&ParamExp{Param: lit("foo")}), 2371 }, 2372 { 2373 Strs: []string{`"(foo)"`}, 2374 common: dblQuoted(lit("(foo)")), 2375 }, 2376 { 2377 Strs: []string{`"${foo}>"`}, 2378 common: dblQuoted( 2379 &ParamExp{Param: lit("foo")}, 2380 lit(">"), 2381 ), 2382 }, 2383 { 2384 Strs: []string{`"$(foo)"`, "\"`foo`\""}, 2385 common: dblQuoted(cmdSubst(litStmt("foo"))), 2386 }, 2387 { 2388 Strs: []string{ 2389 `"$(foo bar)"`, 2390 `"$(foo bar)"`, 2391 "\"`foo bar`\"", 2392 "\"`foo bar`\"", 2393 }, 2394 common: dblQuoted(cmdSubst(litStmt("foo", "bar"))), 2395 }, 2396 { 2397 Strs: []string{`'${foo}'`}, 2398 common: sglQuoted("${foo}"), 2399 }, 2400 { 2401 Strs: []string{"$((1))"}, 2402 common: arithmExp(litWord("1")), 2403 }, 2404 { 2405 Strs: []string{"$((1 + 3))", "$((1+3))"}, 2406 common: arithmExp(&BinaryArithm{ 2407 Op: Add, 2408 X: litWord("1"), 2409 Y: litWord("3"), 2410 }), 2411 }, 2412 { 2413 Strs: []string{`"$((foo))"`}, 2414 common: dblQuoted(arithmExp( 2415 litWord("foo"), 2416 )), 2417 }, 2418 { 2419 Strs: []string{`$((a)) b`}, 2420 common: call( 2421 word(arithmExp(litWord("a"))), 2422 litWord("b"), 2423 ), 2424 }, 2425 { 2426 Strs: []string{`$((arr[0]++))`}, 2427 bsmk: arithmExp(&UnaryArithm{ 2428 Op: Inc, Post: true, 2429 X: word(&ParamExp{ 2430 Short: true, 2431 Param: lit("arr"), 2432 Index: litWord("0"), 2433 }), 2434 }), 2435 }, 2436 { 2437 Strs: []string{`$((++arr[0]))`}, 2438 bsmk: arithmExp(&UnaryArithm{ 2439 Op: Inc, 2440 X: word(&ParamExp{ 2441 Short: true, 2442 Param: lit("arr"), 2443 Index: litWord("0"), 2444 }), 2445 }), 2446 }, 2447 { 2448 Strs: []string{`$((${a:-1}))`}, 2449 bsmk: arithmExp(word(&ParamExp{ 2450 Param: lit("a"), 2451 Exp: &Expansion{ 2452 Op: SubstColMinus, 2453 Word: litWord("1"), 2454 }, 2455 })), 2456 }, 2457 { 2458 Strs: []string{"$((5 * 2 - 1))", "$((5*2-1))"}, 2459 common: arithmExp(&BinaryArithm{ 2460 Op: Sub, 2461 X: &BinaryArithm{ 2462 Op: Mul, 2463 X: litWord("5"), 2464 Y: litWord("2"), 2465 }, 2466 Y: litWord("1"), 2467 }), 2468 }, 2469 { 2470 Strs: []string{"$((i | 13))"}, 2471 common: arithmExp(&BinaryArithm{ 2472 Op: Or, 2473 X: litWord("i"), 2474 Y: litWord("13"), 2475 }), 2476 }, 2477 { 2478 Strs: []string{ 2479 "$(((a) + ((b))))", 2480 "$((\n(a) + \n(\n(b)\n)\n))", 2481 }, 2482 common: arithmExp(&BinaryArithm{ 2483 Op: Add, 2484 X: parenArit(litWord("a")), 2485 Y: parenArit(parenArit(litWord("b"))), 2486 }), 2487 }, 2488 { 2489 Strs: []string{ 2490 "$((3 % 7))", 2491 "$((3\n% 7))", 2492 "$((3\\\n % 7))", 2493 }, 2494 common: arithmExp(&BinaryArithm{ 2495 Op: Rem, 2496 X: litWord("3"), 2497 Y: litWord("7"), 2498 }), 2499 }, 2500 { 2501 Strs: []string{`"$((1 / 3))"`}, 2502 common: dblQuoted(arithmExp(&BinaryArithm{ 2503 Op: Quo, 2504 X: litWord("1"), 2505 Y: litWord("3"), 2506 })), 2507 }, 2508 { 2509 Strs: []string{"$((2 ** 10))"}, 2510 common: arithmExp(&BinaryArithm{ 2511 Op: Pow, 2512 X: litWord("2"), 2513 Y: litWord("10"), 2514 }), 2515 }, 2516 { 2517 Strs: []string{`$(((1) ^ 3))`}, 2518 common: arithmExp(&BinaryArithm{ 2519 Op: Xor, 2520 X: parenArit(litWord("1")), 2521 Y: litWord("3"), 2522 }), 2523 }, 2524 { 2525 Strs: []string{`$((1 >> (3 << 2)))`}, 2526 common: arithmExp(&BinaryArithm{ 2527 Op: Shr, 2528 X: litWord("1"), 2529 Y: parenArit(&BinaryArithm{ 2530 Op: Shl, 2531 X: litWord("3"), 2532 Y: litWord("2"), 2533 }), 2534 }), 2535 }, 2536 { 2537 Strs: []string{`$((-(1)))`}, 2538 common: arithmExp(&UnaryArithm{ 2539 Op: Minus, 2540 X: parenArit(litWord("1")), 2541 }), 2542 }, 2543 { 2544 Strs: []string{`$((i++))`}, 2545 common: arithmExp(&UnaryArithm{ 2546 Op: Inc, 2547 Post: true, 2548 X: litWord("i"), 2549 }), 2550 }, 2551 { 2552 Strs: []string{`$((--i))`}, 2553 common: arithmExp(&UnaryArithm{Op: Dec, X: litWord("i")}), 2554 }, 2555 { 2556 Strs: []string{`$((!i))`}, 2557 common: arithmExp(&UnaryArithm{Op: Not, X: litWord("i")}), 2558 }, 2559 { 2560 Strs: []string{`$((-!+i))`}, 2561 common: arithmExp(&UnaryArithm{ 2562 Op: Minus, 2563 X: &UnaryArithm{ 2564 Op: Not, 2565 X: &UnaryArithm{Op: Plus, X: litWord("i")}, 2566 }, 2567 }), 2568 }, 2569 { 2570 Strs: []string{`$((!!i))`}, 2571 common: arithmExp(&UnaryArithm{ 2572 Op: Not, 2573 X: &UnaryArithm{Op: Not, X: litWord("i")}, 2574 }), 2575 }, 2576 { 2577 Strs: []string{`$((1 < 3))`}, 2578 common: arithmExp(&BinaryArithm{ 2579 Op: Lss, 2580 X: litWord("1"), 2581 Y: litWord("3"), 2582 }), 2583 }, 2584 { 2585 Strs: []string{`$((i = 2))`, `$((i=2))`}, 2586 common: arithmExp(&BinaryArithm{ 2587 Op: Assgn, 2588 X: litWord("i"), 2589 Y: litWord("2"), 2590 }), 2591 }, 2592 { 2593 Strs: []string{`((a[i] = 4))`, `((a[i]=4))`}, 2594 bsmk: arithmCmd(&BinaryArithm{ 2595 Op: Assgn, 2596 X: word(&ParamExp{ 2597 Short: true, 2598 Param: lit("a"), 2599 Index: litWord("i"), 2600 }), 2601 Y: litWord("4"), 2602 }), 2603 }, 2604 { 2605 Strs: []string{"$((a += 2, b -= 3))"}, 2606 common: arithmExp(&BinaryArithm{ 2607 Op: Comma, 2608 X: &BinaryArithm{ 2609 Op: AddAssgn, 2610 X: litWord("a"), 2611 Y: litWord("2"), 2612 }, 2613 Y: &BinaryArithm{ 2614 Op: SubAssgn, 2615 X: litWord("b"), 2616 Y: litWord("3"), 2617 }, 2618 }), 2619 }, 2620 { 2621 Strs: []string{"$((a >>= 2, b <<= 3))"}, 2622 common: arithmExp(&BinaryArithm{ 2623 Op: Comma, 2624 X: &BinaryArithm{ 2625 Op: ShrAssgn, 2626 X: litWord("a"), 2627 Y: litWord("2"), 2628 }, 2629 Y: &BinaryArithm{ 2630 Op: ShlAssgn, 2631 X: litWord("b"), 2632 Y: litWord("3"), 2633 }, 2634 }), 2635 }, 2636 { 2637 Strs: []string{"$((a == b && c > d))"}, 2638 common: arithmExp(&BinaryArithm{ 2639 Op: AndArit, 2640 X: &BinaryArithm{ 2641 Op: Eql, 2642 X: litWord("a"), 2643 Y: litWord("b"), 2644 }, 2645 Y: &BinaryArithm{ 2646 Op: Gtr, 2647 X: litWord("c"), 2648 Y: litWord("d"), 2649 }, 2650 }), 2651 }, 2652 { 2653 Strs: []string{"$((a != b))"}, 2654 common: arithmExp(&BinaryArithm{ 2655 Op: Neq, 2656 X: litWord("a"), 2657 Y: litWord("b"), 2658 }), 2659 }, 2660 { 2661 Strs: []string{"$((a &= b))"}, 2662 common: arithmExp(&BinaryArithm{ 2663 Op: AndAssgn, 2664 X: litWord("a"), 2665 Y: litWord("b"), 2666 }), 2667 }, 2668 { 2669 Strs: []string{"$((a |= b))"}, 2670 common: arithmExp(&BinaryArithm{ 2671 Op: OrAssgn, 2672 X: litWord("a"), 2673 Y: litWord("b"), 2674 }), 2675 }, 2676 { 2677 Strs: []string{"$((a %= b))"}, 2678 common: arithmExp(&BinaryArithm{ 2679 Op: RemAssgn, 2680 X: litWord("a"), 2681 Y: litWord("b"), 2682 }), 2683 }, 2684 { 2685 Strs: []string{"$((a /= b))", "$((a/=b))"}, 2686 common: arithmExp(&BinaryArithm{ 2687 Op: QuoAssgn, 2688 X: litWord("a"), 2689 Y: litWord("b"), 2690 }), 2691 }, 2692 { 2693 Strs: []string{"$((a ^= b))"}, 2694 common: arithmExp(&BinaryArithm{ 2695 Op: XorAssgn, 2696 X: litWord("a"), 2697 Y: litWord("b"), 2698 }), 2699 }, 2700 { 2701 Strs: []string{"$((i *= 3))"}, 2702 common: arithmExp(&BinaryArithm{ 2703 Op: MulAssgn, 2704 X: litWord("i"), 2705 Y: litWord("3"), 2706 }), 2707 }, 2708 { 2709 Strs: []string{"$((2 >= 10))"}, 2710 common: arithmExp(&BinaryArithm{ 2711 Op: Geq, 2712 X: litWord("2"), 2713 Y: litWord("10"), 2714 }), 2715 }, 2716 { 2717 Strs: []string{"$((foo ? b1 : b2))"}, 2718 common: arithmExp(&BinaryArithm{ 2719 Op: Quest, 2720 X: litWord("foo"), 2721 Y: &BinaryArithm{ 2722 Op: Colon, 2723 X: litWord("b1"), 2724 Y: litWord("b2"), 2725 }, 2726 }), 2727 }, 2728 { 2729 Strs: []string{`$((a <= (1 || 2)))`}, 2730 common: arithmExp(&BinaryArithm{ 2731 Op: Leq, 2732 X: litWord("a"), 2733 Y: parenArit(&BinaryArithm{ 2734 Op: OrArit, 2735 X: litWord("1"), 2736 Y: litWord("2"), 2737 }), 2738 }), 2739 }, 2740 { 2741 Strs: []string{"foo$", "foo$\n"}, 2742 common: word(lit("foo"), lit("$")), 2743 }, 2744 { 2745 Strs: []string{"foo$", "foo$\\\n"}, 2746 common: word(lit("foo"), lit("$")), 2747 }, 2748 { 2749 Strs: []string{`$''`}, 2750 bsmk: sglDQuoted(""), 2751 posix: word(lit("$"), sglQuoted("")), 2752 }, 2753 { 2754 Strs: []string{`$""`}, 2755 bsmk: dblDQuoted(), 2756 posix: word(lit("$"), dblQuoted()), 2757 }, 2758 { 2759 Strs: []string{`$'foo'`}, 2760 bsmk: sglDQuoted("foo"), 2761 posix: word(lit("$"), sglQuoted("foo")), 2762 }, 2763 { 2764 Strs: []string{`$'f+oo${'`}, 2765 bsmk: sglDQuoted("f+oo${"), 2766 }, 2767 { 2768 Strs: []string{"$'foo bar`'"}, 2769 bsmk: sglDQuoted("foo bar`"), 2770 }, 2771 { 2772 Strs: []string{"$'a ${b} c'"}, 2773 bsmk: sglDQuoted("a ${b} c"), 2774 }, 2775 { 2776 Strs: []string{`$"a ${b} c"`}, 2777 bsmk: dblDQuoted( 2778 lit("a "), 2779 &ParamExp{Param: lit("b")}, 2780 lit(" c"), 2781 ), 2782 }, 2783 { 2784 Strs: []string{`"a $b c"`}, 2785 common: dblQuoted(lit("a "), litParamExp("b"), lit(" c")), 2786 }, 2787 { 2788 Strs: []string{`$"a $b c"`}, 2789 bsmk: dblDQuoted( 2790 lit("a "), 2791 litParamExp("b"), 2792 lit(" c"), 2793 ), 2794 }, 2795 { 2796 Strs: []string{"$'f\\'oo\n'"}, 2797 bsmk: sglDQuoted("f\\'oo\n"), 2798 }, 2799 { 2800 Strs: []string{`$"foo"`}, 2801 bsmk: dblDQuoted(lit("foo")), 2802 posix: word(lit("$"), dblQuoted(lit("foo"))), 2803 }, 2804 { 2805 Strs: []string{`$"foo$"`}, 2806 bsmk: dblDQuoted(lit("foo"), lit("$")), 2807 }, 2808 { 2809 Strs: []string{`$"foo bar"`}, 2810 bsmk: dblDQuoted(lit("foo bar")), 2811 }, 2812 { 2813 Strs: []string{`$'f\'oo'`}, 2814 bsmk: sglDQuoted(`f\'oo`), 2815 }, 2816 { 2817 Strs: []string{`$"f\"oo"`}, 2818 bsmk: dblDQuoted(lit(`f\"oo`)), 2819 }, 2820 { 2821 Strs: []string{`"foo$"`}, 2822 common: dblQuoted(lit("foo"), lit("$")), 2823 }, 2824 { 2825 Strs: []string{`"foo$$"`}, 2826 common: dblQuoted(lit("foo"), litParamExp("$")), 2827 }, 2828 { 2829 Strs: []string{`"a $\"b\" c"`}, 2830 common: dblQuoted(lit(`a `), lit(`$`), lit(`\"b\" c`)), 2831 }, 2832 { 2833 Strs: []string{"$(foo$)", "`foo$`"}, 2834 common: cmdSubst( 2835 stmt(call(word(lit("foo"), lit("$")))), 2836 ), 2837 }, 2838 { 2839 Strs: []string{"foo$bar"}, 2840 common: word(lit("foo"), litParamExp("bar")), 2841 }, 2842 { 2843 Strs: []string{"foo$(bar)"}, 2844 common: word(lit("foo"), cmdSubst(litStmt("bar"))), 2845 }, 2846 { 2847 Strs: []string{"foo${bar}"}, 2848 common: word(lit("foo"), &ParamExp{Param: lit("bar")}), 2849 }, 2850 { 2851 Strs: []string{"'foo${bar'"}, 2852 common: sglQuoted("foo${bar"), 2853 }, 2854 { 2855 Strs: []string{"(foo)\nbar", "(foo); bar"}, 2856 common: []Command{ 2857 subshell(litStmt("foo")), 2858 litCall("bar"), 2859 }, 2860 }, 2861 { 2862 Strs: []string{"foo\n(bar)", "foo; (bar)"}, 2863 common: []Command{ 2864 litCall("foo"), 2865 subshell(litStmt("bar")), 2866 }, 2867 }, 2868 { 2869 Strs: []string{"foo\n(bar)", "foo; (bar)"}, 2870 common: []Command{ 2871 litCall("foo"), 2872 subshell(litStmt("bar")), 2873 }, 2874 }, 2875 { 2876 Strs: []string{ 2877 "case $i in 1) foo ;; 2 | 3*) bar ;; esac", 2878 "case $i in 1) foo;; 2 | 3*) bar; esac", 2879 "case $i in (1) foo;; 2 | 3*) bar;; esac", 2880 "case $i\nin\n#etc\n1)\nfoo\n;;\n2 | 3*)\nbar\n;;\nesac", 2881 }, 2882 common: &CaseClause{ 2883 Word: word(litParamExp("i")), 2884 Items: []*CaseItem{ 2885 { 2886 Op: Break, 2887 Patterns: litWords("1"), 2888 StmtList: litStmts("foo"), 2889 }, 2890 { 2891 Op: Break, 2892 Patterns: litWords("2", "3*"), 2893 StmtList: litStmts("bar"), 2894 }, 2895 }, 2896 }, 2897 }, 2898 { 2899 Strs: []string{"case i in 1) a ;& 2) ;; esac"}, 2900 bsmk: &CaseClause{ 2901 Word: litWord("i"), 2902 Items: []*CaseItem{ 2903 { 2904 Op: Fallthrough, 2905 Patterns: litWords("1"), 2906 StmtList: litStmts("a"), 2907 }, 2908 {Op: Break, Patterns: litWords("2")}, 2909 }, 2910 }, 2911 }, 2912 { 2913 Strs: []string{ 2914 "case i in 1) a ;; esac", 2915 "case i { 1) a ;; }", 2916 "case i {\n1) a ;;\n}", 2917 }, 2918 mksh: &CaseClause{ 2919 Word: litWord("i"), 2920 Items: []*CaseItem{{ 2921 Op: Break, 2922 Patterns: litWords("1"), 2923 StmtList: litStmts("a"), 2924 }}, 2925 }, 2926 }, 2927 { 2928 Strs: []string{"case i in 1) a ;;& 2) b ;; esac"}, 2929 bash: &CaseClause{ 2930 Word: litWord("i"), 2931 Items: []*CaseItem{ 2932 { 2933 Op: Resume, 2934 Patterns: litWords("1"), 2935 StmtList: litStmts("a"), 2936 }, 2937 { 2938 Op: Break, 2939 Patterns: litWords("2"), 2940 StmtList: litStmts("b"), 2941 }, 2942 }, 2943 }, 2944 }, 2945 { 2946 Strs: []string{"case i in 1) a ;| 2) b ;; esac"}, 2947 mksh: &CaseClause{ 2948 Word: litWord("i"), 2949 Items: []*CaseItem{ 2950 { 2951 Op: ResumeKorn, 2952 Patterns: litWords("1"), 2953 StmtList: litStmts("a"), 2954 }, 2955 { 2956 Op: Break, 2957 Patterns: litWords("2"), 2958 StmtList: litStmts("b"), 2959 }, 2960 }, 2961 }, 2962 }, 2963 { 2964 Strs: []string{"case $i in 1) cat <<EOF ;;\nfoo\nEOF\nesac"}, 2965 common: &CaseClause{ 2966 Word: word(litParamExp("i")), 2967 Items: []*CaseItem{{ 2968 Op: Break, 2969 Patterns: litWords("1"), 2970 StmtList: stmtList(&Stmt{ 2971 Cmd: litCall("cat"), 2972 Redirs: []*Redirect{{ 2973 Op: Hdoc, 2974 Word: litWord("EOF"), 2975 Hdoc: litWord("foo\n"), 2976 }}, 2977 }), 2978 }}, 2979 }, 2980 }, 2981 { 2982 Strs: []string{"foo | while read a; do b; done"}, 2983 common: &BinaryCmd{ 2984 Op: Pipe, 2985 X: litStmt("foo"), 2986 Y: stmt(&WhileClause{ 2987 Cond: stmtList( 2988 litStmt("read", "a"), 2989 ), 2990 Do: litStmts("b"), 2991 }), 2992 }, 2993 }, 2994 { 2995 Strs: []string{"while read l; do foo || bar; done"}, 2996 common: &WhileClause{ 2997 Cond: stmtList(litStmt("read", "l")), 2998 Do: stmts(&BinaryCmd{ 2999 Op: OrStmt, 3000 X: litStmt("foo"), 3001 Y: litStmt("bar"), 3002 }), 3003 }, 3004 }, 3005 { 3006 Strs: []string{"echo if while"}, 3007 common: litCall("echo", "if", "while"), 3008 }, 3009 { 3010 Strs: []string{"${foo}if"}, 3011 common: word(&ParamExp{Param: lit("foo")}, lit("if")), 3012 }, 3013 { 3014 Strs: []string{"$if'|'"}, 3015 common: word(litParamExp("if"), sglQuoted("|")), 3016 }, 3017 { 3018 Strs: []string{"if a; then b=; fi", "if a; then b=\nfi"}, 3019 common: &IfClause{ 3020 Cond: litStmts("a"), 3021 Then: stmtList(stmt(&CallExpr{ 3022 Assigns: []*Assign{ 3023 {Name: lit("b")}, 3024 }, 3025 })), 3026 }, 3027 }, 3028 { 3029 Strs: []string{"if a; then >f; fi", "if a; then >f\nfi"}, 3030 common: &IfClause{ 3031 Cond: litStmts("a"), 3032 Then: stmtList(&Stmt{ 3033 Redirs: []*Redirect{ 3034 {Op: RdrOut, Word: litWord("f")}, 3035 }, 3036 }), 3037 }, 3038 }, 3039 { 3040 Strs: []string{"if a; then (a); fi", "if a; then (a) fi"}, 3041 common: &IfClause{ 3042 Cond: litStmts("a"), 3043 Then: stmts(subshell(litStmt("a"))), 3044 }, 3045 }, 3046 { 3047 Strs: []string{"a=b\nc=d", "a=b; c=d"}, 3048 common: []Command{ 3049 &CallExpr{Assigns: []*Assign{ 3050 {Name: lit("a"), Value: litWord("b")}, 3051 }}, 3052 &CallExpr{Assigns: []*Assign{ 3053 {Name: lit("c"), Value: litWord("d")}, 3054 }}, 3055 }, 3056 }, 3057 { 3058 Strs: []string{"foo && write | read"}, 3059 common: &BinaryCmd{ 3060 Op: AndStmt, 3061 X: litStmt("foo"), 3062 Y: stmt(&BinaryCmd{ 3063 Op: Pipe, 3064 X: litStmt("write"), 3065 Y: litStmt("read"), 3066 }), 3067 }, 3068 }, 3069 { 3070 Strs: []string{"write | read && bar"}, 3071 common: &BinaryCmd{ 3072 Op: AndStmt, 3073 X: stmt(&BinaryCmd{ 3074 Op: Pipe, 3075 X: litStmt("write"), 3076 Y: litStmt("read"), 3077 }), 3078 Y: litStmt("bar"), 3079 }, 3080 }, 3081 { 3082 Strs: []string{"foo >f | bar"}, 3083 common: &BinaryCmd{ 3084 Op: Pipe, 3085 X: &Stmt{ 3086 Cmd: litCall("foo"), 3087 Redirs: []*Redirect{ 3088 {Op: RdrOut, Word: litWord("f")}, 3089 }, 3090 }, 3091 Y: litStmt("bar"), 3092 }, 3093 }, 3094 { 3095 Strs: []string{"(foo) >f | bar"}, 3096 common: &BinaryCmd{ 3097 Op: Pipe, 3098 X: &Stmt{ 3099 Cmd: subshell(litStmt("foo")), 3100 Redirs: []*Redirect{ 3101 {Op: RdrOut, Word: litWord("f")}, 3102 }, 3103 }, 3104 Y: litStmt("bar"), 3105 }, 3106 }, 3107 { 3108 Strs: []string{"foo | >f"}, 3109 common: &BinaryCmd{ 3110 Op: Pipe, 3111 X: litStmt("foo"), 3112 Y: &Stmt{Redirs: []*Redirect{ 3113 {Op: RdrOut, Word: litWord("f")}, 3114 }}, 3115 }, 3116 }, 3117 { 3118 Strs: []string{"[[ a ]]"}, 3119 bsmk: &TestClause{X: litWord("a")}, 3120 posix: litStmt("[[", "a", "]]"), 3121 }, 3122 { 3123 Strs: []string{"[[ a ]]\nb"}, 3124 bsmk: stmts( 3125 &TestClause{X: litWord("a")}, 3126 litCall("b"), 3127 ), 3128 }, 3129 { 3130 Strs: []string{"[[ a > b ]]"}, 3131 bsmk: &TestClause{X: &BinaryTest{ 3132 Op: TsAfter, 3133 X: litWord("a"), 3134 Y: litWord("b"), 3135 }}, 3136 }, 3137 { 3138 Strs: []string{"[[ 1 -nt 2 ]]"}, 3139 bsmk: &TestClause{X: &BinaryTest{ 3140 Op: TsNewer, 3141 X: litWord("1"), 3142 Y: litWord("2"), 3143 }}, 3144 }, 3145 { 3146 Strs: []string{"[[ 1 -eq 2 ]]"}, 3147 bsmk: &TestClause{X: &BinaryTest{ 3148 Op: TsEql, 3149 X: litWord("1"), 3150 Y: litWord("2"), 3151 }}, 3152 }, 3153 { 3154 Strs: []string{ 3155 "[[ -R a ]]", 3156 "[[\n-R a\n]]", 3157 }, 3158 bash: &TestClause{X: &UnaryTest{ 3159 Op: TsRefVar, 3160 X: litWord("a"), 3161 }}, 3162 }, 3163 { 3164 Strs: []string{"[[ a =~ b ]]", "[[ a =~ b ]];"}, 3165 bash: &TestClause{X: &BinaryTest{ 3166 Op: TsReMatch, 3167 X: litWord("a"), 3168 Y: litWord("b"), 3169 }}, 3170 }, 3171 { 3172 Strs: []string{`[[ a =~ " foo "$bar ]]`}, 3173 bash: &TestClause{X: &BinaryTest{ 3174 Op: TsReMatch, 3175 X: litWord("a"), 3176 Y: word( 3177 dblQuoted(lit(" foo ")), 3178 litParamExp("bar"), 3179 ), 3180 }}, 3181 }, 3182 { 3183 Strs: []string{`[[ a =~ foo"bar" ]]`}, 3184 bash: &TestClause{X: &BinaryTest{ 3185 Op: TsReMatch, 3186 X: litWord("a"), 3187 Y: word( 3188 lit("foo"), 3189 dblQuoted(lit("bar")), 3190 ), 3191 }}, 3192 }, 3193 { 3194 Strs: []string{`[[ a =~ [ab](c |d) ]]`}, 3195 bash: &TestClause{X: &BinaryTest{ 3196 Op: TsReMatch, 3197 X: litWord("a"), 3198 Y: litWord("[ab](c |d)"), 3199 }}, 3200 }, 3201 { 3202 Strs: []string{`[[ a =~ ( ]]) ]]`}, 3203 bash: &TestClause{X: &BinaryTest{ 3204 Op: TsReMatch, 3205 X: litWord("a"), 3206 Y: litWord("( ]])"), 3207 }}, 3208 }, 3209 { 3210 Strs: []string{`[[ a =~ ($foo) ]]`}, 3211 bash: &TestClause{X: &BinaryTest{ 3212 Op: TsReMatch, 3213 X: litWord("a"), 3214 Y: word(lit("("), litParamExp("foo"), lit(")")), 3215 }}, 3216 }, 3217 { 3218 Strs: []string{`[[ a =~ b\ c|d ]]`}, 3219 bash: &TestClause{X: &BinaryTest{ 3220 Op: TsReMatch, 3221 X: litWord("a"), 3222 Y: litWord(`b\ c|d`), 3223 }}, 3224 }, 3225 { 3226 Strs: []string{`[[ a == -n ]]`}, 3227 bsmk: &TestClause{X: &BinaryTest{ 3228 Op: TsMatch, 3229 X: litWord("a"), 3230 Y: litWord("-n"), 3231 }}, 3232 }, 3233 { 3234 Strs: []string{`[[ a =~ -n ]]`}, 3235 bash: &TestClause{X: &BinaryTest{ 3236 Op: TsReMatch, 3237 X: litWord("a"), 3238 Y: litWord("-n"), 3239 }}, 3240 }, 3241 { 3242 Strs: []string{"[[ a =~ b$ || c =~ d$ ]]"}, 3243 bash: &TestClause{X: &BinaryTest{ 3244 Op: OrTest, 3245 X: &BinaryTest{ 3246 Op: TsReMatch, 3247 X: litWord("a"), 3248 Y: word(lit("b"), lit("$")), 3249 }, 3250 Y: &BinaryTest{ 3251 Op: TsReMatch, 3252 X: litWord("c"), 3253 Y: word(lit("d"), lit("$")), 3254 }, 3255 }}, 3256 }, 3257 { 3258 Strs: []string{"[[ -n $a ]]"}, 3259 bsmk: &TestClause{ 3260 X: &UnaryTest{Op: TsNempStr, X: word(litParamExp("a"))}, 3261 }, 3262 }, 3263 { 3264 Strs: []string{"[[ ! $a < 'b' ]]"}, 3265 bsmk: &TestClause{X: &UnaryTest{ 3266 Op: TsNot, 3267 X: &BinaryTest{ 3268 Op: TsBefore, 3269 X: word(litParamExp("a")), 3270 Y: word(sglQuoted("b")), 3271 }, 3272 }}, 3273 }, 3274 { 3275 Strs: []string{ 3276 "[[ ! -e $a ]]", 3277 "[[ ! -a $a ]]", 3278 "[[\n!\n-a $a\n]]", 3279 }, 3280 bsmk: &TestClause{X: &UnaryTest{ 3281 Op: TsNot, 3282 X: &UnaryTest{Op: TsExists, X: word(litParamExp("a"))}, 3283 }}, 3284 }, 3285 { 3286 Strs: []string{ 3287 "[[ a && b ]]", 3288 "[[\na &&\nb ]]", 3289 "[[\n\na &&\n\nb ]]", 3290 }, 3291 bsmk: &TestClause{X: &BinaryTest{ 3292 Op: AndTest, 3293 X: litWord("a"), 3294 Y: litWord("b"), 3295 }}, 3296 }, 3297 { 3298 Strs: []string{"[[ (a && b) ]]"}, 3299 bsmk: &TestClause{X: parenTest(&BinaryTest{ 3300 Op: AndTest, 3301 X: litWord("a"), 3302 Y: litWord("b"), 3303 })}, 3304 }, 3305 { 3306 Strs: []string{ 3307 "[[ a && (b) ]]", 3308 "[[ a &&\n(\nb) ]]", 3309 }, 3310 bsmk: &TestClause{X: &BinaryTest{ 3311 Op: AndTest, 3312 X: litWord("a"), 3313 Y: parenTest(litWord("b")), 3314 }}, 3315 }, 3316 { 3317 Strs: []string{"[[ (a && b) || -f c ]]"}, 3318 bsmk: &TestClause{X: &BinaryTest{ 3319 Op: OrTest, 3320 X: parenTest(&BinaryTest{ 3321 Op: AndTest, 3322 X: litWord("a"), 3323 Y: litWord("b"), 3324 }), 3325 Y: &UnaryTest{Op: TsRegFile, X: litWord("c")}, 3326 }}, 3327 }, 3328 { 3329 Strs: []string{ 3330 "[[ -S a && -L b ]]", 3331 "[[ -S a && -h b ]]", 3332 }, 3333 bsmk: &TestClause{X: &BinaryTest{ 3334 Op: AndTest, 3335 X: &UnaryTest{Op: TsSocket, X: litWord("a")}, 3336 Y: &UnaryTest{Op: TsSmbLink, X: litWord("b")}, 3337 }}, 3338 }, 3339 { 3340 Strs: []string{"[[ -k a && -N b ]]"}, 3341 bash: &TestClause{X: &BinaryTest{ 3342 Op: AndTest, 3343 X: &UnaryTest{Op: TsSticky, X: litWord("a")}, 3344 Y: &UnaryTest{Op: TsModif, X: litWord("b")}, 3345 }}, 3346 }, 3347 { 3348 Strs: []string{"[[ -G a && -O b ]]"}, 3349 bsmk: &TestClause{X: &BinaryTest{ 3350 Op: AndTest, 3351 X: &UnaryTest{Op: TsGrpOwn, X: litWord("a")}, 3352 Y: &UnaryTest{Op: TsUsrOwn, X: litWord("b")}, 3353 }}, 3354 }, 3355 { 3356 Strs: []string{"[[ -d a && -c b ]]"}, 3357 bsmk: &TestClause{X: &BinaryTest{ 3358 Op: AndTest, 3359 X: &UnaryTest{Op: TsDirect, X: litWord("a")}, 3360 Y: &UnaryTest{Op: TsCharSp, X: litWord("b")}, 3361 }}, 3362 }, 3363 { 3364 Strs: []string{"[[ -b a && -p b ]]"}, 3365 bsmk: &TestClause{X: &BinaryTest{ 3366 Op: AndTest, 3367 X: &UnaryTest{Op: TsBlckSp, X: litWord("a")}, 3368 Y: &UnaryTest{Op: TsNmPipe, X: litWord("b")}, 3369 }}, 3370 }, 3371 { 3372 Strs: []string{"[[ -g a && -u b ]]"}, 3373 bsmk: &TestClause{X: &BinaryTest{ 3374 Op: AndTest, 3375 X: &UnaryTest{Op: TsGIDSet, X: litWord("a")}, 3376 Y: &UnaryTest{Op: TsUIDSet, X: litWord("b")}, 3377 }}, 3378 }, 3379 { 3380 Strs: []string{"[[ -r a && -w b ]]"}, 3381 bsmk: &TestClause{X: &BinaryTest{ 3382 Op: AndTest, 3383 X: &UnaryTest{Op: TsRead, X: litWord("a")}, 3384 Y: &UnaryTest{Op: TsWrite, X: litWord("b")}, 3385 }}, 3386 }, 3387 { 3388 Strs: []string{"[[ -x a && -s b ]]"}, 3389 bsmk: &TestClause{X: &BinaryTest{ 3390 Op: AndTest, 3391 X: &UnaryTest{Op: TsExec, X: litWord("a")}, 3392 Y: &UnaryTest{Op: TsNoEmpty, X: litWord("b")}, 3393 }}, 3394 }, 3395 { 3396 Strs: []string{"[[ -t a && -z b ]]"}, 3397 bsmk: &TestClause{X: &BinaryTest{ 3398 Op: AndTest, 3399 X: &UnaryTest{Op: TsFdTerm, X: litWord("a")}, 3400 Y: &UnaryTest{Op: TsEmpStr, X: litWord("b")}, 3401 }}, 3402 }, 3403 { 3404 Strs: []string{"[[ -o a && -v b ]]"}, 3405 bsmk: &TestClause{X: &BinaryTest{ 3406 Op: AndTest, 3407 X: &UnaryTest{Op: TsOptSet, X: litWord("a")}, 3408 Y: &UnaryTest{Op: TsVarSet, X: litWord("b")}, 3409 }}, 3410 }, 3411 { 3412 Strs: []string{"[[ a -ot b && c -ef d ]]"}, 3413 bsmk: &TestClause{X: &BinaryTest{ 3414 Op: AndTest, 3415 X: &BinaryTest{ 3416 Op: TsOlder, 3417 X: litWord("a"), 3418 Y: litWord("b"), 3419 }, 3420 Y: &BinaryTest{ 3421 Op: TsDevIno, 3422 X: litWord("c"), 3423 Y: litWord("d"), 3424 }, 3425 }}, 3426 }, 3427 { 3428 Strs: []string{ 3429 "[[ a == b && c != d ]]", 3430 "[[ a = b && c != d ]]", 3431 }, 3432 bsmk: &TestClause{X: &BinaryTest{ 3433 Op: AndTest, 3434 X: &BinaryTest{ 3435 Op: TsMatch, 3436 X: litWord("a"), 3437 Y: litWord("b"), 3438 }, 3439 Y: &BinaryTest{ 3440 Op: TsNoMatch, 3441 X: litWord("c"), 3442 Y: litWord("d"), 3443 }, 3444 }}, 3445 }, 3446 { 3447 Strs: []string{"[[ a -ne b && c -le d ]]"}, 3448 bsmk: &TestClause{X: &BinaryTest{ 3449 Op: AndTest, 3450 X: &BinaryTest{ 3451 Op: TsNeq, 3452 X: litWord("a"), 3453 Y: litWord("b"), 3454 }, 3455 Y: &BinaryTest{ 3456 Op: TsLeq, 3457 X: litWord("c"), 3458 Y: litWord("d"), 3459 }, 3460 }}, 3461 }, 3462 { 3463 Strs: []string{"[[ c -ge d ]]"}, 3464 bsmk: &TestClause{X: &BinaryTest{ 3465 Op: TsGeq, 3466 X: litWord("c"), 3467 Y: litWord("d"), 3468 }}, 3469 }, 3470 { 3471 Strs: []string{"[[ a -lt b && c -gt d ]]"}, 3472 bsmk: &TestClause{X: &BinaryTest{ 3473 Op: AndTest, 3474 X: &BinaryTest{ 3475 Op: TsLss, 3476 X: litWord("a"), 3477 Y: litWord("b"), 3478 }, 3479 Y: &BinaryTest{ 3480 Op: TsGtr, 3481 X: litWord("c"), 3482 Y: litWord("d"), 3483 }, 3484 }}, 3485 }, 3486 { 3487 Strs: []string{"declare -f func"}, 3488 common: litStmt("declare", "-f", "func"), 3489 bash: &DeclClause{ 3490 Variant: lit("declare"), 3491 Opts: litWords("-f"), 3492 Assigns: []*Assign{{ 3493 Naked: true, 3494 Name: lit("func"), 3495 }}, 3496 }, 3497 }, 3498 { 3499 Strs: []string{"(local bar)"}, 3500 bsmk: subshell(stmt(&DeclClause{ 3501 Variant: lit("local"), 3502 Assigns: []*Assign{{ 3503 Naked: true, 3504 Name: lit("bar"), 3505 }}, 3506 })), 3507 posix: subshell(litStmt("local", "bar")), 3508 }, 3509 { 3510 Strs: []string{"typeset"}, 3511 bsmk: &DeclClause{Variant: lit("typeset")}, 3512 posix: litStmt("typeset"), 3513 }, 3514 { 3515 Strs: []string{"export bar"}, 3516 bsmk: &DeclClause{ 3517 Variant: lit("export"), 3518 Assigns: []*Assign{{ 3519 Naked: true, 3520 Name: lit("bar"), 3521 }}, 3522 }, 3523 posix: litStmt("export", "bar"), 3524 }, 3525 { 3526 Strs: []string{"readonly -n"}, 3527 bsmk: &DeclClause{Variant: lit("readonly"), Opts: litWords("-n")}, 3528 posix: litStmt("readonly", "-n"), 3529 }, 3530 { 3531 Strs: []string{"nameref bar="}, 3532 bsmk: &DeclClause{ 3533 Variant: lit("nameref"), 3534 Assigns: []*Assign{{ 3535 Name: lit("bar"), 3536 }}, 3537 }, 3538 posix: litStmt("nameref", "bar="), 3539 }, 3540 { 3541 Strs: []string{"declare -a +n -b$o foo=bar"}, 3542 bash: &DeclClause{ 3543 Variant: lit("declare"), 3544 Opts: []*Word{ 3545 litWord("-a"), 3546 litWord("+n"), 3547 word(lit("-b"), litParamExp("o")), 3548 }, 3549 Assigns: []*Assign{ 3550 {Name: lit("foo"), Value: litWord("bar")}, 3551 }, 3552 }, 3553 }, 3554 { 3555 Strs: []string{ 3556 "declare -a foo=(b1 $(b2))", 3557 "declare -a foo=(b1 `b2`)", 3558 }, 3559 bash: &DeclClause{ 3560 Variant: lit("declare"), 3561 Opts: litWords("-a"), 3562 Assigns: []*Assign{{ 3563 Name: lit("foo"), 3564 Array: arrValues( 3565 litWord("b1"), 3566 word(cmdSubst(litStmt("b2"))), 3567 ), 3568 }}, 3569 }, 3570 }, 3571 { 3572 Strs: []string{"local -a foo=(b1)"}, 3573 bash: &DeclClause{ 3574 Variant: lit("local"), 3575 Opts: litWords("-a"), 3576 Assigns: []*Assign{{ 3577 Name: lit("foo"), 3578 Array: arrValues(litWord("b1")), 3579 }}, 3580 }, 3581 }, 3582 { 3583 Strs: []string{"declare -A foo=([a]=b)"}, 3584 bash: &DeclClause{ 3585 Variant: lit("declare"), 3586 Opts: litWords("-A"), 3587 Assigns: []*Assign{{ 3588 Name: lit("foo"), 3589 Array: &ArrayExpr{Elems: []*ArrayElem{{ 3590 Index: litWord("a"), 3591 Value: litWord("b"), 3592 }}}, 3593 }}, 3594 }, 3595 }, 3596 { 3597 Strs: []string{"declare foo[a]="}, 3598 bash: &DeclClause{ 3599 Variant: lit("declare"), 3600 Assigns: []*Assign{{ 3601 Name: lit("foo"), 3602 Index: litWord("a"), 3603 }}, 3604 }, 3605 }, 3606 { 3607 Strs: []string{"declare foo[*]"}, 3608 bash: &DeclClause{ 3609 Variant: lit("declare"), 3610 Assigns: []*Assign{{ 3611 Name: lit("foo"), 3612 Index: litWord("*"), 3613 Naked: true, 3614 }}, 3615 }, 3616 }, 3617 { 3618 Strs: []string{`declare foo["x y"]`}, 3619 bash: &DeclClause{ 3620 Variant: lit("declare"), 3621 Assigns: []*Assign{{ 3622 Name: lit("foo"), 3623 Index: word(dblQuoted(lit("x y"))), 3624 Naked: true, 3625 }}, 3626 }, 3627 }, 3628 { 3629 Strs: []string{`declare foo['x y']`}, 3630 bash: &DeclClause{ 3631 Variant: lit("declare"), 3632 Assigns: []*Assign{{ 3633 Name: lit("foo"), 3634 Index: word(sglQuoted("x y")), 3635 Naked: true, 3636 }}, 3637 }, 3638 }, 3639 { 3640 Strs: []string{"foo=([)"}, 3641 mksh: &CallExpr{Assigns: []*Assign{{ 3642 Name: lit("foo"), 3643 Array: arrValues(litWord("[")), 3644 }}}, 3645 }, 3646 { 3647 Strs: []string{ 3648 "a && b=(c)\nd", 3649 "a && b=(c); d", 3650 }, 3651 bsmk: stmts( 3652 &BinaryCmd{ 3653 Op: AndStmt, 3654 X: litStmt("a"), 3655 Y: stmt(&CallExpr{Assigns: []*Assign{{ 3656 Name: lit("b"), 3657 Array: arrValues(litWord("c")), 3658 }}}), 3659 }, 3660 litCall("d"), 3661 ), 3662 }, 3663 { 3664 Strs: []string{"declare -f $func >/dev/null"}, 3665 bash: &Stmt{ 3666 Cmd: &DeclClause{ 3667 Variant: lit("declare"), 3668 Opts: litWords("-f"), 3669 Assigns: []*Assign{{ 3670 Naked: true, 3671 Value: word(litParamExp("func")), 3672 }}, 3673 }, 3674 Redirs: []*Redirect{ 3675 {Op: RdrOut, Word: litWord("/dev/null")}, 3676 }, 3677 }, 3678 }, 3679 { 3680 Strs: []string{"declare a\n{ x; }"}, 3681 bash: stmts( 3682 &DeclClause{ 3683 Variant: lit("declare"), 3684 Assigns: []*Assign{{ 3685 Naked: true, 3686 Name: lit("a"), 3687 }}, 3688 }, 3689 block(litStmt("x")), 3690 ), 3691 }, 3692 { 3693 Strs: []string{"eval a=b foo"}, 3694 common: litStmt("eval", "a=b", "foo"), 3695 }, 3696 { 3697 Strs: []string{"time", "time\n"}, 3698 posix: litStmt("time"), 3699 bsmk: &TimeClause{}, 3700 }, 3701 { 3702 Strs: []string{"time -p"}, 3703 posix: litStmt("time", "-p"), 3704 bsmk: &TimeClause{PosixFormat: true}, 3705 }, 3706 { 3707 Strs: []string{"time -a"}, 3708 posix: litStmt("time", "-a"), 3709 bsmk: &TimeClause{Stmt: litStmt("-a")}, 3710 }, 3711 { 3712 Strs: []string{"time --"}, 3713 posix: litStmt("time", "--"), 3714 bsmk: &TimeClause{Stmt: litStmt("--")}, 3715 }, 3716 { 3717 Strs: []string{"time foo"}, 3718 bsmk: &TimeClause{Stmt: litStmt("foo")}, 3719 }, 3720 { 3721 Strs: []string{"time { foo; }"}, 3722 bsmk: &TimeClause{Stmt: stmt(block(litStmt("foo")))}, 3723 }, 3724 { 3725 Strs: []string{"time\nfoo"}, 3726 bsmk: []*Stmt{ 3727 stmt(&TimeClause{}), 3728 litStmt("foo"), 3729 }, 3730 }, 3731 { 3732 Strs: []string{"coproc foo bar"}, 3733 common: litStmt("coproc", "foo", "bar"), 3734 bash: &CoprocClause{Stmt: litStmt("foo", "bar")}, 3735 }, 3736 { 3737 Strs: []string{"coproc name { foo; }"}, 3738 bash: &CoprocClause{ 3739 Name: lit("name"), 3740 Stmt: stmt(block(litStmt("foo"))), 3741 }, 3742 }, 3743 { 3744 Strs: []string{"coproc foo", "coproc foo;"}, 3745 bash: &CoprocClause{Stmt: litStmt("foo")}, 3746 }, 3747 { 3748 Strs: []string{"coproc { foo; }"}, 3749 bash: &CoprocClause{ 3750 Stmt: stmt(block(litStmt("foo"))), 3751 }, 3752 }, 3753 { 3754 Strs: []string{"coproc (foo)"}, 3755 bash: &CoprocClause{ 3756 Stmt: stmt(subshell(litStmt("foo"))), 3757 }, 3758 }, 3759 { 3760 Strs: []string{"coproc name foo | bar"}, 3761 bash: &CoprocClause{ 3762 Name: lit("name"), 3763 Stmt: stmt(&BinaryCmd{ 3764 Op: Pipe, 3765 X: litStmt("foo"), 3766 Y: litStmt("bar"), 3767 }), 3768 }, 3769 }, 3770 { 3771 Strs: []string{"coproc $()", "coproc ``"}, 3772 bash: &CoprocClause{Stmt: stmt(call( 3773 word(cmdSubst()), 3774 ))}, 3775 }, 3776 { 3777 Strs: []string{`let i++`}, 3778 bsmk: letClause( 3779 &UnaryArithm{Op: Inc, Post: true, X: litWord("i")}, 3780 ), 3781 posix: litStmt("let", "i++"), 3782 }, 3783 { 3784 Strs: []string{`let a++ b++ c +d`}, 3785 bsmk: letClause( 3786 &UnaryArithm{Op: Inc, Post: true, X: litWord("a")}, 3787 &UnaryArithm{Op: Inc, Post: true, X: litWord("b")}, 3788 litWord("c"), 3789 &UnaryArithm{Op: Plus, X: litWord("d")}, 3790 ), 3791 }, 3792 { 3793 Strs: []string{`let ++i >/dev/null`}, 3794 bsmk: &Stmt{ 3795 Cmd: letClause(&UnaryArithm{Op: Inc, X: litWord("i")}), 3796 Redirs: []*Redirect{{Op: RdrOut, Word: litWord("/dev/null")}}, 3797 }, 3798 }, 3799 { 3800 Strs: []string{ 3801 `let a=(1 + 2) b=3+4`, 3802 `let a=(1+2) b=3+4`, 3803 }, 3804 bash: letClause( 3805 &BinaryArithm{ 3806 Op: Assgn, 3807 X: litWord("a"), 3808 Y: parenArit(&BinaryArithm{ 3809 Op: Add, 3810 X: litWord("1"), 3811 Y: litWord("2"), 3812 }), 3813 }, 3814 &BinaryArithm{ 3815 Op: Assgn, 3816 X: litWord("b"), 3817 Y: &BinaryArithm{ 3818 Op: Add, 3819 X: litWord("3"), 3820 Y: litWord("4"), 3821 }, 3822 }, 3823 ), 3824 }, 3825 { 3826 Strs: []string{ 3827 `let a=$(echo 3)`, 3828 "let a=`echo 3`", 3829 }, 3830 bash: letClause( 3831 &BinaryArithm{ 3832 Op: Assgn, 3833 X: litWord("a"), 3834 Y: word(cmdSubst(litStmt("echo", "3"))), 3835 }, 3836 ), 3837 }, 3838 { 3839 Strs: []string{"(foo-bar)"}, 3840 common: subshell(litStmt("foo-bar")), 3841 }, 3842 { 3843 Strs: []string{ 3844 "let i++\nbar", 3845 "let i++ \nbar", 3846 "let i++; bar", 3847 }, 3848 bsmk: []*Stmt{ 3849 stmt(letClause(&UnaryArithm{ 3850 Op: Inc, 3851 Post: true, 3852 X: litWord("i"), 3853 })), 3854 litStmt("bar"), 3855 }, 3856 }, 3857 { 3858 Strs: []string{ 3859 "let i++\nfoo=(bar)", 3860 "let i++; foo=(bar)", 3861 "let i++; foo=(bar)\n", 3862 }, 3863 bsmk: []*Stmt{ 3864 stmt(letClause(&UnaryArithm{ 3865 Op: Inc, 3866 Post: true, 3867 X: litWord("i"), 3868 })), 3869 stmt(&CallExpr{Assigns: []*Assign{{ 3870 Name: lit("foo"), 3871 Array: arrValues(litWord("bar")), 3872 }}}), 3873 }, 3874 }, 3875 { 3876 Strs: []string{ 3877 "case a in b) let i++ ;; esac", 3878 "case a in b) let i++;; esac", 3879 }, 3880 bsmk: &CaseClause{ 3881 Word: word(lit("a")), 3882 Items: []*CaseItem{{ 3883 Op: Break, 3884 Patterns: litWords("b"), 3885 StmtList: stmtList(stmt(letClause(&UnaryArithm{ 3886 Op: Inc, 3887 Post: true, 3888 X: litWord("i"), 3889 }))), 3890 }}, 3891 }, 3892 }, 3893 { 3894 Strs: []string{"case a in b) [[ x =~ y ]] ;; esac"}, 3895 bash: &CaseClause{ 3896 Word: word(lit("a")), 3897 Items: []*CaseItem{{ 3898 Op: Break, 3899 Patterns: litWords("b"), 3900 StmtList: stmtList(stmt( 3901 &TestClause{X: &BinaryTest{ 3902 Op: TsReMatch, 3903 X: litWord("x"), 3904 Y: litWord("y"), 3905 }}, 3906 )), 3907 }}, 3908 }, 3909 }, 3910 { 3911 Strs: []string{"a+=1"}, 3912 bsmk: &CallExpr{ 3913 Assigns: []*Assign{{ 3914 Append: true, 3915 Name: lit("a"), 3916 Value: litWord("1"), 3917 }}, 3918 }, 3919 posix: litStmt("a+=1"), 3920 }, 3921 { 3922 Strs: []string{"b+=(2 3)"}, 3923 bsmk: &CallExpr{Assigns: []*Assign{{ 3924 Append: true, 3925 Name: lit("b"), 3926 Array: arrValues(litWords("2", "3")...), 3927 }}}, 3928 }, 3929 { 3930 Strs: []string{"a[2]=b c[-3]= d[x]+=e"}, 3931 posix: litStmt("a[2]=b", "c[-3]=", "d[x]+=e"), 3932 bsmk: &CallExpr{Assigns: []*Assign{ 3933 { 3934 Name: lit("a"), 3935 Index: litWord("2"), 3936 Value: litWord("b"), 3937 }, 3938 { 3939 Name: lit("c"), 3940 Index: &UnaryArithm{ 3941 Op: Minus, 3942 X: litWord("3"), 3943 }, 3944 }, 3945 { 3946 Name: lit("d"), 3947 Index: litWord("x"), 3948 Append: true, 3949 Value: litWord("e"), 3950 }, 3951 }}, 3952 }, 3953 { 3954 Strs: []string{ 3955 "b[i]+=2", 3956 "b[ i ]+=2", 3957 }, 3958 bsmk: &CallExpr{Assigns: []*Assign{{ 3959 Append: true, 3960 Name: lit("b"), 3961 Index: litWord("i"), 3962 Value: litWord("2"), 3963 }}}, 3964 }, 3965 { 3966 Strs: []string{`$((a + "b + $c"))`}, 3967 common: arithmExp(&BinaryArithm{ 3968 Op: Add, 3969 X: litWord("a"), 3970 Y: word(dblQuoted( 3971 lit("b + "), 3972 litParamExp("c"), 3973 )), 3974 }), 3975 }, 3976 { 3977 Strs: []string{`let 'i++'`}, 3978 bsmk: letClause(word(sglQuoted("i++"))), 3979 }, 3980 { 3981 Strs: []string{`echo ${a["x y"]}`}, 3982 bash: call(litWord("echo"), word(&ParamExp{ 3983 Param: lit("a"), 3984 Index: word(dblQuoted(lit("x y"))), 3985 })), 3986 }, 3987 { 3988 Strs: []string{ 3989 `a[$"x y"]=b`, 3990 `a[ $"x y" ]=b`, 3991 }, 3992 bash: &CallExpr{Assigns: []*Assign{{ 3993 Name: lit("a"), 3994 Index: word(&DblQuoted{Dollar: true, Parts: []WordPart{ 3995 lit("x y"), 3996 }}), 3997 Value: litWord("b"), 3998 }}}, 3999 }, 4000 { 4001 Strs: []string{`((a["x y"] = b))`, `((a["x y"]=b))`}, 4002 bsmk: arithmCmd(&BinaryArithm{ 4003 Op: Assgn, 4004 X: word(&ParamExp{ 4005 Short: true, 4006 Param: lit("a"), 4007 Index: word(dblQuoted(lit("x y"))), 4008 }), 4009 Y: litWord("b"), 4010 }), 4011 }, 4012 { 4013 Strs: []string{ 4014 `a=(["x y"]=b)`, 4015 `a=( [ "x y" ]=b)`, 4016 }, 4017 bash: &CallExpr{Assigns: []*Assign{{ 4018 Name: lit("a"), 4019 Array: &ArrayExpr{Elems: []*ArrayElem{{ 4020 Index: word(dblQuoted(lit("x y"))), 4021 Value: litWord("b"), 4022 }}}, 4023 }}}, 4024 }, 4025 { 4026 Strs: []string{ 4027 "a=([x]= [y]=)", 4028 "a=(\n[x]=\n[y]=\n)", 4029 }, 4030 bash: &CallExpr{Assigns: []*Assign{{ 4031 Name: lit("a"), 4032 Array: &ArrayExpr{Elems: []*ArrayElem{ 4033 {Index: litWord("x")}, 4034 {Index: litWord("y")}, 4035 }}, 4036 }}}, 4037 }, 4038 { 4039 Strs: []string{"a]b"}, 4040 common: litStmt("a]b"), 4041 }, 4042 { 4043 Strs: []string{"echo a[b c[de]f"}, 4044 posix: litStmt("echo", "a[b", "c[de]f"), 4045 bsmk: call(litWord("echo"), 4046 word(lit("a"), lit("[b")), 4047 word(lit("c"), lit("[de]f")), 4048 ), 4049 }, 4050 { 4051 Strs: []string{"<<EOF | b\nfoo\nEOF"}, 4052 common: &BinaryCmd{ 4053 Op: Pipe, 4054 X: &Stmt{Redirs: []*Redirect{{ 4055 Op: Hdoc, 4056 Word: litWord("EOF"), 4057 Hdoc: litWord("foo\n"), 4058 }}}, 4059 Y: litStmt("b"), 4060 }, 4061 }, 4062 { 4063 Strs: []string{"<<EOF1 <<EOF2 | c && d\nEOF1\nEOF2"}, 4064 common: &BinaryCmd{ 4065 Op: AndStmt, 4066 X: stmt(&BinaryCmd{ 4067 Op: Pipe, 4068 X: &Stmt{Redirs: []*Redirect{ 4069 {Op: Hdoc, Word: litWord("EOF1")}, 4070 {Op: Hdoc, Word: litWord("EOF2")}, 4071 }}, 4072 Y: litStmt("c"), 4073 }), 4074 Y: litStmt("d"), 4075 }, 4076 }, 4077 { 4078 Strs: []string{ 4079 "<<EOF && { bar; }\nhdoc\nEOF", 4080 "<<EOF &&\nhdoc\nEOF\n{ bar; }", 4081 }, 4082 common: &BinaryCmd{ 4083 Op: AndStmt, 4084 X: &Stmt{Redirs: []*Redirect{{ 4085 Op: Hdoc, 4086 Word: litWord("EOF"), 4087 Hdoc: litWord("hdoc\n"), 4088 }}}, 4089 Y: stmt(block(litStmt("bar"))), 4090 }, 4091 }, 4092 { 4093 Strs: []string{"foo() {\n\t<<EOF && { bar; }\nhdoc\nEOF\n}"}, 4094 common: &FuncDecl{ 4095 Name: lit("foo"), 4096 Body: stmt(block(stmt(&BinaryCmd{ 4097 Op: AndStmt, 4098 X: &Stmt{Redirs: []*Redirect{{ 4099 Op: Hdoc, 4100 Word: litWord("EOF"), 4101 Hdoc: litWord("hdoc\n"), 4102 }}}, 4103 Y: stmt(block(litStmt("bar"))), 4104 }))), 4105 }, 4106 }, 4107 { 4108 Strs: []string{`"a$("")"`, "\"a`\"\"`\""}, 4109 common: dblQuoted( 4110 lit("a"), 4111 cmdSubst(stmt(call( 4112 word(dblQuoted()), 4113 ))), 4114 ), 4115 }, 4116 { 4117 Strs: []string{"echo ?(b)*(c)+(d)@(e)!(f)"}, 4118 bsmk: call(litWord("echo"), word( 4119 &ExtGlob{Op: GlobQuest, Pattern: lit("b")}, 4120 &ExtGlob{Op: GlobStar, Pattern: lit("c")}, 4121 &ExtGlob{Op: GlobPlus, Pattern: lit("d")}, 4122 &ExtGlob{Op: GlobAt, Pattern: lit("e")}, 4123 &ExtGlob{Op: GlobExcl, Pattern: lit("f")}, 4124 )), 4125 }, 4126 { 4127 Strs: []string{"echo foo@(b*(c|d))bar"}, 4128 bsmk: call(litWord("echo"), word( 4129 lit("foo"), 4130 &ExtGlob{Op: GlobAt, Pattern: lit("b*(c|d)")}, 4131 lit("bar"), 4132 )), 4133 }, 4134 { 4135 Strs: []string{"echo $a@(b)$c?(d)$e*(f)$g+(h)$i!(j)$k"}, 4136 bsmk: call(litWord("echo"), word( 4137 litParamExp("a"), 4138 &ExtGlob{Op: GlobAt, Pattern: lit("b")}, 4139 litParamExp("c"), 4140 &ExtGlob{Op: GlobQuest, Pattern: lit("d")}, 4141 litParamExp("e"), 4142 &ExtGlob{Op: GlobStar, Pattern: lit("f")}, 4143 litParamExp("g"), 4144 &ExtGlob{Op: GlobPlus, Pattern: lit("h")}, 4145 litParamExp("i"), 4146 &ExtGlob{Op: GlobExcl, Pattern: lit("j")}, 4147 litParamExp("k"), 4148 )), 4149 }, 4150 } 4151 4152 // these don't have a canonical format with the same syntax tree 4153 var fileTestsNoPrint = []testCase{ 4154 { 4155 Strs: []string{`$[foo]`}, 4156 posix: word(lit("$"), lit("[foo]")), 4157 }, 4158 { 4159 Strs: []string{`"$[foo]"`}, 4160 posix: dblQuoted(lit("$"), lit("[foo]")), 4161 }, 4162 { 4163 Strs: []string{`"$[1 + 3]"`}, 4164 bash: dblQuoted(arithmExpBr(&BinaryArithm{ 4165 Op: Add, 4166 X: litWord("1"), 4167 Y: litWord("3"), 4168 })), 4169 }, 4170 } 4171 4172 func fullProg(v interface{}) *File { 4173 f := &File{} 4174 switch x := v.(type) { 4175 case *File: 4176 return x 4177 case StmtList: 4178 f.Stmts = x.Stmts 4179 return f 4180 case []*Stmt: 4181 f.Stmts = x 4182 return f 4183 case *Stmt: 4184 f.Stmts = append(f.Stmts, x) 4185 return f 4186 case []Command: 4187 for _, cmd := range x { 4188 f.Stmts = append(f.Stmts, stmt(cmd)) 4189 } 4190 return f 4191 case *Word: 4192 return fullProg(call(x)) 4193 case WordPart: 4194 return fullProg(word(x)) 4195 case Command: 4196 return fullProg(stmt(x)) 4197 case nil: 4198 default: 4199 panic(reflect.TypeOf(v)) 4200 } 4201 return nil 4202 } 4203 4204 func clearPosRecurse(tb testing.TB, src string, v interface{}) { 4205 zeroPos := Pos{} 4206 checkSrc := func(pos Pos, strs ...string) { 4207 if src == "" { 4208 return 4209 } 4210 offs := pos.Offset() 4211 if offs > uint(len(src)) { 4212 tb.Fatalf("Pos %d in %T is out of bounds in %q", 4213 pos, v, src) 4214 return 4215 } 4216 if strs == nil { 4217 return 4218 } 4219 if strings.Contains(src, "<<-") { 4220 // since the tab indentation in <<- heredoc bodies 4221 // aren't part of the final literals 4222 return 4223 } 4224 var gotErr string 4225 for i, want := range strs { 4226 got := src[offs:] 4227 if i == 0 { 4228 gotErr = got 4229 } 4230 got = strings.Replace(got, "\\\n", "", -1) 4231 if len(got) > len(want) { 4232 got = got[:len(want)] 4233 } 4234 if got == want { 4235 return 4236 } 4237 } 4238 tb.Fatalf("Expected one of %q at %d in %q, found %q", 4239 strs, pos, src, gotErr) 4240 } 4241 setPos := func(p *Pos, strs ...string) { 4242 checkSrc(*p, strs...) 4243 if *p == zeroPos { 4244 tb.Fatalf("Pos in %T is already %v", v, zeroPos) 4245 } 4246 *p = zeroPos 4247 } 4248 checkPos := func(n Node) { 4249 if n == nil { 4250 return 4251 } 4252 if n.Pos() != zeroPos { 4253 tb.Fatalf("Found unexpected Pos() in %T: want %d, got %d", 4254 n, zeroPos, n.Pos()) 4255 } 4256 if n.Pos().After(n.End()) { 4257 tb.Fatalf("Found End() before Pos() in %T", n) 4258 } 4259 } 4260 recurse := func(v interface{}) { 4261 clearPosRecurse(tb, src, v) 4262 if n, ok := v.(Node); ok { 4263 checkPos(n) 4264 } 4265 } 4266 switch x := v.(type) { 4267 case *File: 4268 recurse(x.StmtList) 4269 checkPos(x) 4270 case []Comment: 4271 for i := range x { 4272 recurse(&x[i]) 4273 } 4274 case *Comment: 4275 setPos(&x.Hash, "#"+x.Text) 4276 case StmtList: 4277 for _, s := range x.Stmts { 4278 recurse(s) 4279 } 4280 recurse(x.Last) 4281 case *Stmt: 4282 endOff := int(x.End().Offset()) 4283 if endOff < len(src) { 4284 end := src[endOff] 4285 switch { 4286 case end == ' ', end == '\n', end == '\t', end == '\r': 4287 // ended by whitespace 4288 case regOps(rune(end)): 4289 // ended by end character 4290 case endOff > 0 && src[endOff-1] == ';': 4291 // ended by semicolon 4292 case endOff > 0 && src[endOff-1] == '&': 4293 // ended by & or |& 4294 default: 4295 tb.Fatalf("Unexpected Stmt.End() %d %q in %q", 4296 endOff, end, src) 4297 } 4298 } 4299 recurse(x.Comments) 4300 if src[x.Position.Offset()] == '#' { 4301 tb.Fatalf("Stmt.Pos() should not be a comment") 4302 } 4303 setPos(&x.Position) 4304 if x.Semicolon.IsValid() { 4305 setPos(&x.Semicolon, ";", "&", "|&") 4306 } 4307 if x.Cmd != nil { 4308 recurse(x.Cmd) 4309 } 4310 for _, r := range x.Redirs { 4311 setPos(&r.OpPos, r.Op.String()) 4312 if r.N != nil { 4313 recurse(r.N) 4314 } 4315 recurse(r.Word) 4316 if r.Hdoc != nil { 4317 recurse(r.Hdoc) 4318 } 4319 } 4320 case []*Assign: 4321 for _, a := range x { 4322 if a.Name != nil { 4323 recurse(a.Name) 4324 } 4325 if a.Index != nil { 4326 recurse(a.Index) 4327 } 4328 if a.Value != nil { 4329 recurse(a.Value) 4330 } 4331 if a.Array != nil { 4332 recurse(a.Array) 4333 } 4334 checkPos(a) 4335 } 4336 case *CallExpr: 4337 recurse(x.Assigns) 4338 recurse(x.Args) 4339 case []*Word: 4340 for _, w := range x { 4341 recurse(w) 4342 } 4343 case *Word: 4344 recurse(x.Parts) 4345 case []WordPart: 4346 for _, wp := range x { 4347 recurse(wp) 4348 } 4349 case *Lit: 4350 pos, end := int(x.Pos().Offset()), int(x.End().Offset()) 4351 want := pos + len(x.Value) 4352 val := x.Value 4353 posLine := x.Pos().Line() 4354 endLine := x.End().Line() 4355 switch { 4356 case src == "": 4357 case strings.Contains(src, "\\\n"): 4358 case !strings.Contains(x.Value, "\n") && posLine != endLine: 4359 tb.Fatalf("Lit without newlines has Pos/End lines %d and %d", 4360 posLine, endLine) 4361 case strings.Contains(src, "`") && strings.Contains(src, "\\"): 4362 // removed quotes inside backquote cmd substs 4363 val = "" 4364 case end < len(src) && src[end] == '\n': 4365 // heredoc literals that end with the 4366 // stop word and a newline 4367 case end == len(src): 4368 // same as above, but with word and EOF 4369 case end != want: 4370 tb.Fatalf("Unexpected Lit %q End() %d (wanted %d) in %q", 4371 val, end, want, src) 4372 } 4373 setPos(&x.ValuePos, val) 4374 setPos(&x.ValueEnd) 4375 case *Subshell: 4376 setPos(&x.Lparen, "(") 4377 setPos(&x.Rparen, ")") 4378 recurse(x.StmtList) 4379 case *Block: 4380 setPos(&x.Lbrace, "{") 4381 setPos(&x.Rbrace, "}") 4382 recurse(x.StmtList) 4383 case *IfClause: 4384 setPos(&x.IfPos, "if", "elif") 4385 setPos(&x.ThenPos, "then") 4386 if x.FiPos.IsValid() { 4387 setPos(&x.FiPos, "fi", "elif") 4388 } 4389 recurse(x.Cond) 4390 recurse(x.Then) 4391 if !x.Else.empty() { 4392 setPos(&x.ElsePos, "else", "elif") 4393 recurse(x.Else) 4394 } 4395 case *WhileClause: 4396 rsrv := "while" 4397 if x.Until { 4398 rsrv = "until" 4399 } 4400 setPos(&x.WhilePos, rsrv) 4401 setPos(&x.DoPos, "do") 4402 setPos(&x.DonePos, "done") 4403 recurse(x.Cond) 4404 recurse(x.Do) 4405 case *ForClause: 4406 if x.Select { 4407 setPos(&x.ForPos, "select") 4408 } else { 4409 setPos(&x.ForPos, "for") 4410 } 4411 setPos(&x.DoPos, "do") 4412 setPos(&x.DonePos, "done") 4413 recurse(x.Loop) 4414 recurse(x.Do) 4415 case *WordIter: 4416 recurse(x.Name) 4417 if x.InPos.IsValid() { 4418 setPos(&x.InPos, "in") 4419 } 4420 recurse(x.Items) 4421 case *CStyleLoop: 4422 setPos(&x.Lparen, "((") 4423 setPos(&x.Rparen, "))") 4424 if x.Init != nil { 4425 recurse(x.Init) 4426 } 4427 if x.Cond != nil { 4428 recurse(x.Cond) 4429 } 4430 if x.Post != nil { 4431 recurse(x.Post) 4432 } 4433 case *SglQuoted: 4434 checkSrc(posAddCol(x.End(), -1), "'") 4435 valuePos := posAddCol(x.Left, 1) 4436 if x.Dollar { 4437 valuePos = posAddCol(valuePos, 1) 4438 } 4439 checkSrc(valuePos, x.Value) 4440 if x.Dollar { 4441 setPos(&x.Left, "$'") 4442 } else { 4443 setPos(&x.Left, "'") 4444 } 4445 setPos(&x.Right, "'") 4446 case *DblQuoted: 4447 checkSrc(posAddCol(x.End(), -1), `"`) 4448 if x.Dollar { 4449 setPos(&x.Position, `$"`) 4450 } else { 4451 setPos(&x.Position, `"`) 4452 } 4453 recurse(x.Parts) 4454 case *UnaryArithm: 4455 setPos(&x.OpPos, x.Op.String()) 4456 recurse(x.X) 4457 case *UnaryTest: 4458 strs := []string{x.Op.String()} 4459 switch x.Op { 4460 case TsExists: 4461 strs = append(strs, "-a") 4462 case TsSmbLink: 4463 strs = append(strs, "-h") 4464 } 4465 setPos(&x.OpPos, strs...) 4466 recurse(x.X) 4467 case *BinaryCmd: 4468 setPos(&x.OpPos, x.Op.String()) 4469 recurse(x.X) 4470 recurse(x.Y) 4471 case *BinaryArithm: 4472 setPos(&x.OpPos, x.Op.String()) 4473 recurse(x.X) 4474 recurse(x.Y) 4475 case *BinaryTest: 4476 strs := []string{x.Op.String()} 4477 switch x.Op { 4478 case TsMatch: 4479 strs = append(strs, "=") 4480 } 4481 setPos(&x.OpPos, strs...) 4482 recurse(x.X) 4483 recurse(x.Y) 4484 case *ParenArithm: 4485 setPos(&x.Lparen, "(") 4486 setPos(&x.Rparen, ")") 4487 recurse(x.X) 4488 case *ParenTest: 4489 setPos(&x.Lparen, "(") 4490 setPos(&x.Rparen, ")") 4491 recurse(x.X) 4492 case *FuncDecl: 4493 if x.RsrvWord { 4494 setPos(&x.Position, "function") 4495 } else { 4496 setPos(&x.Position) 4497 } 4498 recurse(x.Name) 4499 recurse(x.Body) 4500 case *ParamExp: 4501 doll := "$" 4502 if x.nakedIndex() { 4503 doll = "" 4504 } 4505 setPos(&x.Dollar, doll) 4506 if !x.Short { 4507 setPos(&x.Rbrace, "}") 4508 } else if x.nakedIndex() { 4509 checkSrc(posAddCol(x.End(), -1), "]") 4510 } 4511 recurse(x.Param) 4512 if x.Index != nil { 4513 recurse(x.Index) 4514 } 4515 if x.Slice != nil { 4516 if x.Slice.Offset != nil { 4517 recurse(x.Slice.Offset) 4518 } 4519 if x.Slice.Length != nil { 4520 recurse(x.Slice.Length) 4521 } 4522 } 4523 if x.Repl != nil { 4524 if x.Repl.Orig != nil { 4525 recurse(x.Repl.Orig) 4526 } 4527 if x.Repl.With != nil { 4528 recurse(x.Repl.With) 4529 } 4530 } 4531 if x.Exp != nil && x.Exp.Word != nil { 4532 recurse(x.Exp.Word) 4533 } 4534 case *ArithmExp: 4535 if x.Bracket { 4536 // deprecated $(( form 4537 setPos(&x.Left, "$[") 4538 setPos(&x.Right, "]") 4539 } else { 4540 setPos(&x.Left, "$((") 4541 setPos(&x.Right, "))") 4542 } 4543 recurse(x.X) 4544 case *ArithmCmd: 4545 setPos(&x.Left, "((") 4546 setPos(&x.Right, "))") 4547 recurse(x.X) 4548 case *CmdSubst: 4549 switch { 4550 case x.TempFile: 4551 setPos(&x.Left, "${ ", "${\t", "${\n") 4552 setPos(&x.Right, "}") 4553 case x.ReplyVar: 4554 setPos(&x.Left, "${|") 4555 setPos(&x.Right, "}") 4556 default: 4557 setPos(&x.Left, "$(", "`", "\\`") 4558 setPos(&x.Right, ")", "`", "\\`") 4559 } 4560 recurse(x.StmtList) 4561 case *CaseClause: 4562 setPos(&x.Case, "case") 4563 setPos(&x.Esac, "esac", "}") 4564 recurse(x.Word) 4565 for _, ci := range x.Items { 4566 recurse(ci) 4567 } 4568 case *CaseItem: 4569 if x.OpPos.IsValid() { 4570 setPos(&x.OpPos, x.Op.String(), "esac") 4571 } 4572 recurse(x.Patterns) 4573 recurse(x.StmtList) 4574 case *TestClause: 4575 setPos(&x.Left, "[[") 4576 setPos(&x.Right, "]]") 4577 recurse(x.X) 4578 case *DeclClause: 4579 recurse(x.Variant) 4580 recurse(x.Opts) 4581 recurse(x.Assigns) 4582 case *TimeClause: 4583 setPos(&x.Time, "time") 4584 if x.Stmt != nil { 4585 recurse(x.Stmt) 4586 } 4587 case *CoprocClause: 4588 setPos(&x.Coproc, "coproc") 4589 if x.Name != nil { 4590 recurse(x.Name) 4591 } 4592 recurse(x.Stmt) 4593 case *LetClause: 4594 setPos(&x.Let, "let") 4595 for _, expr := range x.Exprs { 4596 recurse(expr) 4597 } 4598 case *ArrayExpr: 4599 setPos(&x.Lparen, "(") 4600 setPos(&x.Rparen, ")") 4601 for _, elem := range x.Elems { 4602 recurse(elem) 4603 } 4604 case *ArrayElem: 4605 if x.Index != nil { 4606 recurse(x.Index) 4607 } 4608 if x.Value != nil { 4609 recurse(x.Value) 4610 } 4611 case *ExtGlob: 4612 setPos(&x.OpPos, x.Op.String()) 4613 checkSrc(posAddCol(x.End(), -1), ")") 4614 recurse(x.Pattern) 4615 case *ProcSubst: 4616 setPos(&x.OpPos, x.Op.String()) 4617 setPos(&x.Rparen, ")") 4618 recurse(x.StmtList) 4619 default: 4620 panic(reflect.TypeOf(v)) 4621 } 4622 }