2018-04-12 19:53:50 +02:00
|
|
|
{- This code was authored by:
|
|
|
|
|
|
|
|
Stephen Diehl
|
|
|
|
Kwang Yul Seo <kwangyul.seo@gmail.com>
|
|
|
|
|
|
|
|
It was made available under the MIT license. See the src/Nix/Type
|
|
|
|
directory for more details.
|
|
|
|
-}
|
|
|
|
|
2020-06-28 11:25:42 +02:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2018-04-12 19:53:50 +02:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2018-04-29 02:13:11 +02:00
|
|
|
{-# LANGUAGE MultiWayIf #-}
|
2018-10-27 13:37:02 +02:00
|
|
|
{-# LANGUAGE CPP #-}
|
2018-04-12 19:53:50 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-04-29 01:13:24 +02:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2018-04-13 01:46:34 +02:00
|
|
|
{-# LANGUAGE TypeApplications #-}
|
2018-04-12 19:53:50 +02:00
|
|
|
{-# LANGUAGE TypeSynonymInstances #-}
|
|
|
|
|
|
|
|
{-# OPTIONS_GHC -Wno-unused-matches #-}
|
|
|
|
{-# OPTIONS_GHC -Wno-unused-imports #-}
|
|
|
|
|
|
|
|
module Repl where
|
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
import Nix hiding ( exec
|
|
|
|
, try
|
|
|
|
)
|
2019-03-16 01:20:10 +01:00
|
|
|
import Nix.Cited
|
2018-04-29 02:13:11 +02:00
|
|
|
import Nix.Convert
|
2018-04-14 18:44:55 +02:00
|
|
|
import Nix.Eval
|
2018-04-13 01:46:34 +02:00
|
|
|
import Nix.Scope
|
2019-03-17 22:47:38 +01:00
|
|
|
import qualified Nix.Type.Env as Env
|
2018-04-13 01:46:34 +02:00
|
|
|
import Nix.Type.Infer
|
2018-04-29 02:13:11 +02:00
|
|
|
import Nix.Utils
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2019-03-16 01:20:10 +01:00
|
|
|
import Control.Comonad
|
2019-03-17 22:47:38 +01:00
|
|
|
import qualified Data.HashMap.Lazy as M
|
|
|
|
import Data.List ( isPrefixOf
|
|
|
|
, foldl'
|
|
|
|
)
|
|
|
|
import qualified Data.Map as Map
|
2020-06-30 10:33:11 +02:00
|
|
|
import Data.Text (Text)
|
|
|
|
import qualified Data.Text
|
|
|
|
import qualified Data.Text.IO
|
2019-03-17 22:47:38 +01:00
|
|
|
import Data.Version ( showVersion )
|
|
|
|
import Paths_hnix ( version )
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2018-11-19 00:32:03 +01:00
|
|
|
import Control.Monad.Catch
|
2018-04-12 19:53:50 +02:00
|
|
|
import Control.Monad.Identity
|
2018-04-29 02:13:11 +02:00
|
|
|
import Control.Monad.Reader
|
2018-04-12 19:53:50 +02:00
|
|
|
import Control.Monad.State.Strict
|
|
|
|
|
2020-06-28 11:25:42 +02:00
|
|
|
import System.Console.Repline ( CompletionFunc
|
|
|
|
, CompleterStyle (Prefix)
|
|
|
|
, ExitDecision(Exit)
|
|
|
|
, HaskelineT
|
|
|
|
, WordCompleter
|
|
|
|
)
|
|
|
|
import qualified System.Console.Repline
|
|
|
|
import qualified System.Exit
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2018-11-24 21:17:45 +01:00
|
|
|
|
2020-05-30 03:32:20 +02:00
|
|
|
main :: (MonadNix e t f m, MonadIO m, MonadMask m) => m ()
|
2019-03-17 22:47:38 +01:00
|
|
|
main = flip evalStateT initState
|
2020-06-28 11:25:42 +02:00
|
|
|
$ System.Console.Repline.evalRepl
|
|
|
|
banner
|
2020-06-26 12:06:45 +02:00
|
|
|
cmd
|
|
|
|
options
|
|
|
|
(Just ':')
|
2020-06-28 11:25:42 +02:00
|
|
|
(Just "paste")
|
2020-06-26 12:06:45 +02:00
|
|
|
completer
|
2020-06-28 11:25:42 +02:00
|
|
|
greeter
|
|
|
|
finalizer
|
2019-03-17 22:47:38 +01:00
|
|
|
where
|
2020-06-28 11:25:42 +02:00
|
|
|
banner = pure . \case
|
|
|
|
System.Console.Repline.SingleLine -> "hnix> "
|
|
|
|
System.Console.Repline.MultiLine -> "| "
|
|
|
|
greeter =
|
2019-03-17 22:47:38 +01:00
|
|
|
liftIO
|
|
|
|
$ putStrLn
|
|
|
|
$ "Welcome to hnix "
|
|
|
|
<> showVersion version
|
|
|
|
<> ". For help type :help\n"
|
2020-06-28 11:25:42 +02:00
|
|
|
finalizer = do
|
|
|
|
liftIO $ putStrLn "Goodbye."
|
|
|
|
return Exit
|
2018-11-24 21:17:45 +01:00
|
|
|
|
2018-04-12 19:53:50 +02:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Types
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
2019-03-16 01:20:10 +01:00
|
|
|
newtype IState t f m = IState
|
|
|
|
{ tmctx :: AttrSet (NValue t f m) -- Value environment
|
2018-04-12 19:53:50 +02:00
|
|
|
}
|
|
|
|
|
2019-03-16 01:20:10 +01:00
|
|
|
initState :: MonadIO m => IState t f m
|
2020-06-30 10:33:11 +02:00
|
|
|
initState = IState mempty
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2019-03-16 01:20:10 +01:00
|
|
|
type Repl e t f m = HaskelineT (StateT (IState t f m) m)
|
2018-04-12 19:53:50 +02:00
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Execution
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
exec
|
|
|
|
:: forall e t f m
|
2020-05-30 03:32:20 +02:00
|
|
|
. (MonadNix e t f m, MonadIO m)
|
2019-03-17 22:47:38 +01:00
|
|
|
=> Bool
|
2020-06-30 10:33:11 +02:00
|
|
|
-> Text
|
|
|
|
-> Repl e t f m (Maybe (NValue t f m))
|
2018-04-12 19:53:50 +02:00
|
|
|
exec update source = do
|
|
|
|
-- Get the current interpreter state
|
2020-06-30 10:33:11 +02:00
|
|
|
st <- get
|
2018-04-12 19:53:50 +02:00
|
|
|
|
|
|
|
-- Parser ( returns AST )
|
2018-11-19 00:32:03 +01:00
|
|
|
-- TODO: parse <var> = <expr>
|
2020-06-30 10:33:11 +02:00
|
|
|
case parseNixTextLoc source of
|
|
|
|
Failure err -> do
|
|
|
|
liftIO $ print err
|
|
|
|
return Nothing
|
|
|
|
Success expr -> do
|
|
|
|
-- Type Inference ( returns Typing Environment )
|
|
|
|
--let tyctx' = inferTop Env.empty [("repl", stripAnnotation expr)]
|
|
|
|
--liftIO $ print tyctx'
|
|
|
|
|
|
|
|
-- TODO: track scope with (tmctx st)
|
|
|
|
mVal <- lift $ lift $ try $ pushScope mempty (evalExprLoc expr)
|
|
|
|
|
|
|
|
case mVal of
|
|
|
|
Left (NixException frames) -> do
|
|
|
|
lift $ lift $ liftIO . print =<< renderFrames @(NValue t f m) @t frames
|
|
|
|
return Nothing
|
|
|
|
Right val -> do
|
|
|
|
-- Update the interpreter state
|
|
|
|
when update $ do
|
|
|
|
-- Create the new environment
|
|
|
|
put st { tmctx = tmctx st } -- TODO: M.insert key val (tmctx st)
|
|
|
|
return $ Just val
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
cmd
|
2020-05-30 03:32:20 +02:00
|
|
|
:: (MonadNix e t f m, MonadIO m)
|
2019-03-17 22:47:38 +01:00
|
|
|
=> String
|
|
|
|
-> Repl e t f m ()
|
2018-11-19 00:32:03 +01:00
|
|
|
cmd source = do
|
2020-06-30 10:33:11 +02:00
|
|
|
mVal <- exec True (Data.Text.pack source)
|
|
|
|
case mVal of
|
|
|
|
Nothing -> return ()
|
|
|
|
Just val -> do
|
|
|
|
lift $ lift $ do
|
|
|
|
opts :: Nix.Options <- asks (view hasLens)
|
|
|
|
if
|
|
|
|
| strict opts -> liftIO . print . prettyNValue =<< normalForm val
|
|
|
|
| values opts -> liftIO . print . prettyNValueProv =<< removeEffects val
|
|
|
|
| otherwise -> liftIO . print . prettyNValue =<< removeEffects val
|
|
|
|
|
2018-04-12 19:53:50 +02:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Commands
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- :browse command
|
2020-06-26 12:06:45 +02:00
|
|
|
browse :: MonadNix e t f m => String -> Repl e t f m ()
|
2018-04-12 19:53:50 +02:00
|
|
|
browse _ = do
|
|
|
|
st <- get
|
|
|
|
undefined
|
|
|
|
-- liftIO $ mapM_ putStrLn $ ppenv (tyctx st)
|
|
|
|
|
|
|
|
-- :load command
|
2019-03-17 22:47:38 +01:00
|
|
|
load
|
2020-05-30 03:32:20 +02:00
|
|
|
:: (MonadNix e t f m, MonadIO m)
|
2020-06-26 12:06:45 +02:00
|
|
|
=> String
|
2019-03-17 22:47:38 +01:00
|
|
|
-> Repl e t f m ()
|
2018-04-12 19:53:50 +02:00
|
|
|
load args = do
|
2020-06-30 10:33:11 +02:00
|
|
|
contents <- liftIO $ Data.Text.IO.readFile args
|
2018-11-19 00:32:03 +01:00
|
|
|
void $ exec True contents
|
2018-04-12 19:53:50 +02:00
|
|
|
|
|
|
|
-- :type command
|
2019-03-17 22:47:38 +01:00
|
|
|
typeof
|
2020-05-30 03:32:20 +02:00
|
|
|
:: (MonadNix e t f m, MonadIO m)
|
2020-06-26 12:06:45 +02:00
|
|
|
=> String
|
2019-03-17 22:47:38 +01:00
|
|
|
-> Repl e t f m ()
|
2018-11-19 00:32:03 +01:00
|
|
|
typeof args = do
|
2020-06-30 10:33:11 +02:00
|
|
|
st <- get
|
|
|
|
mVal <- case M.lookup line (tmctx st) of
|
|
|
|
Just val -> return $ Just val
|
|
|
|
Nothing -> do
|
|
|
|
exec False line
|
|
|
|
|
|
|
|
forM_ mVal $ \val -> do
|
|
|
|
s <- lift . lift . showValueType $ val
|
|
|
|
liftIO $ putStrLn s
|
|
|
|
|
|
|
|
where line = Data.Text.pack args
|
2018-04-12 19:53:50 +02:00
|
|
|
|
|
|
|
-- :quit command
|
2019-03-17 23:30:20 +01:00
|
|
|
quit :: (MonadNix e t f m, MonadIO m) => a -> Repl e t f m ()
|
2020-06-28 11:25:42 +02:00
|
|
|
quit _ = liftIO System.Exit.exitSuccess
|
2018-04-12 19:53:50 +02:00
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Interactive Shell
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- Prefix tab completer
|
|
|
|
defaultMatcher :: MonadIO m => [(String, CompletionFunc m)]
|
2019-03-17 22:47:38 +01:00
|
|
|
defaultMatcher =
|
2020-06-28 11:25:42 +02:00
|
|
|
[(":load", System.Console.Repline.fileCompleter)
|
2018-04-12 19:53:50 +02:00
|
|
|
--, (":type" , values)
|
2019-03-17 22:47:38 +01:00
|
|
|
]
|
2018-04-12 19:53:50 +02:00
|
|
|
-- Default tab completer
|
2018-11-19 00:32:03 +01:00
|
|
|
comp :: Monad m => WordCompleter m
|
2018-04-12 19:53:50 +02:00
|
|
|
comp n = do
|
|
|
|
let cmds = [":load", ":type", ":browse", ":quit"]
|
2018-04-13 01:46:34 +02:00
|
|
|
-- Env.TypeEnv ctx <- gets tyctx
|
2020-06-30 10:33:11 +02:00
|
|
|
-- let defs = map Data.Text.unpack $ Map.keys ctx
|
|
|
|
return $ filter (isPrefixOf n) (cmds
|
|
|
|
-- ++ defs
|
|
|
|
)
|
2019-03-17 22:47:38 +01:00
|
|
|
|
|
|
|
options
|
2020-05-30 03:32:20 +02:00
|
|
|
:: (MonadNix e t f m, MonadIO m)
|
2020-06-26 12:06:45 +02:00
|
|
|
=> System.Console.Repline.Options (Repl e t f m)
|
2019-03-17 22:47:38 +01:00
|
|
|
options =
|
2020-06-26 12:06:45 +02:00
|
|
|
[ ( "load" , load)
|
2018-11-24 21:17:45 +01:00
|
|
|
--, ("browse" , browse)
|
2019-03-17 22:47:38 +01:00
|
|
|
, ("quit", quit)
|
|
|
|
, ("type", typeof)
|
|
|
|
, ("help", help)
|
2018-04-12 19:53:50 +02:00
|
|
|
]
|
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
help
|
|
|
|
:: forall e t f m
|
2020-05-30 03:32:20 +02:00
|
|
|
. (MonadNix e t f m, MonadIO m)
|
2020-06-26 12:06:45 +02:00
|
|
|
=> String
|
2019-03-17 22:47:38 +01:00
|
|
|
-> Repl e t f m ()
|
2018-11-24 21:17:45 +01:00
|
|
|
help _ = liftIO $ do
|
|
|
|
putStrLn "Available commands:\n"
|
2019-03-16 01:20:10 +01:00
|
|
|
mapM_ putStrLn $ map (\o -> ":" ++ (fst o)) (options @e @t @f @m)
|
2020-06-28 11:25:42 +02:00
|
|
|
putStrLn ":paste - enter multi-line mode"
|
2018-04-12 19:53:50 +02:00
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
completer
|
2019-03-17 23:30:20 +01:00
|
|
|
:: (MonadNix e t f m, MonadIO m)
|
2019-03-17 22:47:38 +01:00
|
|
|
=> CompleterStyle (StateT (IState t f m) m)
|
2020-06-28 11:25:42 +02:00
|
|
|
completer = Prefix (System.Console.Repline.wordCompleter comp) defaultMatcher
|