{-# LANGUAGE PatternSynonyms #-}

module Unison.LabeledDependency
  ( derivedTerm,
    derivedType,
    termRef,
    typeRef,
    referent,
    dataConstructor,
    effectConstructor,
    fold,
    referents,
    LabeledDependency (..),
    pattern ConReference,
    pattern TermReference,
    partition,
  )
where

import Data.Set qualified as Set
import Unison.ConstructorReference (ConstructorReference)
import Unison.ConstructorType (ConstructorType (Data, Effect))
import Unison.Prelude hiding (fold)
import Unison.Reference (Id, Reference, Reference' (DerivedId))
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent

-- | A Union Type which contains either Type References or Term Referents.
data LabeledDependency
  = TypeReference Reference
  | TermReferent Referent
  deriving (LabeledDependency -> LabeledDependency -> Bool
(LabeledDependency -> LabeledDependency -> Bool)
-> (LabeledDependency -> LabeledDependency -> Bool)
-> Eq LabeledDependency
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LabeledDependency -> LabeledDependency -> Bool
== :: LabeledDependency -> LabeledDependency -> Bool
$c/= :: LabeledDependency -> LabeledDependency -> Bool
/= :: LabeledDependency -> LabeledDependency -> Bool
Eq, Eq LabeledDependency
Eq LabeledDependency =>
(LabeledDependency -> LabeledDependency -> Ordering)
-> (LabeledDependency -> LabeledDependency -> Bool)
-> (LabeledDependency -> LabeledDependency -> Bool)
-> (LabeledDependency -> LabeledDependency -> Bool)
-> (LabeledDependency -> LabeledDependency -> Bool)
-> (LabeledDependency -> LabeledDependency -> LabeledDependency)
-> (LabeledDependency -> LabeledDependency -> LabeledDependency)
-> Ord LabeledDependency
LabeledDependency -> LabeledDependency -> Bool
LabeledDependency -> LabeledDependency -> Ordering
LabeledDependency -> LabeledDependency -> LabeledDependency
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: LabeledDependency -> LabeledDependency -> Ordering
compare :: LabeledDependency -> LabeledDependency -> Ordering
$c< :: LabeledDependency -> LabeledDependency -> Bool
< :: LabeledDependency -> LabeledDependency -> Bool
$c<= :: LabeledDependency -> LabeledDependency -> Bool
<= :: LabeledDependency -> LabeledDependency -> Bool
$c> :: LabeledDependency -> LabeledDependency -> Bool
> :: LabeledDependency -> LabeledDependency -> Bool
$c>= :: LabeledDependency -> LabeledDependency -> Bool
>= :: LabeledDependency -> LabeledDependency -> Bool
$cmax :: LabeledDependency -> LabeledDependency -> LabeledDependency
max :: LabeledDependency -> LabeledDependency -> LabeledDependency
$cmin :: LabeledDependency -> LabeledDependency -> LabeledDependency
min :: LabeledDependency -> LabeledDependency -> LabeledDependency
Ord, Int -> LabeledDependency -> ShowS
[LabeledDependency] -> ShowS
LabeledDependency -> String
(Int -> LabeledDependency -> ShowS)
-> (LabeledDependency -> String)
-> ([LabeledDependency] -> ShowS)
-> Show LabeledDependency
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LabeledDependency -> ShowS
showsPrec :: Int -> LabeledDependency -> ShowS
$cshow :: LabeledDependency -> String
show :: LabeledDependency -> String
$cshowList :: [LabeledDependency] -> ShowS
showList :: [LabeledDependency] -> ShowS
Show)

-- | Match on a TermReferent which is a Constructor.
pattern ConReference :: ConstructorReference -> ConstructorType -> LabeledDependency
pattern $mConReference :: forall {r}.
LabeledDependency
-> (ConstructorReference -> ConstructorType -> r)
-> ((# #) -> r)
-> r
$bConReference :: ConstructorReference -> ConstructorType -> LabeledDependency
ConReference ref conType = TermReferent (Referent.Con ref conType)

-- | Match on a TermReferent which is NOT a Constructor.
pattern TermReference :: Reference -> LabeledDependency
pattern $mTermReference :: forall {r}.
LabeledDependency -> (Reference -> r) -> ((# #) -> r) -> r
$bTermReference :: Reference -> LabeledDependency
TermReference ref = TermReferent (Referent.Ref ref)

{-# COMPLETE ConReference, TermReference, TypeReference #-}

derivedType :: Id -> LabeledDependency
derivedType :: Id -> LabeledDependency
derivedType = Reference -> LabeledDependency
TypeReference (Reference -> LabeledDependency)
-> (Id -> Reference) -> Id -> LabeledDependency
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> Reference
forall h t. Id' h -> Reference' t h
DerivedId

derivedTerm :: Id -> LabeledDependency
derivedTerm :: Id -> LabeledDependency
derivedTerm = Reference -> LabeledDependency
TermReference (Reference -> LabeledDependency)
-> (Id -> Reference) -> Id -> LabeledDependency
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> Reference
forall h t. Id' h -> Reference' t h
DerivedId

typeRef :: Reference -> LabeledDependency
typeRef :: Reference -> LabeledDependency
typeRef = Reference -> LabeledDependency
TypeReference

termRef :: Reference -> LabeledDependency
termRef :: Reference -> LabeledDependency
termRef = Reference -> LabeledDependency
TermReference

referent :: Referent -> LabeledDependency
referent :: Referent -> LabeledDependency
referent = Referent -> LabeledDependency
TermReferent

dataConstructor :: ConstructorReference -> LabeledDependency
dataConstructor :: ConstructorReference -> LabeledDependency
dataConstructor ConstructorReference
r = ConstructorReference -> ConstructorType -> LabeledDependency
ConReference ConstructorReference
r ConstructorType
Data

effectConstructor :: ConstructorReference -> LabeledDependency
effectConstructor :: ConstructorReference -> LabeledDependency
effectConstructor ConstructorReference
r = ConstructorReference -> ConstructorType -> LabeledDependency
ConReference ConstructorReference
r ConstructorType
Effect

referents :: (Foldable f) => f Referent -> Set LabeledDependency
referents :: forall (f :: * -> *).
Foldable f =>
f Referent -> Set LabeledDependency
referents f Referent
rs = [LabeledDependency] -> Set LabeledDependency
forall a. Ord a => [a] -> Set a
Set.fromList ((Referent -> LabeledDependency)
-> [Referent] -> [LabeledDependency]
forall a b. (a -> b) -> [a] -> [b]
map Referent -> LabeledDependency
referent ([Referent] -> [LabeledDependency])
-> [Referent] -> [LabeledDependency]
forall a b. (a -> b) -> a -> b
$ f Referent -> [Referent]
forall a. f a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList f Referent
rs)

fold :: (Reference -> a) -> (Referent -> a) -> LabeledDependency -> a
fold :: forall a.
(Reference -> a) -> (Referent -> a) -> LabeledDependency -> a
fold Reference -> a
f Referent -> a
_ (TypeReference Reference
r) = Reference -> a
f Reference
r
fold Reference -> a
_ Referent -> a
g (TermReferent Referent
r) = Referent -> a
g Referent
r

partition :: (Foldable t) => t LabeledDependency -> ([Reference], [Referent])
partition :: forall (t :: * -> *).
Foldable t =>
t LabeledDependency -> ([Reference], [Referent])
partition =
  (LabeledDependency -> ([Reference], [Referent]))
-> t LabeledDependency -> ([Reference], [Referent])
forall m a. Monoid m => (a -> m) -> t a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap \case
    TypeReference Reference
ref -> ([Reference
ref], [])
    TermReferent Referent
ref -> ([], [Referent
ref])