2022-01-18 14:25:42 +03:00
|
|
|
module Main (main) where
|
|
|
|
|
2022-05-18 18:10:10 +03:00
|
|
|
import App
|
|
|
|
import CLI
|
2022-05-04 19:17:16 +03:00
|
|
|
import Commands.Termination as Termination
|
2022-04-05 20:57:21 +03:00
|
|
|
import Control.Exception qualified as IO
|
2022-01-21 11:50:37 +03:00
|
|
|
import Control.Monad.Extra
|
2022-05-04 19:17:16 +03:00
|
|
|
import Data.HashMap.Strict qualified as HashMap
|
2022-04-07 13:53:05 +03:00
|
|
|
import MiniJuvix.Pipeline
|
2022-03-25 02:52:30 +03:00
|
|
|
import MiniJuvix.Prelude hiding (Doc)
|
2022-04-11 14:08:37 +03:00
|
|
|
import MiniJuvix.Prelude.Pretty hiding (Doc)
|
2022-05-04 19:17:16 +03:00
|
|
|
import MiniJuvix.Syntax.Abstract.InfoTable qualified as Abstract
|
|
|
|
import MiniJuvix.Syntax.Abstract.Language qualified as Abstract
|
2022-04-11 14:23:55 +03:00
|
|
|
import MiniJuvix.Syntax.Abstract.Pretty qualified as Abstract
|
2022-04-07 13:49:08 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Parser qualified as Parser
|
2022-05-13 17:17:26 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Highlight qualified as Highlight
|
2022-04-07 13:49:08 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.InfoTable qualified as Scoper
|
2022-05-04 19:17:16 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Name qualified as Scoper
|
2022-04-11 14:08:37 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Pretty qualified as Scoper
|
2022-03-25 02:52:30 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Pretty.Html
|
2022-04-07 13:49:08 +03:00
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Scoper qualified as Scoper
|
2022-04-11 14:08:37 +03:00
|
|
|
import MiniJuvix.Syntax.MicroJuvix.Pretty qualified as Micro
|
|
|
|
import MiniJuvix.Syntax.MicroJuvix.TypeChecker qualified as MicroTyped
|
|
|
|
import MiniJuvix.Syntax.MiniHaskell.Pretty qualified as MiniHaskell
|
2022-05-04 11:50:03 +03:00
|
|
|
import MiniJuvix.Syntax.MonoJuvix.Pretty qualified as Mono
|
2022-05-04 19:17:16 +03:00
|
|
|
import MiniJuvix.Termination qualified as Termination
|
2022-04-05 20:57:21 +03:00
|
|
|
import MiniJuvix.Translation.AbstractToMicroJuvix qualified as Micro
|
2022-05-04 11:50:03 +03:00
|
|
|
import MiniJuvix.Translation.MicroJuvixToMonoJuvix qualified as Mono
|
2022-05-05 16:12:17 +03:00
|
|
|
import MiniJuvix.Translation.MonoJuvixToMiniC qualified as MiniC
|
2022-04-22 11:06:34 +03:00
|
|
|
import MiniJuvix.Translation.MonoJuvixToMiniHaskell qualified as MiniHaskell
|
2022-04-07 13:49:08 +03:00
|
|
|
import MiniJuvix.Translation.ScopedToAbstract qualified as Abstract
|
2022-03-25 02:52:30 +03:00
|
|
|
import MiniJuvix.Utils.Version (runDisplayVersion)
|
2022-01-18 14:25:42 +03:00
|
|
|
import Options.Applicative
|
2022-02-05 01:14:06 +03:00
|
|
|
import Text.Show.Pretty hiding (Html)
|
2022-03-25 02:52:30 +03:00
|
|
|
|
2022-04-01 13:32:15 +03:00
|
|
|
minijuvixYamlFile :: FilePath
|
|
|
|
minijuvixYamlFile = "minijuvix.yaml"
|
|
|
|
|
2022-05-18 18:10:10 +03:00
|
|
|
findRoot :: CLI -> IO FilePath
|
|
|
|
findRoot cli = do
|
|
|
|
whenJust dir0 setCurrentDirectory
|
2022-04-01 13:32:15 +03:00
|
|
|
r <- IO.try go :: IO (Either IO.SomeException FilePath)
|
|
|
|
case r of
|
|
|
|
Left err -> do
|
|
|
|
putStrLn "Something went wrong when figuring out the root of the project."
|
|
|
|
putStrLn (pack (IO.displayException err))
|
2022-04-04 16:53:16 +03:00
|
|
|
cur <- getCurrentDirectory
|
|
|
|
putStrLn ("I will try to use the current directory: " <> pack cur)
|
|
|
|
return cur
|
2022-04-01 13:32:15 +03:00
|
|
|
Right root -> return root
|
|
|
|
where
|
2022-04-05 20:57:21 +03:00
|
|
|
possiblePaths :: FilePath -> [FilePath]
|
|
|
|
possiblePaths start = takeWhile (/= "/") (aux start)
|
|
|
|
where
|
|
|
|
aux f = f : aux (takeDirectory f)
|
|
|
|
go :: IO FilePath
|
|
|
|
go = do
|
|
|
|
c <- getCurrentDirectory
|
|
|
|
l <- findFile (possiblePaths c) minijuvixYamlFile
|
|
|
|
case l of
|
|
|
|
Nothing -> return c
|
|
|
|
Just yaml -> return (takeDirectory yaml)
|
2022-05-18 18:10:10 +03:00
|
|
|
dir0 :: Maybe FilePath
|
|
|
|
dir0 = takeDirectory <$> cliMainFile cli
|
2022-04-01 13:32:15 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
class HasEntryPoint a where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint :: FilePath -> GlobalOptions -> a -> EntryPoint
|
2022-04-07 10:43:17 +03:00
|
|
|
|
|
|
|
instance HasEntryPoint ScopeOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . (^. scopeInputFiles)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint ParseOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. parseInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint HighlightOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. highlightInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint HtmlOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. htmlInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-05-04 11:50:03 +03:00
|
|
|
instance HasEntryPoint MicroJuvixTypeOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. microJuvixTypeInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-05-04 11:50:03 +03:00
|
|
|
|
|
|
|
instance HasEntryPoint MicroJuvixPrettyOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. microJuvixPrettyInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-05-04 11:50:03 +03:00
|
|
|
|
|
|
|
instance HasEntryPoint MonoJuvixOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. monoJuvixInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint MiniHaskellOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. miniHaskellInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-05-05 16:12:17 +03:00
|
|
|
instance HasEntryPoint MiniCOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. miniCInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-05-05 16:12:17 +03:00
|
|
|
|
2022-05-30 18:46:17 +03:00
|
|
|
instance HasEntryPoint CompileOptions where
|
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. compileInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint CallsOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. callsInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 13:53:05 +03:00
|
|
|
|
2022-04-07 10:43:17 +03:00
|
|
|
instance HasEntryPoint CallGraphOptions where
|
2022-05-30 14:40:52 +03:00
|
|
|
getEntryPoint r opts = EntryPoint r nT . pure . (^. graphInputFile)
|
|
|
|
where
|
|
|
|
nT = opts ^. globalNoTermination
|
2022-04-07 10:43:17 +03:00
|
|
|
|
2022-05-18 18:10:10 +03:00
|
|
|
runCLI :: Members '[Embed IO, App] r => CLI -> Sem r ()
|
2022-04-11 14:08:37 +03:00
|
|
|
runCLI cli = do
|
2022-04-25 11:40:24 +03:00
|
|
|
let globalOptions = cli ^. cliGlobalOptions
|
2022-04-11 14:08:37 +03:00
|
|
|
toAnsiText' :: forall a. (HasAnsiBackend a, HasTextBackend a) => a -> Text
|
2022-05-18 18:10:10 +03:00
|
|
|
toAnsiText' = toAnsiText (not (globalOptions ^. globalNoColors))
|
|
|
|
root <- embed (findRoot cli)
|
2022-04-11 14:08:37 +03:00
|
|
|
case cli ^. cliCommand of
|
2022-05-18 18:10:10 +03:00
|
|
|
DisplayVersion -> embed runDisplayVersion
|
|
|
|
DisplayRoot -> say (pack root)
|
2022-04-07 10:43:17 +03:00
|
|
|
Highlight o -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
res <- runPipelineEither (upToScoping (getEntryPoint root globalOptions o))
|
2022-05-18 18:10:10 +03:00
|
|
|
absP <- embed (makeAbsolute (o ^. highlightInputFile))
|
|
|
|
case res of
|
|
|
|
Left err -> say (Highlight.goError (errorIntervals err))
|
|
|
|
Right r -> do
|
|
|
|
let tbl = r ^. Scoper.resultParserTable
|
|
|
|
items = tbl ^. Parser.infoParsedItems
|
|
|
|
names = r ^. (Scoper.resultScoperTable . Scoper.infoNames)
|
|
|
|
hinput =
|
|
|
|
Highlight.filterInput
|
|
|
|
absP
|
|
|
|
Highlight.HighlightInput
|
|
|
|
{ _highlightNames = names,
|
|
|
|
_highlightParsed = items
|
|
|
|
}
|
|
|
|
say (Highlight.go hinput)
|
2022-05-13 17:17:26 +03:00
|
|
|
Parse opts -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
m <-
|
|
|
|
head . (^. Parser.resultModules)
|
|
|
|
<$> runPipeline (upToParsing (getEntryPoint root globalOptions opts))
|
2022-05-18 18:10:10 +03:00
|
|
|
if opts ^. parseNoPrettyShow then say (show m) else say (pack (ppShow m))
|
2022-04-25 11:40:24 +03:00
|
|
|
Scope opts -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
l <- (^. Scoper.resultModules) <$> runPipeline (upToScoping (getEntryPoint root globalOptions opts))
|
2022-04-25 11:40:24 +03:00
|
|
|
forM_ l $ \s -> do
|
|
|
|
renderStdOut (Scoper.ppOut (mkScopePrettyOptions globalOptions opts) s)
|
2022-04-07 10:43:17 +03:00
|
|
|
Html o@HtmlOptions {..} -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
res <- runPipeline (upToScoping (getEntryPoint root globalOptions o))
|
2022-04-07 10:43:17 +03:00
|
|
|
let m = head (res ^. Scoper.resultModules)
|
2022-05-18 18:10:10 +03:00
|
|
|
embed (genHtml Scoper.defaultOptions _htmlRecursive _htmlTheme m)
|
2022-04-08 17:36:48 +03:00
|
|
|
MicroJuvix (Pretty opts) -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
micro <- head . (^. Micro.resultModules) <$> runPipeline (upToMicroJuvix (getEntryPoint root globalOptions opts))
|
2022-04-25 11:40:24 +03:00
|
|
|
let ppOpts =
|
|
|
|
Micro.defaultOptions
|
|
|
|
{ Micro._optShowNameId = globalOptions ^. globalShowNameIds
|
|
|
|
}
|
2022-05-18 18:10:10 +03:00
|
|
|
App.renderStdOut (Micro.ppOut ppOpts micro)
|
2022-04-11 14:08:37 +03:00
|
|
|
MicroJuvix (TypeCheck opts) -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
res <- runPipeline (upToMicroJuvixTyped (getEntryPoint root globalOptions opts))
|
2022-05-18 18:10:10 +03:00
|
|
|
say "Well done! It type checks"
|
|
|
|
when (opts ^. microJuvixTypePrint) $ do
|
|
|
|
let ppOpts =
|
|
|
|
Micro.defaultOptions
|
|
|
|
{ Micro._optShowNameId = globalOptions ^. globalShowNameIds
|
|
|
|
}
|
|
|
|
checkedModule = head (res ^. MicroTyped.resultModules)
|
|
|
|
renderStdOut (Micro.ppOut ppOpts checkedModule)
|
|
|
|
newline
|
|
|
|
let typeCalls = Mono.buildTypeCallMap res
|
|
|
|
renderStdOut (Micro.ppOut ppOpts typeCalls)
|
|
|
|
newline
|
|
|
|
let concreteTypeCalls = Mono.collectTypeCalls res
|
|
|
|
renderStdOut (Micro.ppOut ppOpts concreteTypeCalls)
|
2022-05-04 11:50:03 +03:00
|
|
|
MonoJuvix o -> do
|
|
|
|
let ppOpts =
|
|
|
|
Mono.defaultOptions
|
|
|
|
{ Mono._optShowNameIds = globalOptions ^. globalShowNameIds
|
|
|
|
}
|
2022-05-30 14:40:52 +03:00
|
|
|
monojuvix <- head . (^. Mono.resultModules) <$> runPipeline (upToMonoJuvix (getEntryPoint root globalOptions o))
|
2022-05-18 18:10:10 +03:00
|
|
|
renderStdOut (Mono.ppOut ppOpts monojuvix)
|
2022-04-07 10:43:17 +03:00
|
|
|
MiniHaskell o -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
minihaskell <- head . (^. MiniHaskell.resultModules) <$> runPipeline (upToMiniHaskell (getEntryPoint root globalOptions o))
|
2022-05-18 18:10:10 +03:00
|
|
|
renderStdOut (MiniHaskell.ppOutDefault minihaskell)
|
2022-05-05 16:12:17 +03:00
|
|
|
MiniC o -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
miniC <- (^. MiniC.resultCCode) <$> runPipeline (upToMiniC (getEntryPoint root globalOptions o))
|
2022-05-18 18:10:10 +03:00
|
|
|
say miniC
|
2022-05-30 18:46:17 +03:00
|
|
|
Compile o -> do
|
|
|
|
miniC <- (^. MiniC.resultCCode) <$> runPipeline (upToMiniC (getEntryPoint root globalOptions o))
|
|
|
|
result <- embed (runCompile root o miniC)
|
|
|
|
case result of
|
|
|
|
Left err -> say ("Error: " <> err)
|
|
|
|
_ -> return ()
|
2022-03-08 14:53:26 +03:00
|
|
|
Termination (Calls opts@CallsOptions {..}) -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
results <- runPipeline (upToAbstract (getEntryPoint root globalOptions opts))
|
2022-05-04 15:05:58 +03:00
|
|
|
let topModule = head (results ^. Abstract.resultModules)
|
|
|
|
infotable = results ^. Abstract.resultTable
|
2022-05-04 19:17:16 +03:00
|
|
|
callMap0 = Termination.buildCallMap infotable topModule
|
2022-03-07 18:32:24 +03:00
|
|
|
callMap = case _callsFunctionNameFilter of
|
|
|
|
Nothing -> callMap0
|
2022-05-04 19:17:16 +03:00
|
|
|
Just f -> Termination.filterCallMap f callMap0
|
|
|
|
opts' = Termination.callsPrettyOptions opts
|
2022-05-18 18:10:10 +03:00
|
|
|
renderStdOut (Abstract.ppOut opts' callMap)
|
|
|
|
newline
|
2022-05-04 15:05:58 +03:00
|
|
|
Termination (CallGraph opts@CallGraphOptions {..}) -> do
|
2022-05-30 14:40:52 +03:00
|
|
|
results <- runPipeline (upToAbstract (getEntryPoint root globalOptions opts))
|
2022-05-04 15:05:58 +03:00
|
|
|
let topModule = head (results ^. Abstract.resultModules)
|
|
|
|
infotable = results ^. Abstract.resultTable
|
2022-05-04 19:17:16 +03:00
|
|
|
callMap = Termination.buildCallMap infotable topModule
|
2022-04-25 11:40:24 +03:00
|
|
|
opts' =
|
|
|
|
Abstract.defaultOptions
|
|
|
|
{ Abstract._optShowNameId = globalOptions ^. globalShowNameIds
|
|
|
|
}
|
2022-05-04 19:17:16 +03:00
|
|
|
completeGraph = Termination.completeCallGraph callMap
|
|
|
|
filteredGraph = maybe completeGraph (`Termination.unsafeFilterGraph` completeGraph) _graphFunctionNameFilter
|
|
|
|
rEdges = Termination.reflexiveEdges filteredGraph
|
|
|
|
recBehav = map Termination.recursiveBehaviour rEdges
|
2022-05-18 18:10:10 +03:00
|
|
|
App.renderStdOut (Abstract.ppOut opts' filteredGraph)
|
|
|
|
newline
|
2022-03-04 04:13:43 +03:00
|
|
|
forM_ recBehav $ \r -> do
|
2022-05-06 12:48:07 +03:00
|
|
|
let funName = r ^. Termination.recursiveBehaviourFun
|
2022-05-04 19:17:16 +03:00
|
|
|
funRef = Abstract.FunctionRef (Scoper.unqualifiedSymbol funName)
|
|
|
|
funInfo = HashMap.lookupDefault impossible funRef (infotable ^. Abstract.infoFunctions)
|
|
|
|
markedTerminating = funInfo ^. (Abstract.functionInfoDef . Abstract.funDefTerminating)
|
|
|
|
sopts =
|
2022-04-25 11:40:24 +03:00
|
|
|
Scoper.defaultOptions
|
|
|
|
{ Scoper._optShowNameId = globalOptions ^. globalShowNameIds
|
|
|
|
}
|
2022-05-04 19:17:16 +03:00
|
|
|
n = toAnsiText' (Scoper.ppOut sopts funName)
|
2022-05-18 18:10:10 +03:00
|
|
|
App.renderStdOut (Abstract.ppOut opts' r)
|
|
|
|
newline
|
2022-05-04 19:17:16 +03:00
|
|
|
if
|
2022-05-18 18:10:10 +03:00
|
|
|
| markedTerminating -> say (n <> " Terminates by assumption")
|
2022-05-04 19:17:16 +03:00
|
|
|
| otherwise ->
|
|
|
|
case Termination.findOrder r of
|
2022-05-18 18:10:10 +03:00
|
|
|
Nothing -> say (n <> " Fails the termination checking") >> embed exitFailure
|
|
|
|
Just (Termination.LexOrder k) -> say (n <> " Terminates with order " <> show (toList k))
|
|
|
|
newline
|
2022-03-04 04:13:43 +03:00
|
|
|
|
2022-01-18 14:25:42 +03:00
|
|
|
main :: IO ()
|
2022-05-18 18:10:10 +03:00
|
|
|
main = do
|
|
|
|
cli <- execParser descr >>= makeAbsPaths
|
|
|
|
runM (runAppIO (cli ^. cliGlobalOptions) (runCLI cli))
|