# Scalar Functions and Operators

Scanner supports some functions and operators for scalar evaluation, i.e. direct evaluation of values. These are most commonly used in the [`eval` function](https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/querying-and-analysis/aggregation-functions/eval) in the pipeline, and in [detection alert templates](https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-alert-formatting).

In general, scalar operators and functions are meant to be used with particular types of inputs (e.g. arithmetic operators are intended to be used with numbers). If any of the inputs are of an incorrect type, the operation returns `null` instead.

## Basic Syntax

Operators are standard unary or infix arithmetic and logical operators. Numbers are expressed as-is. Strings are delimited by double-quotes.

```python
1 + 1 # => 2
-(2 * 3) # => -6
true and false # => false
not true # => false
"foo" # => "foo"
```

Scope values (i.e. column names) can be referenced using backticks, or using bare (i.e. unquoted) strings. Bare strings must start with a letter or `$@%*_` character, and can only contain letters, digits, and `._*[]@%`. `@` and `%` may only appear at the start or immediately after `.` (e.g. `@foo`, `bar.%baz`). Bare strings also can't be any reserved keywords (see [#reserved-keywords](#reserved-keywords "mention")).

```python
# returns one fewer than the number of fenceposts
number_of_fenceposts - 1

# returns true iff a cat named Biscuit
`animal:species` == "cat" and name == "Biscuit"
```

Parentheses may be used to explicitly specify precedence:

```python
(1 + 2) * 3 # => 9
(true or false) and false # => false
```

Infix operators must be separated from their operands with spaces. E.g.:

```python
# Reads a value called `total_count` and subtracts 1 from it
total_count - 1
# Reads a value called `us_west-1` and doesn't subtract anything
`us_west-1`
```

Values are not implicitly cast to other types. Any operand that is the wrong type results in a null value. E.g. all of the following return `null`:

```python
not 1
true and "false"
"cat" + "dog"
```

We support the following infix operators in scalar evaluation contexts:

<table><thead><tr><th width="84.8046875">Operator</th><th width="149.42578125">Name</th><th>Behavior</th></tr></thead><tbody><tr><td><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code></td><td>Infix Arithmetic</td><td><p>If <code>a</code> and <code>b</code> are both numbers, then this returns the result of that arithmetic operation, e.g. <code>a + b</code> returns the sum of <code>a</code> and <code>b</code>.</p><p>If <code>a</code> and <code>b</code>are <em>not</em> both numbers, this returns <code>null</code>.</p></td></tr><tr><td><code>==</code>, <code>!=</code></td><td>Equality</td><td><code>a == b</code> returns <code>true</code> if <code>a</code> and <code>b</code> are value-equal, and <code>false</code> otherwise. <code>!=</code> returns the inverse.</td></tr><tr><td><code>&#x3C;</code>, <code>></code>, <code>&#x3C;=</code>, <code>>=</code></td><td>Ordered Comparison</td><td><p>This returns a truth value based on the ordering.</p><p>If <code>a</code>and <code>b</code>are both strings, then this performs a lexical (i.e. alphabetical) comparison. E.g. <code>"abc" &#x3C; "bbc"</code> would be <code>true</code>.<br>If <code>a</code> and <code>b</code> are both numbers, then this performs a numerical comparison. E.g. <code>1 >= 1</code> would be <code>true</code>.<br>Otherwise, this returns <code>null</code>.</p></td></tr><tr><td><code>and</code></td><td>Logical And</td><td><code>a and b</code> returns <code>true</code> if <code>a</code> and <code>b</code> are both true boolean values, <code>false</code> if <code>a</code> and <code>b</code> are boolean but not true, and <code>null</code> otherwise.</td></tr><tr><td><code>or</code></td><td>Logical Or</td><td><code>a or b</code> returns <code>true</code> if <code>a</code> and <code>b</code> are both boolean values and either is <code>true</code>, <code>false</code> if <code>a</code> and <code>b</code> are boolean but both not <code>true</code>, and <code>null</code> otherwise.</td></tr><tr><td><code>-</code></td><td>Unary Negation</td><td><code>-a</code> returns the arithmetic negation of <code>a</code>if it is a number. Otherwise, it returns <code>null</code>.</td></tr><tr><td><code>not</code></td><td>Logical Not</td><td><code>not a</code> returns the logical negation of <code>a</code> if it is a boolean value. I.e. it returns <code>true</code> if <code>a</code> is <code>false</code> and <code>false</code> if <code>a</code> is <code>true</code>. Otherwise, it returns <code>null</code>.</td></tr></tbody></table>

Operator precedence is, in descending order:

* all unary operators
* `*` `/`
* `+` `-`
* `<` `>` `<=` `>=` `==` `!=`
* `and`
* `or`

All operators are left-associative.

## Scalar Functions

Scalar functions are invoked with the parentheses `()`. As is standard, arguments can be passed, and are delimited by commas `,`.

```python
# Computes the closest whole-number number of seconds
math.round(elapsed_ms / 1000)

# Resolves to a different string value based on the http status
if(`http.status` == 200, "OK", "Something went wrong")
```

See individual function documentation for more details.

## Regex Literals

Regular expression literals are patterns enclosed by `/` characters:

```javascript
regex.is_match("abc", /ab?c*/); // => true
```

To include a literal `/` in the pattern, escape it with a backslash:

```javascript
regex.extract("url/path/page.html", /url\/path\/(.*)/, 1); // => "page.html"
```

Regex literals support flags, which are appended after the closing `/`:

```javascript
// Case-insensitive match
regex.is_match("ABC", /abc/i); // => true

// Multi-line mode
regex.extract(message, /^error:(.*)$/m, 1);
```

The following flags are supported:

* `i` - case-insensitive: letters match both upper and lower case
* `m` - multi-line mode: `^` and `$` match begin/end of line
* `s` - allow `.` to match `\n`
* `R` - enables CRLF mode: when multi-line mode is enabled, `\r\n` is used
* `U` - swap the meaning of `x*` and `x*?`
* `x` - verbose mode: ignore whitespace and allow line comments (starting with `#`)

For more information about supported regular expression syntax, refer to the [`regex` library](https://docs.rs/regex/latest/regex/#syntax) which provides the execution engine currently in use.

### Reserved Keywords

The following keywords are reserved in scalar expressions: `null` , `false`, `true`, `as`, `by`, `from`, `in`, `and`, `or`, `not`, `let`. Use backticks if you need to reference columns or values with those names.
