How comes `if (Test-Path...)` actually works?

powershell, syntax

Solution

Referring to C.2.2 from Appendix C: The PowerShell grammar in Bruce Payette's Windows PowerShell in Action, we have:

<ifStatementRule> =
  'if' '(' <pipelineRule> ')' <statementBlockRule>
  [ 'elseif' '(' <pipelineRule> ')' <statementBlockRule> ]*
  [ 'else' <statementBlockRule> ]{0|1}

This indicates the `(` and `)` tokens as part of the literal syntax for recognizing an `if` statement, and that the `<test>` from the `about_If` documentation refers to a pipeline that will be resolved to a Boolean.

Following the pipeline rules, we find:

- `Test-Path ...` parses to a `<cmdletCall>` of `<name> <parameterArgumentToken>`,

- `!Test-Path ...` results in an `<expressionRule>` of `<UnaryOperatorToken> <propertyOrArrayReferenceRule>`, which fails when the cmdlet call cannot match the simple property or array rule, whereas

- `!(Test-Path ...)` is able to match the parenthesized cmdlet call as a sub-expression.

Edit: See also PowerShell 2.0 Language Specification (thanks to Roman's answer to another question).

Problem

In PowerShell, syntax for `if` is as so: ``` if (<test1>) {<statement list 1>} [elseif (<test2>) {<statement list 2>}] [else {<statement list 3>}] ``` Another syntax rule is that for subexpressions, you need to use parentheses like this: ``` write-output (get-date) ``` So with these two rules combined, I would expect that the test for some path needs to be written with two sets of parentheses like this: ``` if ((Test-Path ...)) { # do something } ``` However, this also works: ``` if (Test-Path ...) { # do something } ``` and just for the sake of completeness, this doesn't work: ``` if (!Test-Path ...) { # do something } ``` (here, you would need to wrap the subexpression in parenthesis as usual). Can anyone explain the syntax rules that apply here and how comes that I can use the IF test with one parenthesis only? Is it some PowerShell magic or am I misunderstanding the basic syntax rules?

Original source