Bitwise Operators & Bitfields

Word-form bitwise operators and bitfield helpers, run live below — see the Grammar reference for precedence rules and the Standard Library reference for the full bitfield-helper list.

Word-form keyword operators — band/bor/bxor/bnot/shl/shr — rather than C-style symbols: | and & are already taken by the |> pipeline operator and |params| closure syntax, and PatLang already spells and/or/not as words, so this follows the language's own convention instead of importing symbols that don't fit. Plus four bitfield helpers — bit_get/bit_set/bit_slice/bit_set_slice — for packed-integer field access without needing a struct/type system. This demo packs four byte-sized fields into one integer two different ways (via shl/bor directly, and via bit_set_slice) and confirms they agree, then demonstrates flag set/clear/toggle/test.

PatLang source
# Bitwise operators (band/bor/bxor/bnot/shl/shr) and bitfield helpers
# (bit_get/bit_set/bit_slice/bit_set_slice), proven end-to-end.

# ---- pack 4 byte-sized fields into one int (RGBA-in-a-u32 style), unpack,
# and verify a real round-trip -- not just "it compiled" ----
let mut packed = 0
packed = bit_set_slice(packed, 0, 8, 10)
packed = bit_set_slice(packed, 8, 8, 20)
packed = bit_set_slice(packed, 16, 8, 30)
packed = bit_set_slice(packed, 24, 8, 40)

let r = bit_slice(packed, 0, 8)
let g = bit_slice(packed, 8, 8)
let b = bit_slice(packed, 16, 8)
let a = bit_slice(packed, 24, 8)
let roundtrip_ok = (r == 10) and (g == 20) and (b == 30) and (a == 40)
print("packed RGBA round-trip: r=" + r + " g=" + g + " b=" + b + " a=" + a + " ok=" + roundtrip_ok)

# Same pack, expressed directly via shl/bor instead of the bit_* helpers --
# both paths must agree, proving the operators and the helpers are
# consistent with each other, not two independently-drifting implementations.
let packed2 = (10 shl 0) bor (20 shl 8) bor (30 shl 16) bor (40 shl 24)
print("shl/bor pack matches bit_set_slice pack: " + (packed == packed2))

# ---- flag-style bit twiddling: set/clear/toggle/test ----
let mut flags = 0
flags = bit_set(flags, 0, 1)
flags = bit_set(flags, 2, 1)
print("flags after setting bit 0 and bit 2: " + flags + " (expect 5)")
print("test bit 0: " + bit_get(flags, 0) + ", test bit 1: " + bit_get(flags, 1))
# toggle bit 2 via bxor
flags = flags bxor (1 shl 2)
print("flags after toggling bit 2: " + flags + " (expect 1)")
flags = bit_set(flags, 0, 0)
print("flags after clearing bit 0: " + flags + " (expect 0)")

# ---- bnot / band / bor sanity ----
print("bnot 0 = " + (bnot 0) + " (expect -1, all bits set)")
print("5 band 3 = " + (5 band 3) + " (expect 1)")
print("5 bor 2 = " + (5 bor 2) + " (expect 7)")

# Shift-out-of-range is a real runtime error, not silent wraparound or a
# panic -- verified separately (a program that runs `1 shl 100` aborts
# with "shl: shift amount 100 out of range 0..63"), not repeated here since
# PatLang has no try/catch to demonstrate recovering from it inline.
require (1 shl 4) == 16

print("DONE")

(not run yet)

Native run on the build machine:

packed RGBA round-trip: r=10 g=20 b=30 a=40 ok=true
shl/bor pack matches bit_set_slice pack: true
flags after setting bit 0 and bit 2: 5 (expect 5)
test bit 0: 1, test bit 1: 0
flags after toggling bit 2: 1 (expect 1)
flags after clearing bit 0: 0 (expect 0)
bnot 0 = -1 (expect -1, all bits set)
5 band 3 = 1 (expect 1)
5 bor 2 = 7 (expect 7)
DONE