{-# LANGUAGE RecordWildCards #-}

module Unison.UnisonFile.Type where

import Control.Lens
import Unison.ABT qualified as ABT
import Unison.DataDeclaration (DataDeclaration, EffectDeclaration (..))
import Unison.Name (Name)
import Unison.Prelude
import Unison.Reference (TermReference, TermReferenceId, TypeReference, TypeReferenceId)
import Unison.Reference qualified as Reference
import Unison.Term (Term)
import Unison.Term qualified as Term
import Unison.Type (Type)
import Unison.Type qualified as Type
import Unison.WatchKind (WatchKind)

data UnisonFile v a = UnisonFileId
  { -- Files can have an optional namespace prefix.
    forall v a. UnisonFile v a -> Maybe (a, Name)
fileNamespace :: Maybe (a, Name),
    forall v a.
UnisonFile v a -> Map v (TypeReferenceId, DataDeclaration v a)
dataDeclarationsId :: Map v (TypeReferenceId, DataDeclaration v a),
    forall v a.
UnisonFile v a -> Map v (TypeReferenceId, EffectDeclaration v a)
effectDeclarationsId :: Map v (TypeReferenceId, EffectDeclaration v a),
    forall v a. UnisonFile v a -> Map v (a, Term v a)
terms :: Map v (a {- ann for name of the binding -}, Term v a),
    forall v a. UnisonFile v a -> Map WatchKind [(v, a, Term v a)]
watches :: Map WatchKind [(v, a {- ann for whole watch -}, Term v a)]
  }
  deriving stock ((forall x. UnisonFile v a -> Rep (UnisonFile v a) x)
-> (forall x. Rep (UnisonFile v a) x -> UnisonFile v a)
-> Generic (UnisonFile v a)
forall x. Rep (UnisonFile v a) x -> UnisonFile v a
forall x. UnisonFile v a -> Rep (UnisonFile v a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall v a x. Rep (UnisonFile v a) x -> UnisonFile v a
forall v a x. UnisonFile v a -> Rep (UnisonFile v a) x
$cfrom :: forall v a x. UnisonFile v a -> Rep (UnisonFile v a) x
from :: forall x. UnisonFile v a -> Rep (UnisonFile v a) x
$cto :: forall v a x. Rep (UnisonFile v a) x -> UnisonFile v a
to :: forall x. Rep (UnisonFile v a) x -> UnisonFile v a
Generic, Int -> UnisonFile v a -> ShowS
[UnisonFile v a] -> ShowS
UnisonFile v a -> WatchKind
(Int -> UnisonFile v a -> ShowS)
-> (UnisonFile v a -> WatchKind)
-> ([UnisonFile v a] -> ShowS)
-> Show (UnisonFile v a)
forall a.
(Int -> a -> ShowS) -> (a -> WatchKind) -> ([a] -> ShowS) -> Show a
forall v a. (Show a, Show v) => Int -> UnisonFile v a -> ShowS
forall v a. (Show a, Show v) => [UnisonFile v a] -> ShowS
forall v a. (Show a, Show v) => UnisonFile v a -> WatchKind
$cshowsPrec :: forall v a. (Show a, Show v) => Int -> UnisonFile v a -> ShowS
showsPrec :: Int -> UnisonFile v a -> ShowS
$cshow :: forall v a. (Show a, Show v) => UnisonFile v a -> WatchKind
show :: UnisonFile v a -> WatchKind
$cshowList :: forall v a. (Show a, Show v) => [UnisonFile v a] -> ShowS
showList :: [UnisonFile v a] -> ShowS
Show)

pattern UnisonFile ::
  Maybe (a, Name) ->
  Map v (TypeReference, DataDeclaration v a) ->
  Map v (TypeReference, EffectDeclaration v a) ->
  Map v (a, Term v a) ->
  Map WatchKind [(v, a, Term v a)] ->
  UnisonFile v a
pattern $mUnisonFile :: forall {r} {a} {v}.
UnisonFile v a
-> (Maybe (a, Name)
    -> Map v (TypeReference, DataDeclaration v a)
    -> Map v (TypeReference, EffectDeclaration v a)
    -> Map v (a, Term v a)
    -> Map WatchKind [(v, a, Term v a)]
    -> r)
-> ((# #) -> r)
-> r
UnisonFile fn ds es tms ws <-
  UnisonFileId
    fn
    (fmap (first Reference.DerivedId) -> ds)
    (fmap (first Reference.DerivedId) -> es)
    tms
    ws

{-# COMPLETE UnisonFile #-}

-- | A UnisonFile after typechecking. Terms are split into groups by
--  cycle and the type of each term is known.
data TypecheckedUnisonFile v a = TypecheckedUnisonFileId
  { forall v a. TypecheckedUnisonFile v a -> Maybe (a, Name)
fileNamespace' :: Maybe (a, Name),
    forall v a.
TypecheckedUnisonFile v a
-> Map v (TypeReferenceId, DataDeclaration v a)
dataDeclarationsId' :: Map v (TypeReferenceId, DataDeclaration v a),
    forall v a.
TypecheckedUnisonFile v a
-> Map v (TypeReferenceId, EffectDeclaration v a)
effectDeclarationsId' :: Map v (TypeReferenceId, EffectDeclaration v a),
    forall v a.
TypecheckedUnisonFile v a -> [[(v, a, Term v a, Type v a)]]
topLevelComponents' :: [[(v, a {- ann for whole binding -}, Term v a, Type v a)]],
    forall v a.
TypecheckedUnisonFile v a
-> [(WatchKind, [(v, a, Term v a, Type v a)])]
watchComponents :: [(WatchKind, [(v, a {- ann for whole watch -}, Term v a, Type v a)])],
    forall v a.
TypecheckedUnisonFile v a
-> Map v (a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
hashTermsId :: Map v (a {- ann for whole binding -}, TermReferenceId, Maybe WatchKind, Term v a, Type v a)
  }
  deriving stock ((forall x.
 TypecheckedUnisonFile v a -> Rep (TypecheckedUnisonFile v a) x)
-> (forall x.
    Rep (TypecheckedUnisonFile v a) x -> TypecheckedUnisonFile v a)
-> Generic (TypecheckedUnisonFile v a)
forall x.
Rep (TypecheckedUnisonFile v a) x -> TypecheckedUnisonFile v a
forall x.
TypecheckedUnisonFile v a -> Rep (TypecheckedUnisonFile v a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall v a x.
Rep (TypecheckedUnisonFile v a) x -> TypecheckedUnisonFile v a
forall v a x.
TypecheckedUnisonFile v a -> Rep (TypecheckedUnisonFile v a) x
$cfrom :: forall v a x.
TypecheckedUnisonFile v a -> Rep (TypecheckedUnisonFile v a) x
from :: forall x.
TypecheckedUnisonFile v a -> Rep (TypecheckedUnisonFile v a) x
$cto :: forall v a x.
Rep (TypecheckedUnisonFile v a) x -> TypecheckedUnisonFile v a
to :: forall x.
Rep (TypecheckedUnisonFile v a) x -> TypecheckedUnisonFile v a
Generic, Int -> TypecheckedUnisonFile v a -> ShowS
[TypecheckedUnisonFile v a] -> ShowS
TypecheckedUnisonFile v a -> WatchKind
(Int -> TypecheckedUnisonFile v a -> ShowS)
-> (TypecheckedUnisonFile v a -> WatchKind)
-> ([TypecheckedUnisonFile v a] -> ShowS)
-> Show (TypecheckedUnisonFile v a)
forall a.
(Int -> a -> ShowS) -> (a -> WatchKind) -> ([a] -> ShowS) -> Show a
forall v a.
(Show a, Show v) =>
Int -> TypecheckedUnisonFile v a -> ShowS
forall v a.
(Show a, Show v) =>
[TypecheckedUnisonFile v a] -> ShowS
forall v a.
(Show a, Show v) =>
TypecheckedUnisonFile v a -> WatchKind
$cshowsPrec :: forall v a.
(Show a, Show v) =>
Int -> TypecheckedUnisonFile v a -> ShowS
showsPrec :: Int -> TypecheckedUnisonFile v a -> ShowS
$cshow :: forall v a.
(Show a, Show v) =>
TypecheckedUnisonFile v a -> WatchKind
show :: TypecheckedUnisonFile v a -> WatchKind
$cshowList :: forall v a.
(Show a, Show v) =>
[TypecheckedUnisonFile v a] -> ShowS
showList :: [TypecheckedUnisonFile v a] -> ShowS
Show)

{-# COMPLETE TypecheckedUnisonFile #-}

pattern TypecheckedUnisonFile ::
  Maybe (a, Name) ->
  Map v (TypeReference, DataDeclaration v a) ->
  Map v (TypeReference, EffectDeclaration v a) ->
  [[(v, a, Term v a, Type v a)]] ->
  [(WatchKind, [(v, a, Term v a, Type v a)])] ->
  Map
    v
    ( a,
      TermReference,
      Maybe WatchKind,
      ABT.Term (Term.F v a a) v a,
      ABT.Term Type.F v a
    ) ->
  TypecheckedUnisonFile v a
pattern $mTypecheckedUnisonFile :: forall {r} {a} {v}.
TypecheckedUnisonFile v a
-> (Maybe (a, Name)
    -> Map v (TypeReference, DataDeclaration v a)
    -> Map v (TypeReference, EffectDeclaration v a)
    -> [[(v, a, Term v a, Type v a)]]
    -> [(WatchKind, [(v, a, Term v a, Type v a)])]
    -> Map v (a, TypeReference, Maybe WatchKind, Term v a, Type v a)
    -> r)
-> ((# #) -> r)
-> r
TypecheckedUnisonFile fn ds es tlcs wcs hts <-
  TypecheckedUnisonFileId
    fn
    (fmap (first Reference.DerivedId) -> ds)
    (fmap (first Reference.DerivedId) -> es)
    tlcs
    wcs
    (fmap (over _2 Reference.DerivedId) -> hts)

instance (Ord v) => Functor (TypecheckedUnisonFile v) where
  fmap :: forall a b.
(a -> b) -> TypecheckedUnisonFile v a -> TypecheckedUnisonFile v b
fmap a -> b
f (TypecheckedUnisonFileId Maybe (a, Name)
fn Map v (TypeReferenceId, DataDeclaration v a)
ds Map v (TypeReferenceId, EffectDeclaration v a)
es [[(v, a, Term v a, Type v a)]]
tlcs [(WatchKind, [(v, a, Term v a, Type v a)])]
wcs Map v (a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
hashTerms) =
    Maybe (b, Name)
-> Map v (TypeReferenceId, DataDeclaration v b)
-> Map v (TypeReferenceId, EffectDeclaration v b)
-> [[(v, b, Term v b, Type v b)]]
-> [(WatchKind, [(v, b, Term v b, Type v b)])]
-> Map v (b, TypeReferenceId, Maybe WatchKind, Term v b, Type v b)
-> TypecheckedUnisonFile v b
forall v a.
Maybe (a, Name)
-> Map v (TypeReferenceId, DataDeclaration v a)
-> Map v (TypeReferenceId, EffectDeclaration v a)
-> [[(v, a, Term v a, Type v a)]]
-> [(WatchKind, [(v, a, Term v a, Type v a)])]
-> Map v (a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
-> TypecheckedUnisonFile v a
TypecheckedUnisonFileId Maybe (b, Name)
fn' Map v (TypeReferenceId, DataDeclaration v b)
ds' Map v (TypeReferenceId, EffectDeclaration v b)
es' [[(v, b, Term v b, Type v b)]]
tlcs' [(WatchKind, [(v, b, Term v b, Type v b)])]
wcs' Map v (b, TypeReferenceId, Maybe WatchKind, Term v b, Type v b)
hashTerms'
    where
      fn' :: Maybe (b, Name)
fn' = (((a, Name) -> (b, Name)) -> Maybe (a, Name) -> Maybe (b, Name)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((a, Name) -> (b, Name)) -> Maybe (a, Name) -> Maybe (b, Name))
-> ((a -> b) -> (a, Name) -> (b, Name))
-> (a -> b)
-> Maybe (a, Name)
-> Maybe (b, Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> (a, Name) -> (b, Name)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first) a -> b
f Maybe (a, Name)
fn
      ds' :: Map v (TypeReferenceId, DataDeclaration v b)
ds' = Map v (TypeReferenceId, DataDeclaration v a)
ds Map v (TypeReferenceId, DataDeclaration v a)
-> ((TypeReferenceId, DataDeclaration v a)
    -> (TypeReferenceId, DataDeclaration v b))
-> Map v (TypeReferenceId, DataDeclaration v b)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(TypeReferenceId
refId, DataDeclaration v a
decl) -> (TypeReferenceId
refId, (a -> b) -> DataDeclaration v a -> DataDeclaration v b
forall a b. (a -> b) -> DataDeclaration v a -> DataDeclaration v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f DataDeclaration v a
decl)
      es' :: Map v (TypeReferenceId, EffectDeclaration v b)
es' = Map v (TypeReferenceId, EffectDeclaration v a)
es Map v (TypeReferenceId, EffectDeclaration v a)
-> ((TypeReferenceId, EffectDeclaration v a)
    -> (TypeReferenceId, EffectDeclaration v b))
-> Map v (TypeReferenceId, EffectDeclaration v b)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(TypeReferenceId
refId, EffectDeclaration v a
effect) -> (TypeReferenceId
refId, (a -> b) -> EffectDeclaration v a -> EffectDeclaration v b
forall a b.
(a -> b) -> EffectDeclaration v a -> EffectDeclaration v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f EffectDeclaration v a
effect)
      tlcs' :: [[(v, b, Term v b, Type v b)]]
tlcs' =
        [[(v, a, Term v a, Type v a)]]
tlcs
          [[(v, a, Term v a, Type v a)]]
-> ([[(v, a, Term v a, Type v a)]]
    -> [[(v, b, Term v b, Type v b)]])
-> [[(v, b, Term v b, Type v b)]]
forall a b. a -> (a -> b) -> b
& (([(v, a, Term v a, Type v a)] -> [(v, b, Term v b, Type v b)])
-> [[(v, a, Term v a, Type v a)]] -> [[(v, b, Term v b, Type v b)]]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([(v, a, Term v a, Type v a)] -> [(v, b, Term v b, Type v b)])
 -> [[(v, a, Term v a, Type v a)]]
 -> [[(v, b, Term v b, Type v b)]])
-> (((v, a, Term v a, Type v a) -> (v, b, Term v b, Type v b))
    -> [(v, a, Term v a, Type v a)] -> [(v, b, Term v b, Type v b)])
-> ((v, a, Term v a, Type v a) -> (v, b, Term v b, Type v b))
-> [[(v, a, Term v a, Type v a)]]
-> [[(v, b, Term v b, Type v b)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((v, a, Term v a, Type v a) -> (v, b, Term v b, Type v b))
-> [(v, a, Term v a, Type v a)] -> [(v, b, Term v b, Type v b)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) \(v
v, a
a, Term v a
tm, Type v a
tp) -> (v
v, a -> b
f a
a, (a -> b) -> Term v a -> Term v b
forall v a a2. Ord v => (a -> a2) -> Term v a -> Term v a2
Term.amap a -> b
f Term v a
tm, (a -> b) -> Type v a -> Type v b
forall a b. (a -> b) -> Term F v a -> Term F v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Type v a
tp)
      wcs' :: [(WatchKind, [(v, b, Term v b, Type v b)])]
wcs' = ((WatchKind, [(v, a, Term v a, Type v a)])
 -> (WatchKind, [(v, b, Term v b, Type v b)]))
-> [(WatchKind, [(v, a, Term v a, Type v a)])]
-> [(WatchKind, [(v, b, Term v b, Type v b)])]
forall a b. (a -> b) -> [a] -> [b]
map (\(WatchKind
wk, [(v, a, Term v a, Type v a)]
tms) -> (WatchKind
wk, ((v, a, Term v a, Type v a) -> (v, b, Term v b, Type v b))
-> [(v, a, Term v a, Type v a)] -> [(v, b, Term v b, Type v b)]
forall a b. (a -> b) -> [a] -> [b]
map (\(v
v, a
a, Term v a
tm, Type v a
tp) -> (v
v, a -> b
f a
a, (a -> b) -> Term v a -> Term v b
forall v a a2. Ord v => (a -> a2) -> Term v a -> Term v a2
Term.amap a -> b
f Term v a
tm, (a -> b) -> Type v a -> Type v b
forall a b. (a -> b) -> Term F v a -> Term F v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Type v a
tp)) [(v, a, Term v a, Type v a)]
tms)) [(WatchKind, [(v, a, Term v a, Type v a)])]
wcs
      hashTerms' :: Map v (b, TypeReferenceId, Maybe WatchKind, Term v b, Type v b)
hashTerms' = ((a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
 -> (b, TypeReferenceId, Maybe WatchKind, Term v b, Type v b))
-> Map v (a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
-> Map v (b, TypeReferenceId, Maybe WatchKind, Term v b, Type v b)
forall a b. (a -> b) -> Map v a -> Map v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(a
a, TypeReferenceId
id, Maybe WatchKind
wk, Term v a
tm, Type v a
tp) -> (a -> b
f a
a, TypeReferenceId
id, Maybe WatchKind
wk, (a -> b) -> Term v a -> Term v b
forall v a a2. Ord v => (a -> a2) -> Term v a -> Term v a2
Term.amap a -> b
f Term v a
tm, (a -> b) -> Type v a -> Type v b
forall a b. (a -> b) -> Term F v a -> Term F v b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Type v a
tp)) Map v (a, TypeReferenceId, Maybe WatchKind, Term v a, Type v a)
hashTerms