Skip to content

Add bitwise operators - #77

Merged
wtholliday merged 1 commit into
mainfrom
bitwise-operators
Oct 23, 2026
Merged

wtholliday merged 1 commit into
mainfrom
bitwise-operators

Conversation

@wtholliday

Copy link
Copy Markdown
Collaborator

Summary

Lyte gains bitwise operators on i32 and u32:

Syntax Meaning
a & b, a | b and, or
a ~ b xor (^ is already power, so this follows Lua)
~a complement
a << n, a >> n shifts; >> is arithmetic on i32, logical on u32

Both sides of &, |, ~ must share a type. The shift amount may be i32 or u32, so w << 24 works on a u32 with an unsuffixed literal. Shift amounts are taken modulo 32 on every backend. Precedence matches Rust and Lua: looser than arithmetic, tighter than comparisons, so x & 7 == 0 is (x & 7) == 0.

Motivation: the Audulus MIDI 2.0 script template currently says "Lyte has no bit operators, so build and split words by multiplying and dividing by powers of 256." That example becomes:

var w0 = (64u << 24) | (144u << 16) | (60u << 8)
var w1 = 1u << 31

Changes

  • Front end: lexer tokens, five Binop variants plus Unop::BitNot, four new precedence levels (shared parse_left_assoc helper), checker overload tables. Nested type argument lists like Wrapper<Wrapper<i32>> still parse; the closing >> is split back into two >.
  • Backends: Cranelift and LLVM use native instructions. The register VM, ARM64 interpreter, and stack VM already had the opcodes; since they hold i32 values sign-extended in 64-bit slots, a new I64ToI32 opcode re-normalizes after a left shift, and u32 results are re-masked after << and ~.
  • Overloading: __and, __or, __xor, __shl, __shr for structs. The overload rewrite pass now fires when either operand is a named type; before, __mul(f32, Point)-style overloads type-checked but broke codegen.
  • Safety checker: i & mask with a non-negative mask lies in [0, mask], and x >> n with non-negative x in [0, x], so buf[i & 1023] is accepted without a requires clause.
  • Docs and tooling: grammar, language guide, README, VS Code grammar, and the differential fuzzer (adds &, |, ~; shifts left out because VM multiplication is 64-bit and would surface the pre-existing overflow divergence as noise).

Tests

Six new golden tests: operator semantics on both types, precedence, MIDI word packing, struct overloads on either side, the mask bounds proof, nested generics, and a float type error. Full suite passes on JIT, VM, ASM, stack, and LLVM backends.

Known follow-ups

  • Unary ~ is not overloadable for structs, matching unary - today.
  • Safety-checker intervals do not model i32 wraparound; this predates the change and applies to + - * equally.
  • Variable shift amounts cost two VM instructions for the mask; an and-immediate opcode would remove that.

🤖 Generated with Claude Code

Lyte gains &, |, ~ (xor), <<, >> and prefix ~ on i32 and u32. Since ^ is
already power, xor follows Lua and uses ~. Shift amounts may be i32 or u32
and are taken modulo 32 on every backend; >> is arithmetic on i32 and
logical on u32.

- Lexer, parser (four new precedence levels between comparisons and
  arithmetic), checker, and pretty-printer. Nested type argument lists
  like Wrapper<Wrapper<i32>> still parse: the closing >> is split.
- Codegen on Cranelift, LLVM, the register VM, the ARM64 interpreter, and
  the stack VM. The VMs hold i32 values sign-extended in 64-bit slots, so
  a new I64ToI32 opcode re-normalizes after a left shift.
- Overloadable for structs via __and, __or, __xor, __shl, __shr. The
  overload rewrite now also fires when only the right operand is a named
  type, which previously broke codegen for e.g. __mul(f32, Point).
- Safety checker narrows `i & mask` with a non-negative mask and `x >> n`
  with non-negative x, so buf[i & 1023] is provably in bounds.
- Docs, VS Code grammar, differential fuzzer, and golden tests updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@wtholliday
wtholliday merged commit 5871786 into main Oct 23, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant