tail-fold.tri (3582B)
1 !import prelude * 2 !import consumers_structural as S 3 !import consumers_lowerings_specialize as P 4 !export * 5 -- Experimental tricu-owned lowering for two-rule list consumers. 6 -- Reject unsupported input shapes rather than changing their semantics. 7 8 leafRule rule = matchPair (input more : matchPair (state output : 9 matchPair (tag payload : lazyBool (_ : just (pair state output)) 10 (_ : nothing) (equal? tag 1)) input) more) rule 11 consRule rule = matchPair (input more : matchPair (state output : 12 matchPair (tag children : lazyBool (_ : matchPair (left right : 13 matchPair (leftTag leftSlot : matchPair (rightTag rightSlot : 14 lazyBool (_ : just (pair (pair leftSlot rightSlot) (pair state output))) 15 (_ : nothing) (and? (equal? leftTag 4) (equal? rightTag 4))) right) left) children) 16 (_ : nothing) (equal? tag 3)) input) more) rule 17 18 -- Inputs are disjoint, so rule order cannot affect this accepted fragment. 19 classify first second = (lazyMaybe (_ : lazyMaybe (_ : nothing) (cons : lazyMaybe (_ : nothing) 20 (leaf : just (pair leaf cons)) (leafRule second)) (consRule first)) 21 (leaf : lazyMaybe (_ : nothing) (cons : just (pair leaf cons)) (consRule second)) 22 (leafRule first)) 23 24 compileLeaf statePattern output = (state recur invoke : lazyMaybe (_ : err "no matching consumer rule" t) (bindings : (P.indexedOutput output (P.patternSlots statePattern t)) bindings recur invoke) ((P.indexedPattern statePattern) state t)) 25 compileCons slots statePattern output = (byte rest state recur invoke : matchPair (byteSlot restSlot : lazyMaybe (_ : err "no matching consumer rule" t) (bindings : (P.indexedOutput output (P.patternSlots statePattern (pair restSlot (pair byteSlot t)))) bindings recur invoke) ((P.indexedPattern statePattern) state (pair rest (pair byte t)))) slots) 26 compileBranches branches = matchPair (leaf cons : matchPair 27 (leafState leafOutput : matchPair (slots more : matchPair 28 (consState consOutput : pair (compileLeaf leafState leafOutput) 29 (compileCons slots consState consOutput)) more) cons) leaf) branches 30 31 -- The only per-byte input dispatch is the actual list constructor. The two 32 -- rule functions are prepared before runtime recursion, not parsed per byte. 33 loop_ self input state leaf cons = ((selected : selected t) (triage 34 (_ : leaf state 35 (nextInput nextState : self nextInput nextState leaf cons) 36 (worker argument initial : y P.runDirect_ argument worker initial)) 37 (child : _ : err "no matching consumer rule" t) 38 (byte rest : _ : cons byte rest state 39 (nextInput nextState : self nextInput nextState leaf cons) 40 (worker argument initial : y P.runDirect_ argument worker initial)) input)) 41 run program input = matchPair (initial branches : matchPair (leaf cons : 42 y loop_ input initial leaf cons) branches) program 43 -- Compatible with runDirect's (initial, step) protocol. Once invoked, the 44 -- fixed-point loop handles its own recurrence, not runDirect's recur callback. 45 asDirect program = matchPair (initial branches : matchPair (leaf cons : 46 S.makeConsumer initial (input state recur invoke : y loop_ input state leaf cons)) branches) program 47 compile consumer = (lazyList (_ : err "tail-fold requires exactly two rules" t) (first rest : lazyList (_ : err "tail-fold requires exactly two rules" t) 48 (second extra : lazyList (_ : lazyMaybe 49 (_ : err "tail-fold requires leaf and captured cons rules" t) 50 (branches : ok (pair (fst consumer) (compileBranches branches)) t) 51 (classify first second)) 52 (_ _ : err "tail-fold requires exactly two rules" t) extra) rest) 53 (snd consumer))