Bitwise & word operators

The bitwise operators are words, because | belongs to pipelines and lambdas.

a band b        # AND
a bor b         # OR
a bxor b        # XOR
a shl 3         # shift left
a shr 2        # shift right (arithmetic, sign-extending)
bnot a          # complement

This is the same choice as and, or and not: where a symbol would be ambiguous with something more common in this language, the operator gets a name.

On int

Two's complement on 64 bits. A shift amount outside 0..64 is an error, not a silent wrap - the C behaviour here is undefined in practice and a source of real bugs. shr is arithmetic, so it sign-extends.

On bytes

band, bor and bxor are element-wise and require equal lengths. bnot complements each byte. Shifts do not apply.

key = b"\x5a\x5a\x5a\x5a"
masked = message bxor key
original = masked bxor key

Mixing int and bytes operands is a type error.

Precedence

Between comparison and range - looser than arithmetic:

a + b shl 2        # means (a + b) shl 2

Relative order mirrors Python's: band tighter than bxor tighter than bor.

Because this trips people up, ecko fmt always prints clarifying parentheses where bitwise mixes with arithmetic. You do not have to remember the table; the formatter makes the grouping visible in the source.

Full precedence, loosest to tightest:

|> < or < and < comparisons < bor < bxor < band < shl/shr < .. < + - < * / % < unary