Skip to content

Commit c42226b

Browse files
proof(idris2): tighten Ephapax.Parse.Stream to %default total (#90)
## Summary Second file in the `%default partial` → `%default total` chain for `ephapax/idris2/src/Ephapax/`. SExpr.idr (#89) was first; Stream.idr is this one. Only one definition in `Stream.idr` actually recurses: the `where`-bound `build` inside `remaining`. It walks an `Int` index up to `s.len` — Idris2 can't detect this as terminating because Int is not a structural recursor. Fix: replace `build` with a Nat-fueled helper `buildFuel`, with fuel `= integerToNat (s.len - s.index)`. Each recursive call decrements fuel by 1 and increments the index by 1 in lockstep, so the fuel can never run out before the `i >= s.len` guard fires. When `s.index >= s.len` the cast/truncation produces fuel 0 — matching the partial original's empty-return. No `assert_total` / `assert_smaller` / `believe_me` escapes anywhere. ## Verification ``` $ IDRIS2_PREFIX=…/idris2/0.8.0 idris2 --check Ephapax/Parse/Stream.idr 1/3: Building Ephapax.Parse.Lexer 2/3: Building Ephapax.Parse.ZigBuffer 3/3: Building Ephapax.Parse.Stream ``` Downstream `Ephapax.Parse.Parser` (which `import Ephapax.Parse.Stream`) also still builds clean — checked locally. ## Refs - `#124` (proof-debt audit epic) - `#134` (ephapax totality sub-issue) - Companion: PR `#89` (Ephapax.IR.SExpr — same campaign, file 1 of 9) ## Test plan - [x] `idris2 --check Ephapax/Parse/Stream.idr` builds green under `%default total` - [x] Downstream `Ephapax.Parse.Parser` still builds - [ ] CI green - [ ] No `assert_*` / `believe_me` introduced (verified by inspection — see diff) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 94a8d71 commit c42226b

1 file changed

Lines changed: 6 additions & 5 deletions

File tree

idris2/src/Ephapax/Parse/Stream.idr

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module Ephapax.Parse.Stream
33
import Ephapax.Parse.Lexer
44
import Ephapax.Parse.ZigBuffer
55

6-
%default partial
6+
%default total
77

88
public export
99
record Stream where
@@ -45,12 +45,13 @@ atEnd s = s.index >= s.len
4545

4646
public export
4747
remaining : Stream -> List Token
48-
remaining s = build s.index
48+
remaining s = buildFuel (integerToNat (cast (s.len - s.index))) s.index
4949
where
50-
build : Int -> List Token
51-
build i =
50+
buildFuel : Nat -> Int -> List Token
51+
buildFuel Z _ = []
52+
buildFuel (S k) i =
5253
if i >= s.len then []
53-
else MkToken (getTokKind s.buf i) (getTokPos s.buf i) :: build (i + 1)
54+
else MkToken (getTokKind s.buf i) (getTokPos s.buf i) :: buildFuel k (i + 1)
5455

5556
public export
5657
at : Int -> Stream -> Maybe Token

0 commit comments

Comments
 (0)