Skip to content

Syntax reference

This page collects Pluvial’s surface syntax. For explanations, follow the links into the language guide.

# line comment to end of line
auto x = 1 # trailing comment
## doc comment — attaches to the declaration below it
def f() {}
42 # int
3.14 # float
true false # bool
"text" # string
null # absence (for nullable types)
[1, 2, 3] # array literal
{"a": 1, "b": 2} # map literal
(1, "hello") # tuple literal
f"hi {name}" # f-string interpolation

String escapes: \n, \t, \\, \", \r, \0, plus \xNN and \uXXXX. Any other escape is a compile error.

int age = 25
float rate = 1.5
bool active = true
string name = "Pluvial"
int? maybe = null # nullable
auto count = 10 # inferred, then fixed

The initializer is required; with an explicit type it must match exactly. See Variables.

FormMeaning
int float bool stringbase types
autoinferred
T?nullable
array<T>array
map<K, V>map
(T1, T2)tuple
Result<T>result with a string error
Result<T, E>result with a struct error E
(T1, T2) => Rfunction type
a struct / enum nameuser-defined type

See Types.

+ - * / % ** — same numeric type on both sides; no implicit promotion. string + string concatenates. / truncates for int. ** is right-associative.

& | ^ ~ << >>int operands only; shifts are arithmetic.

< > <= >= (same numeric type), == != (same type). string == string compares contents. x == null / x != null only for nullable x.

&& || !bool only, short-circuiting.

  • isr is ok / r is errbool.
  • ?? — null coalescing (T? ?? T → T).
  • . — member / method access; ?. — optional chaining on a nullable receiver.
  • [i] — index access.
|| → ?? → && → | → ^ → & → == != is →
< > <= >= → << >> → + - → * / % → ** (right-assoc) →
unary ! - ~ → . / [i] → grouping ( )

+= -= *= /= %= **= &= |= ^= <<= >>= — sugar for x = x op e. Left-hand side may be a variable, an array element, or a struct field. See Variables.

if (cond) { ... } else if (cond2) { ... } else { ... }
while (cond) { ... }
for item in arr { ... }
for (i, x) in arr { ... } # enumerate
for k in m { ... }
for (k, v) in m { ... }
break continue
outer: while (cond) { break outer continue outer } # labeled

Conditions must be bool; braces are mandatory. See Control flow.

match expr {
1 | 2 => { ... } # literal / OR
ok(v) => { ... } # Result ok
err(e) => { ... } # Result err
null => { ... } # nullable absent
binding => { ... } # nullable present
(int x, string s) => { ... } # tuple
Shape.Circle(r) => { ... } # enum variant
_ => { ... } # wildcard, last
}

Match is a statement; arms use braces and are checked for exhaustiveness.

def add(int a, int b) int { return a + b }
def greet(string name) { println(name) } # no return value
def connect(string host, int port = 8080) { ... } # default argument
add(1, 2)
greet(name: "x") # named argument

Lambdas and function types:

auto f = (int x) => x * 2
auto g = (int x) => { return x + 1 }
(int) => int h = f

See Functions.

struct Point {
int x
int y
def translate(int dx, int dy) Point {
return Point { x: self.x + dx, y: self.y + dy }
}
}
Point p = Point { x: 1, y: 2 }
Point p2 = Point { ...p, x: 5 } # struct update
enum Direction { North South East West }
enum Status { Ok = 200 NotFound = 404 }
enum Shape { Circle(float r) Rectangle(float w, float h) Point }

See Structs.

export def add(int a, int b) int { return a + b }
export struct Point { int x int y }
import "math" # math.add(1, 2)
import "./utils" as u # u.name
from "math" import add, mul as times
import std.io # std/ shorthand
from std.http import get

See Modules.

Result<int> r = to_int("42")
if (r is ok) { println(r.value) } else { println(r.error) }
match r {
ok(v) => { println(v) }
err(e) => { println(e) }
}

See Error handling.