Last updated January 12, 2018
Fastly 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
- conditional-expr - An expression evaluating to BOOL suitable for use with
- string-expr - An expression evaluating to STRING
- CNUM - An INTEGER literal
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.
||Grouping for precedence||left to right|
||Boolean NOT||right to left|
||Boolean AND||left to right|
||Boolean OR||left to right|
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 ]
Adjacent strings are concatenated implicitly, but may also be concatenated explicitly by the
1 2 := string-expr string-expr | string-expr "+" _string-expr
"abc" "def" is equivalent to
Assignment and arithmetic operators
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
Assignment is provided by the
1 := "set" variable "=" assignment-expr ";"
Addition and subtraction
Addition and subtraction are provided by the
-= operators respectively:
1 2 := "set" variable "+=" assignment-expr ";" | "set" variable "-=" assignment-expr ";"
Multiplication, division and modulus
Multiplication, division and modulus are provided by the
%= operators respectively:
1 2 3 := "set" variable "*=" assignment-expr ";" | "set" variable "/=" assignment-expr ";" | "set" variable "%=" assignment-expr ";"
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
Logical AND and OR operators are provided by the
||= operators respectively:
1 2 := "set" variable "&&=" assignment-expr ";" | "set" variable "||=" assignment-expr ";"
These are short-circuit operators; see below.
Conditional operators produce BOOL values, suitable for use in
if statement conditions.
Conditional expressions may be inverted by prefixing the
1 := "!" conditional-expr
Boolean AND and OR operators (
|| 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.
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
!~ 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).
Punctuation appears in various syntactic roles which are not operators (that is, they do not produce a value).
||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: