module Unison.Codebase.Editor.HandleInput.Load
  ( handleLoad,
    loadUnisonFile,
    EvalMode (..),
    evalUnisonFile,
  )
where

import Control.Lens ((.=))
import Control.Monad.Reader (ask)
import Control.Monad.State.Strict qualified as State
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Text qualified as Text
import System.Environment (withArgs)
import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.MonadUtils qualified as Cli
import Unison.Cli.NamesUtils qualified as Cli
import Unison.Cli.TypeCheck (computeTypecheckingEnvironment)
import Unison.Cli.UniqueTypeGuidLookup qualified as Cli
import Unison.Codebase qualified as Codebase
import Unison.Codebase.Editor.HandleInput.RuntimeUtils qualified as RuntimeUtils
import Unison.Codebase.Editor.Output qualified as Output
import Unison.Codebase.Editor.Slurp qualified as Slurp
import Unison.Codebase.Execute qualified as Codebase
import Unison.Codebase.Runtime qualified as Runtime
import Unison.FileParsers qualified as FileParsers
import Unison.Names (Names)
import Unison.Names qualified as Names
import Unison.Parser.Ann (Ann)
import Unison.Parser.Ann qualified as Ann
import Unison.Parsers qualified as Parsers
import Unison.Prelude
import Unison.PrettyPrintEnv qualified as PPE
import Unison.PrettyPrintEnv.Names qualified as PPE
import Unison.PrettyPrintEnvDecl qualified as PPE
import Unison.PrettyPrintEnvDecl qualified as PPED
import Unison.PrettyPrintEnvDecl.Names qualified as PPED
import Unison.Reference qualified as Reference
import Unison.Result qualified as Result
import Unison.Symbol (Symbol)
import Unison.Syntax.Name qualified as Name
import Unison.Syntax.Parser qualified as Parser
import Unison.Term (Term)
import Unison.Term qualified as Term
import Unison.UnisonFile (TypecheckedUnisonFile)
import Unison.UnisonFile qualified as UF
import Unison.UnisonFile.Names qualified as UF
import Unison.Util.Timing qualified as Timing
import Unison.Var qualified as Var
import Unison.WatchKind qualified as WK

handleLoad :: Maybe FilePath -> Cli ()
handleLoad :: Maybe FilePath -> Cli ()
handleLoad Maybe FilePath
maybePath = do
  Maybe (FilePath, Bool)
latestFile <- Cli (Maybe (FilePath, Bool))
Cli.getLatestFile
  FilePath
path <- (Maybe FilePath
maybePath Maybe FilePath -> Maybe FilePath -> Maybe FilePath
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (FilePath, Bool) -> FilePath
forall a b. (a, b) -> a
fst ((FilePath, Bool) -> FilePath)
-> Maybe (FilePath, Bool) -> Maybe FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (FilePath, Bool)
latestFile) Maybe FilePath -> (Maybe FilePath -> Cli FilePath) -> Cli FilePath
forall a b. a -> (a -> b) -> b
& Cli FilePath -> Maybe FilePath -> Cli FilePath
forall (m :: * -> *) a. Applicative m => m a -> Maybe a -> m a
onNothing (Output -> Cli FilePath
forall a. Output -> Cli a
Cli.returnEarly Output
Output.NoUnisonFile)
  Cli.Env {SourceName -> IO LoadSourceResult
loadSource :: SourceName -> IO LoadSourceResult
$sel:loadSource:Env :: Env -> SourceName -> IO LoadSourceResult
loadSource} <- Cli Env
forall r (m :: * -> *). MonadReader r m => m r
ask
  SourceName
contents <-
    IO LoadSourceResult -> Cli LoadSourceResult
forall a. IO a -> Cli a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (SourceName -> IO LoadSourceResult
loadSource (FilePath -> SourceName
Text.pack FilePath
path)) Cli LoadSourceResult
-> (LoadSourceResult -> Cli SourceName) -> Cli SourceName
forall a b. Cli a -> (a -> Cli b) -> Cli b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      LoadSourceResult
Cli.InvalidSourceNameError -> Output -> Cli SourceName
forall a. Output -> Cli a
Cli.returnEarly (Output -> Cli SourceName) -> Output -> Cli SourceName
forall a b. (a -> b) -> a -> b
$ FilePath -> Output
Output.InvalidSourceName FilePath
path
      LoadSourceResult
Cli.LoadError -> Output -> Cli SourceName
forall a. Output -> Cli a
Cli.returnEarly (Output -> Cli SourceName) -> Output -> Cli SourceName
forall a b. (a -> b) -> a -> b
$ FilePath -> Output
Output.SourceLoadFailed FilePath
path
      Cli.LoadSuccess SourceName
contents -> SourceName -> Cli SourceName
forall a. a -> Cli a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SourceName
contents
  SourceName -> SourceName -> Cli ()
loadUnisonFile (FilePath -> SourceName
Text.pack FilePath
path) SourceName
contents

loadUnisonFile :: Text -> Text -> Cli ()
loadUnisonFile :: SourceName -> SourceName -> Cli ()
loadUnisonFile SourceName
sourceName SourceName
text = do
  Output -> Cli ()
Cli.respond (Output -> Cli ()) -> Output -> Cli ()
forall a b. (a -> b) -> a -> b
$ SourceName -> Output
Output.LoadingFile SourceName
sourceName
  Names
currentNames <- Cli Names
Cli.currentNames
  TypecheckedUnisonFile Symbol Ann
unisonFile <- Names
-> SourceName
-> SourceName
-> Cli (TypecheckedUnisonFile Symbol Ann)
withFile Names
currentNames SourceName
sourceName SourceName
text
  let sr :: SlurpResult
sr = TypecheckedUnisonFile Symbol Ann
-> Set Symbol -> SlurpOp -> Names -> SlurpResult
Slurp.slurpFile TypecheckedUnisonFile Symbol Ann
unisonFile Set Symbol
forall a. Monoid a => a
mempty SlurpOp
Slurp.CheckOp Names
currentNames
  let names :: Names
names = TypecheckedUnisonFile Symbol Ann -> Names -> Names
forall v a. Var v => TypecheckedUnisonFile v a -> Names -> Names
UF.addNamesFromTypeCheckedUnisonFile TypecheckedUnisonFile Symbol Ann
unisonFile Names
currentNames
  let pped :: PrettyPrintEnvDecl
pped = Namer -> Suffixifier -> PrettyPrintEnvDecl
PPED.makePPED (Int -> Names -> Namer
PPE.hqNamer Int
10 Names
names) (Names -> Suffixifier
PPE.suffixifyByHash Names
names)
  let ppe :: PrettyPrintEnv
ppe = PrettyPrintEnvDecl -> PrettyPrintEnv
PPE.suffixifiedPPE PrettyPrintEnvDecl
pped
  Output -> Cli ()
Cli.respond (Output -> Cli ()) -> Output -> Cli ()
forall a b. (a -> b) -> a -> b
$ SourceName
-> PrettyPrintEnv
-> SlurpResult
-> TypecheckedUnisonFile Symbol Ann
-> Output
Output.Typechecked SourceName
sourceName PrettyPrintEnv
ppe SlurpResult
sr TypecheckedUnisonFile Symbol Ann
unisonFile

  Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool)
-> ([(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
    -> Bool)
-> [(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
-> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
 -> Bool)
-> [(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
-> Bool
forall a b. (a -> b) -> a -> b
$ TypecheckedUnisonFile Symbol Ann
-> [(FilePath, [(Symbol, Ann, Term Symbol Ann, Type Symbol Ann)])]
forall v a.
TypecheckedUnisonFile v a
-> [(FilePath, [(v, a, Term v a, Type v a)])]
UF.watchComponents TypecheckedUnisonFile Symbol Ann
unisonFile) do
    FilePath -> Cli () -> Cli ()
forall (m :: * -> *) a. MonadIO m => FilePath -> m a -> m a
Timing.time FilePath
"evaluating watches" do
      ([(Symbol, Term Symbol ())]
bindings, Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
e) <- EvalMode
-> PrettyPrintEnv
-> TypecheckedUnisonFile Symbol Ann
-> [FilePath]
-> Cli
     ([(Symbol, Term Symbol ())],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
evalUnisonFile EvalMode
Permissive PrettyPrintEnv
ppe TypecheckedUnisonFile Symbol Ann
unisonFile []
      let e' :: Map Symbol (Ann, FilePath, Term Symbol (), Bool)
e' = ((Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
 -> (Ann, FilePath, Term Symbol (), Bool))
-> Map
     Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
-> Map Symbol (Ann, FilePath, Term Symbol (), Bool)
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
-> (Ann, FilePath, Term Symbol (), Bool)
forall {a} {b} {c} {d} {c} {d}. (a, b, c, d, c, d) -> (a, b, c, d)
go Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
e
          go :: (a, b, c, d, c, d) -> (a, b, c, d)
go (a
ann, b
kind, c
_hash, d
_uneval, c
eval, d
isHit) = (a
ann, b
kind, c
eval, d
isHit)
      Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Map Symbol (Ann, FilePath, Term Symbol (), Bool) -> Bool
forall a. Map Symbol a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Map Symbol (Ann, FilePath, Term Symbol (), Bool)
e')) do
        Output -> Cli ()
Cli.respond (Output -> Cli ()) -> Output -> Cli ()
forall a b. (a -> b) -> a -> b
$ SourceName
-> PrettyPrintEnv
-> [(Symbol, Term Symbol ())]
-> Map Symbol (Ann, FilePath, Term Symbol (), Bool)
-> Output
Output.Evaluated SourceName
text PrettyPrintEnv
ppe [(Symbol, Term Symbol ())]
bindings Map Symbol (Ann, FilePath, Term Symbol (), Bool)
e'
  #latestTypecheckedFile .= Just (Right unisonFile)
  where
    withFile ::
      Names ->
      Text ->
      Text ->
      Cli (TypecheckedUnisonFile Symbol Ann)
    withFile :: Names
-> SourceName
-> SourceName
-> Cli (TypecheckedUnisonFile Symbol Ann)
withFile Names
names SourceName
sourceName SourceName
text = do
      ProjectPath
pp <- Cli ProjectPath
Cli.getCurrentProjectPath
      (LoopState -> LoopState) -> Cli ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
State.modify' \LoopState
loopState ->
        LoopState
loopState
          LoopState -> (LoopState -> LoopState) -> LoopState
forall a b. a -> (a -> b) -> b
& (ASetter
  LoopState
  LoopState
  (Maybe (FilePath, Bool))
  (Maybe (FilePath, Bool))
#latestFile ASetter
  LoopState
  LoopState
  (Maybe (FilePath, Bool))
  (Maybe (FilePath, Bool))
-> Maybe (FilePath, Bool) -> LoopState -> LoopState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ (FilePath, Bool) -> Maybe (FilePath, Bool)
forall a. a -> Maybe a
Just (SourceName -> FilePath
Text.unpack SourceName
sourceName, Bool
False))
          LoopState -> (LoopState -> LoopState) -> LoopState
forall a b. a -> (a -> b) -> b
& (ASetter
  LoopState
  LoopState
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
#latestTypecheckedFile ASetter
  LoopState
  LoopState
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
-> Maybe
     (Either (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann))
-> LoopState
-> LoopState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe
  (Either (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann))
forall a. Maybe a
Nothing)
      Cli.Env {Codebase IO Symbol Ann
codebase :: Codebase IO Symbol Ann
$sel:codebase:Env :: Env -> Codebase IO Symbol Ann
codebase, IO UniqueName
generateUniqueName :: IO UniqueName
$sel:generateUniqueName:Env :: Env -> IO UniqueName
generateUniqueName} <- Cli Env
forall r (m :: * -> *). MonadReader r m => m r
ask
      UniqueName
uniqueName <- IO UniqueName -> Cli UniqueName
forall a. IO a -> Cli a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UniqueName
generateUniqueName
      let parsingEnv :: ParsingEnv Transaction
parsingEnv =
            Parser.ParsingEnv
              { $sel:uniqueNames:ParsingEnv :: UniqueName
uniqueNames = UniqueName
uniqueName,
                $sel:uniqueTypeGuid:ParsingEnv :: Name -> Transaction (Maybe SourceName)
uniqueTypeGuid = ProjectPath -> Name -> Transaction (Maybe SourceName)
Cli.loadUniqueTypeGuid ProjectPath
pp,
                Names
names :: Names
$sel:names:ParsingEnv :: Names
names,
                $sel:maybeNamespace:ParsingEnv :: Maybe Name
maybeNamespace = Maybe Name
forall a. Maybe a
Nothing,
                $sel:localNamespacePrefixedTypesAndConstructors:ParsingEnv :: Names
localNamespacePrefixedTypesAndConstructors = Names
forall a. Monoid a => a
mempty
              }
      UnisonFile Symbol Ann
unisonFile <-
        Transaction (Either (Err Symbol) (UnisonFile Symbol Ann))
-> Cli (Either (Err Symbol) (UnisonFile Symbol Ann))
forall a. Transaction a -> Cli a
Cli.runTransaction (FilePath
-> FilePath
-> ParsingEnv Transaction
-> Transaction (Either (Err Symbol) (UnisonFile Symbol Ann))
forall (m :: * -> *) v.
(Monad m, Var v) =>
FilePath
-> FilePath
-> ParsingEnv m
-> m (Either (Err v) (UnisonFile v Ann))
Parsers.parseFile (SourceName -> FilePath
Text.unpack SourceName
sourceName) (SourceName -> FilePath
Text.unpack SourceName
text) ParsingEnv Transaction
parsingEnv)
          Cli (Either (Err Symbol) (UnisonFile Symbol Ann))
-> (Cli (Either (Err Symbol) (UnisonFile Symbol Ann))
    -> Cli (UnisonFile Symbol Ann))
-> Cli (UnisonFile Symbol Ann)
forall a b. a -> (a -> b) -> b
& (Err Symbol -> Cli (UnisonFile Symbol Ann))
-> Cli (Either (Err Symbol) (UnisonFile Symbol Ann))
-> Cli (UnisonFile Symbol Ann)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> m (Either a b) -> m b
onLeftM \Err Symbol
err -> Output -> Cli (UnisonFile Symbol Ann)
forall a. Output -> Cli a
Cli.returnEarly (SourceName -> [Err Symbol] -> Output
Output.ParseErrors SourceName
text [Err Symbol
err])
      -- set that the file at least parsed (but didn't typecheck)
      (LoopState -> LoopState) -> Cli ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
State.modify' (LoopState -> (LoopState -> LoopState) -> LoopState
forall a b. a -> (a -> b) -> b
& ASetter
  LoopState
  LoopState
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
#latestTypecheckedFile ASetter
  LoopState
  LoopState
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
  (Maybe
     (Either
        (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)))
-> Maybe
     (Either (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann))
-> LoopState
-> LoopState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Either (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)
-> Maybe
     (Either (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann))
forall a. a -> Maybe a
Just (UnisonFile Symbol Ann
-> Either
     (UnisonFile Symbol Ann) (TypecheckedUnisonFile Symbol Ann)
forall a b. a -> Either a b
Left UnisonFile Symbol Ann
unisonFile))
      Env Symbol Ann
typecheckingEnv <-
        Transaction (Env Symbol Ann) -> Cli (Env Symbol Ann)
forall a. Transaction a -> Cli a
Cli.runTransaction do
          ShouldUseTndr Transaction
-> Codebase IO Symbol Ann
-> [Type Symbol Ann]
-> UnisonFile Symbol Ann
-> Transaction (Env Symbol Ann)
computeTypecheckingEnvironment (ParsingEnv Transaction -> ShouldUseTndr Transaction
forall (m :: * -> *). ParsingEnv m -> ShouldUseTndr m
FileParsers.ShouldUseTndr'Yes ParsingEnv Transaction
parsingEnv) Codebase IO Symbol Ann
codebase [] UnisonFile Symbol Ann
unisonFile
      let Result.Result Seq (Note Symbol Ann)
notes Maybe (TypecheckedUnisonFile Symbol Ann)
maybeTypecheckedUnisonFile = Env Symbol Ann
-> UnisonFile Symbol Ann
-> MaybeT
     (WriterT (Seq (Note Symbol Ann)) Identity)
     (TypecheckedUnisonFile Symbol Ann)
forall (m :: * -> *) v.
(Monad m, Var v) =>
Env v Ann
-> UnisonFile v
-> ResultT (Seq (Note v Ann)) m (TypecheckedUnisonFile v Ann)
FileParsers.synthesizeFile Env Symbol Ann
typecheckingEnv UnisonFile Symbol Ann
unisonFile
      Maybe (TypecheckedUnisonFile Symbol Ann)
maybeTypecheckedUnisonFile Maybe (TypecheckedUnisonFile Symbol Ann)
-> (Maybe (TypecheckedUnisonFile Symbol Ann)
    -> Cli (TypecheckedUnisonFile Symbol Ann))
-> Cli (TypecheckedUnisonFile Symbol Ann)
forall a b. a -> (a -> b) -> b
& Cli (TypecheckedUnisonFile Symbol Ann)
-> Maybe (TypecheckedUnisonFile Symbol Ann)
-> Cli (TypecheckedUnisonFile Symbol Ann)
forall (m :: * -> *) a. Applicative m => m a -> Maybe a -> m a
onNothing do
        let pped :: PrettyPrintEnvDecl
pped =
              let ns :: Names
ns =
                    Names
names
                      -- Shadow just the type decl and constructor names (because the unison file didn't typecheck so we
                      -- don't have term `Names`)
                      Names -> (Names -> Names) -> Names
forall a b. a -> (a -> b) -> b
& Names -> Names -> Names
Names.shadowing (UnisonFile Symbol Ann -> Names
forall v a. Var v => UnisonFile v a -> Names
UF.toNames UnisonFile Symbol Ann
unisonFile)
               in Namer -> Suffixifier -> PrettyPrintEnvDecl
PPED.makePPED
                    (Int -> Names -> Namer
PPE.hqNamer Int
10 Names
ns)
                    ( Set Name -> Names -> Suffixifier
PPE.suffixifyByHashWithUnhashedTermsInScope
                        ( Set Name -> Set Name -> Set Name
forall a. Ord a => Set a -> Set a -> Set a
Set.union
                            ((Symbol -> Name) -> Set Symbol -> Set Name
forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map Symbol -> Name
forall v. Var v => v -> Name
Name.unsafeParseVar (Map Symbol (Ann, Term Symbol Ann) -> Set Symbol
forall k a. Map k a -> Set k
Map.keysSet (UnisonFile Symbol Ann -> Map Symbol (Ann, Term Symbol Ann)
forall v a. UnisonFile v a -> Map v (a, Term v a)
UF.terms UnisonFile Symbol Ann
unisonFile)))
                            ( ([(Symbol, Ann, Term Symbol Ann)] -> Set Name)
-> Map FilePath [(Symbol, Ann, Term Symbol Ann)] -> Set Name
forall m a. Monoid m => (a -> m) -> Map FilePath a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap
                                ( ((Symbol, Ann, Term Symbol Ann) -> Set Name)
-> [(Symbol, Ann, Term Symbol Ann)] -> Set Name
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap \case
                                    (Symbol
v, Ann
_, Term Symbol Ann
_) ->
                                      case Symbol -> Type
forall v. Var v => v -> Type
Var.typeOf Symbol
v of
                                        Var.User SourceName
_ -> Name -> Set Name
forall a. a -> Set a
Set.singleton (Symbol -> Name
forall v. Var v => v -> Name
Name.unsafeParseVar Symbol
v)
                                        Type
_ -> Set Name
forall a. Set a
Set.empty
                                )
                                (UnisonFile Symbol Ann
-> Map FilePath [(Symbol, Ann, Term Symbol Ann)]
forall v a. UnisonFile v a -> Map FilePath [(v, a, Term v a)]
UF.watches UnisonFile Symbol Ann
unisonFile)
                            )
                        )
                        Names
ns
                    )
        let suffixifiedPPE :: PrettyPrintEnv
suffixifiedPPE = PrettyPrintEnvDecl -> PrettyPrintEnv
PPED.suffixifiedPPE PrettyPrintEnvDecl
pped
        let tes :: [ErrorNote Symbol Ann]
tes = [ErrorNote Symbol Ann
err | Result.TypeError ErrorNote Symbol Ann
err <- Seq (Note Symbol Ann) -> [Note Symbol Ann]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq (Note Symbol Ann)
notes]
            cbs :: [CompilerBug Symbol Ann]
cbs =
              [ CompilerBug Symbol Ann
bug
                | Result.CompilerBug (Result.TypecheckerBug CompilerBug Symbol Ann
bug) <-
                    Seq (Note Symbol Ann) -> [Note Symbol Ann]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq (Note Symbol Ann)
notes
              ]
        Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([ErrorNote Symbol Ann] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ErrorNote Symbol Ann]
tes)) do
          Absolute
currentPath <- Cli Absolute
Cli.getCurrentPath
          Output -> Cli ()
Cli.respond (Absolute
-> SourceName -> PrettyPrintEnv -> [ErrorNote Symbol Ann] -> Output
Output.TypeErrors Absolute
currentPath SourceName
text PrettyPrintEnv
suffixifiedPPE [ErrorNote Symbol Ann]
tes)
        Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([CompilerBug Symbol Ann] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [CompilerBug Symbol Ann]
cbs)) do
          Output -> Cli ()
Cli.respond (SourceName -> PrettyPrintEnv -> [CompilerBug Symbol Ann] -> Output
Output.CompilerBugs SourceName
text PrettyPrintEnv
suffixifiedPPE [CompilerBug Symbol Ann]
cbs)
        Cli (TypecheckedUnisonFile Symbol Ann)
forall a. Cli a
Cli.returnEarlyWithoutOutput

data EvalMode = Sandboxed | Permissive | Native

-- | Evaluate all watched expressions in a UnisonFile and return
-- their results, keyed by the name of the watch variable. The tuple returned
-- has the form:
--   (hash, (ann, sourceTerm, evaluatedTerm, isCacheHit))
--
-- where
--   `hash` is the hash of the original watch expression definition
--   `ann` gives the location of the watch expression
--   `sourceTerm` is a closed term (no free vars) for the watch expression
--   `evaluatedTerm` is the result of evaluating that `sourceTerm`
--   `isCacheHit` is True if the result was computed by just looking up
--   in a cache
--
-- It's expected that the user of this action might add the
-- `(hash, evaluatedTerm)` mapping to a cache to make future evaluations
-- of the same watches instantaneous.
evalUnisonFile ::
  EvalMode ->
  PPE.PrettyPrintEnv ->
  TypecheckedUnisonFile Symbol Ann ->
  [String] ->
  Cli
    ( [(Symbol, Term Symbol ())],
      Map Symbol (Ann, WK.WatchKind, Reference.Id, Term Symbol (), Term Symbol (), Bool)
    )
evalUnisonFile :: EvalMode
-> PrettyPrintEnv
-> TypecheckedUnisonFile Symbol Ann
-> [FilePath]
-> Cli
     ([(Symbol, Term Symbol ())],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
evalUnisonFile EvalMode
mode PrettyPrintEnv
ppe TypecheckedUnisonFile Symbol Ann
unisonFile [FilePath]
args = do
  Cli.Env {Codebase IO Symbol Ann
$sel:codebase:Env :: Env -> Codebase IO Symbol Ann
codebase :: Codebase IO Symbol Ann
codebase, Runtime Symbol
runtime :: Runtime Symbol
$sel:runtime:Env :: Env -> Runtime Symbol
runtime, Runtime Symbol
sandboxedRuntime :: Runtime Symbol
$sel:sandboxedRuntime:Env :: Env -> Runtime Symbol
sandboxedRuntime, Runtime Symbol
nativeRuntime :: Runtime Symbol
$sel:nativeRuntime:Env :: Env -> Runtime Symbol
nativeRuntime} <- Cli Env
forall r (m :: * -> *). MonadReader r m => m r
ask
  let theRuntime :: Runtime Symbol
theRuntime = case EvalMode
mode of
        EvalMode
Sandboxed -> Runtime Symbol
sandboxedRuntime
        EvalMode
Permissive -> Runtime Symbol
runtime
        EvalMode
Native -> Runtime Symbol
nativeRuntime

  let watchCache :: Reference.Id -> IO (Maybe (Term Symbol ()))
      watchCache :: Id -> IO (Maybe (Term Symbol ()))
watchCache Id
ref = do
        Maybe (Term Symbol Ann)
maybeTerm <- Codebase IO Symbol Ann
-> Transaction (Maybe (Term Symbol Ann))
-> IO (Maybe (Term Symbol Ann))
forall (m :: * -> *) v a b.
MonadIO m =>
Codebase m v a -> Transaction b -> m b
Codebase.runTransaction Codebase IO Symbol Ann
codebase (Codebase IO Symbol Ann
-> Id -> Transaction (Maybe (Term Symbol Ann))
forall (m :: * -> *) v a.
Codebase m v a -> Id -> Transaction (Maybe (Term v a))
Codebase.lookupWatchCache Codebase IO Symbol Ann
codebase Id
ref)
        pure ((Ann -> ()) -> Term Symbol Ann -> Term Symbol ()
forall v a a2. Ord v => (a -> a2) -> Term v a -> Term v a2
Term.amap (\(Ann
_ :: Ann) -> ()) (Term Symbol Ann -> Term Symbol ())
-> Maybe (Term Symbol Ann) -> Maybe (Term Symbol ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Term Symbol Ann)
maybeTerm)

  (forall x. IO x -> IO x)
-> Cli
     ([(Symbol, Term Symbol ())],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
-> Cli
     ([(Symbol, Term Symbol ())],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
forall a. (forall x. IO x -> IO x) -> Cli a -> Cli a
Cli.with_ ([FilePath] -> IO x -> IO x
forall a. [FilePath] -> IO a -> IO a
withArgs [FilePath]
args) do
    ([(Symbol, Term Symbol ())]
nts, [Error]
errs, Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
map) <-
      IO
  (Either
     Error
     ([(Symbol, Term Symbol ())], [Error],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)))
-> (Error
    -> Cli
         ([(Symbol, Term Symbol ())], [Error],
          Map
            Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)))
-> Cli
     ([(Symbol, Term Symbol ())], [Error],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
forall e a. IO (Either e a) -> (e -> Cli a) -> Cli a
Cli.ioE (CodeLookup Symbol IO Ann
-> PrettyPrintEnv
-> (Id -> IO (Maybe (Term Symbol ())))
-> Runtime Symbol
-> TypecheckedUnisonFile Symbol Ann
-> IO
     (Either
        Error
        ([(Symbol, Term Symbol ())], [Error],
         Map
           Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)))
forall v a.
Var v =>
CodeLookup v IO a
-> PrettyPrintEnv
-> (Id -> IO (Maybe (Term v)))
-> Runtime v
-> TypecheckedUnisonFile v a
-> IO (WatchResults v a)
Runtime.evaluateWatches (Codebase IO Symbol Ann -> CodeLookup Symbol IO Ann
forall (m :: * -> *).
MonadIO m =>
Codebase m Symbol Ann -> CodeLookup Symbol m Ann
Codebase.codebaseToCodeLookup Codebase IO Symbol Ann
codebase) PrettyPrintEnv
ppe Id -> IO (Maybe (Term Symbol ()))
watchCache Runtime Symbol
theRuntime TypecheckedUnisonFile Symbol Ann
unisonFile) \Error
err -> do
        Output
-> Cli
     ([(Symbol, Term Symbol ())], [Error],
      Map
        Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool))
forall a. Output -> Cli a
Cli.returnEarly (Error -> Output
Output.EvaluationFailure Error
err)
    Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [Error] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Error]
errs) ([Error] -> Cli ()
RuntimeUtils.displayDecompileErrors [Error]
errs)
    [(Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)]
-> ((Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
    -> Cli ())
-> Cli ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
-> [(Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)]
forall k a. Map k a -> [a]
Map.elems Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
map) \(Ann
_loc, FilePath
kind, Id
hash, Term Symbol ()
_src, Term Symbol ()
value, Bool
isHit) -> do
      -- only update the watch cache when there are no errors
      Bool -> Cli () -> Cli ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
isHit Bool -> Bool -> Bool
&& [Error] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Error]
errs) do
        let value' :: Term Symbol Ann
value' = (() -> Ann) -> Term Symbol () -> Term Symbol Ann
forall v a a2. Ord v => (a -> a2) -> Term v a -> Term v a2
Term.amap (\() -> Ann
Ann.External) Term Symbol ()
value
        Transaction () -> Cli ()
forall a. Transaction a -> Cli a
Cli.runTransaction (FilePath -> Id -> Term Symbol Ann -> Transaction ()
Codebase.putWatch FilePath
kind Id
hash Term Symbol Ann
value')
    pure ([(Symbol, Term Symbol ())]
nts, Map
  Symbol (Ann, FilePath, Id, Term Symbol (), Term Symbol (), Bool)
map)