# Operators

Last updated January 12, 2018

Fastly's VCL provides various arithmetic and conditional operators. Operators are syntactic items which evaluate to a value. Syntax is given in a BNF-like form with the following conventions:

- [ … ] Square brackets enclose an optional item,
- "!" Literal spellings (typically punctuation) are indicated in quotes,
- CNUM Lexical terminals are given in uppercase,
- INTEGER Types are also given in uppercase,
- numeric-expr Grammatical productions are given in lowercase.

Where a binary operator is provided, not all types are implemented on either side. This is a limitation of the current implementation. The following placeholder grammatical clauses are used in this document to indicate which types are valid operands. These are not precisely defined until the grammar has been formally specified, and are intended as a guide for operator context only.

- variable - A variable name
- acl - An ACL name
- expr - An expression of any type
- numeric-expr - An expression evaluating to INTEGER, FLOAT, RTIME, or another numeric type
- time-expr - An expression evaluating to TIME
- assignment-expr - An expression suitable for assignment to a variable by
`set`

- conditional-expr - An expression evaluating to BOOL suitable for use with
`if`

conditions - string-expr - An expression evaluating to STRING
- CNUM - An INTEGER literal

## Operator precedence

Operator precedence defines the *order of operations* when evaluating an expression.
Higher precedence operators are evaluated before those with lower precedence.
Operators are listed in the following table as the highest precedence first.
For example, `a || b && c`

reads as `a || (b && c)`

because `&&`

has higher precedence than `||`

.

Operator *associativity* determines which side binds first for multiple
instances of the same operator at equal precedence.
For example, `a && b && c`

reads as `(a && b) && c`

because `&&`

has left to right associativity.

Operator | Name | Associativity |
---|---|---|

`(` `)` |
Grouping for precedence | left to right |

`!` |
Boolean NOT | right to left |

`&&` |
Boolean AND | left to right |

`||` |
Boolean OR | left to right |

## Negation

Numeric literals may be negated by prefixing the `-`

unary operator.
This operator may only be applied to literals, and not to numeric
values in other contexts.

1
2

:= [ "-" ] CNUM
| [ "-" ] CNUM "." [ CNUM ]

## String concatenation

Adjacent strings are concatenated implicitly,
but may also be concatenated explicitly by the `+`

operator:

1
2

:= string-expr string-expr
| string-expr "+" _string-expr

For example, `"abc" "def"`

is equivalent to `"abcdef"`

.

## Assignment and arithmetic operators

The `set`

syntax is the only situation in which these operators may be used.
Since the operator may only occur once in a `set`

statement, these operators
are mutually exclusive, so precedence between them is nonsensical.

The values the operators produce are used for assignment only.
The `set`

statement assigns this value to a variable,
but does not itself evaluate to a value.

FLOAT arithmetic has special cases for operands which are NaN: Arithmetic operators evaluate to NaN when either operand is NaN.

FLOAT arithmetic has special cases for operands which are floating point infinities:
In general all arithmetic operations evaluate to positive or negative infinity
when either operand is infinity.
However some situations evaluate to NaN instead.
Some of these situations are *domain errors*, in which case `fastly.error`

is set to `"EDOM"`

accordingly.
Others situations are not domain errors: ∞ − ∞ and 0 × ∞.
These evaluate to NaN but do not set `fastly.error`

.

### Assignment

Assignment is provided by the `=`

operator:

1

:= "set" variable "=" assignment-expr ";"

### Addition and subtraction

Addition and subtraction are provided by the `+=`

and `-=`

operators
respectively:

1
2

:= "set" variable "+=" assignment-expr ";"
| "set" variable "-=" assignment-expr ";"

### Multiplication, division and modulus

Multiplication, division and modulus are provided by the `*=`

, `/=`

and `%=`

operators respectively:

1
2
3

:= "set" variable "*=" assignment-expr ";"
| "set" variable "/=" assignment-expr ";"
| "set" variable "%=" assignment-expr ";"

### Bitwise operators

1
2
3
4
5
6
7

:= "set" variable "|=" assignment-expr ";"
| "set" variable "&=" assignment-expr ";"
| "set" variable "^=" assignment-expr ";"
| "set" variable ">>=" assignment-expr ";"
| "set" variable "<<=" assignment-expr ";"
| "set" variable "ror=" assignment-expr ";"
| "set" variable "rol=" assignment-expr ";"

Right shifts sign-extend negative numbers. For example, `-32 >> 5`

gives -1.

Shift and rotate operations with negative shift widths perform the operation in
the opposite direction. For example, `32 << -5`

gives 1. For right operands
larger than the width of `INTEGER`

, shifts will yield zero or -1 and rotates
will use the operand modulo the width of `INTEGER`

.

### Logical operators

Logical AND and OR operators are provided by the `&&=`

and `||=`

operators
respectively:

1
2

:= "set" variable "&&=" assignment-expr ";"
| "set" variable "||=" assignment-expr ";"

These are *short-circuit* operators; see below.

## Conditional operators

Conditional operators produce BOOL values, suitable for use in `if`

statement conditions.

### Logical operators

Conditional expressions may be inverted by prefixing the `!`

operator:

1

:= "!" conditional-expr

Boolean AND and OR operators (`&&`

and `||`

respectively)
are defined for conditional expressions:

1
2

:= conditional-expr "&&" conditional-expr
| conditional-expr "||" conditional-expr

These boolean operators have *short-circuit* evaluation, whereby the right-hand operand
is only evaluated when necessary in order to compute the resulting value.
For example, given `a && b`

when the left-hand operand is false, the resulting value
will always be false, regardless of the value of the right-hand operand.
So in this situation, the right-hand operand will not be evaluated.
This can be seen when the right-hand operand has a visible side effect,
such as a call to a function which performs some action.

### Comparison operators

FLOAT comparisons have special cases for operands which are NaN:
The `!=`

operator always evaluates to true when either operand is NaN.
All other conditional operators always evaluate to false when either
operand is NaN.
For example, if a given variable is NaN, that variable will compare
unequal to itself:
both `var.nan == var.nan`

and `var.nan >= var.nan`

will be false.

STRING comparisons have special cases for operands which are not set (as opposed to empty):
The `!=`

and `!~`

operators always evaluate to true when either operand is not set.
All other conditional operators always evaluate to false when either
operand is not set.
For example, if a given variable is not set, that variable will compare
unequal to itself:
both `req.http.unset == req.http.unset`

and `req.http.unset ~ ".?"`

will be false.

Floating point infinities are signed, and compare as beyond the maximum and minimum values for FLOAT types, such that for any finite value: −∞ < n < +∞

The comparison operators are:

1
2
3

lg-op := "<" | ">" | "<=" | ">="
eq-op := "==" | "!="
re-op := "~" | "!~"

Equality is defined for all types:

1

:= expr eq-op expr

Inequalities are defined for numeric types and TIME:

1
2

:= numeric-expr lg-op numeric-expr
| time-expr lg-op time-expr

Note that as there are currently no numeric expressions in general;
these operators are limited to use with specific operands.
For example, `var.i < 5`

is permitted but `2 < 5`

is not.

Regular expression conditional operators are defined for STRING types and ACLs only:

1
2

:= string-expr re-op STRING
| acl re-op STRING

The right-hand operand must be a literal string (regular expressions cannot be constructed dynamically).

## Reserved punctuation

Punctuation appears in various syntactic roles which are not operators (that is, they do not produce a value).

Punctuation | Example Uses |
---|---|

`{` `}` |
Block syntax |

`[` `]` |
Stats ranges |

`(` `)` |
Syntax around if conditions, function argument lists |

`/` |
Netmasks for ACLs |

`,` |
Separator for function arguments |

`;` |
Separator for statements and various other syntactic things |

`!` |
Invert ACL entry |

`.` |
To prefix fields in backend declarations |

`:` |
Port numbers for backend declarations, and used in the stats syntax |

The following lexical tokens are reserved, but not used:
`*`

`&`

`|`

`>>`

`<<`

`++`

`--`

`%`