# file      : libbuild2/test/script/parser+for.test.testscript
# license   : MIT; see accompanying LICENSE file

: form-1
:
: for x: ...
:
{{
  : for
  :
  {{
    : no-var
    :
    $* <<EOI 2>>EOE != 0
    for
      cmd
    EOI
    testscript:1:1: error: for: missing variable name
    EOE

    : untyped
    :
    $* <<EOI >>EOO
    for x: a b
      cmd $x
    EOI
    cmd a
    cmd b
    EOO

    : null
    :
    $* <<EOI >:''
    for x: [null]
      cmd $x
    EOI

    : empty
    :
    $* <<EOI >:''
    for x:
      cmd $x
    EOI

    : expansion
    :
    $* <<EOI >>EOO
    vs = a b
    for x: $vs
      cmd $x
    EOI
    cmd a
    cmd b
    EOO

    : typed-values
    :
    $* <<EOI >>~%EOO%
    for x: [dir_paths] a b
      cmd $x
    EOI
    %cmd (a/|'a\\')%
    %cmd (b/|'b\\')%
    EOO

    : typed-elem
    :
    $* <<EOI >>~%EOO%
    for x [dir_path]: a b
      cmd $x
    EOI
    %cmd (a/|'a\\')%
    %cmd (b/|'b\\')%
    EOO

    : typed-elem-value
    :
    $* <<EOI >>~%EOO%
    for x [dir_path]: [strings] a b
      cmd $x
    EOI
    %cmd (a/|'a\\')%
    %cmd (b/|'b\\')%
    EOO

    : scope-var
    :
    $* <<EOI >>EOO
    x = x

    for x: a b
      cmd $x

    -cmd $x
    EOI
    cmd a
    cmd b
    -cmd x
    EOO
  }}

  : after-semi
  :
  $* -s <<EOI >>EOO
  cmd1;
  for x: a b
    cmd2 $x
  EOI
  {{
    {
      cmd1
      cmd2 a
      cmd2 b
    }
  }}
  EOO

  : description
  :
  $* -s <<EOI >>EOO
  : description
  for x: a
    cmd $x
  EOI
  {{
    : id:description
    {
      cmd a
    }
  }}
  EOO

  : both-descriptions
  :
  $* <<EOI 2>>EOE != 0
  : description1
  for x: a
    cmd $x : description2
  EOI
  testscript:3:10: error: both leading and trailing descriptions specified
  EOE

  : empty-body
  :
  $* <<EOI >>EOO
  for x: a
  {
  };
  cmd $x
  EOI
  cmd a
  EOO

  : setup
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    +for x: a b
      cmd $x
    EOI
    {{
      +cmd a
      +cmd b
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    +for x: a b c d e
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      ? false
      ? false
      +cmd a
      ? true
      ? false
      ? false
      +cmd c
      ? false
      ? true
    }}
    EOO
  }}

  : tdown
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    -for x: a b
      cmd $x
    EOI
    {{
      -cmd a
      -cmd b
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    -for x: a b c d e
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      ? false
      ? false
      -cmd a
      ? true
      ? false
      ? false
      -cmd c
      ? false
      ? true
    }}
    EOO
  }}

  : rcbrace
  :
  {{
    : without-rcbrace
    :
    $* <<EOI 2>>EOE != 0
    for x: a b
    {
      cmd
    EOI
    testscript:4:1: error: expected '}' at the end of 'for'
    EOE
  }}

  : elif
  :
  {{
    : without-if
    :
    $* <<EOI 2>>EOE != 0
    for x: a b
      elif true
        cmd
    EOI
    testscript:2:3: error: 'elif' without preceding 'if'
    EOE
  }}

  : continue
  :
  {{
    : basics
    :
    $* -l -r <<EOI >>EOO
    for x: a b
    {
      cmd1            # 1
      continue
      cmd2            # 2
    };
    cmd3              # 3
    EOI
    cmd1 # 1 i1
    cmd1 # 1 i2
    cmd3 # 3
    EOO

    : trailing
    :
    $* <<EOI 2>>EOE != 0
    for x: y
      continue junk
    EOI
    testscript:2:12: error: expected newline instead of 'junk'
    EOE

    : outside
    :
    $* <<EOI 2>>EOE != 0
    for x: y
      break
    continue
    EOI
    testscript:3:1: error: 'continue' outside loop
    EOE
  }}

  : break
  :
  {{
    : basics
    :
    $* -l -r <<EOI >>EOO
    for x: a b
    {
      cmd1     # 1
      break
      cmd2     # 2
    };
    cmd3       # 3
    EOI
    cmd1 # 1 i1
    cmd3 # 3
    EOO

    : trailing
    :
    $* <<EOI 2>>EOE != 0
    for x: y
      break junk
    EOI
    testscript:2:9: error: expected newline instead of 'junk'
    EOE

    : outside
    :
    $* <<EOI 2>>EOE != 0
    for x: y
      continue
    break
    EOI
    testscript:3:1: error: 'break' outside loop
    EOE
  }}

  : nested
  :
  {
    $* -l -r <<EOI >>EOO
    for x: a b c d
    {
      cmd1 $x               # 1
      if ($x == "a")        # 2
      {
        cmd2                # 3
        for y: x y
          cmd3              # 4
      }
      else
        cmd4                # 5
      cmd5                  # 6

      if ($x == "c")        # 7
        continue

      if ($x == "d")        # 8
        break
    };
    cmd6                    # 9
    EOI
    cmd1 a # 1 i1
    ? true # 2 i1
    cmd2 # 3 i1
    cmd3 # 4 i1 i1
    cmd3 # 4 i1 i2
    cmd5 # 6 i1
    ? false # 7 i1
    ? false # 8 i1
    cmd1 b # 1 i2
    ? false # 2 i2
    cmd4 # 5 i2
    cmd5 # 6 i2
    ? false # 7 i2
    ? false # 8 i2
    cmd1 c # 1 i3
    ? false # 2 i3
    cmd4 # 5 i3
    cmd5 # 6 i3
    ? true # 7 i3
    cmd1 d # 1 i4
    ? false # 2 i4
    cmd4 # 5 i4
    cmd5 # 6 i4
    ? false # 7 i4
    ? true # 8 i4
    cmd6 # 9
    EOO
  }

  : contained
  :
  {{
    : semi
    :
    $* <<EOI 2>>EOE != 0
    for x:
    {
      cmd;
      cmd
    }
    EOI
    testscript:3:6: error: ';' inside 'for'
    EOE

    : colon-leading
    :
    $* <<EOI 2>>EOE != 0
    for x:
    {
      : foo
      cmd
    }
    EOI
    testscript:3:3: error: description inside 'for'
    EOE

    : colon-trailing
    :
    $* <<EOI 2>>EOE != 0
    for x:
    {
      cmd : foo
    }
    EOI
    testscript:3:7: error: description inside 'for'
    EOE

    : eos
    :
    $* <<EOI 2>>EOE != 0
    for x:
    EOI
    testscript:2:1: error: expected command instead of <end of file> inside 'for'
    EOE

    : scope
    :
    $* <<EOI 2>>EOE != 0
    for x:
    {
      cmd
      {
      }
    }
    EOI
    testscript:4:3: error: expected command instead of '{' inside 'for'
    EOE

    : setup
    :
    $* <<EOI 2>>EOE != 0
    for x:
      +cmd
    EOI
    testscript:2:3: error: setup command inside 'for'
    EOE

    : tdown
    :
    $* <<EOI 2>>EOE != 0
    for x:
      -cmd
    EOI
    testscript:2:3: error: teardown command inside 'for'
    EOE
  }}

  : var
  :
  $* <<EOI >>EOO
  for x: a b
    cmd1 $x;
  cmd2 $x
  EOI
  cmd1 a
  cmd1 b
  cmd2 b
  EOO

  : leading-and-trailing-description
  :
  $* <<EOI 2>>EOE != 0
  : foo
  for x: a b
  {
    cmd
  } : bar
  EOI
  testscript:5:3: error: both leading and trailing descriptions specified
  EOE
}}

: form-2
:
: ... | for x
:
{{
  : for
  :
  {{
    : status
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x != 0
      cmd
    EOI
    testscript:1:20: error: for-loop exit code cannot be checked
    EOE

    : not-last
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x | echo x
      cmd
    EOI
    testscript:1:20: error: for-loop must be last command in a pipe
    EOE

    : not-last-relex
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x|echo x
      cmd
    EOI
    testscript:1:19: error: for-loop must be last command in a pipe
    EOE

    : expression-after
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x && echo x
      cmd
    EOI
    testscript:1:20: error: command expression involving for-loop
    EOE

    : expression-after-relex
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x&&echo x
      cmd
    EOI
    testscript:1:19: error: command expression involving for-loop
    EOE

    : expression-before
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' && echo x | for x
      cmd
    EOI
    testscript:1:24: error: command expression involving for-loop
    EOE

    : expression-before-relex
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' && echo x|for x
      cmd
    EOI
    testscript:1:22: error: command expression involving for-loop
    EOE

    : cleanup
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x &f
      cmd
    EOI
    testscript:1:20: error: cleanup in for-loop
    EOE

    : cleanup-relex
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x&f
      cmd
    EOI
    testscript:1:19: error: cleanup in for-loop
    EOE

    : stdout-redirect
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x >a
      cmd
    EOI
    testscript:1:20: error: output redirect in for-loop
    EOE

    : stdout-redirect-relex
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x>a
      cmd
    EOI
    testscript:1:19: error: output redirect in for-loop
    EOE

    : stdin-redirect
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x <a
      cmd
    EOI
    testscript:1:20: error: stdin is both piped and redirected
    EOE

    : no-var
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for
      cmd
    EOI
    testscript:1:1: error: for: missing variable name
    EOE

    : untyped
    :
    $* <<EOI >>EOO
    echo 'a b' | for -w x
      cmd $x
    EOI
    echo 'a b' | for -w x
    EOO

    : expansion
    :
    $* <<EOI >>EOO
    vs = a b
    echo $vs | for x
      cmd $x
    EOI
    echo a b | for x
    EOO

    : typed-elem
    :
    $* <<EOI >>EOO
    echo 'a b' | for -w x [dir_path]
      cmd $x
    EOI
    echo 'a b' | for -w x [dir_path]
    EOO
  }}

  : after-semi
  :
  $* -s <<EOI >>EOO
  cmd1;
  echo 'a b' | for x
    cmd2 $x
  EOI
  {{
    {
      cmd1
      echo 'a b' | for x
    }
  }}
  EOO

  : empty-body
  :
  $* <<EOI >>EOO
  echo a | for x
  {
  };
  cmd
  EOI
  echo a | for x
  cmd
  EOO

  : setup
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    +echo 'a b' | for x
      cmd $x
    EOI
    {{
      +echo 'a b' | for x
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    +echo 'a b c d e' | for x
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      +echo 'a b c d e' | for x
    }}
    EOO
  }}

  : tdown
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    -echo 'a b' | for x
      cmd $x
    EOI
    {{
      -echo 'a b' | for x
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    -echo 'a b c d e' | for x
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      -echo 'a b c d e' | for x
    }}
    EOO
  }}

  : rcbrace
  :
  {{
    : without-rcbrace
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      cmd
    EOI
    testscript:4:1: error: expected '}' at the end of 'for'
    EOE
  }}

  : elif
  :
  {{
    : without-if
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      elif true
        cmd
    }
    EOI
    testscript:3:3: error: 'elif' without preceding 'if'
    EOE
  }}

  : continue
  :
  {
    $* -l -r <<EOI >>EOO
    echo 'a b' | for x  # 1
    {
      cmd1              # 2
      continue
      cmd2              # 3
    };
    cmd3                # 4
    EOI
    echo 'a b' | for x # 1
    cmd3 # 4
    EOO
  }

  : break
  :
  {
    $* -l -r <<EOI >>EOO
    echo 'a b' | for x  # 1
    {
      cmd1              # 2
      break
      cmd2              # 3
    };
    cmd3                # 4
    EOI
    echo 'a b' | for x # 1
    cmd3 # 4
    EOO
  }

  : nested
  :
  {
    $* -l -r <<EOI >>EOO
    echo 'a b c d' | for x  # 1
    {
      cmd1 $x               # 2
      if ($x == "a")        # 3
      {
        cmd2                # 4
        echo x y | for y    # 5
          cmd3              # 6
      }
      else
        cmd4                # 7
      cmd5                  # 8

      if ($x == "c")        # 9
        continue

      if ($x == "d")        # 10
        break
    };
    cmd6                    # 11
    EOI
    echo 'a b c d' | for x # 1
    cmd6 # 11
    EOO
  }

  : contained
  :
  {{
    : semi
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      cmd;
      cmd
    }
    EOI
    testscript:3:6: error: ';' inside 'for'
    EOE

    : colon-leading
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      : foo
      cmd
    }
    EOI
    testscript:3:3: error: description inside 'for'
    EOE

    : colon-trailing
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      cmd : foo
    }
    EOI
    testscript:3:7: error: description inside 'for'
    EOE

    : eos
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    EOI
    testscript:2:1: error: expected command instead of <end of file> inside 'for'
    EOE

    : scope
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
    {
      cmd
      {
      }
    }
    EOI
    testscript:4:3: error: expected command instead of '{' inside 'for'
    EOE

    : setup
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
      +cmd
    EOI
    testscript:2:3: error: setup command inside 'for'
    EOE

    : tdown
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' | for x
      -cmd
    EOI
    testscript:2:3: error: teardown command inside 'for'
    EOE
  }}

  : leading-and-trailing-description
  :
  $* <<EOI 2>>EOE != 0
  : foo
  echo 'a b' | for x
    cmd : bar
  EOI
  testscript:3:7: error: both leading and trailing descriptions specified
  EOE
}}

: form-3
:
: for x <...
:
{{
  : for
  :
  {{
    : status
    :
    $* <<EOI 2>>EOE != 0
    for x <a != 0
      cmd
    EOI
    testscript:1:10: error: for-loop exit code cannot be checked
    EOE

    : not-last
    :
    $* <<EOI 2>>EOE != 0
    for x <a | echo x
      cmd
    EOI
    testscript:1:10: error: for-loop must be last command in a pipe
    EOE

    : not-last-relex
    :
    $* <<EOI 2>>EOE != 0
    for <a x|echo x
      cmd
    EOI
    testscript:1:9: error: for-loop must be last command in a pipe
    EOE

    : expression-after
    :
    $* <<EOI 2>>EOE != 0
    for x <a && echo x
      cmd
    EOI
    testscript:1:10: error: command expression involving for-loop
    EOE

    : expression-after-relex
    :
    $* <<EOI 2>>EOE != 0
    for <a x&&echo x
      cmd
    EOI
    testscript:1:9: error: command expression involving for-loop
    EOE

    : expression-before
    :
    $* <<EOI 2>>EOE != 0
    echo 'a b' && for x <a
      cmd
    EOI
    testscript:1:15: error: command expression involving for-loop
    EOE

    : cleanup
    :
    $* <<EOI 2>>EOE != 0
    for x <a &f
      cmd
    EOI
    testscript:1:10: error: cleanup in for-loop
    EOE

    : cleanup-before-var
    :
    $* <<EOI 2>>EOE != 0
    for &f x <a
      cmd
    EOI
    testscript:1:5: error: cleanup in for-loop
    EOE

    : cleanup-relex
    :
    $* <<EOI 2>>EOE != 0
    for <a x&f
      cmd
    EOI
    testscript:1:9: error: cleanup in for-loop
    EOE

    : stdout-redirect
    :
    $* <<EOI 2>>EOE != 0
    for x >a
      cmd
    EOI
    testscript:1:7: error: output redirect in for-loop
    EOE

    : stdout-redirect-before-var
    :
    $* <<EOI 2>>EOE != 0
    for >a x
      cmd
    EOI
    testscript:1:5: error: output redirect in for-loop
    EOE

    : stdout-redirect-relex
    :
    $* <<EOI 2>>EOE != 0
    for x>a
      cmd
    EOI
    testscript:1:6: error: output redirect in for-loop
    EOE

    : no-var
    :
    $* <<EOI 2>>EOE != 0
    for <a
      cmd
    EOI
    testscript:1:1: error: for: missing variable name
    EOE

    : quoted-opt
    :
    $* <<EOI >>EOO
    o = -w
    for "$o" x <'a b'
      cmd $x;
    for "($o)" x <'a b'
      cmd $x
    EOI
    for -w x <'a b'
    for -w x <'a b'
    EOO

    : untyped
    :
    $* <<EOI >>EOO
    for -w x <'a b'
      cmd $x
    EOI
    for -w x <'a b'
    EOO

    : expansion
    :
    $* <<EOI >>EOO
    vs = a b
    for x <$vs
      cmd $x
    EOI
    for x b <a
    EOO

    : typed-elem
    :
    $* <<EOI >>EOO
    for -w x [dir_path] <'a b'
      cmd $x
    EOI
    for -w x [dir_path] <'a b'
    EOO
  }}

  : after-semi
  :
  $* -s <<EOI >>EOO
  cmd1;
  for x <'a b'
    cmd2 $x
  EOI
  {{
    {
      cmd1
      for x <'a b'
    }
  }}
  EOO

  : empty-body
  :
  $* <<EOI >>EOO
  for x <'a'
  {
  };
  cmd
  EOI
  for x <a
  cmd
  EOO

  : setup
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    +for x <'a b'
      cmd $x
    EOI
    {{
      +for x <'a b'
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    +for x <'a b c d e'
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      +for x <'a b c d e'
    }}
    EOO
  }}

  : tdown
  :
  {{
    : line
    :
    $* -s <<EOI >>EOO
    -for x <'a b'
      cmd $x
    EOI
    {{
      -for x <'a b'
    }}
    EOO

    : block
    :
    $* -s <<EOI >>EOO
    -for x <'a b c d e'
     {
       if ($x == b)
         continue

       if ($x == d)
         break

       cmd $x
     }
    EOI
    {{
      -for x <'a b c d e'
    }}
    EOO
  }}

  : rcbrace
  :
  {{
    : without-rcbrace
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      cmd
    EOI
    testscript:4:1: error: expected '}' at the end of 'for'
    EOE
  }}

  : elif
  :
  {{
    : without-if
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      elif true
        cmd
    }
    EOI
    testscript:3:3: error: 'elif' without preceding 'if'
    EOE
  }}

  : continue
  :
  {
    $* -l -r <<EOI >>EOO
    for -w x <'a b'     # 1
    {
      cmd1              # 2
      continue
      cmd2              # 3
    };
    cmd3                # 4
    EOI
    for -w x <'a b' # 1
    cmd3 # 4
    EOO
  }

  : break
  :
  {
    $* -l -r <<EOI >>EOO
    for -w x <'a b'     # 1
    {
      cmd1              # 2
      break
      cmd2              # 3
    };
    cmd3                # 4
    EOI
    for -w x <'a b' # 1
    cmd3 # 4
    EOO
  }

  : nested
  :
  {
    $* -l -r <<EOI >>EOO
    for -w x <'a b c d'     # 1
    {
      cmd1 $x               # 2
      if ($x == "a")        # 3
      {
        cmd2                # 4
        for -w y <'x y'     # 5
          cmd3              # 6
      }
      else
        cmd4                # 7
      cmd5                  # 8

      if ($x == "c")        # 9
        continue

      if ($x == "d")        # 10
        break
    };
    cmd6                    # 11
    EOI
    for -w x <'a b c d' # 1
    cmd6 # 11
    EOO
  }

  : contained
  :
  {{
    : semi
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      cmd;
      cmd
    }
    EOI
    testscript:3:6: error: ';' inside 'for'
    EOE

    : colon-leading
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      : foo
      cmd
    }
    EOI
    testscript:3:3: error: description inside 'for'
    EOE

    : colon-trailing
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      cmd : foo
    }
    EOI
    testscript:3:7: error: description inside 'for'
    EOE

    : eos
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    EOI
    testscript:2:1: error: expected command instead of <end of file> inside 'for'
    EOE

    : scope
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
    {
      cmd
      {
      }
    }
    EOI
    testscript:4:3: error: expected command instead of '{' inside 'for'
    EOE

    : setup
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
      +cmd
    EOI
    testscript:2:3: error: setup command inside 'for'
    EOE

    : tdown
    :
    $* <<EOI 2>>EOE != 0
    for x <'a b'
      -cmd
    EOI
    testscript:2:3: error: teardown command inside 'for'
    EOE
  }}

  : leading-and-trailing-description
  :
  $* <<EOI 2>>EOE != 0
  : foo
  for x <'a b'
    cmd : bar
  EOI
  testscript:3:7: error: both leading and trailing descriptions specified
  EOE
}}

: syntax-1
:
{{
  test.options += -v 1

  : form-1
  :
  : for x: ...
  :
  {{
    : for
    :
    {{
      : no-var
      :
      $* <<EOI 2>>EOE != 0
      for
        cmd
      end
      EOI
      testscript:1:1: error: for: missing variable name
      EOE

      : untyped
      :
      $* <<EOI >>EOO
      for x: a b
        cmd $x
      end
      EOI
      cmd a
      cmd b
      EOO

      : null
      :
      $* <<EOI >:''
      for x: [null]
        cmd $x
      end
      EOI

      : empty
      :
      $* <<EOI >:''
      for x:
        cmd $x
      end
      EOI

      : expansion
      :
      $* <<EOI >>EOO
      vs = a b
      for x: $vs
        cmd $x
      end
      EOI
      cmd a
      cmd b
      EOO

      : typed-values
      :
      $* <<EOI >>~%EOO%
      for x: [dir_paths] a b
        cmd $x
      end
      EOI
      %cmd (a/|'a\\')%
      %cmd (b/|'b\\')%
      EOO

      : typed-elem
      :
      $* <<EOI >>~%EOO%
      for x [dir_path]: a b
        cmd $x
      end
      EOI
      %cmd (a/|'a\\')%
      %cmd (b/|'b\\')%
      EOO

      : typed-elem-value
      :
      $* <<EOI >>~%EOO%
      for x [dir_path]: [strings] a b
        cmd $x
      end
      EOI
      %cmd (a/|'a\\')%
      %cmd (b/|'b\\')%
      EOO

      : scope-var
      :
      $* <<EOI >>EOO
      x = x

      for x: a b
        cmd $x
      end

      -cmd $x
      EOI
      cmd a
      cmd b
      -cmd x
      EOO
    }}

    : after-semi
    :
    $* -s <<EOI >>EOO
    cmd1;
    for x: a b
      cmd2 $x
    end
    EOI
    {
      {
        cmd1
        cmd2 a
        cmd2 b
      }
    }
    EOO

    : setup
    :
    $* -s <<EOI >>EOO
    +for x: a b
      cmd $x
    end
    EOI
    {
      +cmd a
      +cmd b
    }
    EOO

    : tdown
    :
    $* -s <<EOI >>EOO
    -for x: a b
      cmd $x
    end
    EOI
    {
      -cmd a
      -cmd b
    }
    EOO

    : end
    :
    {{
      : without-end
      :
      $* <<EOI 2>>EOE != 0
      for x: a b
        cmd
      EOI
      testscript:3:1: error: expected closing 'end'
      EOE
    }}

    : elif
    :
    {{
      : without-if
      :
      $* <<EOI 2>>EOE != 0
      for x: a b
        elif true
          cmd
        end
      end
      EOI
      testscript:2:3: error: 'elif' without preceding 'if'
      EOE
    }}

    : nested
    :
    {
      $* -l -r <<EOI >>EOO
      for x: a b
        cmd1 $x               # 1
        if ($x == "a")        # 2
          cmd2                # 3
          for y: x y
            cmd3              # 4
          end
        else
          cmd4                # 5
        end
        cmd5                  # 6
      end;
      cmd6                    # 7
      EOI
      cmd1 a # 1 i1
      ? true # 2 i1
      cmd2 # 3 i1
      cmd3 # 4 i1 i1
      cmd3 # 4 i1 i2
      cmd5 # 6 i1
      cmd1 b # 1 i2
      ? false # 2 i2
      cmd4 # 5 i2
      cmd5 # 6 i2
      cmd6 # 7
      EOO
    }

    : contained
    :
    {{
      : semi
      :
      $* <<EOI 2>>EOE != 0
      for x:
        cmd;
        cmd
      end
      EOI
      testscript:2:3: error: ';' inside 'for'
      EOE

      : colon-leading
      :
      $* <<EOI 2>>EOE != 0
      for x:
        : foo
        cmd
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : colon-trailing
      :
      $* <<EOI 2>>EOE != 0
      for x:
        cmd : foo
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : eos
      :
      $* <<EOI 2>>EOE != 0
      for x:
      EOI
      testscript:2:1: error: expected closing 'end'
      EOE

      : scope
      :
      $* <<EOI 2>>EOE != 0
      for x:
        cmd
        {
        }
      end
      EOI
      testscript:3:3: error: expected closing 'end'
      EOE

      : setup
      :
      $* <<EOI 2>>EOE != 0
      for x:
        +cmd
      end
      EOI
      testscript:2:3: error: setup command inside 'for'
      EOE

      : tdown
      :
      $* <<EOI 2>>EOE != 0
      for x:
        -cmd
      end
      EOI
      testscript:2:3: error: teardown command inside 'for'
      EOE
    }}

    : var
    :
    $* <<EOI >>EOO
    for x: a b
      cmd1 $x
    end;
    cmd2 $x
    EOI
    cmd1 a
    cmd1 b
    cmd2 b
    EOO

    : leading-and-trailing-description
    :
    $* <<EOI 2>>EOE != 0
    : foo
    for x: a b
      cmd
    end : bar
    EOI
    testscript:4:1: error: both leading and trailing descriptions specified
    EOE
  }}

  : form-2
  :
  : ... | for x
  :
  {{
    : for
    :
    {{
      : status
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x != 0
        cmd
      end
      EOI
      testscript:1:20: error: for-loop exit code cannot be checked
      EOE

      : not-last
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x | echo x
        cmd
      end
      EOI
      testscript:1:20: error: for-loop must be last command in a pipe
      EOE

      : not-last-relex
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x|echo x
        cmd
      end
      EOI
      testscript:1:19: error: for-loop must be last command in a pipe
      EOE

      : expression-after
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x && echo x
        cmd
      end
      EOI
      testscript:1:20: error: command expression involving for-loop
      EOE

      : expression-after-relex
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x&&echo x
        cmd
      end
      EOI
      testscript:1:19: error: command expression involving for-loop
      EOE

      : expression-before
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' && echo x | for x
        cmd
      end
      EOI
      testscript:1:24: error: command expression involving for-loop
      EOE

      : expression-before-relex
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' && echo x|for x
        cmd
      end
      EOI
      testscript:1:22: error: command expression involving for-loop
      EOE

      : cleanup
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x &f
        cmd
      end
      EOI
      testscript:1:20: error: cleanup in for-loop
      EOE

      : cleanup-relex
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x&f
        cmd
      end
      EOI
      testscript:1:19: error: cleanup in for-loop
      EOE

      : stdout-redirect
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x >a
        cmd
      end
      EOI
      testscript:1:20: error: output redirect in for-loop
      EOE

      : stdout-redirect-relex
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x>a
        cmd
      end
      EOI
      testscript:1:19: error: output redirect in for-loop
      EOE

      : stdin-redirect
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x <a
        cmd
      end
      EOI
      testscript:1:20: error: stdin is both piped and redirected
      EOE

      : no-var
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for
        cmd
      end
      EOI
      testscript:1:1: error: for: missing variable name
      EOE

      : untyped
      :
      $* <<EOI >>EOO
      echo 'a b' | for -w x
        cmd $x
      end
      EOI
      echo 'a b' | for -w x
      EOO

      : expansion
      :
      $* <<EOI >>EOO
      vs = a b
      echo $vs | for x
        cmd $x
      end
      EOI
      echo a b | for x
      EOO

      : typed-elem
      :
      $* <<EOI >>EOO
      echo 'a b' | for -w x [dir_path]
        cmd $x
      end
      EOI
      echo 'a b' | for -w x [dir_path]
      EOO
    }}

    : after-semi
    :
    $* -s <<EOI >>EOO
    cmd1;
    echo 'a b' | for x
      cmd2 $x
    end
    EOI
    {
      {
        cmd1
        echo 'a b' | for x
      }
    }
    EOO

    : setup
    :
    $* -s <<EOI >>EOO
    +echo 'a b' | for x
      cmd $x
    end
    EOI
    {
      +echo 'a b' | for x
    }
    EOO

    : tdown
    :
    $* -s <<EOI >>EOO
    -echo 'a b' | for x
      cmd $x
    end
    EOI
    {
      -echo 'a b' | for x
    }
    EOO

    : end
    :
    {{
      : without-end
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        cmd
      EOI
      testscript:3:1: error: expected closing 'end'
      EOE
    }}

    : elif
    :
    {{
      : without-if
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        elif true
          cmd
        end
      end
      EOI
      testscript:2:3: error: 'elif' without preceding 'if'
      EOE
    }}

    : nested
    :
    {
      $* -l -r <<EOI >>EOO
      echo 'a b' | for x      # 1
        cmd1 $x               # 2
        if ($x == "a")        # 3
          cmd2                # 4
          echo x y | for y    # 5
            cmd3              # 6
          end
        else
          cmd4                # 7
        end
        cmd5                  # 8
      end;
      cmd6                    # 9
      EOI
      echo 'a b' | for x # 1
      cmd6 # 9
      EOO
    }

    : contained
    :
    {{
      : semi
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        cmd;
        cmd
      end
      EOI
      testscript:2:3: error: ';' inside 'for'
      EOE

      : colon-leading
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        : foo
        cmd
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : colon-trailing
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        cmd : foo
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : eos
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
      EOI
      testscript:2:1: error: expected closing 'end'
      EOE

      : scope
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        cmd
        {
        }
      end
      EOI
      testscript:3:3: error: expected closing 'end'
      EOE

      : setup
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        +cmd
      end
      EOI
      testscript:2:3: error: setup command inside 'for'
      EOE

      : tdown
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' | for x
        -cmd
      end
      EOI
      testscript:2:3: error: teardown command inside 'for'
      EOE
    }}

    : leading-and-trailing-description
    :
    $* <<EOI 2>>EOE != 0
    : foo
    echo 'a b' | for x
      cmd
    end : bar
    EOI
    testscript:4:1: error: both leading and trailing descriptions specified
    EOE
  }}

  : form-3
  :
  : for x <...
  :
  {{
    : for
    :
    {{
      : status
      :
      $* <<EOI 2>>EOE != 0
      for x <a != 0
        cmd
      end
      EOI
      testscript:1:10: error: for-loop exit code cannot be checked
      EOE

      : not-last
      :
      $* <<EOI 2>>EOE != 0
      for x <a | echo x
        cmd
      end
      EOI
      testscript:1:10: error: for-loop must be last command in a pipe
      EOE

      : not-last-relex
      :
      $* <<EOI 2>>EOE != 0
      for <a x|echo x
        cmd
      end
      EOI
      testscript:1:9: error: for-loop must be last command in a pipe
      EOE

      : expression-after
      :
      $* <<EOI 2>>EOE != 0
      for x <a && echo x
        cmd
      end
      EOI
      testscript:1:10: error: command expression involving for-loop
      EOE

      : expression-after-relex
      :
      $* <<EOI 2>>EOE != 0
      for <a x&&echo x
        cmd
      end
      EOI
      testscript:1:9: error: command expression involving for-loop
      EOE

      : expression-before
      :
      $* <<EOI 2>>EOE != 0
      echo 'a b' && for x <a
        cmd
      end
      EOI
      testscript:1:15: error: command expression involving for-loop
      EOE

      : cleanup
      :
      $* <<EOI 2>>EOE != 0
      for x <a &f
        cmd
      end
      EOI
      testscript:1:10: error: cleanup in for-loop
      EOE

      : cleanup-before-var
      :
      $* <<EOI 2>>EOE != 0
      for &f x <a
        cmd
      end
      EOI
      testscript:1:5: error: cleanup in for-loop
      EOE

      : cleanup-relex
      :
      $* <<EOI 2>>EOE != 0
      for <a x&f
        cmd
      end
      EOI
      testscript:1:9: error: cleanup in for-loop
      EOE

      : stdout-redirect
      :
      $* <<EOI 2>>EOE != 0
      for x >a
        cmd
      end
      EOI
      testscript:1:7: error: output redirect in for-loop
      EOE

      : stdout-redirect-before-var
      :
      $* <<EOI 2>>EOE != 0
      for >a x
        cmd
      end
      EOI
      testscript:1:5: error: output redirect in for-loop
      EOE

      : stdout-redirect-relex
      :
      $* <<EOI 2>>EOE != 0
      for x>a
        cmd
      end
      EOI
      testscript:1:6: error: output redirect in for-loop
      EOE

      : no-var
      :
      $* <<EOI 2>>EOE != 0
      for <a
        cmd
      end
      EOI
      testscript:1:1: error: for: missing variable name
      EOE

      : quoted-opt
      :
      $* <<EOI >>EOO
      o = -w
      for "$o" x <'a b'
        cmd $x
      end;
      for "($o)" x <'a b'
        cmd $x
      end
      EOI
      for -w x <'a b'
      for -w x <'a b'
      EOO

      : untyped
      :
      $* <<EOI >>EOO
      for -w x <'a b'
        cmd $x
      end
      EOI
      for -w x <'a b'
      EOO

      : expansion
      :
      $* <<EOI >>EOO
      vs = a b
      for x <$vs
        cmd $x
      end
      EOI
      for x b <a
      EOO

      : typed-elem
      :
      $* <<EOI >>EOO
      for -w x [dir_path] <'a b'
        cmd $x
      end
      EOI
      for -w x [dir_path] <'a b'
      EOO
    }}

    : after-semi
    :
    $* -s <<EOI >>EOO
    cmd1;
    for x <'a b'
      cmd2 $x
    end
    EOI
    {
      {
        cmd1
        for x <'a b'
      }
    }
    EOO

    : setup
    :
    $* -s <<EOI >>EOO
    +for x <'a b'
      cmd $x
    end
    EOI
    {
      +for x <'a b'
    }
    EOO

    : tdown
    :
    $* -s <<EOI >>EOO
    -for x <'a b'
      cmd $x
    end
    EOI
    {
      -for x <'a b'
    }
    EOO

    : end
    :
    {{
      : without-end
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        cmd
      EOI
      testscript:3:1: error: expected closing 'end'
      EOE
    }}

    : elif
    :
    {{
      : without-if
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        elif true
          cmd
        end
      end
      EOI
      testscript:2:3: error: 'elif' without preceding 'if'
      EOE
    }}

    : nested
    :
    {
      $* -l -r <<EOI >>EOO
      for -w x <'a b'         # 1
        cmd1 $x               # 2
        if ($x == "a")        # 3
          cmd2                # 4
          for -w y <'x y'     # 5
            cmd3              # 6
          end
        else
          cmd4                # 7
        end
        cmd5                  # 8
      end;
      cmd6                    # 9
      EOI
      for -w x <'a b' # 1
      cmd6 # 9
      EOO
    }

    : contained
    :
    {{
      : semi
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        cmd;
        cmd
      end
      EOI
      testscript:2:3: error: ';' inside 'for'
      EOE

      : colon-leading
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        : foo
        cmd
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : colon-trailing
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        cmd : foo
      end
      EOI
      testscript:2:3: error: description inside 'for'
      EOE

      : eos
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
      EOI
      testscript:2:1: error: expected closing 'end'
      EOE

      : scope
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        cmd
        {
        }
      end
      EOI
      testscript:3:3: error: expected closing 'end'
      EOE

      : setup
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        +cmd
      end
      EOI
      testscript:2:3: error: setup command inside 'for'
      EOE

      : tdown
      :
      $* <<EOI 2>>EOE != 0
      for x <'a b'
        -cmd
      end
      EOI
      testscript:2:3: error: teardown command inside 'for'
      EOE
    }}

    : leading-and-trailing-description
    :
    $* <<EOI 2>>EOE != 0
    : foo
    for x <'a b'
      cmd
    end : bar
    EOI
    testscript:4:1: error: both leading and trailing descriptions specified
    EOE
  }}
}}
