{-# LANGUAGE RecordWildCards #-}

module Unison.UnisonFile.Type where

import Control.Lens
import Unison.ABT qualified as ABT
import Unison.DataDeclaration (DataDeclaration, EffectDeclaration (..))
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
  { 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 whole 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 ::
  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} {v} {a}.
UnisonFile v a
-> (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 ds es tms ws <-
  UnisonFileId
    (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
-> 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 ::
  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} {v} {a}.
TypecheckedUnisonFile v a
-> (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 ds es tlcs wcs hts <-
  TypecheckedUnisonFileId
    (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 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) =
    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.
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 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
      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