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
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.
String concatenation
Adjacent strings are concatenated implicitly, or explicitly by using the +
operator. All 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";
Concatenation works with literal strings, as well as headers and variables (including non-string types):
set var.string_variable = "Hello " + req.http.cookie:user_name + " you are number " + var.int_variable;
Conditional operators
Logical AND and OR operators (&&
and ||
respectively) are defined for conditional expressions.
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.
Conditional expressions may be inverted by prefixing the !
operator.
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}
Comparison operators
The comparison operators are:
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(?:/?.*)\z" | 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; |
%= | Remainder | 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); |
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.
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
, shifting off the highest three bits.
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
, shifting off the lowest three bits. 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
.
The remainder operator %=
performs the same function as a modulus operator for positive numbers.
For right operands larger than the bit width of INTEGER (64), shifts will yield zero for non-negative numbers, or -1 for negative numbers. 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 is 35.
Logical AND and OR are provided in assignment form by the &&=
and ||=
operators respectively. These are short-circuit operators, see conditional operators above.
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: *
&
|
>>
<<
++
--
%