Patterns

Patterns are used to bind values to variables, and as 'conditions' in match-expressions. Patterns match a set of values, and bind (essentially assigns) a set of partial values to variables.

Name patterns

The simplest pattern is a variable name, like x. It matches all values, and binds the value to the name, x in this case.

Literal patterns

Integers and booleans can be matched on literals of their type. For example, true only matches booleans that are true and 10 only matches integers whose value is 10. Literal patterns do not bind any variables.

Tuple patterns

Another simple pattern is the tuple-pattern. It matches tuples of a specific length, and binds all elements of the tuples to sub-patterns. All patterns can be nested

For example

let ((a, b), c) = ((1, 2), 3);

will result in a=1, b=2 and c=3.

If parts of a tuple pattern are conditional, the pattern will only match if the subpatterns do. For example,

match (x, y) {
    (true, _) => true,
    _ => false,
}

will only return true if x is true, and false otherwise

Struct and enum patterns

Named patterns are used to match structs and enum variants. They consist of the name of the type or variant, followed by an argument list if the type has arguments.

Argument lists can be positional: () or named: $(). In a positional argument list, the fields of the type are matched based on the order of the fields. In a named list, patterns are instead bound by name, either field_name: pattern or just field_name which binds a new local variable field_name to field. Argument matching in patterns works the same way as in argument lists during instantiation

This is best shown by examples

struct S {
    x: int<8>,
    y: int<8>,
}

// Positional pattern, binds `a` to the value of `x` and `b` to the value of `y`
S(a, b)
// Named pattern with no shorthand. The whole pattern matches if the `y` field is `0`
// in which case `a` will be bound to the value of `x`
S$(y: 0, x: a)
// Shorthand named. This binds a local variable `y` to the value of the field `y`. The field `x` is ignored.
S$(y, x: _)

enum variants work the same way, but only match the enum of the specified name. For example

enum E {
    A,
    B{val: int<8>}
}

match e {
    E::A => {},
    E::B(0) => {},
    E::B(val) => {}
}

Wildcard

The wildcard pattern _. It matches all values but does not bind the value to any variable. It is useful as a catch-all in match blocks

For example, if we want to do something special for 0 and 1, but don't care about other values we might write:

match integer {
    0 => {},
    1 => {},
    _ => {}
}