Skip to content

Hello! 👋 My name is Nathan Weir. This is a fun personal project for using AI to build a bespoke, domain-specific programming language. It is not a serious, professional project. This site and the language itself are largely generated via Claude Code. If you find yourself programming with Weir, have fun - but use at your own risk!

Operator Precedence

Weir uses S-expression syntax with prefix notation — there is no operator precedence in the traditional sense. The nesting of parentheses fully determines evaluation order.

In infix languages, 2 + 3 * 4 requires precedence rules to determine whether it means (2 + 3) * 4 or 2 + (3 * 4). In Weir, the parentheses make it explicit:

(+ 2 (* 3 4)) ;; 2 + (3 * 4) = 14
(* (+ 2 3) 4) ;; (2 + 3) * 4 = 20

No ambiguity — what you write is what you get.

OperatorArityDescriptionExample
+Variadic (2+)Addition(+ 1 2 3)6
-1 or variadicNegation / subtraction(- 5)-5, (- 10 3)7
*Variadic (2+)Multiplication(* 2 3 4)24
/2Division(/ 10 3)3
mod2Modulo(mod 10 3)1

Arithmetic operators are polymorphic — they work on any numeric type, but all operands must be the same type:

(+ 1 2) ;; OK: i64 + i64
(+ 1.0 2.0) ;; OK: f64 + f64
(+ 1 2.0) ;; Error: can't mix i64 and f64
OperatorDescriptionExample
=Equal(= 1 1)true
!=Not equal(!= 1 2)true
<Less than(< 3 5)true
>Greater than(> 5 3)true
<=Less than or equal(<= 5 5)true
>=Greater than or equal(>= 5 5)true

All comparison operators take exactly two arguments and return Bool. Operands are unified (must be the same type).

OperatorArityDescriptionExample
not1Logical NOT(not true)false
andVariadic (2+)Logical AND(and true true false)false
orVariadic (2+)Logical OR(or false false true)true

Logical operators require Bool operands and return Bool.

OperatorDescriptionExample
?Error propagation (postfix)(read-file path)?
->Thread-first macro(-> x f g)(g (f x))
->>Thread-last macro(->> x f g)(g (f x))
.fieldField accessor(.x vec)

-> inserts the previous result as the first argument:

(-> enemy .pos .x)
;; expands to: (.x (.pos enemy))

->> inserts as the last argument:

(->> (range 100) (filter even?) (take 10))
;; expands to: (take (filter (range 100) even?) 10)

Within an S-expression, arguments are evaluated left to right before the function is called:

(f (g x) (h y))
;; 1. Evaluate (g x)
;; 2. Evaluate (h y)
;; 3. Call f with both results

Short-circuit evaluation applies to and, or, if, cond, and when/unless — they may not evaluate all of their arguments.