ilo 26.5.0

ilo - the token-minimal programming language AI agents write
Documentation
-- Postfix `.N` / `.field` access works on a multi-token call result
-- without needing parentheses around the call. `spl "a.b.c" "." .0`
-- reads the first piece directly; `at rows i .2` reads column 2 of
-- row i in one line.
--
-- Before this landed, the parser's greedy call-args loop stopped at
-- the leading `.` (Dot isn't an operand-start token) and the trailing
-- `.N` was left dangling for the infix parser, surfacing as
-- ILO-P001 "expected declaration, got `.`". Agents had to wrap the
-- call in parens (`(spl ... ".").0`) or bind first, costing 2-3
-- tokens per access. The fix routes every Call return site in
-- `parse_call_or_atom` / `parse_call_arg` through `parse_field_chain`,
-- the same helper the parenthesised and bare-ident branches use, so
-- all three head shapes accept the same postfix chain.
--
-- The shapes that matter most are list-element pick-off after a
-- `spl` / `at` / `slc` call and second-field pick-off after a custom
-- accessor that returns a record or tuple-shaped list.

-- spl "a.b.c" "." .0 — first piece of a dotted name without parens.
first-segment s:t>t
  spl s "." .0

-- spl "k=v" "=" .1 — second piece of a kv pair, the most common
-- shape after `splitn`-style parsing.
second-segment s:t>t
  spl s "=" .1

-- at rows 0 .1 — pick column 1 off the first row. Saves a token vs
-- `(at rows 0).1` and reads naturally left-to-right. The trailing
-- `.N` reattaches to the `at` call result rather than dangling.
--
-- Heads-up: the `.N` only reattaches when it follows a literal arg
-- (number / string / list literal) at the call's last slot. If the
-- last arg is a bare ident like `i`, the lexer-parser glues `.N` to
-- the ident as field access on the variable, not on the call result.
-- Bind the call result or wrap in parens in that case:
--   r=at rows i;r.1     -- bind first
--   (at rows i).1        -- parens force the grouping
col-from-row rows:L L n>n
  at rows 0 .1

-- The safe form `.?N` works through the same helper. nil on out-of-
-- range instead of raising.
safe-first s:t>O t
  spl s "." .?0

-- run: first-segment "a.b.c"
-- out: a
-- run: second-segment "name=jane"
-- out: jane
-- run: col-from-row [[10,20,30],[40,50,60],[70,80,90]]
-- out: 20
-- run: safe-first "x.y"
-- out: x