/ Specification
Playground Docs Performance GitHub
Chapter 9

Pattern Matching

Lattice provides pattern matching through the match expression, which compares a value against a series of patterns and executes the body of the first matching arm.

Match Expression

match_expr  ::= "match" expression "{" { match_arm } "}"
match_arm   ::= [ phase_qual ] pattern [ "if" expression ] "=>" ( expression | block )

The match expression evaluates the subject expression once, then tests each arm's pattern in order. The first pattern that matches (and whose optional guard is true) has its body evaluated. The result of the match expression is the value of the matched arm's body.

let result = match x {
    0 => "zero",
    1 => "one",
    n if n < 0 => "negative",
    _ => "other"
}

Pattern Types

Lattice supports four types of patterns:

Literal Patterns

literal_pattern  ::= int_literal | ["-"] int_literal
                 |   float_literal | ["-"] float_literal
                 |   string_literal
                 |   "true" | "false" | "nil"

A literal pattern matches when the subject value equals the literal. Integer, float, string, boolean, and nil literals are supported. Negative numbers are written as -42 or -3.14.

match status {
    200 => "OK",
    404 => "Not Found",
    500 => "Server Error",
    _ => "Unknown"
}

Wildcard Pattern

wildcard_pattern  ::= "_"

The wildcard _ matches any value and discards it. It is typically used as the last arm to handle all remaining cases.

Binding Patterns

binding_pattern  ::= identifier

A binding pattern matches any value and binds it to the identifier within the arm's body. This allows the matched value to be used in the arm's expression or block.

match x {
    n if n > 0 => print("positive: ${n}"),
    n => print("non-positive: ${n}")
}

Range Patterns

range_pattern  ::= int_literal ".." int_literal

A range pattern matches integer values within the half-open range [start, end).

match score {
    90..101 => "A",
    80..90 => "B",
    70..80 => "C",
    60..70 => "D",
    _ => "F"
}

Guard Clauses

Any match arm may include a guard clause with the if keyword. The guard expression is evaluated after the pattern matches; if the guard evaluates to false, the arm is skipped and the next arm is tried.

match value {
    n if n % 2 == 0 => "even",
    n if n % 2 == 1 => "odd",
    _ => "unknown"
}

Phase Qualifiers

Match arms can be qualified with fluid or crystal to match only values in the specified phase. This enables phase-dependent behavior:

match data {
    fluid x => {
        print("mutable: ${x}")
    },
    crystal x => {
        print("frozen: ${x}")
    }
}

Exhaustiveness

Lattice does not enforce exhaustive pattern matching at parse time. If no arm matches at runtime, the match expression evaluates to nil. For safety, always include a wildcard _ or binding pattern as the final arm.

Note Match arms are tested in order. Place more specific patterns before general ones to ensure correct behavior.