# Language: Boolean Expressions

Boolean expressions are expressions that evaluate to a boolean value from the result of a combination of one or more comparisons and logical operators. Boolean expressions form the basis of policy since policy can be broken down to a set of logical decisions that turn into true or false.

A single boolean expression is the body of a rule. Additionally, boolean expressions are used with conditionals, and more.

## Order of Operations

The precedence of operators is shown below. Operators with higher precedence values (larger numbers) are evaluated first. Operators with the same precedence value are evaluated left-to-right.

```
Precedence Operator
6 * / %
5 + -
4 else
3 == != < <= > >= "is" "is not" "matches" "contains" "in"
2 and
1 or xor
```

Examples of this precedence are shown below:

```
4 * 5 / 5 // 4
4 * 5 + 2 // 22
4 + 5 * 2 // 14
```

## Logical Operators

Logical operators are used to change or combine logical expressions.
There are three binary operators `and`

, `or`

, and `xor`

. There is
a single unary operator `not`

(which can also be specified as `!`

).

The binary operators require two boolean operands and the unary operator requires a single boolean operand. In both case, the operands are values or expressions that are boolean types.

Below is a basic explanation of the logical operators directly from the specification:

```
and conditional AND p and q is "if p then q else false"
or conditional OR p or q is "if p then true else q"
xor conditional XOR p xor q is "if p and not q or not p and q then true"
! NOT !p is "not p"
not NOT !p is "not p"
```

Using parentheses to group boolean expressions, you can combine boolean expressions to become more complex or affect ordering:

```
(p and q) or r
p and (q or r)
```

## Comparison Operators

Comparison operators compare two operands and yield a boolean value.

For any comparison, the two operands must be equivalent types. The one exception are integers and floats. When an integer is compared with a float, the integer is promoted to a floating point value.

The available comparison operators are:

```
== equal
!= not equal
< less
<= less or equal
> greater
>= greater or equal
"is" equal
"is not" not equal
```

The behavior of `is`

with `==`

and `is not`

with `!=`

is identical.

Example comparisons:

```
name is "Mitchell"
idnumber > 42
idnumber <= 12
```

Using the logical operators, these can be combined:

```
name is "Mitchell" and idnumber > 42
```

The language specification provides more detail on exactly how comparison behaves.

## Set Operators

The set operators `contains`

and `in`

test for inclusion in a collection
(a list or map).

Set operators may be negated by prefixing the operator with `not`

, such
as `not contains`

and `not in`

. This is equivalent to wrapping the expression
in a unary `not`

but results in a more readable form.

`contains`

tests if the left-hand collection contains the right-hand value.
`in`

tests if the right-hand collection contains the left-hand value. For
maps, "contains" looks at the keys, not the values.

Examples:

```
[1, 2, 3] contains 2 // true
[1, 2, 3] contains 5 // false
[1, 2, 3] contains "value" // false
[1, 2, 3] not contains "value" // true
{ "a": 1, "b": 2 } contains "a" // true
{ "a": 1, "b": 2 } contains "c" // false
{ "a": 1, "b": 2 } contains 2 // false
{ "a": 1, "b": 2 } not contains 2 // true
```

## Matches Operator

The `matches`

operator tests if a string matches a regular expression.
The `matches`

operator can be negated by prefixing the operator with
`not`

, such as `not matches`

.

The left-hand value is the string to test. The right-hand value is a string value representing a regular expression. The syntax of the regular expression is the same general syntax used by Python, Ruby, and other languages. The precise syntax accepted is the syntax accepted by RE2.

Regular expressions are not anchored by default; any anchoring must be explicitly specified.

```
"test" matches "e" // true
"test" matches "^e" // false
"TEST" matches "test" // false
"TEST" matches "(?i)test" // true
"ABC123" matches "[A-Z]+\\d+" // true
"test" not matches "e" // false
```

## Any, All Expressions

`any`

and `all`

expressions allow testing that any or all elements of a
collection match some boolean expression. The result of an `any`

and `all`

expression is a boolean.

`any`

returns the boolean value `true`

if any value in the collection expression
results in the body expression evaluating to `true`

. If the body expression
evalutes to `false`

for all values, the any expression returns `false`

.

`all`

returns the boolean `true`

if all values in the collection expression
result in the body expression evaluating to `true`

. If any value in the
collection expression result in the body expression evaluating to `false`

,
the `all`

expression returns `false`

.

For empty collections, `any`

returns `false`

and `all`

returns `true`

.

```
all group.tasks as t { t.driver is "vmware" }
any group.tasks as t { t.driver is "vmware" }
```

Since `any`

and `all`

expressions are themselves boolean expressions, they
can be combined with other operators:

```
any ["a", "b"] as char { char is "a" } or
other_value is "another"
```