2022-01-18 14:25:42 +03:00
|
|
|
{-# LANGUAGE ApplicativeDo #-}
|
|
|
|
module Main (main) where
|
|
|
|
|
2022-01-21 11:50:37 +03:00
|
|
|
import Control.Monad.Extra
|
2022-01-20 14:50:01 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Concrete.Language as M
|
2022-01-21 11:50:37 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Concrete.Parser as M
|
2022-01-19 14:41:16 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Concrete.Scoped.Pretty.Ansi as M
|
2022-03-17 20:18:10 +03:00
|
|
|
import qualified MiniJuvix.Syntax.MicroJuvix.Pretty.Ansi as Micro
|
2022-03-04 01:31:45 +03:00
|
|
|
import qualified MiniJuvix.Termination as T
|
2022-02-23 23:22:28 +03:00
|
|
|
import qualified MiniJuvix.Translation.ScopedToAbstract as A
|
2022-03-17 20:18:10 +03:00
|
|
|
import qualified MiniJuvix.Translation.AbstractToMicroJuvix as Micro
|
2022-01-19 14:49:07 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Concrete.Scoped.Pretty.Base as M
|
2022-03-04 11:13:14 +03:00
|
|
|
import qualified MiniJuvix.Termination.CallGraph as A
|
2022-02-24 13:03:02 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Abstract.Pretty.Base as A
|
2022-01-21 11:50:37 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Concrete.Scoped.Scoper as M
|
2022-02-18 19:47:41 +03:00
|
|
|
import MiniJuvix.Prelude hiding (Doc)
|
2022-01-18 14:25:42 +03:00
|
|
|
import Options.Applicative
|
|
|
|
import Options.Applicative.Help.Pretty
|
2022-02-05 01:14:06 +03:00
|
|
|
import Text.Show.Pretty hiding (Html)
|
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Pretty.Html
|
|
|
|
import MiniJuvix.Syntax.Concrete.Scoped.Pretty.Base (defaultOptions)
|
2022-02-24 03:32:58 +03:00
|
|
|
import qualified MiniJuvix.Syntax.Abstract.Pretty.Ansi as A
|
2022-03-08 14:53:26 +03:00
|
|
|
import Commands.Extra
|
|
|
|
import Commands.Termination as T
|
2022-03-15 20:01:28 +03:00
|
|
|
import Commands.MiniHaskell
|
2022-03-17 20:18:10 +03:00
|
|
|
import Commands.MicroJuvix
|
2022-01-18 14:25:42 +03:00
|
|
|
|
2022-01-21 11:50:37 +03:00
|
|
|
data Command
|
|
|
|
= Scope ScopeOptions
|
2022-01-18 14:25:42 +03:00
|
|
|
| Parse ParseOptions
|
2022-02-05 01:14:06 +03:00
|
|
|
| Html HtmlOptions
|
2022-03-08 14:53:26 +03:00
|
|
|
| Termination TerminationCommand
|
2022-03-15 20:01:28 +03:00
|
|
|
| MiniHaskell MiniHaskellOptions
|
2022-03-17 20:18:10 +03:00
|
|
|
| MicroJuvix MicroJuvixOptions
|
2022-01-18 14:25:42 +03:00
|
|
|
|
2022-01-21 11:50:37 +03:00
|
|
|
data ScopeOptions = ScopeOptions
|
|
|
|
{ _scopeRootDir :: FilePath,
|
2022-02-17 21:28:19 +03:00
|
|
|
_scopeInputFiles :: [FilePath],
|
2022-02-03 12:24:43 +03:00
|
|
|
_scopeShowIds :: Bool,
|
|
|
|
_scopeInlineImports :: Bool
|
2022-01-18 14:25:42 +03:00
|
|
|
}
|
|
|
|
|
2022-01-21 11:50:37 +03:00
|
|
|
data ParseOptions = ParseOptions
|
|
|
|
{ _parseInputFile :: FilePath,
|
|
|
|
_parseNoPrettyShow :: Bool
|
2022-01-20 14:50:01 +03:00
|
|
|
}
|
|
|
|
|
2022-02-05 01:14:06 +03:00
|
|
|
data HtmlOptions = HtmlOptions
|
2022-02-05 21:08:03 +03:00
|
|
|
{ _htmlInputFile :: FilePath,
|
2022-02-06 01:15:42 +03:00
|
|
|
_htmlRecursive :: Bool,
|
|
|
|
_htmlTheme :: Theme
|
2022-02-05 01:14:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
parseHtml :: Parser HtmlOptions
|
|
|
|
parseHtml = do
|
2022-03-02 13:10:11 +03:00
|
|
|
_htmlInputFile <- parseInputFile
|
2022-02-05 21:08:03 +03:00
|
|
|
_htmlRecursive <-
|
|
|
|
switch
|
|
|
|
( long "recursive"
|
|
|
|
<> help "export imported modules recursively"
|
|
|
|
)
|
2022-02-06 01:15:42 +03:00
|
|
|
_htmlTheme <- option (eitherReader parseTheme)
|
|
|
|
( long "theme"
|
|
|
|
<> metavar "THEME"
|
|
|
|
<> value Nord
|
|
|
|
<> showDefault
|
|
|
|
<> help "selects a theme: ayu (light); nord (dark)"
|
|
|
|
)
|
2022-02-05 01:14:06 +03:00
|
|
|
pure HtmlOptions {..}
|
2022-02-06 01:15:42 +03:00
|
|
|
where
|
|
|
|
parseTheme :: String -> Either String Theme
|
|
|
|
parseTheme s = case s of
|
|
|
|
"nord" -> Right Nord
|
|
|
|
"ayu" -> Right Ayu
|
|
|
|
_ -> Left $ "unrecognised theme: " <> s
|
2022-02-05 01:14:06 +03:00
|
|
|
|
2022-02-24 13:03:02 +03:00
|
|
|
|
2022-03-02 13:10:11 +03:00
|
|
|
parseParse :: Parser ParseOptions
|
|
|
|
parseParse = do
|
|
|
|
_parseInputFile <- parseInputFile
|
2022-01-21 11:50:37 +03:00
|
|
|
_parseNoPrettyShow <-
|
|
|
|
switch
|
|
|
|
( long "no-pretty-show"
|
|
|
|
<> help "Disable formatting of the Haskell AST"
|
|
|
|
)
|
2022-01-20 14:50:01 +03:00
|
|
|
pure ParseOptions {..}
|
|
|
|
|
2022-01-18 14:25:42 +03:00
|
|
|
parseScope :: Parser ScopeOptions
|
|
|
|
parseScope = do
|
2022-01-21 11:50:37 +03:00
|
|
|
_scopeRootDir <-
|
|
|
|
strOption
|
|
|
|
( long "rootDir"
|
|
|
|
<> short 'd'
|
|
|
|
<> metavar "DIR"
|
|
|
|
<> value "."
|
|
|
|
<> showDefault
|
|
|
|
<> help "Root directory"
|
|
|
|
)
|
2022-02-17 21:28:19 +03:00
|
|
|
_scopeInputFiles <-
|
|
|
|
some $ argument
|
2022-01-21 11:50:37 +03:00
|
|
|
str
|
2022-02-17 21:28:19 +03:00
|
|
|
( metavar "MINIJUVIX_FILE(s)"
|
|
|
|
<> help "Path to one ore more .mjuvix files"
|
2022-01-21 11:50:37 +03:00
|
|
|
)
|
|
|
|
_scopeShowIds <-
|
|
|
|
switch
|
|
|
|
( long "show-name-ids"
|
|
|
|
<> help "Show the unique number of each identifier"
|
|
|
|
)
|
2022-02-03 12:24:43 +03:00
|
|
|
_scopeInlineImports <-
|
|
|
|
switch
|
|
|
|
( long "inline-imports"
|
|
|
|
<> help "Show the code of imported modules next to the import statement"
|
|
|
|
)
|
2022-01-18 14:25:42 +03:00
|
|
|
pure ScopeOptions {..}
|
|
|
|
|
|
|
|
descr :: ParserInfo Command
|
2022-01-21 11:50:37 +03:00
|
|
|
descr =
|
|
|
|
info
|
|
|
|
(parseCommand <**> helper)
|
|
|
|
( fullDesc
|
2022-01-18 14:25:42 +03:00
|
|
|
<> progDesc "The MiniJuvix compiler."
|
2022-01-20 14:50:01 +03:00
|
|
|
<> headerDoc (Just headDoc)
|
2022-01-18 14:25:42 +03:00
|
|
|
<> footerDoc (Just foot)
|
2022-01-21 11:50:37 +03:00
|
|
|
)
|
2022-01-18 14:25:42 +03:00
|
|
|
where
|
2022-01-21 11:50:37 +03:00
|
|
|
headDoc :: Doc
|
|
|
|
headDoc = dullblue $ bold $ underline "MiniJuvix help"
|
|
|
|
foot :: Doc
|
|
|
|
foot = bold "maintainers: " <> "jan@heliax.dev; jonathan@heliax.dev"
|
2022-01-18 14:25:42 +03:00
|
|
|
|
|
|
|
parseCommand :: Parser Command
|
2022-01-21 11:50:37 +03:00
|
|
|
parseCommand =
|
|
|
|
hsubparser $
|
|
|
|
mconcat
|
|
|
|
[ commandParse,
|
2022-02-05 01:14:06 +03:00
|
|
|
commandScope,
|
2022-02-23 23:22:28 +03:00
|
|
|
commandHtml,
|
2022-03-15 20:01:28 +03:00
|
|
|
commandTermination,
|
2022-03-17 20:18:10 +03:00
|
|
|
commandMicroJuvix,
|
2022-03-15 20:01:28 +03:00
|
|
|
commandMiniHaskell
|
2022-01-21 11:50:37 +03:00
|
|
|
]
|
2022-01-20 14:50:01 +03:00
|
|
|
where
|
2022-03-17 20:18:10 +03:00
|
|
|
commandMicroJuvix :: Mod CommandFields Command
|
|
|
|
commandMicroJuvix = command "microjuvix" minfo
|
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
|
|
|
(MicroJuvix <$> parseMicroJuvix)
|
|
|
|
(progDesc "Translate a .mjuvix file to MicroJuvix")
|
|
|
|
|
2022-03-15 20:01:28 +03:00
|
|
|
commandMiniHaskell :: Mod CommandFields Command
|
|
|
|
commandMiniHaskell = command "minihaskell" minfo
|
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
|
|
|
(MiniHaskell <$> parseMiniHaskell)
|
|
|
|
(progDesc "Translate a .mjuvix file to MiniHaskell")
|
|
|
|
|
2022-01-21 11:50:37 +03:00
|
|
|
commandParse :: Mod CommandFields Command
|
|
|
|
commandParse = command "parse" minfo
|
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
|
|
|
(Parse <$> parseParse)
|
|
|
|
(progDesc "Parse a .mjuvix file")
|
|
|
|
|
2022-02-05 01:14:06 +03:00
|
|
|
commandHtml :: Mod CommandFields Command
|
|
|
|
commandHtml = command "html" minfo
|
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
|
|
|
(Html <$> parseHtml)
|
|
|
|
(progDesc "Generate html for a .mjuvix file")
|
2022-01-21 11:50:37 +03:00
|
|
|
commandScope :: Mod CommandFields Command
|
|
|
|
commandScope = command "scope" minfo
|
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
|
|
|
(Scope <$> parseScope)
|
|
|
|
(progDesc "Parse and scope a .mjuvix file")
|
2022-03-08 14:53:26 +03:00
|
|
|
commandTermination :: Mod CommandFields Command
|
|
|
|
commandTermination = command "termination" minfo
|
2022-03-02 13:10:11 +03:00
|
|
|
where
|
|
|
|
minfo :: ParserInfo Command
|
|
|
|
minfo =
|
|
|
|
info
|
2022-03-08 14:53:26 +03:00
|
|
|
(Termination <$> parseTerminationCommand)
|
|
|
|
(progDesc "Subcommands related to termination checking")
|
2022-03-02 13:10:11 +03:00
|
|
|
|
2022-01-18 14:25:42 +03:00
|
|
|
|
2022-02-23 23:22:28 +03:00
|
|
|
mkScopePrettyOptions :: ScopeOptions -> M.Options
|
|
|
|
mkScopePrettyOptions ScopeOptions {..} =
|
2022-01-21 11:50:37 +03:00
|
|
|
M.defaultOptions
|
2022-02-24 13:03:02 +03:00
|
|
|
{ M._optShowNameId = _scopeShowIds,
|
|
|
|
M._optInlineImports = _scopeInlineImports
|
2022-01-21 11:50:37 +03:00
|
|
|
}
|
2022-01-19 14:49:07 +03:00
|
|
|
|
2022-01-20 14:50:01 +03:00
|
|
|
parseModuleIO :: FilePath -> IO (M.Module 'M.Parsed 'M.ModuleTop)
|
|
|
|
parseModuleIO = fromRightIO id . M.runModuleParserIO
|
|
|
|
|
2022-02-11 21:12:48 +03:00
|
|
|
fromRightIO' :: (e -> IO ()) -> IO (Either e r) -> IO r
|
|
|
|
fromRightIO' pp = do
|
|
|
|
eitherM ifLeft return
|
|
|
|
where
|
|
|
|
ifLeft e = pp e >> exitFailure
|
|
|
|
|
2022-01-20 14:50:01 +03:00
|
|
|
fromRightIO :: (e -> Text) -> IO (Either e r) -> IO r
|
2022-02-11 21:12:48 +03:00
|
|
|
fromRightIO pp = fromRightIO' (putStrLn . pp)
|
2022-01-20 14:50:01 +03:00
|
|
|
|
2022-01-18 14:25:42 +03:00
|
|
|
go :: Command -> IO ()
|
2022-03-02 13:10:11 +03:00
|
|
|
go c = do
|
|
|
|
root <- getCurrentDirectory
|
|
|
|
case c of
|
|
|
|
Scope opts@ScopeOptions {..} -> do
|
|
|
|
forM_ _scopeInputFiles $ \scopeInputFile -> do
|
|
|
|
m <- parseModuleIO scopeInputFile
|
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
|
|
|
M.printPrettyCode (mkScopePrettyOptions opts) s
|
|
|
|
Parse ParseOptions {..} -> do
|
|
|
|
m <- parseModuleIO _parseInputFile
|
|
|
|
if _parseNoPrettyShow then print m else pPrint m
|
|
|
|
Html HtmlOptions {..} -> do
|
|
|
|
m <- parseModuleIO _htmlInputFile
|
2022-02-18 19:47:41 +03:00
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
2022-03-02 13:10:11 +03:00
|
|
|
genHtml defaultOptions _htmlRecursive _htmlTheme s
|
2022-03-17 20:18:10 +03:00
|
|
|
MicroJuvix MicroJuvixOptions {..} -> do
|
|
|
|
m <- parseModuleIO _mjuvixInputFile
|
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
|
|
|
a <- fromRightIO' putStrLn (return $ A.translateModule s)
|
|
|
|
let mini = Micro.translateModule a
|
|
|
|
Micro.printPrettyCodeDefault mini
|
2022-03-15 20:01:28 +03:00
|
|
|
MiniHaskell MiniHaskellOptions {..} -> do
|
|
|
|
m <- parseModuleIO _mhaskellInputFile
|
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
2022-03-23 13:40:03 +03:00
|
|
|
-- a <- fromRightIO' putStrLn (return $ A.translateModule s)
|
|
|
|
fromRightIO' putStrLn (return $ A.translateModule s)
|
2022-03-17 20:18:10 +03:00
|
|
|
-- let mini = Micro.translateModule a
|
|
|
|
-- Micro.printPrettyCodeDefault mini
|
|
|
|
-- TODO
|
|
|
|
error "todo"
|
2022-03-08 14:53:26 +03:00
|
|
|
Termination (Calls opts@CallsOptions {..}) -> do
|
2022-03-02 13:10:11 +03:00
|
|
|
m <- parseModuleIO _callsInputFile
|
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
|
|
|
a <- fromRightIO' putStrLn (return $ A.translateModule s)
|
2022-03-07 18:32:24 +03:00
|
|
|
let callMap0 = T.buildCallMap a
|
|
|
|
callMap = case _callsFunctionNameFilter of
|
|
|
|
Nothing -> callMap0
|
|
|
|
Just f -> T.filterCallMap f callMap0
|
2022-03-08 14:53:26 +03:00
|
|
|
opts' = T.callsPrettyOptions opts
|
2022-03-02 13:10:11 +03:00
|
|
|
A.printPrettyCode opts' callMap
|
|
|
|
putStrLn ""
|
2022-03-08 14:53:26 +03:00
|
|
|
Termination (CallGraph CallGraphOptions {..}) -> do
|
2022-03-02 13:10:11 +03:00
|
|
|
m <- parseModuleIO _graphInputFile
|
|
|
|
s <- fromRightIO' printErrorAnsi $ M.scopeCheck1IO root m
|
|
|
|
a <- fromRightIO' putStrLn (return $ A.translateModule s)
|
2022-03-07 19:14:16 +03:00
|
|
|
let callMap = T.buildCallMap a
|
2022-03-02 13:10:11 +03:00
|
|
|
opts' = A.defaultOptions
|
2022-03-04 01:31:45 +03:00
|
|
|
completeGraph = T.completeCallGraph callMap
|
2022-03-07 19:14:16 +03:00
|
|
|
filteredGraph = maybe completeGraph (`T.unsafeFilterGraph` completeGraph) _graphFunctionNameFilter
|
|
|
|
recBehav = map T.recursiveBehaviour (T.reflexiveEdges filteredGraph)
|
|
|
|
A.printPrettyCode opts' filteredGraph
|
2022-03-02 13:10:11 +03:00
|
|
|
putStrLn ""
|
2022-03-04 04:13:43 +03:00
|
|
|
forM_ recBehav $ \r -> do
|
2022-03-04 11:13:14 +03:00
|
|
|
let n = M.renderPrettyCode M.defaultOptions $ A._recBehaviourFunction r
|
2022-03-04 04:13:43 +03:00
|
|
|
A.printPrettyCode A.defaultOptions r
|
|
|
|
putStrLn ""
|
|
|
|
case T.findOrder r of
|
2022-03-04 11:13:14 +03:00
|
|
|
Nothing -> putStrLn (n <> " Fails the termination checking")
|
2022-03-07 19:14:16 +03:00
|
|
|
Just (T.LexOrder k) -> putStrLn (n <> " Terminates with order " <> show (toList k))
|
2022-03-04 04:13:43 +03:00
|
|
|
putStrLn ""
|
|
|
|
|
2022-01-18 14:25:42 +03:00
|
|
|
main :: IO ()
|
|
|
|
main = execParser descr >>= go
|