# Operators

Fastly VCL provides various arithmetic and conditional operators.

## 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, 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 |

**HINT:** use explicit parentheses in expressions to avoid having to remember operator precedence rules.

## Negation

`-`

is a unary operator, which can be prefixed to numeric literals (numbers) to make them negative, e.g. `-4`

, `-87.3`

.

## String concatenation

Adjacent strings are concatenated implicitly, or explicitly by using the `+`

operator. Both of the following lines of code achieve the same result:

`set req.http.some-header = "helloworld";set req.http.some-header = "hello" "world";set req.http.some-header = "hello" + "world";`

## Conditional operators

Conditional operators produce `BOOL`

values, suitable for use in `if (...)`

statements:

`if (!(beresp.status >= 500 && beresp.status < 600)) { # ... the response is not an HTTP 5XX status}`

Conditional expressions may be inverted by prefixing the `!`

operator, and combined using AND and OR operators (`&&`

and `||`

respectively).

**WARNING:** Logical operators have *short-circuit* evaluation, whereby the right-hand side is only evaluated when necessary. For example, given `a && b`

, if `a`

is false the resulting value will always be false, so there's no need to evaluate `b`

. This can be important when the right-hand operand has a visible side effect, such as a call to a function.

The following operators are valid for comparisons:

Operator | Purpose | Example | Types |
---|---|---|---|

`==` | Equal | `resp.status == 200` (note there is no `===` in VCL) | All types |

`!=` | Not equal | `req.url.path != "/"` | All types |

`~` | Matches regex | `req.url ~ "^/products(/?.*)$"` | `STRING` |

`~` | Matches ACL | `client.ip ~ allowed_users` | `IP` |

`!~` | Does not match regex | `req.http.cookie:optin !~ "ads"` | `STRING` |

`!~` | Does not match ACL | `client.ip !~ blocked_users` | `IP` |

`>` | Greater than | `req.restarts > 0` | Numeric types and `TIME` |

`<` | Less than | `now < var.expiry_time` | Numeric types and `TIME` |

`>=` | At least | `resp.status >= 500` | Numeric types and `TIME` |

`<=` | At most | `randomint(1,100) <= 75` | Numeric types and `TIME` |

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 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 < +∞`

.

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.

## Assignment operators

These operators allow values or the results of expressions to be assigned to a variable using the `set`

statement.

Operator | Purpose | Example |
---|---|---|

`=` | Simple assignment | `set var.my_string = "42";` |

`+=` | Addition | `set var.my_integer += 4;` |

`-=` | Subtraction | `set var.my_integer -= 4;` |

`*=` | Multiplication | `set var.my_integer *= 4;` |

`/=` | Division | `set var.my_integer /= 4;` |

`%=` | Modulus | `set var.my_integer %= 4;` |

`|=` | Bitwise OR | `set var.my_integer |= 16;` |

`&=` | Bitwise AND | `set var.my_integer &= 65280;` |

`^=` | Bitwise XOR | `set var.my_integer ^= 16;` |

`<<=` | Left shift | `set var.my_integer <<= 4;` |

`>>=` | Right shift | `set var.my_integer >>= 4;` |

`rol=` | Left rotate | `set var.my_integer rol= 4;` |

`ror=` | Right rotate | `set var.my_integer ror= 4;` |

`&&=` | Logical AND | `set var.my_boolean &&= var.is_authenticated;` |

`||=` | Logical OR | `set var.my_boolean ||= randombool(1,3);` |

If both operands (left-hand side and right-hand-side) are `INTEGER`

, an `INTEGER`

variant of the operator, where available, is used. The advantage of this is that the operation is faster and more precise (compared with `FLOAT`

variants), but because the range of `INTEGER`

is more limited, overflows can happen. For example, the integer variants of the `+=`

, `-=`

, and `*=`

operators wrap around as if they were unsigned 64-bit integers.

`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. 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`

.

The left-shift `<<=`

is equivalent to multiplying by powers of two, but the high-order bits disappearing. For example, `<<= 3`

is equivalent to multiplying by `8`

, but the highest three bits will disappear.

The right-shift `>>=`

is the arithmetic shift: that is, for both positive and negative integers it is equivalent to dividing by powers of two. For example, `>>= 3`

is equivalent to dividing by `8`

, but the lowest three bits will disappear. For negative integers this is also known as sign-extension: at the binary level, the sign bit (the highest bit) is copied to all the vacant bits.

The left-rotate `rol=`

moves the bits towards the high end but the bits dropping off from the high end are rotated back to the low end. For example, `rol= 1`

moves the highest bit to the low end, and moves all the other bits up.

The right-rotate `ror=`

moves the bits towards the low end but the bits dropping off the low end are rotated back to the high end. For example, `ror= 1`

moves the lowest bit to the high end, and moves all the other bits down.

Shift and rotate operations with negative amounts perform the operation in the opposite direction. For example, `<<= -3`

is equivalent to `>>= 3`

, and `rol= >> -3`

is equivalent to `ror= 3`

.

For right operands larger than the bit width of INTEGER (64), shifts will yield zero for non-negative numbers, or -1 for negative numbers, and rotates will use the operand modulo the bit width of INTEGER. For example, `>>= 99`

will yield zero or -1, and `ror= 99`

is equivalent to `ror= 35`

because `99 % 64 == 35`

.

## 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: `*`

`&`

`|`

`>>`

`<<`

`++`

`--`

`%`