Expressions & Control Flow
Handlers have a body of statements whose values are real, type-checked expressions.
Expressions
Weld supports + - * / %, comparisons, && || !, ?? (coalesce), string concatenation with +, and parenthesization — all with precedence. Integer arithmetic wraps.
route GET "/add/:a/:b" (a: int, b: int) {
respond "sum={a + b} diff={a - b} prod={a * b} quot={a / b} mod={a % b}\n"
}
route GET "/cmp/:a/:b" (a: int, b: int) {
let bigger = a > b
respond "a>b: {bigger}, equal: {a == b}, in_range: {a > 0 && a < 100}\n"
}Bindings
let x = e— an immutable binding (optionallylet x: T = e).var x = e— a mutable binding; assign withx = e2for accumulation.
route GET "/greet/:name" (name: string) {
let greeting = "Hello, " + name
respond "{greeting}\n"
}Conditionals
route GET "/classify/:n" (n: int) {
if n < 0 {
respond "negative"
} else if n == 0 {
respond "zero"
} else {
respond "positive"
}
}Loops
for x in list { … } iterates a list; for k, v in map { … } iterates a map. Any type with a next(mut self) -> T? method is also iterable — see Methods & Iterators.
route GET "/sum/:n" (n: int) {
var total = 0
var xs = push([1, 2, 3], n)
for x in xs { total = total + x }
respond "total={total}\n"
}Two bindings over a list give a 0-based int index and the element — for i, x in xs:
route GET "/names" {
var names = ["ann", "bo", "cy"]
var out = ""
for i, name in names {
out = out + "{i}: {name}\n"
}
respond out
}Match
match subject { pattern => expr, _ => expr } works over enums, ints, or strings, and needs a _ arm (except when matching an exhaustive sum type). It is an expression, so it yields a value:
route GET "/label/:n" (n: int) {
let label = match n {
0 => "zero",
_ => "nonzero",
}
respond "n={label}\n"
}List builtins
Beyond push, the list library offers:
slice(list, start, end) -> [T]— the sub-range[start, end), clamped to bounds.pop(list) -> [T]— the list without its last element (empty stays empty).concat(a, b) -> [T]— two lists of the same element type joined.reverse(list) -> [T]— the list reversed.contains(list, elem) -> bool— membership, for primitive/enum element types (in addition tocontains(string, substring)).
route GET "/tags" -> string {
var tags = ["intro", "weld", "demo", "lists"]
tags = concat(tags, ["extra"]) # join two lists
tags = slice(tags, 1, 4) # sub-range [1, 4)
var recent = reverse(tags) # reversed
recent = pop(recent) # drop the last
var out = ""
for i, t in recent { # 0-based index + element
out = out + "{i}:{t} "
}
respond "has-weld={contains(tags, "weld")} list={out}"
}An empty list literal takes its element type from context, and that inference now flows through ?? — optionalList ?? [] gives the [] the element type of the optional:
route GET "/merge" (query extra: string?) -> string {
var base: [string]? = null
var items = base ?? [] # [] is inferred as [string]
items = push(items, extra ?? "none")
respond "count={len(items)}"
}Functions & builtins
fn greet(name: string) -> string {
return "Hello, " + upper(name)
}
route GET "/hi/:name" (name: string) {
respond "{greet(name)}\n"
}The builtin library covers strings (len, upper, lower, trim, trimPrefix, contains, startsWith, endsWith, parseInt), conversion (str, int, hash), collections (push, filled, has, remove), environment and time (env, now_ms), request context (request_header, client_ip), and JWT (jwt_verify, jwt_decode).
For the complete list — every builtin function, statement, and global, with exact signatures — see the Builtins & Globals reference. For the full grammar, keywords, and operator precedence, see the Language Reference.