{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}

module Unison.ReferentPrime
  ( Referent' (..),

    -- * Basic queries
    isConstructor,
    Unison.ReferentPrime.fold,

    -- * Lenses
    reference_,

    -- * Conversions
    toReference',
    toTermReference,
    toTypeReference,
  )
where

import Control.Lens (Lens, lens)
import Unison.ConstructorReference (GConstructorReference (..))
import Unison.ConstructorType (ConstructorType)
import Unison.DataDeclaration.ConstructorId (ConstructorId)
import Unison.Prelude

-- | Specifies a term.
--
-- Either a term 'Reference', a data constructor, or an effect constructor.
--
-- Slightly odd naming. This is the "referent of term name in the codebase",
-- rather than the target of a Reference.

-- | When @Ref'@ then @r@ represents a term.
--
-- When @Con'@ then @r@ is a type declaration.
data Referent' r = Ref' r | Con' (GConstructorReference r) ConstructorType
  deriving (Int -> Referent' r -> ShowS
[Referent' r] -> ShowS
Referent' r -> String
(Int -> Referent' r -> ShowS)
-> (Referent' r -> String)
-> ([Referent' r] -> ShowS)
-> Show (Referent' r)
forall r. Show r => Int -> Referent' r -> ShowS
forall r. Show r => [Referent' r] -> ShowS
forall r. Show r => Referent' r -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall r. Show r => Int -> Referent' r -> ShowS
showsPrec :: Int -> Referent' r -> ShowS
$cshow :: forall r. Show r => Referent' r -> String
show :: Referent' r -> String
$cshowList :: forall r. Show r => [Referent' r] -> ShowS
showList :: [Referent' r] -> ShowS
Show, Referent' r -> Referent' r -> Bool
(Referent' r -> Referent' r -> Bool)
-> (Referent' r -> Referent' r -> Bool) -> Eq (Referent' r)
forall r. Eq r => Referent' r -> Referent' r -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall r. Eq r => Referent' r -> Referent' r -> Bool
== :: Referent' r -> Referent' r -> Bool
$c/= :: forall r. Eq r => Referent' r -> Referent' r -> Bool
/= :: Referent' r -> Referent' r -> Bool
Eq, Eq (Referent' r)
Eq (Referent' r) =>
(Referent' r -> Referent' r -> Ordering)
-> (Referent' r -> Referent' r -> Bool)
-> (Referent' r -> Referent' r -> Bool)
-> (Referent' r -> Referent' r -> Bool)
-> (Referent' r -> Referent' r -> Bool)
-> (Referent' r -> Referent' r -> Referent' r)
-> (Referent' r -> Referent' r -> Referent' r)
-> Ord (Referent' r)
Referent' r -> Referent' r -> Bool
Referent' r -> Referent' r -> Ordering
Referent' r -> Referent' r -> Referent' r
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
forall r. Ord r => Eq (Referent' r)
forall r. Ord r => Referent' r -> Referent' r -> Bool
forall r. Ord r => Referent' r -> Referent' r -> Ordering
forall r. Ord r => Referent' r -> Referent' r -> Referent' r
$ccompare :: forall r. Ord r => Referent' r -> Referent' r -> Ordering
compare :: Referent' r -> Referent' r -> Ordering
$c< :: forall r. Ord r => Referent' r -> Referent' r -> Bool
< :: Referent' r -> Referent' r -> Bool
$c<= :: forall r. Ord r => Referent' r -> Referent' r -> Bool
<= :: Referent' r -> Referent' r -> Bool
$c> :: forall r. Ord r => Referent' r -> Referent' r -> Bool
> :: Referent' r -> Referent' r -> Bool
$c>= :: forall r. Ord r => Referent' r -> Referent' r -> Bool
>= :: Referent' r -> Referent' r -> Bool
$cmax :: forall r. Ord r => Referent' r -> Referent' r -> Referent' r
max :: Referent' r -> Referent' r -> Referent' r
$cmin :: forall r. Ord r => Referent' r -> Referent' r -> Referent' r
min :: Referent' r -> Referent' r -> Referent' r
Ord, (forall a b. (a -> b) -> Referent' a -> Referent' b)
-> (forall a b. a -> Referent' b -> Referent' a)
-> Functor Referent'
forall a b. a -> Referent' b -> Referent' a
forall a b. (a -> b) -> Referent' a -> Referent' b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Referent' a -> Referent' b
fmap :: forall a b. (a -> b) -> Referent' a -> Referent' b
$c<$ :: forall a b. a -> Referent' b -> Referent' a
<$ :: forall a b. a -> Referent' b -> Referent' a
Functor, (forall x. Referent' r -> Rep (Referent' r) x)
-> (forall x. Rep (Referent' r) x -> Referent' r)
-> Generic (Referent' r)
forall x. Rep (Referent' r) x -> Referent' r
forall x. Referent' r -> Rep (Referent' r) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall r x. Rep (Referent' r) x -> Referent' r
forall r x. Referent' r -> Rep (Referent' r) x
$cfrom :: forall r x. Referent' r -> Rep (Referent' r) x
from :: forall x. Referent' r -> Rep (Referent' r) x
$cto :: forall r x. Rep (Referent' r) x -> Referent' r
to :: forall x. Rep (Referent' r) x -> Referent' r
Generic)

-- | A lens onto the reference in a referent.
reference_ :: Lens (Referent' r) (Referent' r') r r'
reference_ :: forall r r' (f :: * -> *).
Functor f =>
(r -> f r') -> Referent' r -> f (Referent' r')
reference_ =
  (Referent' r -> r)
-> (Referent' r -> r' -> Referent' r')
-> Lens (Referent' r) (Referent' r') r r'
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens Referent' r -> r
forall r. Referent' r -> r
toReference' \Referent' r
rt r'
rc ->
    case Referent' r
rt of
      Ref' r
_ -> r' -> Referent' r'
forall r. r -> Referent' r
Ref' r'
rc
      Con' (ConstructorReference r
_ ConstructorId
cid) ConstructorType
ct -> GConstructorReference r' -> ConstructorType -> Referent' r'
forall r. GConstructorReference r -> ConstructorType -> Referent' r
Con' (r' -> ConstructorId -> GConstructorReference r'
forall r. r -> ConstructorId -> GConstructorReference r
ConstructorReference r'
rc ConstructorId
cid) ConstructorType
ct

isConstructor :: Referent' r -> Bool
isConstructor :: forall r. Referent' r -> Bool
isConstructor Con' {} = Bool
True
isConstructor Referent' r
_ = Bool
False

toTermReference :: Referent' r -> Maybe r
toTermReference :: forall r. Referent' r -> Maybe r
toTermReference = \case
  Ref' r
r -> r -> Maybe r
forall a. a -> Maybe a
Just r
r
  Referent' r
_ -> Maybe r
forall a. Maybe a
Nothing

toReference' :: Referent' r -> r
toReference' :: forall r. Referent' r -> r
toReference' = \case
  Ref' r
r -> r
r
  Con' (ConstructorReference r
r ConstructorId
_i) ConstructorType
_t -> r
r

toTypeReference :: Referent' r -> Maybe r
toTypeReference :: forall r. Referent' r -> Maybe r
toTypeReference = \case
  Con' (ConstructorReference r
r ConstructorId
_i) ConstructorType
_t -> r -> Maybe r
forall a. a -> Maybe a
Just r
r
  Referent' r
_ -> Maybe r
forall a. Maybe a
Nothing

fold :: (r -> a) -> (r -> ConstructorId -> ConstructorType -> a) -> Referent' r -> a
fold :: forall r a.
(r -> a)
-> (r -> ConstructorId -> ConstructorType -> a) -> Referent' r -> a
fold r -> a
fr r -> ConstructorId -> ConstructorType -> a
fc = \case
  Ref' r
r -> r -> a
fr r
r
  Con' (ConstructorReference r
r ConstructorId
i) ConstructorType
ct -> r -> ConstructorId -> ConstructorType -> a
fc r
r ConstructorId
i ConstructorType
ct