diff --git a/bench/goldens/fnew_Bench.CurriedStep.txt b/bench/goldens/fnew_Bench.CurriedStep.txt index cb2d8b6b..b81ba9d3 100644 --- a/bench/goldens/fnew_Bench.CurriedStep.txt +++ b/bench/goldens/fnew_Bench.CurriedStep.txt @@ -1,8 +1,7 @@ chunk: Bench.CurriedStep.lua runtime: LuaJIT 2.1.1741730670 main-chunk FNEW: 1 -function-body FNEW: 1 -total FNEW: 2 -prototypes: 3 +function-body FNEW: 0 +total FNEW: 1 +prototypes: 2 function-body FNEW sites: - Bench.CurriedStep.lua:12 diff --git a/bench/goldens/fnew_Bench.MutualStep.txt b/bench/goldens/fnew_Bench.MutualStep.txt new file mode 100644 index 00000000..0ca6c6e6 --- /dev/null +++ b/bench/goldens/fnew_Bench.MutualStep.txt @@ -0,0 +1,9 @@ +chunk: Bench.MutualStep.lua +runtime: LuaJIT 2.1.1741730670 +main-chunk FNEW: 1 +function-body FNEW: 2 +total FNEW: 3 +prototypes: 4 +function-body FNEW sites: + Bench.MutualStep.lua:24 + Bench.MutualStep.lua:27 diff --git a/bench/goldens/fnew_Bench.StateStep.txt b/bench/goldens/fnew_Bench.StateStep.txt index 956dc786..2d95f35f 100644 --- a/bench/goldens/fnew_Bench.StateStep.txt +++ b/bench/goldens/fnew_Bench.StateStep.txt @@ -1,9 +1,8 @@ chunk: Bench.StateStep.lua runtime: LuaJIT 2.1.1741730670 main-chunk FNEW: 3 -function-body FNEW: 2 -total FNEW: 5 -prototypes: 6 +function-body FNEW: 1 +total FNEW: 4 +prototypes: 5 function-body FNEW sites: Bench.StateStep.lua:9 - Bench.StateStep.lua:44 diff --git a/bench/goldens/tnew_Bench.CurriedStep.txt b/bench/goldens/tnew_Bench.CurriedStep.txt index 7e78d999..f5cd7dcc 100644 --- a/bench/goldens/tnew_Bench.CurriedStep.txt +++ b/bench/goldens/tnew_Bench.CurriedStep.txt @@ -3,5 +3,5 @@ runtime: LuaJIT 2.1.1741730670 main-chunk TNEW+TDUP: 1 function-body TNEW+TDUP: 0 total TNEW+TDUP: 1 -prototypes: 3 +prototypes: 2 function-body TNEW+TDUP sites: diff --git a/bench/goldens/tnew_Bench.MutualStep.txt b/bench/goldens/tnew_Bench.MutualStep.txt new file mode 100644 index 00000000..5dba0555 --- /dev/null +++ b/bench/goldens/tnew_Bench.MutualStep.txt @@ -0,0 +1,7 @@ +chunk: Bench.MutualStep.lua +runtime: LuaJIT 2.1.1741730670 +main-chunk TNEW+TDUP: 1 +function-body TNEW+TDUP: 0 +total TNEW+TDUP: 1 +prototypes: 4 +function-body TNEW+TDUP sites: diff --git a/bench/goldens/tnew_Bench.StateStep.txt b/bench/goldens/tnew_Bench.StateStep.txt index bb3559f9..f6ce375d 100644 --- a/bench/goldens/tnew_Bench.StateStep.txt +++ b/bench/goldens/tnew_Bench.StateStep.txt @@ -3,5 +3,5 @@ runtime: LuaJIT 2.1.1741730670 main-chunk TNEW+TDUP: 2 function-body TNEW+TDUP: 0 total TNEW+TDUP: 2 -prototypes: 6 +prototypes: 5 function-body TNEW+TDUP sites: diff --git a/bench/goldens/trace_curried_step.txt b/bench/goldens/trace_curried_step.txt index 80becddd..0ef350c9 100644 --- a/bench/goldens/trace_curried_step.txt +++ b/bench/goldens/trace_curried_step.txt @@ -2,11 +2,10 @@ spec: curried_step runtime: LuaJIT 2.1.1741730670 workload: n=100000 reps=4 result=5000050000 aborts (distinct site -- reason): - Bench.CurriedStep.lua:12 -- NYI: bytecode FNEW Bench.CurriedStep.lua:6 -- inner loop in root trace bytecode end state (J*=compiled, I*=blacklisted): Bench.CurriedStep.lua:5 JLOOP curried_step.lua:10 JFUNCF curried_step.lua:12 JFORI curried_step.lua:12 JFORL -counts: aborts=2 compiled=4 blacklisted=0 +counts: aborts=1 compiled=4 blacklisted=0 diff --git a/bench/goldens/trace_mutual_step.txt b/bench/goldens/trace_mutual_step.txt new file mode 100644 index 00000000..9943a92d --- /dev/null +++ b/bench/goldens/trace_mutual_step.txt @@ -0,0 +1,12 @@ +spec: mutual_step +runtime: LuaJIT 2.1.1741730670 +workload: n=100000 reps=4 result=5000050000 +aborts (distinct site -- reason): + Bench.MutualStep.lua:24 -- NYI: bytecode FNEW + Bench.MutualStep.lua:8 -- inner loop in root trace +bytecode end state (J*=compiled, I*=blacklisted): + Bench.MutualStep.lua:7 JLOOP + mutual_step.lua:11 JFUNCF + mutual_step.lua:13 JFORI + mutual_step.lua:13 JFORL +counts: aborts=2 compiled=4 blacklisted=0 diff --git a/bench/goldens/trace_state_step.txt b/bench/goldens/trace_state_step.txt index 1a9c9cd0..bd101772 100644 --- a/bench/goldens/trace_state_step.txt +++ b/bench/goldens/trace_state_step.txt @@ -2,7 +2,6 @@ spec: state_step runtime: LuaJIT 2.1.1741730670 workload: n=100000 reps=4 result=99998 aborts (distinct site -- reason): - Bench.StateStep.lua:44 -- NYI: bytecode FNEW Bench.StateStep.lua:9 -- NYI: bytecode FNEW state_step.lua:32 -- NYI: bytecode FNEW bytecode end state (J*=compiled, I*=blacklisted): @@ -13,4 +12,4 @@ bytecode end state (J*=compiled, I*=blacklisted): state_step.lua:13 JFUNCF state_step.lua:34 JFORI state_step.lua:34 JFORL -counts: aborts=3 compiled=4 blacklisted=3 +counts: aborts=2 compiled=4 blacklisted=3 diff --git a/bench/macro/mutual_step.lua b/bench/macro/mutual_step.lua new file mode 100644 index 00000000..d7343d3c --- /dev/null +++ b/bench/macro/mutual_step.lua @@ -0,0 +1,16 @@ +-- The mutual twin of curried_step: the same hot accumulator loop, split +-- across two workers tail-calling each other. Dispatched, the pair runs +-- as one while-true loop over a branch selector; undispatched, every +-- iteration pays a real call for the transition. +return { + artifact = "Bench.MutualStep", + n = 100000, + drive = function(mod, n) + return mod.run(n) + end, + ideal = function(n) + local acc = 0 + for i = n, 1, -1 do acc = acc + i end + return acc + end, +} diff --git a/changelog.d/20260725_150000_unisay_mutual_and_join_loopification.md b/changelog.d/20260725_150000_unisay_mutual_and_join_loopification.md new file mode 100644 index 00000000..9cf649a8 --- /dev/null +++ b/changelog.d/20260725_150000_unisay_mutual_and_join_loopification.md @@ -0,0 +1,21 @@ +### Added + +- Loopification now covers mutual recursion and join points (#234), the two + shapes #181 left as calls. The members of a recursive group's mutual + tail-call cycle lower to one `while true do` dispatcher over a branch + selector plus shared argument slots — every transition, sibling or self, is + one simultaneous multiple assignment — while the member bindings survive as + entry wrappers, so non-tail uses, the curried wrappers left in the group by + uncurrying, and external callers keep working unchanged. A chunk-local + helper only ever tail-called from the enclosing body (a `where`-bound `go`, + a shared continuation) loses its function shell entirely: its parameters + hoist as locals, each entry call becomes an assignment falling through into + the helper's body — an already-loopified worker's entries fall straight + into its loop, and chains of such helpers flatten one round at a time. + Under LuaJIT the dispatcher is the shape the trace compiler wants: the new + `mutual_step` macrobenchmark trace-compiles to parity with hand-written Lua + (~21x over the cross-calling shape), and join-point fusion brings + `curried_step`'s per-iteration closure allocations to zero. Under PUC the + dispatcher trades tail-call machinery for a selector test and per-branch + parameter rebinds, a small constant-factor regression on pure transition + loops that substituting slot names for parameters would remove. diff --git a/lib/Language/PureScript/Backend/Lua.hs b/lib/Language/PureScript/Backend/Lua.hs index 436bf205..52173b5d 100644 --- a/lib/Language/PureScript/Backend/Lua.hs +++ b/lib/Language/PureScript/Backend/Lua.hs @@ -92,15 +92,61 @@ fromUberModule foreigns needsRuntimeLazy appOrModule uber = (`evalStateT` 0) do recBinds ← forM (toList recGroup) \(IR.QName modname name, irExp) → (modname,name,) . asExpression <$> fromIR foreigns Set.empty modname irExp - pure $ DList.fromList do - (modname, name, exp) ← recBinds - -- A self-recursive member references itself through the - -- module-scope table, mirroring the Ref case of 'fromIR'. - let self = - Loopify.SelfField - Fixture.moduleName - (qualifyName modname (fromName name)) - pure $ mkBinding modname (fromName name) (Loopify.loopify self exp) + -- A recursive member references itself (and its siblings) + -- through the module-scope table, mirroring the Ref case of + -- 'fromIR'. + let memberSelf modname name = + Loopify.SelfField + Fixture.moduleName + (qualifyName modname (fromName name)) + -- The members of every mutual tail-call cycle lower to one + -- while-true dispatcher plus entry wrappers (issue #234); see + -- Language.PureScript.Backend.Lua.Loopify. + dispatched ← + forM + ( Loopify.planGroupDispatch + [ (memberSelf modname name, exp) + | (modname, name, exp) ← recBinds + ] + ) + \group → do + selector ← freshName "$sel" + slots ← + replicateM (Loopify.dispatchArity group) (freshName "$a") + let leader = NE.head (Loopify.dispatchMembers group) + -- The leader's Self already carries the qualified + -- module-scope field, so the dispatcher derives its + -- name from it directly. + dispatcherName = + Name.makeSafe $ + Name.toText (Loopify.selfName (Loopify.dispatchSelf leader)) + <> "$loop" + dispatcherSelf = + Loopify.SelfField Fixture.moduleName dispatcherName + (dispatcherExp, wrappers) = + Loopify.emitDispatchGroup + dispatcherSelf + selector + slots + group + pure ((dispatcherName, dispatcherExp), wrappers) + let wrapperByIndex = concatMap snd dispatched + pure $ + DList.fromList + [ Lua.assign + ( Lua.VarField + (Lua.ann (Lua.varName Fixture.moduleName)) + dispatcherName + ) + dispatcherExp + | ((dispatcherName, dispatcherExp), _) ← dispatched + ] + <> DList.fromList do + (index, (modname, name, exp)) ← zip [0 ..] recBinds + let luaExp = case List.lookup index wrapperByIndex of + Just wrapper → wrapper + Nothing → Loopify.loopify (memberSelf modname name) exp + pure $ mkBinding modname (fromName name) luaExp returnExp ← case appOrModule of @@ -137,9 +183,12 @@ mkBinding modname name = (Lua.ann (Lua.varName Fixture.moduleName)) (qualifyName modname name) +-- Chunks are finalized here and in the 'IR.AbsN' case of 'fromIR', so +-- both fuse the chunk's join points first (issue #234); see +-- Language.PureScript.Backend.Lua.Loopify. asExpression ∷ Either Lua.Chunk Lua.Exp → Lua.Exp asExpression = \case - Left chunk → Lua.chunkToExpression chunk + Left chunk → Lua.chunkToExpression (Loopify.joinifyChunk chunk) Right expr → expr fromName ∷ HasCallStack ⇒ IR.Name → Lua.Name @@ -262,7 +311,7 @@ fromIR foreigns topLevelNames modname ir = case ir of List.dropWhileEnd isUnusedParam (toList params) ] pure . Right $ case body of - Left chunk → Lua.functionDef luaParams chunk + Left chunk → Lua.functionDef luaParams (Loopify.joinifyChunk chunk) Right e → Lua.functionDef luaParams [Lua.return e] -- Running the literal thunk that a saturated lifted @*.Uncurried@ effect -- wrapper reduces to — @(\_ -> fn(a, …)) EffectRunArg@ — is just the call @@ -341,27 +390,61 @@ fromIR foreigns topLevelNames modname ir = case ir of IR.Standalone (_ann, name, expr) → DList.singleton . Lua.local1 (fromName name) <$> goExp expr IR.RecursiveGroup grp → do - let binds = - toList grp <&> \(_ann, fromName → name, _) → - Lua.local0 - ( if Set.member (qualifyName modname name) topLevelNames - then qualifyName modname name - else name - ) - assignments ← forM (toList grp) \(_ann, fromName → name, expr) → do + compiled ← forM (toList grp) \(_ann, name, expr) → do + luaExp ← goExp expr -- The self-reference mirrors the Ref case below: through the -- module-scope table for a top-level name, plain otherwise. - let (target, self) - | Set.member (qualifyName modname name) topLevelNames = - ( qualifyName modname name + let luaName = fromName name + (target, self) + | Set.member (qualifyName modname luaName) topLevelNames = + ( qualifyName modname luaName , Loopify.SelfField Fixture.moduleName - (qualifyName modname name) + (qualifyName modname luaName) ) - | otherwise = (name, Loopify.SelfLocal name) - goExp expr - <&> Lua.assign (Lua.VarName target) - . Loopify.loopify self + | otherwise = (luaName, Loopify.SelfLocal luaName) + pure (name, target, self, luaExp) + -- The members of every mutual tail-call cycle dispatch through + -- a shared local (issue #234), mirroring the top-level case in + -- 'fromUberModule'. + dispatched ← + forM + ( Loopify.planGroupDispatch + [(self, luaExp) | (_, _, self, luaExp) ← compiled] + ) + \group → do + selector ← freshName "$sel" + slots ← + replicateM (Loopify.dispatchArity group) (freshName "$a") + let leader = NE.head (Loopify.dispatchMembers group) + dispatcherName = + Name.makeSafe $ + Name.toText (Loopify.selfName (Loopify.dispatchSelf leader)) + <> "$loop" + (dispatcherExp, wrappers) = + Loopify.emitDispatchGroup + (Loopify.SelfLocal dispatcherName) + selector + slots + group + pure ((dispatcherName, dispatcherExp), wrappers) + let wrapperByIndex = concatMap snd dispatched + binds = + [ Lua.local0 dispatcherName + | ((dispatcherName, _), _) ← dispatched + ] + <> [Lua.local0 target | (_, target, _, _) ← compiled] + assignments = + [ Lua.assign (Lua.VarName dispatcherName) dispatcherExp + | ((dispatcherName, dispatcherExp), _) ← dispatched + ] + <> [ Lua.assign (Lua.VarName target) luaExp' + | (index, (_, target, self, luaExp)) ← + zip [0 ..] compiled + , let luaExp' = case List.lookup index wrapperByIndex of + Just wrapper → wrapper + Nothing → Loopify.loopify self luaExp + ] pure $ DList.fromList binds <> DList.fromList assignments pure . Left . DList.toList $ recs <> either DList.fromList (DList.singleton . Lua.return) body diff --git a/lib/Language/PureScript/Backend/Lua/Loopify.hs b/lib/Language/PureScript/Backend/Lua/Loopify.hs index 70d4f118..bd6c5f30 100644 --- a/lib/Language/PureScript/Backend/Lua/Loopify.hs +++ b/lib/Language/PureScript/Backend/Lua/Loopify.hs @@ -83,26 +83,125 @@ The veto errs conservatively (a captured parameter name is assumed to escape even where a human could prove it does not), which only costs an optimization opportunity, never correctness. +== Mutual recursion (issue #234) + +'loopify' rewrites self-calls only, so a group of functions that +tail-call /each other/ keeps paying a call per transition. The members +of every tail-call cycle lower instead to one dispatcher function + +> f₁$loop = function(sel, s₁, …, sₖ) +> while true do +> if sel == 1 then +> local p₁, … = s₁, … -- member 1's parameters +> … -- member 1's body, where a tail +> sel, s₁, …, sₖ = 2, e₁, … -- call of member 2 became this +> else +> … +> end +> end +> end + +over a branch selector plus shared argument slots (one per parameter +of the widest member), while the member bindings survive as entry +wrappers @f₁ = function(p₁, …) return f₁$loop(1, p₁, …) end@. A cycle +is a strongly-connected component of size two or more of the /spine +tail-call graph/: member X has an edge to member Y when X's body tail- +calls Y at the block spine ('planGroupDispatch'). Self-calls of a cycle +member become same-branch transitions of the shared dispatcher. + +Because the bindings survive as wrappers, every other reference stays +valid without any use analysis: a non-tail use inside the group, an +uncurrying wrapper left in the group (which references the worker from +under a nested lambda and therefore never joins a cycle), an external +caller, an export. The uniform-tail-call test is thereby a +profitability criterion, not a soundness precondition — a transition +whose explist cannot be balanced simply stays a real call, now landing +on the callee's entry wrapper. + +The dispatcher needs no capture veto: each branch rebinds its member's +parameters as loop-body locals, re-created every iteration, so a +closure captures per-iteration bindings exactly as a fresh activation +would provide. Only the selector and the slots are shared across +iterations, and their names are minted fresh by the code generator — +no user code can reference them. A member whose body can fall off its +end (a value-less native-loop chunk) is excluded: falling through a +dispatcher branch would iterate the loop instead of returning nil +('exitTotal'). + +== Join points (issue #234) + +A chunk-local helper only ever tail-called from the chunk's spine is a +loop in disguise, but compiles as a function plus an entry call per +use. 'joinifyChunk' removes the shell: + +> local k = function(p₁, …, pₘ) K end +> … +> return k(e₁, …, eₘ) -- every use: a spine-final tail call +> … +> return r -- any other exit + +becomes + +> local p₁, …, pₘ -- the parameters, hoisted in place of k +> … +> p₁, …, pₘ = e₁, …, eₘ -- each entry: assign and fall through +> … +> return r +> K -- the helper's body ends the chunk + +Every path through the rewritten prefix either @return@s (leaving the +function before reaching K) or has assigned the parameters and falls +through into K, whose own exits @return@ as before. A self-recursive +helper arrives here already loopified — its body is the @while true@ +loop, all self-calls gone — so the fusion composes: entry assignments +fall into the loop. The transform iterates until no candidate fuses; +a helper whose only entries sit in a just-appended body fuses in the +next round, so chains of join points flatten completely. + +The transform commits only when it can account for every use of the +helper: after rewriting, no read of its name may remain anywhere in +the chunk (a reference from a nested closure, an argument position, a +non-spine call — any survivor vetoes), at least one entry must have +been rewritten, the chunk's spine leaves must all be @return@s both +before (no falling off the chunk's end into K) and, calls excepted, +after the rewrite. That last condition — no remaining spine leaf may +@return@ a bare call — is deliberate conservatism: this transform runs +before 'loopify' sees the enclosing binding, and burying a potential +tail self-call mid-chunk would rob the enclosing loopification (or a +mutual-dispatch cycle) of its tail position. + +No capture veto is needed: the hoisted parameters are locals of the +chunk, re-created per activation (and per iteration once an enclosing +@while true@ wraps the chunk), and at most one entry executes per +chunk run — exactly the one activation the helper had as a function. + == Behaviour preservation PUC's tail-call optimization already guarantees O(1) stack for the -rewritten shapes, so the transform changes constants, not semantics; -the one observable difference is the shape of error tracebacks. The -transform runs during code generation on bindings that come from IR -recursive groups only — foreign (hand-written) Lua never passes -through it. +rewritten shapes, so the transforms change constants, not semantics; +the one observable difference is the shape of error tracebacks. All +three transforms run during code generation on IR-derived code only — +foreign (hand-written) Lua never passes through them. -} module Language.PureScript.Backend.Lua.Loopify ( Self (..) + , selfName , loopify + , DispatchGroup (..) + , DispatchMember (..) + , planGroupDispatch + , emitDispatchGroup + , joinifyChunk ) where +import Data.Graph qualified as Graph import Data.List qualified as List import Data.List.NonEmpty qualified as NE import Data.Set qualified as Set import Language.PureScript.Backend.Lua.Name (Name) import Language.PureScript.Backend.Lua.Types ( Annotated + , BinaryOp (EqualTo) , Comments , Exp , ExpF (..) @@ -125,6 +224,12 @@ data Self = SelfLocal Name | SelfField Name Name +-- | The binding's own name: the local, or the field of the scope table. +selfName ∷ Self → Name +selfName = \case + SelfLocal name → name + SelfField _table field → field + type Block = [Annotated Comments StatementF] {- | Rewrite the tail self-calls of a recursive binding's function into @@ -140,13 +245,13 @@ loopify self original = fromMaybe original do Set.disjoint (Set.fromList (toList carried)) (closureRefs BodyLevel body) - case rewriteBlock self carried body of + case rewriteSpine (selfCallRewrite self carried) body of (body', Loopified) → pure $ Function params [ann (While (ann (Boolean True)) body')] (_, NotLoopified) → Nothing -------------------------------------------------------------------------------- --- Tail self-call rewriting ---------------------------------------------------- +-- Tail-call rewriting --------------------------------------------------------- data Loopified = Loopified | NotLoopified @@ -154,31 +259,41 @@ instance Semigroup Loopified where NotLoopified <> NotLoopified = NotLoopified _ <> _ = Loopified +{- | A rewrite applied at the spine positions of a block: 'Just' +replaces the statement (counting as 'Loopified'), 'Nothing' leaves it +alone. +-} +type SpineRewrite = StatementF Comments → Maybe (StatementF Comments) + -- | Rewrite the tail position of a block: its final statement. -rewriteBlock ∷ Self → NonEmpty Name → Block → (Block, Loopified) -rewriteBlock self carried block = case List.unsnoc block of +rewriteSpine ∷ SpineRewrite → Block → (Block, Loopified) +rewriteSpine rewrite block = case List.unsnoc block of Nothing → (block, NotLoopified) Just (leading, (comments, final)) → - let (final', looped) = rewriteFinal self carried final + let (final', looped) = rewriteFinal rewrite final in (leading <> [(comments, final')], looped) rewriteFinal - ∷ Self - → NonEmpty Name - → StatementF Comments - → (StatementF Comments, Loopified) -rewriteFinal self carried = \case - original@(Return [Ann (FunctionCall (Ann callee) args)]) + ∷ SpineRewrite → StatementF Comments → (StatementF Comments, Loopified) +rewriteFinal rewrite statement + | Just statement' ← rewrite statement = (statement', Loopified) + | IfThenElse predicate thenBlock elseBlock ← statement = + let (thenBlock', loopedThen) = rewriteSpine rewrite thenBlock + (elseBlock', loopedElse) = rewriteSpine rewrite elseBlock + in (IfThenElse predicate thenBlock' elseBlock', loopedThen <> loopedElse) + | otherwise = (statement, NotLoopified) + +{- | Replace a tail self-call with the simultaneous reassignment of the +carried parameters. A self-call whose explist cannot be balanced is +left a real tail call. +-} +selfCallRewrite ∷ Self → NonEmpty Name → SpineRewrite +selfCallRewrite self carried = \case + Return [Ann (FunctionCall (Ann callee) args)] | isSelfCallee self callee → - case balanceExplist (length carried) args of - Just explist → - (Assign (ann . VarName <$> carried) explist, Loopified) - Nothing → (original, NotLoopified) - IfThenElse predicate thenBlock elseBlock → - let (thenBlock', loopedThen) = rewriteBlock self carried thenBlock - (elseBlock', loopedElse) = rewriteBlock self carried elseBlock - in (IfThenElse predicate thenBlock' elseBlock', loopedThen <> loopedElse) - statement → (statement, NotLoopified) + Assign (ann . VarName <$> carried) + <$> balanceExplist (length carried) args + _ → Nothing {- | Balance the self-call's argument explist against the count of assigned variables — see the module documentation. 'Nothing' declines @@ -234,6 +349,398 @@ isSelfCallee self callee = case (self, callee) of t == table && f == field _ → False +-------------------------------------------------------------------------------- +-- Mutual-recursion dispatch --------------------------------------------------- + +{- | One dispatchable tail-call cycle of a recursive group — see the +mutual-recursion section of the module documentation. +-} +data DispatchGroup = DispatchGroup + { dispatchMembers ∷ NonEmpty DispatchMember + -- ^ the cycle's members, in original group order + , dispatchArity ∷ Int + -- ^ shared slot count: the widest member's parameter count + } + +data DispatchMember = DispatchMember + { dispatchIndex ∷ Int + -- ^ the member's position in the original group (0-based) + , dispatchSelf ∷ Self + -- ^ how the member's own name renders in Lua + , dispatchParams ∷ [Name] + -- ^ the member function's parameters + , dispatchBody ∷ Block + -- ^ the member function's body + } + +{- | The tail-call cycles of a compiled recursive group: the strongly- +connected components (of size two or more) of the spine tail-call graph +over the group's function members. Members outside every cycle — non- +functions, uncurrying wrappers (their group references sit under nested +lambdas, never at the spine), functions with unused\/vararg parameters, +bodies that can fall off their end — are left for the per-member +'loopify'. +-} +planGroupDispatch ∷ [(Self, Exp)] → [DispatchGroup] +planGroupDispatch members = mapMaybe dispatchable sccs + where + candidates ∷ [DispatchMember] + candidates = + [ DispatchMember index self params body + | (index, (self, expr)) ← zip [0 ..] members + , Function annotatedParams body ← [expr] + , exitTotal body + , Just params ← [traverse (paramNamed . unAnn) annotatedParams] + ] + candidateIndex ∷ ExpF Comments → Maybe Int + candidateIndex callee = + listToMaybe + [dispatchIndex m | m ← candidates, isSelfCallee (dispatchSelf m) callee] + sccs = + Graph.stronglyConnComp + [ (m, dispatchIndex m, spineCallees candidateIndex (dispatchBody m)) + | m ← candidates + ] + dispatchable = \case + Graph.CyclicSCC cycleMembers@(_ : _ : _) → + let ordered = sortOn dispatchIndex cycleMembers + in Just + DispatchGroup + { dispatchMembers = NE.fromList ordered + , dispatchArity = + foldr (max . length . dispatchParams) 0 ordered + } + _ → Nothing + +{- | Lower one tail-call cycle to its dispatcher function and the entry +wrappers replacing the member bindings. The caller mints the selector +and slot names (fresh, so no user code can reference them) and decides +how the dispatcher itself is bound. +-} +emitDispatchGroup + ∷ Self + -- ^ how the dispatcher renders (for the wrappers' delegation call) + → Name + -- ^ branch-selector parameter + → [Name] + -- ^ shared argument slots, 'dispatchArity' of them + → DispatchGroup + → (Exp, [(Int, Exp)]) + {- ^ the dispatcher function, and the entry wrapper for each member + keyed by its original group index + -} +emitDispatchGroup dispatcher selector slots DispatchGroup {dispatchMembers} = + (dispatcherFunction, wrappers) + where + variables ∷ NonEmpty Name + variables = selector :| slots + + branches ∷ NonEmpty (Integer, DispatchMember) + branches = NE.zip (1 :| [2 ..]) dispatchMembers + + branchIndex ∷ ExpF Comments → Maybe Integer + branchIndex callee = + listToMaybe + [j | (j, m) ← toList branches, isSelfCallee (dispatchSelf m) callee] + + -- A spine tail call of a cycle member becomes the simultaneous + -- assignment of the selector and the slots; the balancing rules of + -- 'balanceExplist' carry over with the selector literal prepended. + transitionRewrite ∷ SpineRewrite + transitionRewrite = \case + Return [Ann (FunctionCall (Ann callee) args)] + | Just j ← branchIndex callee → + Assign (ann . VarName <$> variables) + <$> balanceExplist (length variables) (ann (Integer j) : args) + _ → Nothing + + branchBody ∷ DispatchMember → Block + branchBody DispatchMember {dispatchParams, dispatchBody} = + rebind <> body + where + rebind = case NE.nonEmpty dispatchParams of + Nothing → [] + Just params → + [ ann . Local params $ + take (length dispatchParams) (ann . Var . ann . VarName <$> slots) + ] + (body, _looped) = rewriteSpine transitionRewrite dispatchBody + + -- @if sel == 1 then … else[if …] …@ — the last branch needs no test. + branchChain ∷ NonEmpty (Integer, DispatchMember) → Block + branchChain ((j, m) :| rest) = case rest of + [] → branchBody m + next : more → + [ ann $ + IfThenElse + ( ann $ + BinOp + EqualTo + (ann (Var (ann (VarName selector)))) + (ann (Integer j)) + ) + (branchBody m) + (branchChain (next :| more)) + ] + + dispatcherFunction ∷ Exp + dispatcherFunction = + Function + (ann . ParamNamed <$> toList variables) + [ann (While (ann (Boolean True)) (branchChain branches))] + + wrappers ∷ [(Int, Exp)] + wrappers = + [ ( dispatchIndex m + , Function + (ann . ParamNamed <$> dispatchParams m) + [ ann . Return . pure . ann $ + FunctionCall + (ann (selfExp dispatcher)) + ( ann (Integer j) + : (ann . Var . ann . VarName <$> dispatchParams m) + ) + ] + ) + | (j, m) ← toList branches + ] + +-- | The expression a 'Self' reads as. +selfExp ∷ Self → ExpF Comments +selfExp = \case + SelfLocal name → Var (ann (VarName name)) + SelfField table field → + Var (ann (VarField (ann (Var (ann (VarName table)))) field)) + +-- | The original-group indices of members tail-called at the block spine. +spineCallees ∷ (ExpF Comments → Maybe Int) → Block → [Int] +spineCallees calleeIndex block = case List.unsnoc block of + Nothing → [] + Just (_leading, (_comments, final)) → finalCallees final + where + finalCallees = \case + Return [Ann (FunctionCall (Ann callee) _args)] → + maybeToList (calleeIndex callee) + IfThenElse _predicate thenBlock elseBlock → + spineCallees calleeIndex thenBlock <> spineCallees calleeIndex elseBlock + _ → [] + +{- | Control can never fall off the block's end: every spine leaf is a +@return@ (recursing through final @if@ branches), or a @while true@ +loop no @break@ escapes — a loopified body's shape, which exits through +its internal @return@s only. Bodies failing this — a value-less +native-loop chunk is the one shape the code generator emits — must not +become dispatcher branches or appended join-point bodies: reaching +their end would iterate the enclosing dispatcher loop (or run whatever +follows) instead of returning nil. +-} +exitTotal ∷ Block → Bool +exitTotal block = case List.unsnoc block of + Nothing → False + Just (_leading, (_comments, final)) → case final of + Return _ → True + IfThenElse _predicate thenBlock elseBlock → + exitTotal thenBlock && exitTotal elseBlock + While (Ann (Boolean True)) body → not (loopLevelBreak body) + _ → False + +{- | Whether the block has a @break@ binding to the loop enclosing it — +one not nested inside a loop of the block's own. +-} +loopLevelBreak ∷ Block → Bool +loopLevelBreak = any (breaks . unAnn) + where + breaks = \case + Break → True + IfThenElse _predicate thenBlock elseBlock → + loopLevelBreak thenBlock || loopLevelBreak elseBlock + Do block → loopLevelBreak block + -- A break inside a nested loop binds to that loop. + While _ _ → False + Repeat _ _ → False + ForNum {} → False + ForIn {} → False + _ → False + +-------------------------------------------------------------------------------- +-- Join points ----------------------------------------------------------------- + +{- | Fuse the chunk's join points — see the join-points section of the +module documentation. Applied by the code generator wherever a compiled +chunk is finalized into a function body or a scope call. +-} +joinifyChunk ∷ [StatementF Comments] → [StatementF Comments] +joinifyChunk chunk = unAnn <$> joinify (ann <$> chunk) + +-- Iterates until no candidate fuses: each committed fusion removes one +-- function literal, so the iteration terminates. +joinify ∷ Block → Block +joinify block = + maybe block joinify (asum (tryJoin block <$> joinCandidates block)) + +{- | A helper eligible for fusion: a chunk-level @local k = function@ +(or the forward-declaration\/assignment pair a recursive group +compiles to), with named parameters and a body control cannot fall out +of. +-} +data JoinCandidate = JoinCandidate + { joinName ∷ Name + , joinParams ∷ NonEmpty Name + , joinBody ∷ Block + , joinDeclIndex ∷ Int + -- ^ where the parameters hoist: the candidate's declaration statement + , joinAssignIndex ∷ Maybe Int + -- ^ the separate assignment of a forward-declared candidate + } + +joinCandidates ∷ Block → [JoinCandidate] +joinCandidates block = mapMaybe candidateAt indexed + where + indexed = zip [0 ..] (unAnn <$> block) + candidateAt (index, statement) = case statement of + Local (name :| []) [Ann (Function annotatedParams body)] → do + params ← functionParams annotatedParams body + Just + JoinCandidate + { joinName = name + , joinParams = params + , joinBody = body + , joinDeclIndex = index + , joinAssignIndex = Nothing + } + Assign + (Ann (VarName name) :| []) + (Ann (Function annotatedParams body) :| []) → do + params ← functionParams annotatedParams body + declIndex ← + listToMaybe + [ j + | (j, Local (declared :| []) []) ← indexed + , declared == name + ] + Just + JoinCandidate + { joinName = name + , joinParams = params + , joinBody = body + , joinDeclIndex = declIndex + , joinAssignIndex = Just index + } + _ → Nothing + functionParams annotatedParams body = do + params ← NE.nonEmpty =<< traverse (paramNamed . unAnn) annotatedParams + params <$ guard (exitTotal body) + +-- | Fuse one candidate, or decline — see the module documentation. +tryJoin ∷ Block → JoinCandidate → Maybe Block +tryJoin block candidate = do + let withoutDef = flip mapMaybe (zip [0 ..] block) \(index, statement) → + if + | index == joinDeclIndex candidate → + Just (ann (Local (joinParams candidate) [])) + | Just index == joinAssignIndex candidate → Nothing + | otherwise → Just statement + -- No falling off the chunk's end into the appended body. + guard (exitTotal withoutDef) + case rewriteSpine + (selfCallRewrite (SelfLocal (joinName candidate)) (joinParams candidate)) + withoutDef of + (_, NotLoopified) → Nothing + (rewritten, Loopified) → do + -- Burying a spine tail call would rob the enclosing binding's + -- loopification of it. + guard (not (spineReturnsCall rewritten)) + -- Every use must be gone — any surviving read vetoes the fusion. + guard (nameReads (joinName candidate) rewritten == 0) + pure (rewritten <> joinBody candidate) + +-- | Whether any spine leaf returns a bare call. +spineReturnsCall ∷ Block → Bool +spineReturnsCall block = case List.unsnoc block of + Nothing → False + Just (_leading, (_comments, final)) → case final of + Return [Ann FunctionCall {}] → True + IfThenElse _predicate thenBlock elseBlock → + spineReturnsCall thenBlock || spineReturnsCall elseBlock + _ → False + +{- | How many times the name is read anywhere in the block — every +position counts, including nested closures (unlike 'closureRefs', which +implements the capture veto and is position-sensitive). Bare assignment +targets are writes, not reads; binders never collide with the searched +name under global uniqueness of compiled names. +-} +nameReads ∷ Name → Block → Int +nameReads name = readsInBlock + where + readsInBlock ∷ Block → Int + readsInBlock = sum . fmap (readsInStatement . unAnn) + + readsInStatement ∷ StatementF Comments → Int + readsInStatement = \case + Assign vars vals → + sum (readsInWrite . unAnn <$> vars) + + sum (readsInExp . unAnn <$> vals) + Local _names vals → sum (readsInExp . unAnn <$> vals) + IfThenElse predicate thenBlock elseBlock → + readsInExp (unAnn predicate) + + readsInBlock thenBlock + + readsInBlock elseBlock + Return exps → sum (readsInExp . unAnn <$> exps) + CallStatement e → readsInExp (unAnn e) + Do block → readsInBlock block + While predicate block → + readsInExp (unAnn predicate) + readsInBlock block + Repeat block predicate → + readsInBlock block + readsInExp (unAnn predicate) + ForNum _name start limit step block → + readsInExp (unAnn start) + + readsInExp (unAnn limit) + + sum (readsInExp . unAnn <$> step) + + readsInBlock block + ForIn _names exps block → + sum (readsInExp . unAnn <$> exps) + readsInBlock block + LocalFunction _name _params block → readsInBlock block + Break → 0 + + readsInExp ∷ ExpF Comments → Int + readsInExp = \case + Function _params block → readsInBlock block + Var (Ann v) → readsInRead v + FunctionCall fn args → + readsInExp (unAnn fn) + sum (readsInExp . unAnn <$> args) + MethodCall obj _name args → + readsInExp (unAnn obj) + sum (readsInExp . unAnn <$> args) + TableCtor rows → sum (readsInRow . unAnn <$> rows) + UnOp _op e → readsInExp (unAnn e) + BinOp _op e1 e2 → readsInExp (unAnn e1) + readsInExp (unAnn e2) + Paren e → readsInExp (unAnn e) + Nil → 0 + Boolean _ → 0 + Integer _ → 0 + Float _ → 0 + String _ → 0 + Vararg → 0 + + readsInRow ∷ TableRowF Comments → Int + readsInRow = \case + TableRowKV k v → readsInExp (unAnn k) + readsInExp (unAnn v) + TableRowNV _name v → readsInExp (unAnn v) + TableRowV v → readsInExp (unAnn v) + + -- A bare name as an assignment target is a write. + readsInWrite ∷ VarF Comments → Int + readsInWrite = \case + VarName _ → 0 + VarIndex e1 e2 → readsInExp (unAnn e1) + readsInExp (unAnn e2) + VarField e _name → readsInExp (unAnn e) + + readsInRead ∷ VarF Comments → Int + readsInRead = \case + VarName n → if n == name then 1 else 0 + VarIndex e1 e2 → readsInExp (unAnn e1) + readsInExp (unAnn e2) + VarField e _name → readsInExp (unAnn e) + -------------------------------------------------------------------------------- -- Capture analysis ------------------------------------------------------------ diff --git a/test/Language/PureScript/Backend/Lua/Spec.hs b/test/Language/PureScript/Backend/Lua/Spec.hs index 22a2aaf4..90ac9444 100644 --- a/test/Language/PureScript/Backend/Lua/Spec.hs +++ b/test/Language/PureScript/Backend/Lua/Spec.hs @@ -168,6 +168,99 @@ spec = describe "Lua.fromUberModule" do (shortCall topSelf (IR.App IR.noAnn (ref "g") (ref "x"))) rendered `shouldSatisfy` (not . Text.isInfixOf "while true do") + describe "loopification of mutual recursion (#234)" do + it "lowers a mutual pair to a single while-true dispatcher" do + rendered ← + compileMutualGroup (("ping", mutualPing) :| [("pong", mutualPong)]) + rendered `shouldSatisfy` Text.isInfixOf "while true do" + -- Sibling transitions set the selector and all slots at once. + rendered `shouldSatisfy` Text.isInfixOf "_S_sel0, _S_a1, _S_a2 = 2, n, acc" + rendered `shouldSatisfy` Text.isInfixOf "_S_sel0, _S_a1, _S_a2 = 1, b, a" + -- Each branch rebinds its parameters from the shared slots. + rendered `shouldSatisfy` Text.isInfixOf "local acc, n = _S_a1, _S_a2" + -- Entry wrappers delegate to the dispatcher… + rendered + `shouldSatisfy` Text.isInfixOf + "return M.Test_Loopify_ping_S_loop(1, acc, n)" + rendered + `shouldSatisfy` Text.isInfixOf + "return M.Test_Loopify_ping_S_loop(2, a, b)" + -- …and no cross-call between the members remains. + rendered `shouldSatisfy` (not . Text.isInfixOf "M.Test_Loopify_pong(") + + it "keeps a group without a spine tail-call cycle untouched" do + rendered ← + compileMutualGroup (("ping", nonTailPing) :| [("pong", mutualPong)]) + rendered `shouldSatisfy` (not . Text.isInfixOf "while true do") + rendered `shouldSatisfy` (not . Text.isInfixOf "_S_loop") + rendered `shouldSatisfy` Text.isInfixOf "M.Test_Loopify_pong(n, acc)" + + it "pads a narrower member's transition with nil" do + rendered ← + compileMutualGroup (("uno", unoCallsDos) :| [("dos", dosCallsUno)]) + rendered `shouldSatisfy` Text.isInfixOf "_S_sel0, _S_a1, _S_a2 = 2, n, 1" + rendered `shouldSatisfy` Text.isInfixOf "_S_sel0, _S_a1, _S_a2 = 1, a, nil" + + it "dispatches a Let-bound mutual pair through a local dispatcher" do + rendered ← compileExportedExpr letMutualLoop + rendered `shouldSatisfy` Text.isInfixOf "local tick_S_loop" + rendered `shouldSatisfy` Text.isInfixOf "while true do" + rendered `shouldSatisfy` Text.isInfixOf "_S_sel0, _S_a1, _S_a2 = 2, k, c" + rendered `shouldSatisfy` Text.isInfixOf "return tick_S_loop(1, c, k)" + + it "leaves a member outside the cycle referencing dispatched entries" do + rendered ← + compileMutualGroup + (("wA", waCallsWb) :| [("wB", wbCallsWa), ("pw", curriedOverWa)]) + rendered `shouldSatisfy` Text.isInfixOf "while true do" + -- The curried member keeps its reference; it now hits wA's entry + -- wrapper, whose binding survives under the original name. + rendered `shouldSatisfy` Text.isInfixOf "return M.Test_Loopify_wA(x, y)" + rendered `shouldSatisfy` (not . Text.isInfixOf "M.Test_Loopify_wB(") + + describe "join points (#234)" do + it "fuses a Let-bound recursive worker into the enclosing body" do + rendered ← compileExportedExpr letRecLoop + -- The function shell and its entry call are gone; the entry + -- became a parameter assignment falling through into the loop. + rendered `shouldSatisfy` (not . Text.isInfixOf "local go") + rendered `shouldSatisfy` (not . Text.isInfixOf "go(") + rendered `shouldSatisfy` Text.isInfixOf "local acc, n" + rendered `shouldSatisfy` Text.isInfixOf "acc, n = 0, m" + rendered `shouldSatisfy` Text.isInfixOf "while true do" + + it "fuses a non-recursive continuation called from two branches" do + rendered ← compileExportedExpr joinContinuation + rendered `shouldSatisfy` (not . Text.isInfixOf "finish") + rendered `shouldSatisfy` Text.isInfixOf "r = a" + rendered `shouldSatisfy` Text.isInfixOf "r = b" + rendered `shouldSatisfy` Text.isInfixOf "return g(r)" + -- No self-recursion, so no loop either. + rendered `shouldSatisfy` (not . Text.isInfixOf "while true do") + + it "fuses chained join points" do + rendered ← compileExportedExpr chainedJoins + rendered `shouldSatisfy` (not . Text.isInfixOf "k1") + rendered `shouldSatisfy` (not . Text.isInfixOf "k2") + rendered `shouldSatisfy` Text.isInfixOf "return g(b)" + + it "keeps a helper that escapes into a closure" do + rendered ← compileExportedExpr escapingHelper + rendered `shouldSatisfy` Text.isInfixOf "local esc" + rendered `shouldSatisfy` Text.isInfixOf "esc(m)" + + it "keeps a helper with a non-tail call site" do + rendered ← compileExportedExpr nonTailHelper + rendered `shouldSatisfy` Text.isInfixOf "local h" + rendered `shouldSatisfy` Text.isInfixOf "h(n)" + + it "declines when a spine leaf returns a call" do + rendered ← compileExportedExpr callLeafBeside + -- Fusing would bury the sibling `return f(n)` mid-chunk, robbing + -- the enclosing binding's own loopification of a tail position. + rendered `shouldSatisfy` Text.isInfixOf "local k" + rendered `shouldSatisfy` Text.isInfixOf "k(n)" + describe "foreign export check (#249)" do it "rejects a declared foreign name missing from the FFI exports" do result ← compileForeignModule "return { foo = 42 }" ["foo", "bar"] @@ -209,6 +302,22 @@ compileRecBinding expr = , uberModuleExports = [(IR.Name "value", topSelf)] } +{- | Compile a module with one top-level 'IR.RecursiveGroup' holding the +given members, the first of which is exported. +-} +compileMutualGroup ∷ NonEmpty (Text, IR.Exp) → IO Text +compileMutualGroup members = + compileUberModule + UberModule + { uberModuleBindings = + [ IR.RecursiveGroup $ + members <&> \(name, expr) → + (IR.QName testModuleName (IR.Name name), expr) + ] + , uberModuleForeigns = [] + , uberModuleExports = [(IR.Name "value", topRef (fst (head members)))] + } + testModuleName ∷ IR.ModuleName testModuleName = IR.ModuleName "Test.Loopify" @@ -454,6 +563,233 @@ shortCall self arg = (ref "acc") (IR.AppN IR.noAnn self (arg :| [primUndefined])) +-- Mutual loopification fixtures (#234) ---------------------------------------- + +-- | A reference to the given top-level binding of the test module. +topRef ∷ Text → IR.Exp +topRef = IR.Ref IR.noAnn . IR.Imported testModuleName . IR.Name + +{- | @ping acc n = if p then acc else pong n acc@ — tail-calls its +sibling with the arguments swapped. +-} +mutualPing ∷ IR.Exp +mutualPing = + absN ["acc", "n"] $ + IR.IfThenElse + IR.noAnn + (ref "p") + (ref "acc") + (IR.AppN IR.noAnn (topRef "pong") (ref "n" :| [ref "acc"])) + +-- | @pong a b = if q then b else ping b a@. +mutualPong ∷ IR.Exp +mutualPong = + absN ["a", "b"] $ + IR.IfThenElse + IR.noAnn + (ref "q") + (ref "b") + (IR.AppN IR.noAnn (topRef "ping") (ref "b" :| [ref "a"])) + +{- | @ping acc n = if p then acc else f (pong n acc)@ — the sibling call +is an operand, so the pair has no tail-call cycle. +-} +nonTailPing ∷ IR.Exp +nonTailPing = + absN ["acc", "n"] $ + IR.IfThenElse + IR.noAnn + (ref "p") + (ref "acc") + ( IR.App + IR.noAnn + (ref "f") + (IR.AppN IR.noAnn (topRef "pong") (ref "n" :| [ref "acc"])) + ) + +-- | @uno n = if p then n else dos n 1@ — the narrower member. +unoCallsDos ∷ IR.Exp +unoCallsDos = + absN ["n"] $ + IR.IfThenElse + IR.noAnn + (ref "p") + (ref "n") + ( IR.AppN + IR.noAnn + (topRef "dos") + (ref "n" :| [IR.LiteralInt IR.noAnn 1]) + ) + +-- | @dos a b = if q then b else uno a@ — transitions back one slot short. +dosCallsUno ∷ IR.Exp +dosCallsUno = + absN ["a", "b"] $ + IR.IfThenElse + IR.noAnn + (ref "q") + (ref "b") + (IR.AppN IR.noAnn (topRef "uno") (ref "a" :| [])) + +-- | @\\m → let tick c k = … tock …; tock d j = … tick … in tick 0 m@. +letMutualLoop ∷ IR.Exp +letMutualLoop = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "m")) $ + IR.Let + IR.noAnn + ( IR.RecursiveGroup + ( ( IR.noAnn + , IR.Name "tick" + , absN ["c", "k"] $ + IR.IfThenElse + IR.noAnn + (ref "p") + (ref "c") + (IR.AppN IR.noAnn (ref "tock") (ref "k" :| [ref "c"])) + ) + :| [ + ( IR.noAnn + , IR.Name "tock" + , absN ["d", "j"] $ + IR.IfThenElse + IR.noAnn + (ref "q") + (ref "d") + (IR.AppN IR.noAnn (ref "tick") (ref "j" :| [ref "d"])) + ) + ] + ) + :| [] + ) + ( IR.AppN + IR.noAnn + (ref "tick") + (IR.LiteralInt IR.noAnn 0 :| [ref "m"]) + ) + +-- | @wA x1 y1 = if p then x1 else wB y1 x1@. +waCallsWb ∷ IR.Exp +waCallsWb = + absN ["x1", "y1"] $ + IR.IfThenElse + IR.noAnn + (ref "p") + (ref "x1") + (IR.AppN IR.noAnn (topRef "wB") (ref "y1" :| [ref "x1"])) + +-- | @wB x2 y2 = if q then x2 else wA y2 x2@. +wbCallsWa ∷ IR.Exp +wbCallsWa = + absN ["x2", "y2"] $ + IR.IfThenElse + IR.noAnn + (ref "q") + (ref "x2") + (IR.AppN IR.noAnn (topRef "wA") (ref "y2" :| [ref "x2"])) + +{- | @pw x = \\y → wA x y@ — references a dispatched member from under a +nested lambda, the shape of an uncurrying wrapper left in the group. +-} +curriedOverWa ∷ IR.Exp +curriedOverWa = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "x")) $ + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "y")) $ + IR.AppN IR.noAnn (topRef "wA") (ref "x" :| [ref "y"]) + +-- Join-point fixtures (#234) -------------------------------------------------- + +{- | @\\n → let finish r = g r in if c then finish a else finish b@ — a +non-recursive continuation tail-called from both branches. +-} +joinContinuation ∷ IR.Exp +joinContinuation = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "n")) $ + IR.Let + IR.noAnn + ( IR.Standalone + ( IR.noAnn + , IR.Name "finish" + , absN ["r"] (IR.App IR.noAnn (ref "g") (ref "r")) + ) + :| [] + ) + ( IR.IfThenElse + IR.noAnn + (ref "c") + (IR.AppN IR.noAnn (ref "finish") (ref "a" :| [])) + (IR.AppN IR.noAnn (ref "finish") (ref "b" :| [])) + ) + +{- | @\\n → let k2 b = g b; k1 a = k2 a in k1 n@ — the body enters k1, +whose own tail position enters k2; both fuse, one per round. +-} +chainedJoins ∷ IR.Exp +chainedJoins = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "n")) $ + IR.Let + IR.noAnn + ( IR.Standalone + ( IR.noAnn + , IR.Name "k2" + , absN ["b"] (IR.App IR.noAnn (ref "g") (ref "b")) + ) + :| [ IR.Standalone + ( IR.noAnn + , IR.Name "k1" + , absN ["a"] (IR.AppN IR.noAnn (ref "k2") (ref "a" :| [])) + ) + ] + ) + (IR.AppN IR.noAnn (ref "k1") (ref "n" :| [])) + +{- | @\\n → let esc a = a in \\m → esc m@ — the helper is referenced from +inside the returned closure, so it must keep its function shell. +-} +escapingHelper ∷ IR.Exp +escapingHelper = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "n")) $ + IR.Let + IR.noAnn + ( IR.Standalone (IR.noAnn, IR.Name "esc", absN ["a"] (ref "a")) + :| [] + ) + ( IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "m")) $ + IR.AppN IR.noAnn (ref "esc") (ref "m" :| []) + ) + +-- | @\\n → let h a = a in g (h n)@ — the helper's call is an operand. +nonTailHelper ∷ IR.Exp +nonTailHelper = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "n")) $ + IR.Let + IR.noAnn + ( IR.Standalone (IR.noAnn, IR.Name "h", absN ["a"] (ref "a")) + :| [] + ) + ( IR.App + IR.noAnn + (ref "g") + (IR.AppN IR.noAnn (ref "h") (ref "n" :| [])) + ) + +{- | @\\n → let k a = a in if c then k n else f n@ — one branch enters +the join point, the other tail-calls something else. +-} +callLeafBeside ∷ IR.Exp +callLeafBeside = + IR.Abs IR.noAnn (IR.ParamNamed IR.noAnn (IR.Name "n")) $ + IR.Let + IR.noAnn + ( IR.Standalone (IR.noAnn, IR.Name "k", absN ["a"] (ref "a")) + :| [] + ) + ( IR.IfThenElse + IR.noAnn + (ref "c") + (IR.AppN IR.noAnn (ref "k") (ref "n" :| [])) + (IR.AppN IR.noAnn (ref "f") (ref "n" :| [])) + ) + -- Multi-value fixtures (#206) ------------------------------------------------- -- | @function(a, b) return a, b end@ — a result worker's shape. diff --git a/test/ps/output/Golden.JoinPoints.Test/corefn.json b/test/ps/output/Golden.JoinPoints.Test/corefn.json new file mode 100644 index 00000000..8ebc4269 --- /dev/null +++ b/test/ps/output/Golden.JoinPoints.Test/corefn.json @@ -0,0 +1 @@ +{"builtWith":"0.15.16","comments":[{"LineComment":" | Exercises join points (issue #234): a let-bound helper only ever"},{"LineComment":" | tail-called from the enclosing body loses its function shell — the"},{"LineComment":" | entry calls become parameter assignments falling through into the"},{"LineComment":" | helper's body (a loop when the helper is self-recursive). The eval"},{"LineComment":" | oracle pins that every shape keeps its runtime behavior, fused or"},{"LineComment":" | not."}],"decls":[{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[21,21],"start":[21,19]}},"type":"Var","value":{"identifier":"eq","moduleName":["Data","Eq"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[21,23],"start":[21,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eqInt","moduleName":["Data","Eq"]}},"type":"App"},"identifier":"eq"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[21,47],"start":[21,46]}},"type":"Var","value":{"identifier":"add","moduleName":["Data","Semiring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"semiringInt","moduleName":["Data","Semiring"]}},"type":"App"},"identifier":"add"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[21,51],"start":[21,50]}},"type":"Var","value":{"identifier":"mul","moduleName":["Data","Semiring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"semiringInt","moduleName":["Data","Semiring"]}},"type":"App"},"identifier":"mul"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[21,65],"start":[21,64]}},"type":"Var","value":{"identifier":"sub","moduleName":["Data","Ring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[21,67],"start":[21,62]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ringInt","moduleName":["Data","Ring"]}},"type":"App"},"identifier":"sub"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[42,25],"start":[42,23]}},"type":"Var","value":{"identifier":"greaterThanOrEq","moduleName":["Data","Ord"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[42,27],"start":[42,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ordInt","moduleName":["Data","Ord"]}},"type":"App"},"identifier":"greaterThanOrEq"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[29,21],"start":[29,19]}},"type":"Var","value":{"identifier":"lessThanOrEq","moduleName":["Data","Ord"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[29,23],"start":[29,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ordInt","moduleName":["Data","Ord"]}},"type":"App"},"identifier":"lessThanOrEq"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[26,22],"start":[26,21]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Data","Ord"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[26,26],"start":[26,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ordInt","moduleName":["Data","Ord"]}},"type":"App"},"identifier":"greaterThan"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[49,25],"start":[49,18]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Effect","Console"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[49,33],"start":[49,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"showInt","moduleName":["Data","Show"]}},"type":"App"},"identifier":"logShow"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[54,27],"start":[54,3]}},"type":"Var","value":{"identifier":"discard","moduleName":["Control","Bind"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discardUnit","moduleName":["Control","Bind"]}},"type":"App"},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"bindEffect","moduleName":["Effect"]}},"type":"App"},"identifier":"discard"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[58,24],"start":[58,22]}},"type":"Var","value":{"identifier":"negate","moduleName":["Data","Ring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[58,24],"start":[58,22]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ringInt","moduleName":["Data","Ring"]}},"type":"App"},"identifier":"negate"},{"annotation":{"meta":null,"sourceSpan":{"end":[17,27],"start":[17,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[17,27],"start":[17,1]}},"argument":"m","body":{"annotation":{"meta":{"metaType":"IsWhere"},"sourceSpan":{"end":[18,24],"start":[18,18]}},"binds":[{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[20,26],"start":[20,3]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[20,26],"start":[20,3]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[20,26],"start":[20,3]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[21,68],"start":[21,14]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[21,68],"start":[21,14]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[21,32],"start":[21,29]}},"type":"Var","value":{"identifier":"acc","sourcePos":[21,3]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[21,68],"start":[21,14]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[21,40],"start":[21,38]}},"type":"Var","value":{"identifier":"go","sourcePos":[20,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,60],"start":[21,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,45],"start":[21,42]}},"type":"Var","value":{"identifier":"acc","sourcePos":[21,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"mul","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,49],"start":[21,48]}},"type":"Var","value":{"identifier":"n","sourcePos":[21,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,59],"start":[21,42]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,58],"start":[21,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,54],"start":[21,53]}},"type":"Var","value":{"identifier":"n","sourcePos":[21,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,58],"start":[21,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,58],"start":[21,57]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,68],"start":[21,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,67],"start":[21,62]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,63],"start":[21,62]}},"type":"Var","value":{"identifier":"n","sourcePos":[21,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,67],"start":[21,62]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,67],"start":[21,66]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[21,23],"start":[21,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,18],"start":[21,17]}},"type":"Var","value":{"identifier":"n","sourcePos":[21,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[21,23],"start":[21,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[21,23],"start":[21,22]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"go"}]}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[18,20],"start":[18,18]}},"type":"Var","value":{"identifier":"go","sourcePos":[20,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[18,22],"start":[18,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[18,22],"start":[18,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[18,24],"start":[18,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[18,24],"start":[18,23]}},"type":"Var","value":{"identifier":"m","sourcePos":[18,1]}},"type":"App"},"type":"Let"},"type":"Abs"},"identifier":"sumTriangles"},{"annotation":{"meta":null,"sourceSpan":{"end":[40,32],"start":[40,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[40,32],"start":[40,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[43,16],"start":[42,3]}},"binds":[{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,7]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,7]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,16]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,16]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[42,36],"start":[42,33]}},"type":"Var","value":{"identifier":"acc","sourcePos":[42,7]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,16]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[42,44],"start":[42,42]}},"type":"Var","value":{"identifier":"go","sourcePos":[42,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[42,54],"start":[42,42]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[42,53],"start":[42,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[42,49],"start":[42,46]}},"type":"Var","value":{"identifier":"acc","sourcePos":[42,7]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[42,53],"start":[42,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[42,53],"start":[42,52]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"greaterThanOrEq","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[42,27],"start":[42,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[42,22],"start":[42,19]}},"type":"Var","value":{"identifier":"acc","sourcePos":[42,7]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[42,27],"start":[42,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[42,27],"start":[42,26]}},"type":"Var","value":{"identifier":"n","sourcePos":[41,1]}},"type":"App"}],"type":"Case"},"type":"Abs"},"identifier":"go"}]}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[43,16],"start":[43,6]}},"argument":"m","body":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[43,14],"start":[43,12]}},"type":"Var","value":{"identifier":"go","sourcePos":[42,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[43,16],"start":[43,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[43,16],"start":[43,15]}},"type":"Var","value":{"identifier":"m","sourcePos":[43,7]}},"type":"App"},"type":"Abs"},"type":"Let"},"type":"Abs"},"identifier":"escaping"},{"annotation":{"meta":null,"sourceSpan":{"end":[25,25],"start":[25,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[25,25],"start":[25,1]}},"argument":"n","body":{"annotation":{"meta":{"metaType":"IsWhere"},"sourceSpan":{"end":[26,56],"start":[26,16]}},"binds":[{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[28,26],"start":[28,3]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[28,26],"start":[28,3]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[28,26],"start":[28,3]}},"argument":"k","body":{"annotation":{"meta":null,"sourceSpan":{"end":[29,58],"start":[29,14]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[29,58],"start":[29,14]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[29,32],"start":[29,29]}},"type":"Var","value":{"identifier":"acc","sourcePos":[29,3]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[29,58],"start":[29,14]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[29,40],"start":[29,38]}},"type":"Var","value":{"identifier":"go","sourcePos":[28,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[29,50],"start":[29,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[29,49],"start":[29,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,45],"start":[29,42]}},"type":"Var","value":{"identifier":"acc","sourcePos":[29,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[29,49],"start":[29,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,49],"start":[29,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[29,58],"start":[29,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[29,57],"start":[29,52]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,53],"start":[29,52]}},"type":"Var","value":{"identifier":"k","sourcePos":[29,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[29,57],"start":[29,52]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,57],"start":[29,56]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"lessThanOrEq","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[29,23],"start":[29,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,18],"start":[29,17]}},"type":"Var","value":{"identifier":"k","sourcePos":[29,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[29,23],"start":[29,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[29,23],"start":[29,22]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"go"}]}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[26,56],"start":[26,16]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[26,56],"start":[26,16]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[26,34],"start":[26,32]}},"type":"Var","value":{"identifier":"go","sourcePos":[28,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[26,36],"start":[26,32]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,36],"start":[26,35]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[26,38],"start":[26,32]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,38],"start":[26,37]}},"type":"Var","value":{"identifier":"n","sourcePos":[26,1]}},"type":"App"},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[26,56],"start":[26,16]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[26,46],"start":[26,44]}},"type":"Var","value":{"identifier":"go","sourcePos":[28,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[26,48],"start":[26,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,48],"start":[26,47]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[26,56],"start":[26,44]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[26,55],"start":[26,50]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,51],"start":[26,50]}},"type":"Var","value":{"identifier":"n","sourcePos":[26,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[26,55],"start":[26,50]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,55],"start":[26,54]}},"type":"Literal","value":{"literalType":"IntLiteral","value":3}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[26,26],"start":[26,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,20],"start":[26,19]}},"type":"Var","value":{"identifier":"n","sourcePos":[26,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[26,26],"start":[26,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[26,26],"start":[26,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":100}},"type":"App"}],"type":"Case"},"type":"Let"},"type":"Abs"},"identifier":"collatzish"},{"annotation":{"meta":null,"sourceSpan":{"end":[33,23],"start":[33,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[33,23],"start":[33,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[36,54],"start":[35,3]}},"binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,7]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,7]}},"argument":"r","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,18]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"mul","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,18]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[35,29],"start":[35,19]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"mul","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[35,29],"start":[35,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[35,20],"start":[35,19]}},"type":"Var","value":{"identifier":"r","sourcePos":[35,7]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[35,29],"start":[35,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[35,25],"start":[35,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[35,29],"start":[35,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[35,29],"start":[35,28]}},"type":"Var","value":{"identifier":"r","sourcePos":[35,7]}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[35,34],"start":[35,33]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[35,38],"start":[35,37]}},"type":"Var","value":{"identifier":"r","sourcePos":[35,7]}},"type":"App"},"type":"Abs"},"identifier":"finish"}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[36,54],"start":[36,6]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[36,54],"start":[36,6]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[36,26],"start":[36,20]}},"type":"Var","value":{"identifier":"finish","sourcePos":[35,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[36,34],"start":[36,20]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[36,33],"start":[36,28]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,29],"start":[36,28]}},"type":"Var","value":{"identifier":"n","sourcePos":[34,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[36,33],"start":[36,28]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,33],"start":[36,32]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[36,54],"start":[36,6]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[36,46],"start":[36,40]}},"type":"Var","value":{"identifier":"finish","sourcePos":[35,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[36,54],"start":[36,40]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[36,53],"start":[36,48]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,49],"start":[36,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[36,53],"start":[36,48]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,53],"start":[36,52]}},"type":"Var","value":{"identifier":"n","sourcePos":[34,1]}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[36,14],"start":[36,9]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,10],"start":[36,9]}},"type":"Var","value":{"identifier":"n","sourcePos":[34,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[36,14],"start":[36,9]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[36,14],"start":[36,13]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Let"},"type":"Abs"},"identifier":"classify"},{"annotation":{"meta":null,"sourceSpan":{"end":[47,32],"start":[47,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[47,32],"start":[47,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[50,48],"start":[49,3]}},"binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[49,33],"start":[49,7]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[49,33],"start":[49,7]}},"argument":"m","body":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[49,33],"start":[49,18]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"mul","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[49,32],"start":[49,27]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[49,28],"start":[49,27]}},"type":"Var","value":{"identifier":"m","sourcePos":[49,7]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[49,32],"start":[49,27]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[49,32],"start":[49,31]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"type":"App"},"type":"Abs"},"identifier":"report"}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[50,48],"start":[50,6]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[50,48],"start":[50,6]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[50,26],"start":[50,20]}},"type":"Var","value":{"identifier":"report","sourcePos":[49,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[50,28],"start":[50,20]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[50,28],"start":[50,27]}},"type":"Var","value":{"identifier":"n","sourcePos":[48,1]}},"type":"App"},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[50,48],"start":[50,6]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[50,40],"start":[50,34]}},"type":"Var","value":{"identifier":"report","sourcePos":[49,7]}},"annotation":{"meta":null,"sourceSpan":{"end":[50,48],"start":[50,34]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[50,47],"start":[50,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[50,43],"start":[50,42]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[50,47],"start":[50,42]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[50,47],"start":[50,46]}},"type":"Var","value":{"identifier":"n","sourcePos":[48,1]}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[50,14],"start":[50,9]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[50,10],"start":[50,9]}},"type":"Var","value":{"identifier":"n","sourcePos":[48,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[50,14],"start":[50,9]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[50,14],"start":[50,13]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Let"},"type":"Abs"},"identifier":"chooseEff"},{"annotation":{"meta":null,"sourceSpan":{"end":[52,20],"start":[52,1]}},"bindType":"NonRec","expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[54,24],"start":[54,12]}},"type":"Var","value":{"identifier":"sumTriangles","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[54,26],"start":[54,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[54,26],"start":[54,25]}},"type":"Literal","value":{"literalType":"IntLiteral","value":4}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[54,27],"start":[54,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[55,26],"start":[55,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[55,26],"start":[55,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[55,22],"start":[55,12]}},"type":"Var","value":{"identifier":"collatzish","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[55,25],"start":[55,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[55,25],"start":[55,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[55,26],"start":[55,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[55,26],"start":[55,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,27],"start":[56,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,27],"start":[56,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[56,22],"start":[56,12]}},"type":"Var","value":{"identifier":"collatzish","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,26],"start":[56,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,26],"start":[56,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":200}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[56,27],"start":[56,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,27],"start":[56,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[57,23],"start":[57,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[57,23],"start":[57,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[57,20],"start":[57,12]}},"type":"Var","value":{"identifier":"classify","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[57,22],"start":[57,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[57,22],"start":[57,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":3}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[57,23],"start":[57,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[57,23],"start":[57,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[58,26],"start":[58,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[58,26],"start":[58,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[58,20],"start":[58,12]}},"type":"Var","value":{"identifier":"classify","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[58,25],"start":[58,12]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"negate","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[58,24],"start":[58,22]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[58,24],"start":[58,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[58,26],"start":[58,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[58,26],"start":[58,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,27],"start":[59,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,27],"start":[59,3]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[59,21],"start":[59,13]}},"type":"Var","value":{"identifier":"escaping","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,23],"start":[59,13]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,23],"start":[59,22]}},"type":"Literal","value":{"literalType":"IntLiteral","value":5}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[59,26],"start":[59,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,26],"start":[59,25]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[59,27],"start":[59,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,27],"start":[59,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[60,14],"start":[60,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[60,12],"start":[60,3]}},"type":"Var","value":{"identifier":"chooseEff","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[60,14],"start":[60,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[60,14],"start":[60,13]}},"type":"Literal","value":{"literalType":"IntLiteral","value":4}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[60,14],"start":[60,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[60,14],"start":[60,3]}},"argument":"$__unused","body":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[61,12],"start":[61,3]}},"type":"Var","value":{"identifier":"chooseEff","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[61,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"negate","moduleName":["Golden","JoinPoints","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[61,16],"start":[61,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[61,16],"start":[61,15]}},"type":"Literal","value":{"literalType":"IntLiteral","value":3}},"type":"App"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"identifier":"main"}],"exports":["sumTriangles","collatzish","classify","escaping","chooseEff","main"],"foreign":[],"imports":[{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Control","Bind"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Data","Eq"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Data","Ord"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Data","Ring"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Data","Semiring"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Data","Show"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Effect"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Effect","Console"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Golden","JoinPoints","Test"]},{"annotation":{"meta":null,"sourceSpan":{"end":[9,15],"start":[9,1]}},"moduleName":["Prelude"]},{"annotation":{"meta":null,"sourceSpan":{"end":[61,17],"start":[7,1]}},"moduleName":["Prim"]}],"moduleName":["Golden","JoinPoints","Test"],"modulePath":"src/Golden/JoinPoints/Test.purs","reExports":{},"sourceSpan":{"end":[61,17],"start":[7,1]}} \ No newline at end of file diff --git a/test/ps/output/Golden.JoinPoints.Test/eval/.gitignore b/test/ps/output/Golden.JoinPoints.Test/eval/.gitignore new file mode 100644 index 00000000..d2dc29bb --- /dev/null +++ b/test/ps/output/Golden.JoinPoints.Test/eval/.gitignore @@ -0,0 +1 @@ +actual.txt diff --git a/test/ps/output/Golden.JoinPoints.Test/eval/golden.txt b/test/ps/output/Golden.JoinPoints.Test/eval/golden.txt new file mode 100644 index 00000000..113a401c --- /dev/null +++ b/test/ps/output/Golden.JoinPoints.Test/eval/golden.txt @@ -0,0 +1,8 @@ +40 +8 +100 +84 +42 +5 +8 +6 diff --git a/test/ps/output/Golden.JoinPoints.Test/golden.ir b/test/ps/output/Golden.JoinPoints.Test/golden.ir new file mode 100644 index 00000000..5f896b56 --- /dev/null +++ b/test/ps/output/Golden.JoinPoints.Test/golden.ir @@ -0,0 +1,428 @@ +UberModule + { uberModuleBindings = + [ Standalone + ( QName + { qnameModuleName = ModuleName "Data.Show", qnameName = Name "foreign" + }, ForeignImport Nothing + ( ModuleName "Data.Show" ) ".spago/p/prelude/5718c84fdde6247749cb053e816df696c30fe691/src/Data/Show.purs" + [ ( Nothing, Name "showIntImpl" ) ] + ), Standalone + ( QName + { qnameModuleName = ModuleName "Data.Show", qnameName = Name "showIntImpl" + }, ObjectProp Nothing + ( Ref Nothing ( Imported ( ModuleName "Data.Show" ) ( Name "foreign" ) ) ) + ( PropName "showIntImpl" ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Effect.Console", qnameName = Name "foreign" + }, ForeignImport Nothing + ( ModuleName "Effect.Console" ) ".spago/p/console/f82835a0b873aafe6bd7b14dd30cc150553d4ab9/src/Effect/Console.purs" + [ ( Nothing, Name "log" ) ] + ), Standalone + ( QName + { qnameModuleName = ModuleName "Effect.Console", qnameName = Name "log" + }, ObjectProp Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "foreign" ) ) ) + ( PropName "log" ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "logShow" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "a$2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "log" ) ) ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Data.Show" ) ( Name "showIntImpl" ) ) ) + ( Ref Nothing ( Local ( Name "a$2" ) ) :| [] ) :| [] + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "negate" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "a$88" ) :| [] ) + ( PrimBinOp Nothing PrimSub + ( LiteralInt Nothing 0 ) + ( Ref Nothing ( Local ( Name "a$88" ) ) ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "sumTriangles" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "m" ) :| [] ) + ( Let Nothing + ( RecursiveGroup + ( + ( Nothing, Name "go$w", AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go$w" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( PrimBinOp Nothing PrimMul + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ) + ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ) :| [] + ) :| [] + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go$w" ) ) ) + ( LiteralInt Nothing 0 :| [ Ref Nothing ( Local ( Name "m" ) ) ] ) + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "escaping" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( Let Nothing + ( RecursiveGroup + ( + ( Nothing, Name "go", AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [] ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( Ref Nothing ( Local ( Name "n" ) ) ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ) + ) :| [] + ) :| [] + ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "m" ) :| [] ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go" ) ) ) + ( Ref Nothing ( Local ( Name "m" ) ) :| [] ) + ) + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "collatzish" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( Let Nothing + ( RecursiveGroup + ( + ( Nothing, Name "go$w", AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "k" ) ] ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "k" ) ) ) + ( LiteralInt Nothing 0 ) + ) + ) + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "k" ) ) ) ( LiteralInt Nothing 0 ) ) + ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go$w" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "k" ) ) ) + ( LiteralInt Nothing 2 ) + ] + ) + ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ) + ) :| [] + ) :| [] + ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 100 ) + ) + ) + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 100 ) ) + ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go$w" ) ) ) + ( LiteralInt Nothing 0 :| [ Ref Nothing ( Local ( Name "n" ) ) ] ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "go$w" ) ) ) + ( LiteralInt Nothing 1 :| + [ PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 3 ) + ] + ) + ) + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "classify" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( Let Nothing + ( Standalone + ( Nothing, Name "finish", AbsN Nothing + ( ParamNamed Nothing ( Name "r" ) :| [] ) + ( PrimBinOp Nothing PrimSub + ( PrimBinOp Nothing PrimMul + ( PrimBinOp Nothing PrimAdd + ( PrimBinOp Nothing PrimMul + ( Ref Nothing ( Local ( Name "r" ) ) ) + ( LiteralInt Nothing 10 ) + ) + ( Ref Nothing ( Local ( Name "r" ) ) ) + ) + ( LiteralInt Nothing 2 ) + ) + ( Ref Nothing ( Local ( Name "r" ) ) ) + ) + ) :| [] + ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 0 ) + ) + ) + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "finish" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "finish" ) ) ) + ( PrimBinOp Nothing PrimSub + ( LiteralInt Nothing 0 ) + ( Ref Nothing ( Local ( Name "n" ) ) ) :| [] + ) + ) + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.JoinPoints.Test", qnameName = Name "chooseEff" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( Let Nothing + ( Standalone + ( Nothing, Name "report", AbsN Nothing + ( ParamNamed Nothing ( Name "m" ) :| [] ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "log" ) ) ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Data.Show" ) ( Name "showIntImpl" ) ) ) + ( PrimBinOp Nothing PrimMul + ( Ref Nothing ( Local ( Name "m" ) ) ) + ( LiteralInt Nothing 2 ) :| [] + ) :| [] + ) + ) + ) :| [] + ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 0 ) + ) + ) + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "report" ) ) ) + ( Ref Nothing ( Local ( Name "n" ) ) :| [] ) + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "report" ) ) ) + ( PrimBinOp Nothing PrimSub + ( LiteralInt Nothing 0 ) + ( Ref Nothing ( Local ( Name "n" ) ) ) :| [] + ) + ) + ) + ) + ) + ], uberModuleForeigns = [], uberModuleExports = + [ + ( Name "sumTriangles", Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "sumTriangles" ) ) + ), + ( Name "collatzish", Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "collatzish" ) ) + ), + ( Name "classify", Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "classify" ) ) + ), + ( Name "escaping", Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "escaping" ) ) + ), + ( Name "chooseEff", Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "chooseEff" ) ) + ), + ( Name "main", AbsN Nothing + ( ParamUnused Nothing :| [] ) + ( Let Nothing + ( Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "sumTriangles" ) ) + ) + ( LiteralInt Nothing 4 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) :| + [ Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "collatzish" ) ) + ) + ( LiteralInt Nothing 10 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "collatzish" ) ) + ) + ( LiteralInt Nothing 200 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "classify" ) ) + ) + ( LiteralInt Nothing 3 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "classify" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "negate" ) ) + ) + ( LiteralInt Nothing 2 :| [] ) :| [] + ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "escaping" ) ) + ) + ( LiteralInt Nothing 5 :| [] ) + ) + ( LiteralInt Nothing 2 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "chooseEff" ) ) + ) + ( LiteralInt Nothing 4 :| [] ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) + ] + ) + ( AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "chooseEff" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.JoinPoints.Test" ) ( Name "negate" ) ) + ) + ( LiteralInt Nothing 3 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) + ) + ) + ] + } \ No newline at end of file diff --git a/test/ps/output/Golden.JoinPoints.Test/golden.lua b/test/ps/output/Golden.JoinPoints.Test/golden.lua new file mode 100644 index 00000000..20288017 --- /dev/null +++ b/test/ps/output/Golden.JoinPoints.Test/golden.lua @@ -0,0 +1,51 @@ +local Data_Show_foreign = { showIntImpl = function(n) return tostring(n) end } +local Data_Show_showIntImpl = Data_Show_foreign.showIntImpl +local Effect_Console_foreign = { + log = function(s) return function() print(s) end end +} +local Effect_Console_log = Effect_Console_foreign.log +local Golden_JoinPoints_Test_logShow = function(a_S_2) + return Effect_Console_log(Data_Show_showIntImpl(a_S_2)) +end +local Golden_JoinPoints_Test_negate = function(a_S_88) return 0 - a_S_88 end +local Golden_JoinPoints_Test_sumTriangles = function(m) + local acc, n + acc, n = 0, m + while true do + if n == 0 then return acc else acc, n = acc + n * (n + 1), n - 1 end + end +end +local Golden_JoinPoints_Test_escaping = function(n) + local go + go = function(acc) + while true do if acc < n then acc = acc + 1 else return acc end end + end + return function(m) return go(m) end +end +local Golden_JoinPoints_Test_collatzish = function(n) + local acc, k + if not(n < 100) and n ~= 100 then acc, k = 0, n else acc, k = 1, n + 3 end + while true do + if not(k < 0) and k ~= 0 then acc, k = acc + 1, k - 2 else return acc end + end +end +local Golden_JoinPoints_Test_classify = function(n) + local r + if not(n < 0) and n ~= 0 then r = n + 1 else r = 0 - n end + return (r * 10 + r) * 2 - r +end +local Golden_JoinPoints_Test_chooseEff = function(n) + local m + if not(n < 0) and n ~= 0 then m = n else m = 0 - n end + return Effect_Console_log(Data_Show_showIntImpl(m * 2)) +end +return (function() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_sumTriangles(4))() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_collatzish(10))() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_collatzish(200))() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_classify(3))() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_classify(Golden_JoinPoints_Test_negate(2)))() + local _ = Golden_JoinPoints_Test_logShow(Golden_JoinPoints_Test_escaping(5)(2))() + local _ = Golden_JoinPoints_Test_chooseEff(4)() + return Golden_JoinPoints_Test_chooseEff(Golden_JoinPoints_Test_negate(3))() +end)() diff --git a/test/ps/output/Golden.Loopification.Test/golden.lua b/test/ps/output/Golden.Loopification.Test/golden.lua index 99a0489f..e6c21b3d 100644 --- a/test/ps/output/Golden.Loopification.Test/golden.lua +++ b/test/ps/output/Golden.Loopification.Test/golden.lua @@ -15,13 +15,11 @@ M.Golden_Loopification_Test_sumTo = function(sumTo_S_p1) end end local Golden_Loopification_Test_sumSquares = function(m) - local go_S_w - go_S_w = function(acc, n) - while true do - if n == 0 then return acc else acc, n = acc + n * n, n - 1 end - end + local acc, n + acc, n = 0, m + while true do + if n == 0 then return acc else acc, n = acc + n * n, n - 1 end end - return go_S_w(0, m) end local Golden_Loopification_Test_sumCPS_S_w Golden_Loopification_Test_sumCPS_S_w = function(n, k) diff --git a/test/ps/output/Golden.MutualLoopification.Test/corefn.json b/test/ps/output/Golden.MutualLoopification.Test/corefn.json new file mode 100644 index 00000000..42f19c21 --- /dev/null +++ b/test/ps/output/Golden.MutualLoopification.Test/corefn.json @@ -0,0 +1 @@ +{"builtWith":"0.15.16","comments":[{"LineComment":" | Exercises loopification of mutual recursion (issue #234): a group"},{"LineComment":" | of workers whose members tail-call each other lowers to a single"},{"LineComment":" | `while true` dispatcher over a branch selector plus shared argument"},{"LineComment":" | slots, with per-member entry wrappers. The eval oracle pins that"},{"LineComment":" | every shape keeps its runtime behavior, dispatched or not."}],"decls":[{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[27,23],"start":[27,21]}},"type":"Var","value":{"identifier":"eq","moduleName":["Data","Eq"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[27,25],"start":[27,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eqInt","moduleName":["Data","Eq"]}},"type":"App"},"identifier":"eq"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[30,52],"start":[30,51]}},"type":"Var","value":{"identifier":"add","moduleName":["Data","Semiring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[30,54],"start":[30,47]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"semiringInt","moduleName":["Data","Semiring"]}},"type":"App"},"identifier":"add"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[30,60],"start":[30,59]}},"type":"Var","value":{"identifier":"sub","moduleName":["Data","Ring"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[30,62],"start":[30,57]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ringInt","moduleName":["Data","Ring"]}},"type":"App"},"identifier":"sub"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[47,14],"start":[47,13]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Data","Ord"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[47,17],"start":[47,11]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"ordInt","moduleName":["Data","Ord"]}},"type":"App"},"identifier":"greaterThan"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[74,22],"start":[74,3]}},"type":"Var","value":{"identifier":"discard","moduleName":["Control","Bind"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discardUnit","moduleName":["Control","Bind"]}},"type":"App"},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"bindEffect","moduleName":["Effect"]}},"type":"App"},"identifier":"discard"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[74,10],"start":[74,3]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Effect","Console"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"showBoolean","moduleName":["Data","Show"]}},"type":"App"},"identifier":"logShow"},{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"bindType":"NonRec","expression":{"abstraction":{"annotation":{"meta":{"metaType":"IsForeign"},"sourceSpan":{"end":[76,10],"start":[76,3]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Effect","Console"]}},"annotation":{"meta":{"metaType":"IsSyntheticApp"},"sourceSpan":{"end":[76,23],"start":[76,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"showInt","moduleName":["Data","Show"]}},"type":"App"},"identifier":"logShow1"},{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[26,28],"start":[26,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[26,28],"start":[26,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[26,28],"start":[26,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[27,51],"start":[27,16]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[27,51],"start":[27,16]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[27,34],"start":[27,31]}},"type":"Var","value":{"identifier":"acc","sourcePos":[27,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[27,51],"start":[27,16]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[27,43],"start":[27,40]}},"type":"Var","value":{"identifier":"zag","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[27,47],"start":[27,40]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[27,47],"start":[27,44]}},"type":"Var","value":{"identifier":"acc","sourcePos":[27,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[27,49],"start":[27,40]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[27,49],"start":[27,48]}},"type":"Var","value":{"identifier":"n","sourcePos":[27,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[27,51],"start":[27,40]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[27,51],"start":[27,50]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[27,25],"start":[27,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[27,20],"start":[27,19]}},"type":"Var","value":{"identifier":"n","sourcePos":[27,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[27,25],"start":[27,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[27,25],"start":[27,24]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"zigzag"},{"annotation":{"meta":null,"sourceSpan":{"end":[29,32],"start":[29,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[29,32],"start":[29,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[29,32],"start":[29,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[29,32],"start":[29,1]}},"argument":"d","body":{"annotation":{"meta":null,"sourceSpan":{"end":[30,63],"start":[30,15]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[30,63],"start":[30,15]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[30,33],"start":[30,30]}},"type":"Var","value":{"identifier":"acc","sourcePos":[30,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[30,63],"start":[30,15]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[30,45],"start":[30,39]}},"type":"Var","value":{"identifier":"zigzag","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[30,55],"start":[30,39]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[30,54],"start":[30,47]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,50],"start":[30,47]}},"type":"Var","value":{"identifier":"acc","sourcePos":[30,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[30,54],"start":[30,47]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,54],"start":[30,53]}},"type":"Var","value":{"identifier":"d","sourcePos":[30,1]}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[30,63],"start":[30,39]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[30,62],"start":[30,57]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,58],"start":[30,57]}},"type":"Var","value":{"identifier":"n","sourcePos":[30,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[30,62],"start":[30,57]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,62],"start":[30,61]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[30,24],"start":[30,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,19],"start":[30,18]}},"type":"Var","value":{"identifier":"n","sourcePos":[30,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[30,24],"start":[30,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[30,24],"start":[30,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"type":"Abs"},"identifier":"zag"}]},{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[58,20],"start":[58,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[58,20],"start":[58,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,11]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,11]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[59,27],"start":[59,26]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,11]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,33]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,34],"start":[59,33]}},"type":"Literal","value":{"literalType":"IntLiteral","value":2}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,33]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[59,42],"start":[59,37]}},"type":"Var","value":{"identifier":"treeA","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,50],"start":[59,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,49],"start":[59,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,45],"start":[59,44]}},"type":"Var","value":{"identifier":"n","sourcePos":[59,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[59,49],"start":[59,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,49],"start":[59,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[59,20],"start":[59,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,15],"start":[59,14]}},"type":"Var","value":{"identifier":"n","sourcePos":[59,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[59,20],"start":[59,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[59,20],"start":[59,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"identifier":"treeB"},{"annotation":{"meta":null,"sourceSpan":{"end":[55,20],"start":[55,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[55,20],"start":[55,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,11]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,11]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[56,27],"start":[56,26]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,11]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,33]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,34],"start":[56,33]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,33]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[56,42],"start":[56,37]}},"type":"Var","value":{"identifier":"treeB","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,50],"start":[56,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,49],"start":[56,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,45],"start":[56,44]}},"type":"Var","value":{"identifier":"n","sourcePos":[56,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[56,49],"start":[56,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,49],"start":[56,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[56,20],"start":[56,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,15],"start":[56,14]}},"type":"Var","value":{"identifier":"n","sourcePos":[56,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[56,20],"start":[56,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[56,20],"start":[56,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"identifier":"treeA"}]},{"annotation":{"meta":null,"sourceSpan":{"end":[63,23],"start":[63,1]}},"bindType":"NonRec","expression":{"annotation":{"meta":null,"sourceSpan":{"end":[63,23],"start":[63,1]}},"argument":"n","body":{"annotation":{"meta":{"metaType":"IsWhere"},"sourceSpan":{"end":[64,22],"start":[64,14]}},"binds":[{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[69,28],"start":[69,3]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[69,28],"start":[69,3]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[69,28],"start":[69,3]}},"argument":"k","body":{"annotation":{"meta":null,"sourceSpan":{"end":[70,62],"start":[70,16]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[70,62],"start":[70,16]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[70,34],"start":[70,31]}},"type":"Var","value":{"identifier":"acc","sourcePos":[70,3]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[70,62],"start":[70,16]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[70,44],"start":[70,40]}},"type":"Var","value":{"identifier":"tick","sourcePos":[66,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[70,54],"start":[70,40]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[70,53],"start":[70,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,49],"start":[70,46]}},"type":"Var","value":{"identifier":"acc","sourcePos":[70,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[70,53],"start":[70,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,53],"start":[70,52]}},"type":"Literal","value":{"literalType":"IntLiteral","value":3}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[70,62],"start":[70,40]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[70,61],"start":[70,56]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,57],"start":[70,56]}},"type":"Var","value":{"identifier":"k","sourcePos":[70,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[70,61],"start":[70,56]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,61],"start":[70,60]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[70,25],"start":[70,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,20],"start":[70,19]}},"type":"Var","value":{"identifier":"k","sourcePos":[70,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[70,25],"start":[70,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[70,25],"start":[70,24]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"tock"},{"annotation":{"meta":null,"sourceSpan":{"end":[66,28],"start":[66,3]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[66,28],"start":[66,3]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[66,28],"start":[66,3]}},"argument":"k","body":{"annotation":{"meta":null,"sourceSpan":{"end":[67,62],"start":[67,16]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[67,62],"start":[67,16]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[67,34],"start":[67,31]}},"type":"Var","value":{"identifier":"acc","sourcePos":[67,3]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[67,62],"start":[67,16]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[67,44],"start":[67,40]}},"type":"Var","value":{"identifier":"tock","sourcePos":[69,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[67,54],"start":[67,40]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[67,53],"start":[67,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,49],"start":[67,46]}},"type":"Var","value":{"identifier":"acc","sourcePos":[67,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[67,53],"start":[67,46]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,53],"start":[67,52]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[67,62],"start":[67,40]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[67,61],"start":[67,56]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,57],"start":[67,56]}},"type":"Var","value":{"identifier":"k","sourcePos":[67,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[67,61],"start":[67,56]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,61],"start":[67,60]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[67,25],"start":[67,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,20],"start":[67,19]}},"type":"Var","value":{"identifier":"k","sourcePos":[67,3]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[67,25],"start":[67,19]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[67,25],"start":[67,24]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"tick"}]}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[64,18],"start":[64,14]}},"type":"Var","value":{"identifier":"tick","sourcePos":[66,3]}},"annotation":{"meta":null,"sourceSpan":{"end":[64,20],"start":[64,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[64,20],"start":[64,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[64,22],"start":[64,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[64,22],"start":[64,21]}},"type":"Var","value":{"identifier":"n","sourcePos":[64,1]}},"type":"App"},"type":"Let"},"type":"Abs"},"identifier":"ticktock"},{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[44,30],"start":[44,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[44,30],"start":[44,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[44,30],"start":[44,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[46,3]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[46,3]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[46,21],"start":[46,18]}},"type":"Var","value":{"identifier":"acc","sourcePos":[45,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[46,3]}},"binderType":"NullBinder"}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[47,8]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[47,8]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[47,31],"start":[47,23]}},"type":"Var","value":{"identifier":"stepSelf","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[47,42],"start":[47,23]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[47,41],"start":[47,33]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,36],"start":[47,33]}},"type":"Var","value":{"identifier":"acc","sourcePos":[45,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[47,41],"start":[47,33]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,41],"start":[47,39]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[47,51],"start":[47,23]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[47,50],"start":[47,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,45],"start":[47,44]}},"type":"Var","value":{"identifier":"n","sourcePos":[45,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[47,50],"start":[47,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,50],"start":[47,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[47,8]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[48,17],"start":[48,8]}},"type":"Var","value":{"identifier":"stepOther","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[48,21],"start":[48,8]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[48,21],"start":[48,18]}},"type":"Var","value":{"identifier":"acc","sourcePos":[45,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[48,8]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[48,23],"start":[48,22]}},"type":"Var","value":{"identifier":"n","sourcePos":[45,1]}},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"greaterThan","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[47,17],"start":[47,11]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,12],"start":[47,11]}},"type":"Var","value":{"identifier":"n","sourcePos":[45,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[47,17],"start":[47,11]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[47,17],"start":[47,15]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"}],"type":"Case"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[46,12],"start":[46,6]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[46,7],"start":[46,6]}},"type":"Var","value":{"identifier":"n","sourcePos":[45,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[46,12],"start":[46,6]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[46,12],"start":[46,11]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"stepSelf"},{"annotation":{"meta":null,"sourceSpan":{"end":[50,31],"start":[50,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[50,31],"start":[50,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[50,31],"start":[50,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[51,69],"start":[51,19]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[51,69],"start":[51,19]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[51,37],"start":[51,34]}},"type":"Var","value":{"identifier":"acc","sourcePos":[51,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[51,69],"start":[51,19]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[51,51],"start":[51,43]}},"type":"Var","value":{"identifier":"stepSelf","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[51,61],"start":[51,43]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[51,60],"start":[51,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,56],"start":[51,53]}},"type":"Var","value":{"identifier":"acc","sourcePos":[51,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[51,60],"start":[51,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,60],"start":[51,59]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[51,69],"start":[51,43]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[51,68],"start":[51,63]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,64],"start":[51,63]}},"type":"Var","value":{"identifier":"n","sourcePos":[51,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[51,68],"start":[51,63]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,68],"start":[51,67]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[51,28],"start":[51,22]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,23],"start":[51,22]}},"type":"Var","value":{"identifier":"n","sourcePos":[51,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[51,28],"start":[51,22]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[51,28],"start":[51,27]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"stepOther"}]},{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[21,24],"start":[21,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[21,24],"start":[21,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[22,51],"start":[22,11]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[22,51],"start":[22,11]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[22,31],"start":[22,26]}},"type":"Literal","value":{"literalType":"BooleanLiteral","value":false}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[22,51],"start":[22,11]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[22,43],"start":[22,37]}},"type":"Var","value":{"identifier":"isEven","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[22,51],"start":[22,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[22,50],"start":[22,45]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[22,46],"start":[22,45]}},"type":"Var","value":{"identifier":"n","sourcePos":[22,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[22,50],"start":[22,45]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[22,50],"start":[22,49]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[22,20],"start":[22,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[22,15],"start":[22,14]}},"type":"Var","value":{"identifier":"n","sourcePos":[22,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[22,20],"start":[22,14]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[22,20],"start":[22,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"identifier":"isOdd"},{"annotation":{"meta":null,"sourceSpan":{"end":[18,25],"start":[18,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[18,25],"start":[18,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[19,50],"start":[19,12]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[19,50],"start":[19,12]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[19,31],"start":[19,27]}},"type":"Literal","value":{"literalType":"BooleanLiteral","value":true}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[19,50],"start":[19,12]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[19,42],"start":[19,37]}},"type":"Var","value":{"identifier":"isOdd","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[19,50],"start":[19,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[19,49],"start":[19,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[19,45],"start":[19,44]}},"type":"Var","value":{"identifier":"n","sourcePos":[19,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[19,49],"start":[19,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[19,49],"start":[19,48]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[19,21],"start":[19,15]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[19,16],"start":[19,15]}},"type":"Var","value":{"identifier":"n","sourcePos":[19,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[19,21],"start":[19,15]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[19,21],"start":[19,20]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"identifier":"isEven"}]},{"bindType":"Rec","binds":[{"annotation":{"meta":null,"sourceSpan":{"end":[33,25],"start":[33,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[33,25],"start":[33,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[33,25],"start":[33,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[34,60],"start":[34,13]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[34,60],"start":[34,13]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[34,31],"start":[34,28]}},"type":"Var","value":{"identifier":"acc","sourcePos":[34,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[34,60],"start":[34,13]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[34,42],"start":[34,37]}},"type":"Var","value":{"identifier":"green","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[34,52],"start":[34,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[34,51],"start":[34,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,47],"start":[34,44]}},"type":"Var","value":{"identifier":"acc","sourcePos":[34,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[34,51],"start":[34,44]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,51],"start":[34,50]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[34,60],"start":[34,37]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[34,59],"start":[34,54]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,55],"start":[34,54]}},"type":"Var","value":{"identifier":"n","sourcePos":[34,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[34,59],"start":[34,54]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,59],"start":[34,58]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[34,22],"start":[34,16]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,17],"start":[34,16]}},"type":"Var","value":{"identifier":"n","sourcePos":[34,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[34,22],"start":[34,16]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[34,22],"start":[34,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"red"},{"annotation":{"meta":null,"sourceSpan":{"end":[36,27],"start":[36,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[36,27],"start":[36,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[36,27],"start":[36,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[37,61],"start":[37,15]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[37,61],"start":[37,15]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[37,33],"start":[37,30]}},"type":"Var","value":{"identifier":"acc","sourcePos":[37,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[37,61],"start":[37,15]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[37,43],"start":[37,39]}},"type":"Var","value":{"identifier":"blue","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[37,53],"start":[37,39]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[37,52],"start":[37,45]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,48],"start":[37,45]}},"type":"Var","value":{"identifier":"acc","sourcePos":[37,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[37,52],"start":[37,45]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,52],"start":[37,51]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[37,61],"start":[37,39]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[37,60],"start":[37,55]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,56],"start":[37,55]}},"type":"Var","value":{"identifier":"n","sourcePos":[37,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[37,60],"start":[37,55]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,60],"start":[37,59]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[37,24],"start":[37,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,19],"start":[37,18]}},"type":"Var","value":{"identifier":"n","sourcePos":[37,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[37,24],"start":[37,18]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[37,24],"start":[37,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"green"},{"annotation":{"meta":null,"sourceSpan":{"end":[39,26],"start":[39,1]}},"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[39,26],"start":[39,1]}},"argument":"acc","body":{"annotation":{"meta":null,"sourceSpan":{"end":[39,26],"start":[39,1]}},"argument":"n","body":{"annotation":{"meta":null,"sourceSpan":{"end":[40,59],"start":[40,14]}},"caseAlternatives":[{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[40,59],"start":[40,14]}},"binderType":"LiteralBinder","literal":{"literalType":"BooleanLiteral","value":true}}],"expression":{"annotation":{"meta":null,"sourceSpan":{"end":[40,32],"start":[40,29]}},"type":"Var","value":{"identifier":"acc","sourcePos":[40,1]}},"isGuarded":false},{"binders":[{"annotation":{"meta":null,"sourceSpan":{"end":[40,59],"start":[40,14]}},"binderType":"NullBinder"}],"expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[40,41],"start":[40,38]}},"type":"Var","value":{"identifier":"red","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[40,51],"start":[40,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"add","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[40,50],"start":[40,43]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,46],"start":[40,43]}},"type":"Var","value":{"identifier":"acc","sourcePos":[40,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[40,50],"start":[40,43]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,50],"start":[40,49]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[40,59],"start":[40,38]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"sub","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[40,58],"start":[40,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,54],"start":[40,53]}},"type":"Var","value":{"identifier":"n","sourcePos":[40,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[40,58],"start":[40,53]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,58],"start":[40,57]}},"type":"Literal","value":{"literalType":"IntLiteral","value":1}},"type":"App"},"type":"App"},"isGuarded":false}],"caseExpressions":[{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"eq","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[40,23],"start":[40,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,18],"start":[40,17]}},"type":"Var","value":{"identifier":"n","sourcePos":[40,1]}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[40,23],"start":[40,17]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[40,23],"start":[40,22]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"}],"type":"Case"},"type":"Abs"},"type":"Abs"},"identifier":"blue"}]},{"annotation":{"meta":null,"sourceSpan":{"end":[72,20],"start":[72,1]}},"bindType":"NonRec","expression":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[74,18],"start":[74,12]}},"type":"Var","value":{"identifier":"isEven","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[74,21],"start":[74,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[74,21],"start":[74,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[74,22],"start":[74,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[75,20],"start":[75,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[75,20],"start":[75,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[75,17],"start":[75,12]}},"type":"Var","value":{"identifier":"isOdd","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[75,19],"start":[75,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[75,19],"start":[75,18]}},"type":"Literal","value":{"literalType":"IntLiteral","value":7}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[75,20],"start":[75,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[75,20],"start":[75,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[76,23],"start":[76,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow1","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[76,23],"start":[76,3]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[76,18],"start":[76,12]}},"type":"Var","value":{"identifier":"zigzag","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[76,20],"start":[76,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[76,20],"start":[76,19]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[76,22],"start":[76,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[76,22],"start":[76,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":3}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[76,23],"start":[76,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[76,23],"start":[76,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[77,21],"start":[77,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow1","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[77,21],"start":[77,3]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[77,15],"start":[77,12]}},"type":"Var","value":{"identifier":"red","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[77,17],"start":[77,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[77,17],"start":[77,16]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[77,20],"start":[77,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[77,20],"start":[77,18]}},"type":"Literal","value":{"literalType":"IntLiteral","value":10}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[77,21],"start":[77,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[77,21],"start":[77,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[78,26],"start":[78,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow1","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[78,26],"start":[78,3]}},"argument":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[78,20],"start":[78,12]}},"type":"Var","value":{"identifier":"stepSelf","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[78,22],"start":[78,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[78,22],"start":[78,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":0}},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[78,25],"start":[78,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[78,25],"start":[78,23]}},"type":"Literal","value":{"literalType":"IntLiteral","value":25}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[78,26],"start":[78,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[78,26],"start":[78,3]}},"argument":"$__unused","body":{"abstraction":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"discard","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[79,20],"start":[79,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow1","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[79,20],"start":[79,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[79,17],"start":[79,12]}},"type":"Var","value":{"identifier":"treeA","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[79,19],"start":[79,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[79,19],"start":[79,18]}},"type":"Literal","value":{"literalType":"IntLiteral","value":5}},"type":"App"},"type":"App"},"type":"App"},"annotation":{"meta":null,"sourceSpan":{"end":[79,20],"start":[79,3]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[79,20],"start":[79,3]}},"argument":"$__unused","body":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[0,0],"start":[0,0]}},"type":"Var","value":{"identifier":"logShow1","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[80,3]}},"argument":{"abstraction":{"annotation":{"meta":null,"sourceSpan":{"end":[80,20],"start":[80,12]}},"type":"Var","value":{"identifier":"ticktock","moduleName":["Golden","MutualLoopification","Test"]}},"annotation":{"meta":null,"sourceSpan":{"end":[80,22],"start":[80,12]}},"argument":{"annotation":{"meta":null,"sourceSpan":{"end":[80,22],"start":[80,21]}},"type":"Literal","value":{"literalType":"IntLiteral","value":5}},"type":"App"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"type":"Abs"},"type":"App"},"identifier":"main"}],"exports":["isEven","isOdd","zigzag","zag","red","green","blue","stepSelf","stepOther","treeA","treeB","ticktock","main"],"foreign":[],"imports":[{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Control","Bind"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Data","Eq"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Data","Ord"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Data","Ring"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Data","Semiring"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Data","Show"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Effect"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Effect","Console"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Golden","MutualLoopification","Test"]},{"annotation":{"meta":null,"sourceSpan":{"end":[8,15],"start":[8,1]}},"moduleName":["Prelude"]},{"annotation":{"meta":null,"sourceSpan":{"end":[80,23],"start":[6,1]}},"moduleName":["Prim"]}],"moduleName":["Golden","MutualLoopification","Test"],"modulePath":"src/Golden/MutualLoopification/Test.purs","reExports":{},"sourceSpan":{"end":[80,23],"start":[6,1]}} \ No newline at end of file diff --git a/test/ps/output/Golden.MutualLoopification.Test/eval/.gitignore b/test/ps/output/Golden.MutualLoopification.Test/eval/.gitignore new file mode 100644 index 00000000..d2dc29bb --- /dev/null +++ b/test/ps/output/Golden.MutualLoopification.Test/eval/.gitignore @@ -0,0 +1 @@ +actual.txt diff --git a/test/ps/output/Golden.MutualLoopification.Test/eval/golden.txt b/test/ps/output/Golden.MutualLoopification.Test/eval/golden.txt new file mode 100644 index 00000000..29261dff --- /dev/null +++ b/test/ps/output/Golden.MutualLoopification.Test/eval/golden.txt @@ -0,0 +1,7 @@ +true +true +3 +10 +25 +9 +9 diff --git a/test/ps/output/Golden.MutualLoopification.Test/golden.ir b/test/ps/output/Golden.MutualLoopification.Test/golden.ir new file mode 100644 index 00000000..3366119a --- /dev/null +++ b/test/ps/output/Golden.MutualLoopification.Test/golden.ir @@ -0,0 +1,677 @@ +UberModule + { uberModuleBindings = + [ Standalone + ( QName + { qnameModuleName = ModuleName "Data.Show", qnameName = Name "foreign" + }, ForeignImport Nothing + ( ModuleName "Data.Show" ) ".spago/p/prelude/5718c84fdde6247749cb053e816df696c30fe691/src/Data/Show.purs" + [ ( Nothing, Name "showIntImpl" ) ] + ), Standalone + ( QName + { qnameModuleName = ModuleName "Effect.Console", qnameName = Name "foreign" + }, ForeignImport Nothing + ( ModuleName "Effect.Console" ) ".spago/p/console/f82835a0b873aafe6bd7b14dd30cc150553d4ab9/src/Effect/Console.purs" + [ ( Nothing, Name "log" ) ] + ), Standalone + ( QName + { qnameModuleName = ModuleName "Effect.Console", qnameName = Name "log" + }, ObjectProp Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "foreign" ) ) ) + ( PropName "log" ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "logShow" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "a$294" ) :| [] ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "log" ) ) ) + ( IfThenElse Nothing + ( Ref Nothing ( Local ( Name "a$294" ) ) ) + ( LiteralString Nothing "true" ) + ( LiteralString Nothing "false" ) :| [] + ) + ) + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "logShow1" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "a$292" ) :| [] ) + ( AppN Nothing + ( Ref Nothing ( Imported ( ModuleName "Effect.Console" ) ( Name "log" ) ) ) + ( AppN Nothing + ( ObjectProp Nothing + ( Ref Nothing ( Imported ( ModuleName "Data.Show" ) ( Name "foreign" ) ) ) + ( PropName "showIntImpl" ) + ) + ( Ref Nothing ( Local ( Name "a$292" ) ) :| [] ) :| [] + ) + ) + ), RecursiveGroup + ( + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "zigzag$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zag$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "acc" ) ) :| + [ Ref Nothing ( Local ( Name "n" ) ), LiteralInt Nothing 1 ] + ) + ) + ) + ) :| + [ + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "zigzag" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "zigzag$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "zigzag$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zigzag$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "zigzag$p1" ) ) :| + [ Ref Nothing ( Local ( Name "zigzag$p2" ) ) ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "zag$w" + }, AbsN Nothing + ( ParamNamed Nothing + ( Name "acc" ) :| + [ ParamNamed Nothing ( Name "n" ), ParamNamed Nothing ( Name "d" ) ] + ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zigzag$w" ) ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( Ref Nothing ( Local ( Name "d" ) ) ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "zag" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "zag$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "zag$p2" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "zag$p3" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zag$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "zag$p1" ) ) :| + [ Ref Nothing + ( Local ( Name "zag$p2" ) ), Ref Nothing + ( Local ( Name "zag$p3" ) ) + ] + ) + ) + ) + ) + ) + ] + ), RecursiveGroup + ( + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "treeB" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( LiteralInt Nothing 2 ) + ( PrimBinOp Nothing PrimAdd + ( LiteralInt Nothing 2 ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "treeA" ) ) + ) + ( PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ) + ) + ) :| + [ + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "treeA" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( LiteralInt Nothing 1 ) + ( PrimBinOp Nothing PrimAdd + ( LiteralInt Nothing 1 ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "treeB" ) ) + ) + ( PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ) + ) + ) + ] + ), Standalone + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "ticktock" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( Let Nothing + ( RecursiveGroup + ( + ( Nothing, Name "tock$w", AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "k" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "k" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "tick$w" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 3 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "k" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ) :| + [ + ( Nothing, Name "tick$w", AbsN Nothing + ( ParamNamed Nothing ( Name "acc0" ) :| [ ParamNamed Nothing ( Name "k0" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "k0" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc0" ) ) ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "tock$w" ) ) ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc0" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "k0" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ) + ] + ) :| [] + ) + ( AppN Nothing + ( Ref Nothing ( Local ( Name "tick$w" ) ) ) + ( LiteralInt Nothing 0 :| [ Ref Nothing ( Local ( Name "n" ) ) ] ) + ) + ) + ), RecursiveGroup + ( + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "stepSelf$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( IfThenElse Nothing + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( PrimBinOp Nothing PrimLt + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 10 ) + ) + ) + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 10 ) ) + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepSelf$w" ) + ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 10 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 10 ) + ] + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepOther$w" ) + ) + ) + ( Ref Nothing ( Local ( Name "acc" ) ) :| [ Ref Nothing ( Local ( Name "n" ) ) ] ) + ) + ) + ) + ) :| + [ + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "stepSelf" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "stepSelf$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "stepSelf$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepSelf$w" ) + ) + ) + ( Ref Nothing + ( Local ( Name "stepSelf$p1" ) ) :| + [ Ref Nothing ( Local ( Name "stepSelf$p2" ) ) ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "stepOther$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepSelf$w" ) + ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "stepOther" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "stepOther$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "stepOther$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepOther$w" ) + ) + ) + ( Ref Nothing + ( Local ( Name "stepOther$p1" ) ) :| + [ Ref Nothing ( Local ( Name "stepOther$p2" ) ) ] + ) + ) + ) + ) + ] + ), RecursiveGroup + ( + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "isOdd" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( PrimBinOp Nothing PrimAnd + ( PrimNot Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isEven" ) ) + ) + ( PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ) + ) :| + [ + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "isEven" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "n" ) :| [] ) + ( PrimBinOp Nothing PrimOr + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isOdd" ) ) + ) + ( PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) :| [] + ) + ) + ) + ) + ] + ), RecursiveGroup + ( + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "red$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "green$w" ) ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ) :| + [ + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "red" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "red$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "red$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "red$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "red$p1" ) ) :| + [ Ref Nothing ( Local ( Name "red$p2" ) ) ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "green$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "blue$w" ) ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "green" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "green$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "green$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "green$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "green$p1" ) ) :| + [ Ref Nothing ( Local ( Name "green$p2" ) ) ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "blue$w" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "acc" ) :| [ ParamNamed Nothing ( Name "n" ) ] ) + ( IfThenElse Nothing + ( Eq Nothing ( Ref Nothing ( Local ( Name "n" ) ) ) ( LiteralInt Nothing 0 ) ) + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "red$w" ) ) + ) + ( PrimBinOp Nothing PrimAdd + ( Ref Nothing ( Local ( Name "acc" ) ) ) + ( LiteralInt Nothing 1 ) :| + [ PrimBinOp Nothing PrimSub + ( Ref Nothing ( Local ( Name "n" ) ) ) + ( LiteralInt Nothing 1 ) + ] + ) + ) + ) + ), + ( QName + { qnameModuleName = ModuleName "Golden.MutualLoopification.Test", qnameName = Name "blue" + }, AbsN Nothing + ( ParamNamed Nothing ( Name "blue$p1" ) :| [] ) + ( AbsN Nothing + ( ParamNamed Nothing ( Name "blue$p2" ) :| [] ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "blue$w" ) ) + ) + ( Ref Nothing + ( Local ( Name "blue$p1" ) ) :| + [ Ref Nothing ( Local ( Name "blue$p2" ) ) ] + ) + ) + ) + ) + ] + ) + ], uberModuleForeigns = [], uberModuleExports = + [ + ( Name "isEven", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isEven" ) ) + ), + ( Name "isOdd", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isOdd" ) ) + ), + ( Name "zigzag", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zigzag" ) ) + ), + ( Name "zag", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "zag" ) ) + ), + ( Name "red", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "red" ) ) + ), + ( Name "green", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "green" ) ) + ), + ( Name "blue", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "blue" ) ) + ), + ( Name "stepSelf", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "stepSelf" ) ) + ), + ( Name "stepOther", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "stepOther" ) ) + ), + ( Name "treeA", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "treeA" ) ) + ), + ( Name "treeB", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "treeB" ) ) + ), + ( Name "ticktock", Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "ticktock" ) ) + ), + ( Name "main", AbsN Nothing + ( ParamUnused Nothing :| [] ) + ( Let Nothing + ( Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isEven" ) ) + ) + ( LiteralInt Nothing 10 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) :| + [ Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "logShow" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "isOdd" ) ) + ) + ( LiteralInt Nothing 7 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "logShow1" ) + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "zigzag$w" ) + ) + ) + ( LiteralInt Nothing 0 :| [ LiteralInt Nothing 3 ] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "logShow1" ) + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "red$w" ) ) + ) + ( LiteralInt Nothing 0 :| [ LiteralInt Nothing 10 ] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "logShow1" ) + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "stepSelf$w" ) + ) + ) + ( LiteralInt Nothing 0 :| [ LiteralInt Nothing 25 ] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ), Standalone + ( Nothing, Name "_", AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported + ( ModuleName "Golden.MutualLoopification.Test" ) + ( Name "logShow1" ) + ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "treeA" ) ) + ) + ( LiteralInt Nothing 5 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) + ] + ) + ( AppN Nothing + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "logShow1" ) ) + ) + ( AppN Nothing + ( Ref Nothing + ( Imported ( ModuleName "Golden.MutualLoopification.Test" ) ( Name "ticktock" ) ) + ) + ( LiteralInt Nothing 5 :| [] ) :| [] + ) + ) + ( Ref Nothing ( Imported ( ModuleName "Prim" ) ( Name "$magicDoRun" ) ) :| [] ) + ) + ) + ) + ] + } \ No newline at end of file diff --git a/test/ps/output/Golden.MutualLoopification.Test/golden.lua b/test/ps/output/Golden.MutualLoopification.Test/golden.lua new file mode 100644 index 00000000..f646af09 --- /dev/null +++ b/test/ps/output/Golden.MutualLoopification.Test/golden.lua @@ -0,0 +1,203 @@ +local M = {} +local Data_Show_foreign = { showIntImpl = function(n) return tostring(n) end } +local Effect_Console_foreign = { + log = function(s) return function() print(s) end end +} +local Effect_Console_log = Effect_Console_foreign.log +local Golden_MutualLoopification_Test_logShow = function(a_S_294) + return Effect_Console_log((function() + if a_S_294 then return "true" else return "false" end + end)()) +end +local Golden_MutualLoopification_Test_logShow1 = function(a_S_292) + return Effect_Console_log(Data_Show_foreign.showIntImpl(a_S_292)) +end +local Golden_MutualLoopification_Test_zigzag_S_w_S_loop = function( _S_sel0 +, _S_a1 +, _S_a2 +, _S_a3 ) + while true do + if _S_sel0 == 1 then + local acc, n = _S_a1, _S_a2 + if n == 0 then + return acc + else + _S_sel0, _S_a1, _S_a2, _S_a3 = 2, acc, n, 1 + end + else + local acc, n, d = _S_a1, _S_a2, _S_a3 + if n == 0 then + return acc + else + _S_sel0, _S_a1, _S_a2, _S_a3 = 1, acc + d, n - 1, nil + end + end + end +end +local Golden_MutualLoopification_Test_zigzag_S_w = function(acc, n) + return Golden_MutualLoopification_Test_zigzag_S_w_S_loop(1, acc, n) +end +M.Golden_MutualLoopification_Test_zigzag = function(zigzag_S_p1) + return function(zigzag_S_p2) + return Golden_MutualLoopification_Test_zigzag_S_w(zigzag_S_p1, zigzag_S_p2) + end +end +local Golden_MutualLoopification_Test_zag_S_w = function(acc, n, d) + return Golden_MutualLoopification_Test_zigzag_S_w_S_loop(2, acc, n, d) +end +M.Golden_MutualLoopification_Test_zag = function(zag_S_p1) + return function(zag_S_p2) + return function(zag_S_p3) + return Golden_MutualLoopification_Test_zag_S_w(zag_S_p1, zag_S_p2, zag_S_p3) + end + end +end +local Golden_MutualLoopification_Test_treeA +local Golden_MutualLoopification_Test_treeB = function(n) + if n == 0 then + return 2 + else + return 2 + Golden_MutualLoopification_Test_treeA(n - 1) + end +end +Golden_MutualLoopification_Test_treeA = function(n) + if n == 0 then + return 1 + else + return 1 + Golden_MutualLoopification_Test_treeB(n - 1) + end +end +local Golden_MutualLoopification_Test_ticktock = function(n) + local tock_S_w_S_loop + local tock_S_w + local acc0, k0 + tock_S_w_S_loop = function(_S_sel4, _S_a5, _S_a6) + while true do + if _S_sel4 == 1 then + local acc, k = _S_a5, _S_a6 + if k == 0 then + return acc + else + _S_sel4, _S_a5, _S_a6 = 2, acc + 3, k - 1 + end + else + local acc0, k0 = _S_a5, _S_a6 + if k0 == 0 then + return acc0 + else + _S_sel4, _S_a5, _S_a6 = 1, acc0 + 1, k0 - 1 + end + end + end + end + tock_S_w = function(acc, k) return tock_S_w_S_loop(1, acc, k) end + acc0, k0 = 0, n + return tock_S_w_S_loop(2, acc0, k0) +end +local Golden_MutualLoopification_Test_stepSelf_S_w_S_loop = function( _S_sel7 +, _S_a8 +, _S_a9 ) + while true do + if _S_sel7 == 1 then + local acc, n = _S_a8, _S_a9 + if n == 0 then + return acc + elseif not(n < 10) and n ~= 10 then + _S_sel7, _S_a8, _S_a9 = 1, acc + 10, n - 10 + else + _S_sel7, _S_a8, _S_a9 = 2, acc, n + end + else + local acc, n = _S_a8, _S_a9 + if n == 0 then + return acc + else + _S_sel7, _S_a8, _S_a9 = 1, acc + 1, n - 1 + end + end + end +end +local Golden_MutualLoopification_Test_stepSelf_S_w = function(acc, n) + return Golden_MutualLoopification_Test_stepSelf_S_w_S_loop(1, acc, n) +end +M.Golden_MutualLoopification_Test_stepSelf = function(stepSelf_S_p1) + return function(stepSelf_S_p2) + return Golden_MutualLoopification_Test_stepSelf_S_w(stepSelf_S_p1, stepSelf_S_p2) + end +end +local Golden_MutualLoopification_Test_stepOther_S_w = function(acc, n) + return Golden_MutualLoopification_Test_stepSelf_S_w_S_loop(2, acc, n) +end +M.Golden_MutualLoopification_Test_stepOther = function(stepOther_S_p1) + return function(stepOther_S_p2) + return Golden_MutualLoopification_Test_stepOther_S_w(stepOther_S_p1, stepOther_S_p2) + end +end +local Golden_MutualLoopification_Test_isEven +local Golden_MutualLoopification_Test_isOdd = function(n) + return n ~= 0 and Golden_MutualLoopification_Test_isEven(n - 1) +end +Golden_MutualLoopification_Test_isEven = function(n) + return n == 0 or Golden_MutualLoopification_Test_isOdd(n - 1) +end +local Golden_MutualLoopification_Test_red_S_w_S_loop = function( _S_sel10 +, _S_a11 +, _S_a12 ) + while true do + if _S_sel10 == 1 then + local acc, n = _S_a11, _S_a12 + if n == 0 then + return acc + else + _S_sel10, _S_a11, _S_a12 = 2, acc + 1, n - 1 + end + elseif _S_sel10 == 2 then + local acc, n = _S_a11, _S_a12 + if n == 0 then + return acc + else + _S_sel10, _S_a11, _S_a12 = 3, acc + 1, n - 1 + end + else + local acc, n = _S_a11, _S_a12 + if n == 0 then + return acc + else + _S_sel10, _S_a11, _S_a12 = 1, acc + 1, n - 1 + end + end + end +end +local Golden_MutualLoopification_Test_red_S_w = function(acc, n) + return Golden_MutualLoopification_Test_red_S_w_S_loop(1, acc, n) +end +M.Golden_MutualLoopification_Test_red = function(red_S_p1) + return function(red_S_p2) + return Golden_MutualLoopification_Test_red_S_w(red_S_p1, red_S_p2) + end +end +local Golden_MutualLoopification_Test_green_S_w = function(acc, n) + return Golden_MutualLoopification_Test_red_S_w_S_loop(2, acc, n) +end +M.Golden_MutualLoopification_Test_green = function(green_S_p1) + return function(green_S_p2) + return Golden_MutualLoopification_Test_green_S_w(green_S_p1, green_S_p2) + end +end +local Golden_MutualLoopification_Test_blue_S_w = function(acc, n) + return Golden_MutualLoopification_Test_red_S_w_S_loop(3, acc, n) +end +M.Golden_MutualLoopification_Test_blue = function(blue_S_p1) + return function(blue_S_p2) + return Golden_MutualLoopification_Test_blue_S_w(blue_S_p1, blue_S_p2) + end +end +return (function() + local _ = Golden_MutualLoopification_Test_logShow(Golden_MutualLoopification_Test_isEven(10))() + local _ = Golden_MutualLoopification_Test_logShow(Golden_MutualLoopification_Test_isOdd(7))() + local _ = Golden_MutualLoopification_Test_logShow1(Golden_MutualLoopification_Test_zigzag_S_w(0, 3))() + local _ = Golden_MutualLoopification_Test_logShow1(Golden_MutualLoopification_Test_red_S_w(0, 10))() + local _ = Golden_MutualLoopification_Test_logShow1(Golden_MutualLoopification_Test_stepSelf_S_w(0, 25))() + local _ = Golden_MutualLoopification_Test_logShow1(Golden_MutualLoopification_Test_treeA(5))() + return Golden_MutualLoopification_Test_logShow1(Golden_MutualLoopification_Test_ticktock(5))() +end)() diff --git a/test/ps/output/Golden.RecursiveBindings.Test/golden.lua b/test/ps/output/Golden.RecursiveBindings.Test/golden.lua index c7c1671a..665b7b47 100644 --- a/test/ps/output/Golden.RecursiveBindings.Test/golden.lua +++ b/test/ps/output/Golden.RecursiveBindings.Test/golden.lua @@ -1,32 +1,68 @@ return { letRec = (function() + local yes_S_0_S_loop local yes_S_0 - local no_S_1 - yes_S_0 = function(v_S_2) - if v_S_2 then return no_S_1(false) else return no_S_1(true) end + local v0_S_3 + yes_S_0_S_loop = function(_S_sel0, _S_a1) + while true do + if _S_sel0 == 1 then + local v_S_2 = _S_a1 + if v_S_2 then + _S_sel0, _S_a1 = 2, false + else + _S_sel0, _S_a1 = 2, true + end + else + local v0_S_3 = _S_a1 + if v0_S_3 then + _S_sel0, _S_a1 = 1, false + else + _S_sel0, _S_a1 = 1, true + end + end + end end - no_S_1 = function(v0_S_3) - if v0_S_3 then return yes_S_0(false) else return yes_S_0(true) end - end - return no_S_1(false) + yes_S_0 = function(v_S_2) return yes_S_0_S_loop(1, v_S_2) end + v0_S_3 = false + return yes_S_0_S_loop(2, v0_S_3) end)(), whereRec = (function() + local yes_S_14_S_loop local yes_S_14 - local no_S_15 - yes_S_14 = function(v_S_16) - if v_S_16 then return no_S_15(false) else return no_S_15(true) end - end - no_S_15 = function(v0_S_17) - if v0_S_17 then return yes_S_14(false) else return yes_S_14(true) end + local v0_S_17 + yes_S_14_S_loop = function(_S_sel2, _S_a3) + while true do + if _S_sel2 == 1 then + local v_S_16 = _S_a3 + if v_S_16 then + _S_sel2, _S_a3 = 2, false + else + _S_sel2, _S_a3 = 2, true + end + else + local v0_S_17 = _S_a3 + if v0_S_17 then + _S_sel2, _S_a3 = 1, false + else + _S_sel2, _S_a3 = 1, true + end + end + end end - return no_S_15(false) + yes_S_14 = function(v_S_16) return yes_S_14_S_loop(1, v_S_16) end + v0_S_17 = false + return yes_S_14_S_loop(2, v0_S_17) end)(), letRecMixed = (function() local z_S_4 = 1 + local b_S_5_S_loop local b_S_5 local a_S_6 - b_S_5 = function() return a_S_6(z_S_4) end - a_S_6 = function() return b_S_5(z_S_4) end + b_S_5_S_loop = function(_S_sel4) + while true do if _S_sel4 == 1 then _S_sel4 = 2 else _S_sel4 = 1 end end + end + b_S_5 = function() return b_S_5_S_loop(1) end + a_S_6 = function() return b_S_5_S_loop(2) end local f_S_7_S_w = function(f_S_7_S_u1, k_S_13) return a_S_6(k_S_13) end local y_S_8 = f_S_7_S_w(z_S_4, z_S_4) return f_S_7_S_w(f_S_7_S_w(y_S_8, y_S_8), f_S_7_S_w(y_S_8, 0)) diff --git a/test/ps/output/Golden.SpecConstr.Test/golden.lua b/test/ps/output/Golden.SpecConstr.Test/golden.lua index 8c57a790..4fc12e80 100644 --- a/test/ps/output/Golden.SpecConstr.Test/golden.lua +++ b/test/ps/output/Golden.SpecConstr.Test/golden.lua @@ -12,17 +12,15 @@ local Effect_Console_logShow_S_w = function(dictShow, a) return Effect_Console_foreign.log(dictShow.show(a)) end M.Golden_SpecConstr_Test_sumCount = function(n) - local go_S_sc1Tuple - go_S_sc1Tuple = function(go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2) - while true do - if go_S_sc1Tuple_S_f2 < n then - go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 = go_S_sc1Tuple_S_f1 + go_S_sc1Tuple_S_f2, go_S_sc1Tuple_S_f2 + 1 - else - return { go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 } - end + local go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 + go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 = 0, 0 + while true do + if go_S_sc1Tuple_S_f2 < n then + go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 = go_S_sc1Tuple_S_f1 + go_S_sc1Tuple_S_f2, go_S_sc1Tuple_S_f2 + 1 + else + return { go_S_sc1Tuple_S_f1, go_S_sc1Tuple_S_f2 } end end - return go_S_sc1Tuple(0, 0) end local Golden_SpecConstr_Test_stepDown_S_sc1Just = function( stepDown_S_sc1Just_S_f1 ) while true do @@ -43,15 +41,32 @@ local Golden_SpecConstr_Test_stepDown = function(m) return Golden_SpecConstr_Test_stepDown_S_sc1Just(_S_cse501 - 1) end end -local Golden_SpecConstr_Test_ping_S_sc1Tuple +local Golden_SpecConstr_Test_pong_S_sc1Tuple_S_loop = function( _S_sel0 +, _S_a1 +, _S_a2 ) + while true do + if _S_sel0 == 1 then + local pong_S_sc1Tuple_S_f1, pong_S_sc1Tuple_S_f2 = _S_a1, _S_a2 + if pong_S_sc1Tuple_S_f1 == 0 then + return pong_S_sc1Tuple_S_f2 + else + _S_sel0, _S_a1, _S_a2 = 2, pong_S_sc1Tuple_S_f1 - 1, pong_S_sc1Tuple_S_f2 + 2 + end + else + local ping_S_sc1Tuple_S_f1, ping_S_sc1Tuple_S_f2 = _S_a1, _S_a2 + if ping_S_sc1Tuple_S_f1 == 0 then + return ping_S_sc1Tuple_S_f2 + else + _S_sel0, _S_a1, _S_a2 = 1, ping_S_sc1Tuple_S_f1 - 1, ping_S_sc1Tuple_S_f2 + 1 + end + end + end +end local Golden_SpecConstr_Test_pong_S_sc1Tuple = function( pong_S_sc1Tuple_S_f1 , pong_S_sc1Tuple_S_f2 ) - if pong_S_sc1Tuple_S_f1 == 0 then - return pong_S_sc1Tuple_S_f2 - else - return Golden_SpecConstr_Test_ping_S_sc1Tuple(pong_S_sc1Tuple_S_f1 - 1, pong_S_sc1Tuple_S_f2 + 2) - end + return Golden_SpecConstr_Test_pong_S_sc1Tuple_S_loop(1, pong_S_sc1Tuple_S_f1, pong_S_sc1Tuple_S_f2) end +local Golden_SpecConstr_Test_ping_S_sc1Tuple M.Golden_SpecConstr_Test_pong = function(t) local _S_cse503 = t[2] local _S_cse502 = t[1] @@ -63,11 +78,7 @@ M.Golden_SpecConstr_Test_pong = function(t) end Golden_SpecConstr_Test_ping_S_sc1Tuple = function( ping_S_sc1Tuple_S_f1 , ping_S_sc1Tuple_S_f2 ) - if ping_S_sc1Tuple_S_f1 == 0 then - return ping_S_sc1Tuple_S_f2 - else - return Golden_SpecConstr_Test_pong_S_sc1Tuple(ping_S_sc1Tuple_S_f1 - 1, ping_S_sc1Tuple_S_f2 + 1) - end + return Golden_SpecConstr_Test_pong_S_sc1Tuple_S_loop(2, ping_S_sc1Tuple_S_f1, ping_S_sc1Tuple_S_f2) end M.Golden_SpecConstr_Test_ping = function(t) local _S_cse505 = t[2] @@ -97,18 +108,15 @@ return (function() return "(Tuple " .. Data_Show_showIntImpl(v_S_86[1]) .. " " .. Data_Show_showIntImpl(v_S_86[2]) .. ")" end }, (function() - local go_S_sc1Tuple_S_494 - go_S_sc1Tuple_S_494 = function( go_S_sc1Tuple_S_f1_S_495 - , go_S_sc1Tuple_S_f2_S_496 ) - while true do - if go_S_sc1Tuple_S_f2_S_496 < 5 then - go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 = go_S_sc1Tuple_S_f1_S_495 + go_S_sc1Tuple_S_f2_S_496, go_S_sc1Tuple_S_f2_S_496 + 1 - else - return { go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 } - end + local go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 + go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 = 0, 0 + while true do + if go_S_sc1Tuple_S_f2_S_496 < 5 then + go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 = go_S_sc1Tuple_S_f1_S_495 + go_S_sc1Tuple_S_f2_S_496, go_S_sc1Tuple_S_f2_S_496 + 1 + else + return { go_S_sc1Tuple_S_f1_S_495, go_S_sc1Tuple_S_f2_S_496 } end end - return go_S_sc1Tuple_S_494(0, 0) end)())() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, Golden_SpecConstr_Test_stepDown_S_sc1Just(3))() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, Golden_SpecConstr_Test_stepDown({ diff --git a/test/ps/output/Golden.Uncurry.Test/golden.lua b/test/ps/output/Golden.Uncurry.Test/golden.lua index 2f3ea0a1..3949c588 100644 --- a/test/ps/output/Golden.Uncurry.Test/golden.lua +++ b/test/ps/output/Golden.Uncurry.Test/golden.lua @@ -29,31 +29,39 @@ local Effect_Console_logShow_S_w = function(dictShow, a) return Effect_Console_foreign.log(dictShow.show(a)) end M.Golden_Uncurry_Test_sumTo = function(m) - local go_S_w - go_S_w = function(acc, n) - while true do if n == 0 then return acc else acc, n = acc + n, n - 1 end end + local acc, n + acc, n = 0, m + while true do if n == 0 then return acc else acc, n = acc + n, n - 1 end end +end +local Golden_Uncurry_Test_oddSteps_S_w_S_loop = function(_S_sel0, _S_a1, _S_a2) + while true do + if _S_sel0 == 1 then + local acc, n = _S_a1, _S_a2 + if n == 0 then + return acc + else + _S_sel0, _S_a1, _S_a2 = 2, acc + 1, n - 1 + end + else + local acc, n = _S_a1, _S_a2 + if n == 0 then + return acc + else + _S_sel0, _S_a1, _S_a2 = 1, acc + 1, n - 1 + end + end end - return go_S_w(0, m) end -local Golden_Uncurry_Test_evenSteps_S_w local Golden_Uncurry_Test_oddSteps_S_w = function(acc, n) - if n == 0 then - return acc - else - return Golden_Uncurry_Test_evenSteps_S_w(acc + 1, n - 1) - end + return Golden_Uncurry_Test_oddSteps_S_w_S_loop(1, acc, n) end M.Golden_Uncurry_Test_oddSteps = function(oddSteps_S_p1) return function(oddSteps_S_p2) return Golden_Uncurry_Test_oddSteps_S_w(oddSteps_S_p1, oddSteps_S_p2) end end -Golden_Uncurry_Test_evenSteps_S_w = function(acc, n) - if n == 0 then - return acc - else - return Golden_Uncurry_Test_oddSteps_S_w(acc + 1, n - 1) - end +local Golden_Uncurry_Test_evenSteps_S_w = function(acc, n) + return Golden_Uncurry_Test_oddSteps_S_w_S_loop(2, acc, n) end M.Golden_Uncurry_Test_evenSteps = function(evenSteps_S_p1) return function(evenSteps_S_p2) @@ -81,30 +89,26 @@ return (function() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, Golden_Uncurry_Test_evenSteps_S_w(0, 10))() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, Golden_Uncurry_Test_oddSteps_S_w(0, 7))() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, (function() - local go_S_w_S_326 - go_S_w_S_326 = function(acc_S_327, n_S_328) - while true do - if n_S_328 == 0 then - return acc_S_327 - else - acc_S_327, n_S_328 = acc_S_327 + n_S_328, n_S_328 - 1 - end + local acc_S_327, n_S_328 + acc_S_327, n_S_328 = 0, 10 + while true do + if n_S_328 == 0 then + return acc_S_327 + else + acc_S_327, n_S_328 = acc_S_327 + n_S_328, n_S_328 - 1 end end - return go_S_w_S_326(0, 10) end)())() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, (function() - local go_S_w_S_331 - go_S_w_S_331 = function(acc_S_332, n_S_333) - while true do - if n_S_333 == 0 then - return acc_S_332 - else - acc_S_332, n_S_333 = acc_S_332 + n_S_333, n_S_333 - 1 - end + local acc_S_332, n_S_333 + acc_S_332, n_S_333 = 0, 100 + while true do + if n_S_333 == 0 then + return acc_S_332 + else + acc_S_332, n_S_333 = acc_S_332 + n_S_333, n_S_333 - 1 end end - return go_S_w_S_331(0, 100) end)())() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, 6)() local _ = Effect_Console_logShow_S_w(Data_Show_showInt, 9)() diff --git a/test/ps/src/Bench/MutualStep.purs b/test/ps/src/Bench/MutualStep.purs new file mode 100644 index 00000000..3c927df2 --- /dev/null +++ b/test/ps/src/Bench/MutualStep.purs @@ -0,0 +1,18 @@ +-- | The mutual twin of `Bench.CurriedStep`: the same hot two-argument +-- | accumulator loop, but split across two workers tail-calling each +-- | other, so every iteration is a transition between group members. +-- | Dispatched (issue #234), the pair becomes one `while true` loop +-- | over a branch selector — a stable loop trace instead of a CALL/RET +-- | per transition. +module Bench.MutualStep where + +import Prelude + +run :: Int -> Int +run n = stepA 0 n + where + stepA :: Int -> Int -> Int + stepA acc i = if i == 0 then acc else stepB (acc + i) (i - 1) + + stepB :: Int -> Int -> Int + stepB acc i = if i == 0 then acc else stepA (acc + i) (i - 1) diff --git a/test/ps/src/Golden/JoinPoints/Test.purs b/test/ps/src/Golden/JoinPoints/Test.purs new file mode 100644 index 00000000..7b621b5a --- /dev/null +++ b/test/ps/src/Golden/JoinPoints/Test.purs @@ -0,0 +1,61 @@ +-- | Exercises join points (issue #234): a let-bound helper only ever +-- | tail-called from the enclosing body loses its function shell — the +-- | entry calls become parameter assignments falling through into the +-- | helper's body (a loop when the helper is self-recursive). The eval +-- | oracle pins that every shape keeps its runtime behavior, fused or +-- | not. +module Golden.JoinPoints.Test where + +import Prelude + +import Effect (Effect) +import Effect.Console (logShow) + +-- A where-bound self-recursive worker whose only outside use is the +-- body's tail call: the entry call is assimilated into the worker's +-- loop (composes with #181 loopification). +sumTriangles :: Int -> Int +sumTriangles m = go 0 m + where + go :: Int -> Int -> Int + go acc n = if n == 0 then acc else go (acc + n * (n + 1)) (n - 1) + +-- The recursive worker is tail-called from two branches of the body: +-- both entries fall through into one loop. +collatzish :: Int -> Int +collatzish n = if n > 100 then go 0 n else go 1 (n + 3) + where + go :: Int -> Int -> Int + go acc k = if k <= 0 then acc else go (acc + 1) (k - 2) + +-- A non-recursive shared continuation called in tail position from two +-- branches — a classic join point; loses the call without any loop. +classify :: Int -> Int +classify n = + let finish r = (r * 10 + r) * 2 - r + in if n > 0 then finish (n + 1) else finish (0 - n) + +-- The helper escapes into a closure, so it must stay a real function: +-- the join transform must not fire. +escaping :: Int -> (Int -> Int) +escaping n = + let go acc = if acc >= n then acc else go (acc + 1) + in \m -> go m + +-- A join point in effect land: the continuation is tail-called from +-- both branches of an effectful body. +chooseEff :: Int -> Effect Unit +chooseEff n = + let report m = logShow (m * 2) + in if n > 0 then report n else report (0 - n) + +main :: Effect Unit +main = do + logShow (sumTriangles 4) + logShow (collatzish 10) + logShow (collatzish 200) + logShow (classify 3) + logShow (classify (-2)) + logShow ((escaping 5) 2) + chooseEff 4 + chooseEff (-3) diff --git a/test/ps/src/Golden/MutualLoopification/Test.purs b/test/ps/src/Golden/MutualLoopification/Test.purs new file mode 100644 index 00000000..f35e6d9f --- /dev/null +++ b/test/ps/src/Golden/MutualLoopification/Test.purs @@ -0,0 +1,80 @@ +-- | Exercises loopification of mutual recursion (issue #234): a group +-- | of workers whose members tail-call each other lowers to a single +-- | `while true` dispatcher over a branch selector plus shared argument +-- | slots, with per-member entry wrappers. The eval oracle pins that +-- | every shape keeps its runtime behavior, dispatched or not. +module Golden.MutualLoopification.Test where + +import Prelude + +import Effect (Effect) +import Effect.Console (logShow) + +-- A known gap, pinned as a canary: the boolean-literal branches fold +-- to `and`/`or` chains in the IR, burying the sibling call inside an +-- operand, so this pair stays call-shaped. If a later pass learns to +-- distribute the fold back into branches, this golden flips to a +-- dispatcher and proves it. +isEven :: Int -> Boolean +isEven n = if n == 0 then true else isOdd (n - 1) + +isOdd :: Int -> Boolean +isOdd n = if n == 0 then false else isEven (n - 1) + +-- Differing arities: the shared slots take the maximum width, and the +-- narrower member's transitions pad the surplus slots. +zigzag :: Int -> Int -> Int +zigzag acc n = if n == 0 then acc else zag acc n 1 + +zag :: Int -> Int -> Int -> Int +zag acc n d = if n == 0 then acc else zigzag (acc + d) (n - 1) + +-- A three-state machine: the dispatcher carries more than two branches. +red :: Int -> Int -> Int +red acc n = if n == 0 then acc else green (acc + 1) (n - 1) + +green :: Int -> Int -> Int +green acc n = if n == 0 then acc else blue (acc + 1) (n - 1) + +blue :: Int -> Int -> Int +blue acc n = if n == 0 then acc else red (acc + 1) (n - 1) + +-- Mixed self- and sibling-tail-calls in one member: both become +-- selector transitions of the same dispatcher. +stepSelf :: Int -> Int -> Int +stepSelf acc n = + if n == 0 then acc + else if n > 10 then stepSelf (acc + 10) (n - 10) + else stepOther acc n + +stepOther :: Int -> Int -> Int +stepOther acc n = if n == 0 then acc else stepSelf (acc + 1) (n - 1) + +-- Non-tail mutual recursion: the sibling call is an operand, so the +-- group must keep real calls. +treeA :: Int -> Int +treeA n = if n == 0 then 1 else 1 + treeB (n - 1) + +treeB :: Int -> Int +treeB n = if n == 0 then 2 else 2 + treeA (n - 1) + +-- A let-bound mutual pair: the dispatcher and its wrappers are locals +-- of the enclosing function. +ticktock :: Int -> Int +ticktock n = tick 0 n + where + tick :: Int -> Int -> Int + tick acc k = if k == 0 then acc else tock (acc + 1) (k - 1) + + tock :: Int -> Int -> Int + tock acc k = if k == 0 then acc else tick (acc + 3) (k - 1) + +main :: Effect Unit +main = do + logShow (isEven 10) + logShow (isOdd 7) + logShow (zigzag 0 3) + logShow (red 0 10) + logShow (stepSelf 0 25) + logShow (treeA 5) + logShow (ticktock 5)