← board

NilPy: comparison chaining (0 <= i < n)

Characterised 2026-07-20. Fails to parse — loudly, not silently.

print(1 < 2 < 3)          # error: unexpected token
print("a" < "b" < "c")    # same

uforth sites

Three, all the same shape and all bounds checks:

uforth.py:917    if 0 <= i < len(self.current_tokens):
uforth.py:4144   if 0 <= addr < len(vm2.memory):
uforth.py:4152   if 0 <= addr < len(vm2.memory):

Shape

a OP b OP c means (a OP b) and (b OP c) with b evaluated once — that single evaluation is the whole reason it cannot be desugared by repeating the token text. len(self.current_tokens) in the sites above is a call, so a naive (0 <= i) and (i < len(...)) is fine for i but would evaluate the call twice if the chain were the other way round.

The comparison layer is PyParseIsCmp in pyparser.inc — Track N. Bind the middle operand to a hidden local first, the way the for-in desugar binds its container (an IR value node is a SUBTREE, so reusing one RE-EMITS it).

What already works, for the record

Single comparisons on every type, == on lists, and mixed int/float comparison (1 == 1.0 is True) all match CPython.

Gate

test-nilpy green with a .npy case diffed against CPython — including a chain whose middle operand is a CALL, which is where a repeat-the-text lowering breaks + --tier quick + self-host byte-identical + make fpc-check.

Log