-
-
Notifications
You must be signed in to change notification settings - Fork 0
rules bits
Bitwise rule library.
import {rules as bitsRules} from 'yopl/rules/bits.js';Forward-only: requires X and Y to be bound; computes Z. With all three bound, behaves as a check. Cannot be solved backwards because bitwise AND is not invertible (many (X, Y) pairs produce the same Z).
const Z = variable('Z');
solve(bitsRules, 'bitAnd', [0b1100, 0b1010, Z], env => {
console.log(assemble(Z, env).toString(2)); // 1000
});Forward (X and Y bound → Z computed; all three bound → check) plus zero-identity reverse mode: queries with X (or Y) bound to 0 resolve via (0, Y, Y) / (X, 0, X) fact clauses.
// 0 | Y = 5 → Y = 5
const Y = variable('Y');
solve(bitsRules, 'bitOr', [0, Y, 5], env => console.log(assemble(Y, env))); // 5
// X | 0 = 5 → X = 5
const X = variable('X');
solve(bitsRules, 'bitOr', [X, 0, 5], env => console.log(assemble(X, env))); // 5Other reverse modes (e.g. X | Y = Z with neither operand at zero) are not enumerated — multiple (X, Y) pairs produce the same Z and the rule won't speculate. The forward path also cuts after success, so identity facts don't double-emit forward solutions like bitOr(0, 5, Z).
Reversible. XOR is its own inverse (X ^ Y ^ Y = X), so any one missing operand can be solved for. Includes shortcut clauses 0 ^ Y = Y, X ^ 0 = X, X ^ X = 0.
// Solve for Y: 0b1100 ^ Y = 0b0110
const Y = variable('Y');
solve(bitsRules, 'bitXor', [0b1100, Y, 0b0110], env => {
console.log(assemble(Y, env).toString(2)); // 1010
});Reversible bitwise NOT. Either argument may be unbound and is solved for; with both bound the rule behaves as a check.
Bitwise predicates are most useful when integrating with code that already speaks bit flags — masking, packing, or parsing fixed-width records:
const rules = {
...systemRules,
...bitsRules,
// hasFlag(Flags, Mask) — true if all bits in Mask are set in Flags
hasFlag: (Flags, Mask) => [head(Flags, Mask), term('bitAnd', Flags, Mask, Mask)]
};For pure-arithmetic work, prefer the rules-math library — bitwise tricks are clever but harder to read.
- Operands must be plain JavaScript numbers. The native
&,|,^,~operators coerce to 32-bit signed integers, so values outside that range are truncated. -
bitAndis not reversible — the AND identities don't usefully constrain a missing operand.bitOrreverses only via the zero-identity facts above (0 | Y = Y,X | 0 = X).