-- | Translates guard alternatives to if-then-else cascades.
--
-- The builtin translation must be run before this transformation.
module Agda.Compiler.Treeless.GuardsToPrims ( convertGuards ) where

import qualified Data.List as List

import Agda.Syntax.Treeless

import Agda.Utils.Impossible


convertGuards :: TTerm -> TTerm
convertGuards :: TTerm -> TTerm
convertGuards = TTerm -> TTerm
tr
  where
    tr :: TTerm -> TTerm
tr = \case
      TCase Int
sc CaseInfo
t TTerm
def [TAlt]
alts ->
        if [TAlt] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TAlt]
otherAlts
          then
            TTerm
def'
          else
            Int -> CaseInfo -> TTerm -> [TAlt] -> TTerm
TCase Int
sc CaseInfo
t TTerm
def' ((TAlt -> TAlt) -> [TAlt] -> [TAlt]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TAlt -> TAlt
trAlt [TAlt]
otherAlts)
        where
          ([TAlt]
plusAlts, [TAlt]
otherAlts) = [TAlt] -> ([TAlt], [TAlt])
splitAlts [TAlt]
alts

          guardedAlt :: TAlt -> TTerm -> TTerm
          guardedAlt :: TAlt -> TTerm -> TTerm
guardedAlt (TAGuard TTerm
g TTerm
body) TTerm
cont = TTerm -> TTerm -> TTerm -> TTerm
tIfThenElse (TTerm -> TTerm
tr TTerm
g) (TTerm -> TTerm
tr TTerm
body) (TTerm -> TTerm
tr TTerm
cont)
          guardedAlt TAlt
_ TTerm
_ = TTerm
forall a. HasCallStack => a
__IMPOSSIBLE__

          def' :: TTerm
def' = (TAlt -> TTerm -> TTerm) -> TTerm -> [TAlt] -> TTerm
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr TAlt -> TTerm -> TTerm
guardedAlt (TTerm -> TTerm
tr TTerm
def) [TAlt]
plusAlts

          trAlt :: TAlt -> TAlt
trAlt (TAGuard{}) = TAlt
forall a. HasCallStack => a
__IMPOSSIBLE__
          trAlt TAlt
a = TAlt
a { aBody :: TTerm
aBody = TTerm -> TTerm
tr (TAlt -> TTerm
aBody TAlt
a) }

      t :: TTerm
t@TVar{}    -> TTerm
t
      t :: TTerm
t@TDef{}    -> TTerm
t
      t :: TTerm
t@TCon{}    -> TTerm
t
      t :: TTerm
t@TPrim{}   -> TTerm
t
      t :: TTerm
t@TLit{}    -> TTerm
t
      t :: TTerm
t@TUnit{}   -> TTerm
t
      t :: TTerm
t@TSort{}   -> TTerm
t
      t :: TTerm
t@TErased{} -> TTerm
t
      t :: TTerm
t@TError{}  -> TTerm
t

      TCoerce TTerm
a               -> TTerm -> TTerm
TCoerce (TTerm -> TTerm
tr TTerm
a)
      TLam TTerm
b                  -> TTerm -> TTerm
TLam (TTerm -> TTerm
tr TTerm
b)
      TApp TTerm
a Args
bs               -> TTerm -> Args -> TTerm
TApp (TTerm -> TTerm
tr TTerm
a) ((TTerm -> TTerm) -> Args -> Args
forall a b. (a -> b) -> [a] -> [b]
map TTerm -> TTerm
tr Args
bs)
      TLet TTerm
e TTerm
b                -> TTerm -> TTerm -> TTerm
TLet (TTerm -> TTerm
tr TTerm
e) (TTerm -> TTerm
tr TTerm
b)

-- | Split alts into TAGuard alts and other alts.
splitAlts :: [TAlt] -> ([TAlt], [TAlt])
splitAlts :: [TAlt] -> ([TAlt], [TAlt])
splitAlts = (TAlt -> Bool) -> [TAlt] -> ([TAlt], [TAlt])
forall a. (a -> Bool) -> [a] -> ([a], [a])
List.partition TAlt -> Bool
isGuardAlt
  where isGuardAlt :: TAlt -> Bool
isGuardAlt (TAGuard TTerm
_ TTerm
_) = Bool
True
        isGuardAlt TAlt
_ = Bool
False