1
1
mirror of https://github.com/anoma/juvix.git synced 2025-01-05 22:46:08 +03:00
juvix/app/Main.hs

260 lines
11 KiB
Haskell
Raw Normal View History

2022-01-18 14:25:42 +03:00
module Main (main) where
import App
import CLI
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
import Data.HashMap.Strict qualified as HashMap
2022-04-07 13:53:05 +03:00
import MiniJuvix.Pipeline
import MiniJuvix.Prelude hiding (Doc)
2022-04-11 14:08:37 +03:00
import MiniJuvix.Prelude.Pretty hiding (Doc)
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
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
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
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
import MiniJuvix.Syntax.MonoJuvix.Pretty qualified as Mono
import MiniJuvix.Termination qualified as Termination
2022-04-05 20:57:21 +03:00
import MiniJuvix.Translation.AbstractToMicroJuvix qualified as Micro
import MiniJuvix.Translation.MicroJuvixToMonoJuvix qualified as Mono
Add C code generation backend (#68) * [cbackend] Adds an AST for C This should cover enough C to implement the microjuvix backend. * [cbackend] Add C serializer using language-c library We may decide to write our own serializer for the C AST but this demonstrates that the C AST is sufficient at least. * [cbackend] Declarations will always be typed * [cbackend] Add CPP support to AST * [cbackend] Rename some names for clarity * [cbackend] Add translation of InductiveDef to C * [cbackend] Add CLI for C backend * [cbackend] Add stdbool.h to file header * [cbackend] Allow Cpp and Verbatim code inline * [cbackend] Add a newline after printing C * [cbackend] Support foreign blocks * [cbackend] Add support for axioms * [cbackend] Remove code examples * [cbackend] wip FunctionDef including Expressions * [parser] Support esacping '}' inside a foreign block * [cbackend] Add support for patterns in functions * [cbackend] Add foreign C support to HelloWorld.mjuvix * hlint fixes * More hlint fixes not picked up by pre-commit * [cbackend] Remove CompileStatement from MonoJuvix * [cbackend] Add support for compile blocks * [cbackend] Move compileInfo extraction to MonoJuvixResult * [minihaskell] Fix compile block support * [chore] Remove ununsed isBackendSupported function * [chore] Remove unused imports * [cbackend] Use a Reader for pattern bindings * [cbackend] Fix compiler warnings * [cbackend] Add support for nested patterns * [cbackend] Use functions to instantiate argument names * [cbackend] Add non-exhaustive pattern error message * [cbackend] Adds test for c to WASM compile and execution * [cbackend] Add links to test dependencies in quickstart * [cbackend] Add test with inductive types and patterns * [cbackend] Fix indentation * [cbackend] Remove ExpressionTyped case https://github.com/heliaxdev/minijuvix/issues/79 * [lexer] Fix lexing of \ inside a foreign block * [cbackend] PR review fixes * [chore] Remove unused import * [cbackend] Rename CJuvix to MiniC * [cbackend] Rename MonoJuvixToC to MonoJuvixToMiniC * [cbackend] Add test for polymorphic function * [cbackend] Add module for string literals
2022-05-05 16:12:17 +03:00
import MiniJuvix.Translation.MonoJuvixToMiniC qualified as MiniC
import MiniJuvix.Translation.MonoJuvixToMiniHaskell qualified as MiniHaskell
2022-04-07 13:49:08 +03:00
import MiniJuvix.Translation.ScopedToAbstract qualified as Abstract
import MiniJuvix.Utils.Version (runDisplayVersion)
2022-01-18 14:25:42 +03:00
import Options.Applicative
import Text.Show.Pretty hiding (Html)
minijuvixYamlFile :: FilePath
minijuvixYamlFile = "minijuvix.yaml"
findRoot :: CLI -> IO FilePath
findRoot cli = do
whenJust dir0 setCurrentDirectory
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
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)
dir0 :: Maybe FilePath
dir0 = takeDirectory <$> cliMainFile cli
2022-04-07 10:43:17 +03:00
class HasEntryPoint a where
getEntryPoint :: FilePath -> GlobalOptions -> a -> EntryPoint
2022-04-07 10:43:17 +03:00
instance HasEntryPoint ScopeOptions where
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
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
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
getEntryPoint r opts = EntryPoint r nT . pure . (^. htmlInputFile)
where
nT = opts ^. globalNoTermination
2022-04-07 13:53:05 +03:00
instance HasEntryPoint MicroJuvixTypeOptions where
getEntryPoint r opts = EntryPoint r nT . pure . (^. microJuvixTypeInputFile)
where
nT = opts ^. globalNoTermination
instance HasEntryPoint MicroJuvixPrettyOptions where
getEntryPoint r opts = EntryPoint r nT . pure . (^. microJuvixPrettyInputFile)
where
nT = opts ^. globalNoTermination
instance HasEntryPoint MonoJuvixOptions where
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
getEntryPoint r opts = EntryPoint r nT . pure . (^. miniHaskellInputFile)
where
nT = opts ^. globalNoTermination
2022-04-07 13:53:05 +03:00
Add C code generation backend (#68) * [cbackend] Adds an AST for C This should cover enough C to implement the microjuvix backend. * [cbackend] Add C serializer using language-c library We may decide to write our own serializer for the C AST but this demonstrates that the C AST is sufficient at least. * [cbackend] Declarations will always be typed * [cbackend] Add CPP support to AST * [cbackend] Rename some names for clarity * [cbackend] Add translation of InductiveDef to C * [cbackend] Add CLI for C backend * [cbackend] Add stdbool.h to file header * [cbackend] Allow Cpp and Verbatim code inline * [cbackend] Add a newline after printing C * [cbackend] Support foreign blocks * [cbackend] Add support for axioms * [cbackend] Remove code examples * [cbackend] wip FunctionDef including Expressions * [parser] Support esacping '}' inside a foreign block * [cbackend] Add support for patterns in functions * [cbackend] Add foreign C support to HelloWorld.mjuvix * hlint fixes * More hlint fixes not picked up by pre-commit * [cbackend] Remove CompileStatement from MonoJuvix * [cbackend] Add support for compile blocks * [cbackend] Move compileInfo extraction to MonoJuvixResult * [minihaskell] Fix compile block support * [chore] Remove ununsed isBackendSupported function * [chore] Remove unused imports * [cbackend] Use a Reader for pattern bindings * [cbackend] Fix compiler warnings * [cbackend] Add support for nested patterns * [cbackend] Use functions to instantiate argument names * [cbackend] Add non-exhaustive pattern error message * [cbackend] Adds test for c to WASM compile and execution * [cbackend] Add links to test dependencies in quickstart * [cbackend] Add test with inductive types and patterns * [cbackend] Fix indentation * [cbackend] Remove ExpressionTyped case https://github.com/heliaxdev/minijuvix/issues/79 * [lexer] Fix lexing of \ inside a foreign block * [cbackend] PR review fixes * [chore] Remove unused import * [cbackend] Rename CJuvix to MiniC * [cbackend] Rename MonoJuvixToC to MonoJuvixToMiniC * [cbackend] Add test for polymorphic function * [cbackend] Add module for string literals
2022-05-05 16:12:17 +03:00
instance HasEntryPoint MiniCOptions where
getEntryPoint r opts = EntryPoint r nT . pure . (^. miniCInputFile)
where
nT = opts ^. globalNoTermination
Add C code generation backend (#68) * [cbackend] Adds an AST for C This should cover enough C to implement the microjuvix backend. * [cbackend] Add C serializer using language-c library We may decide to write our own serializer for the C AST but this demonstrates that the C AST is sufficient at least. * [cbackend] Declarations will always be typed * [cbackend] Add CPP support to AST * [cbackend] Rename some names for clarity * [cbackend] Add translation of InductiveDef to C * [cbackend] Add CLI for C backend * [cbackend] Add stdbool.h to file header * [cbackend] Allow Cpp and Verbatim code inline * [cbackend] Add a newline after printing C * [cbackend] Support foreign blocks * [cbackend] Add support for axioms * [cbackend] Remove code examples * [cbackend] wip FunctionDef including Expressions * [parser] Support esacping '}' inside a foreign block * [cbackend] Add support for patterns in functions * [cbackend] Add foreign C support to HelloWorld.mjuvix * hlint fixes * More hlint fixes not picked up by pre-commit * [cbackend] Remove CompileStatement from MonoJuvix * [cbackend] Add support for compile blocks * [cbackend] Move compileInfo extraction to MonoJuvixResult * [minihaskell] Fix compile block support * [chore] Remove ununsed isBackendSupported function * [chore] Remove unused imports * [cbackend] Use a Reader for pattern bindings * [cbackend] Fix compiler warnings * [cbackend] Add support for nested patterns * [cbackend] Use functions to instantiate argument names * [cbackend] Add non-exhaustive pattern error message * [cbackend] Adds test for c to WASM compile and execution * [cbackend] Add links to test dependencies in quickstart * [cbackend] Add test with inductive types and patterns * [cbackend] Fix indentation * [cbackend] Remove ExpressionTyped case https://github.com/heliaxdev/minijuvix/issues/79 * [lexer] Fix lexing of \ inside a foreign block * [cbackend] PR review fixes * [chore] Remove unused import * [cbackend] Rename CJuvix to MiniC * [cbackend] Rename MonoJuvixToC to MonoJuvixToMiniC * [cbackend] Add test for polymorphic function * [cbackend] Add module for string literals
2022-05-05 16:12: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
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
getEntryPoint r opts = EntryPoint r nT . pure . (^. graphInputFile)
where
nT = opts ^. globalNoTermination
2022-04-07 10:43:17 +03:00
runCLI :: Members '[Embed IO, App] r => CLI -> Sem r ()
2022-04-11 14:08:37 +03:00
runCLI cli = do
let globalOptions = cli ^. cliGlobalOptions
2022-04-11 14:08:37 +03:00
toAnsiText' :: forall a. (HasAnsiBackend a, HasTextBackend a) => a -> Text
toAnsiText' = toAnsiText (not (globalOptions ^. globalNoColors))
root <- embed (findRoot cli)
2022-04-11 14:08:37 +03:00
case cli ^. cliCommand of
DisplayVersion -> embed runDisplayVersion
DisplayRoot -> say (pack root)
2022-04-07 10:43:17 +03:00
Highlight o -> do
res <- runPipelineEither (upToScoping (getEntryPoint root globalOptions o))
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)
Parse opts -> do
m <-
head . (^. Parser.resultModules)
<$> runPipeline (upToParsing (getEntryPoint root globalOptions opts))
if opts ^. parseNoPrettyShow then say (show m) else say (pack (ppShow m))
Scope opts -> do
l <- (^. Scoper.resultModules) <$> runPipeline (upToScoping (getEntryPoint root globalOptions opts))
forM_ l $ \s -> do
renderStdOut (Scoper.ppOut (mkScopePrettyOptions globalOptions opts) s)
2022-04-07 10:43:17 +03:00
Html o@HtmlOptions {..} -> do
res <- runPipeline (upToScoping (getEntryPoint root globalOptions o))
2022-04-07 10:43:17 +03:00
let m = head (res ^. Scoper.resultModules)
embed (genHtml Scoper.defaultOptions _htmlRecursive _htmlTheme m)
2022-04-08 17:36:48 +03:00
MicroJuvix (Pretty opts) -> do
micro <- head . (^. Micro.resultModules) <$> runPipeline (upToMicroJuvix (getEntryPoint root globalOptions opts))
let ppOpts =
Micro.defaultOptions
{ Micro._optShowNameId = globalOptions ^. globalShowNameIds
}
App.renderStdOut (Micro.ppOut ppOpts micro)
2022-04-11 14:08:37 +03:00
MicroJuvix (TypeCheck opts) -> do
res <- runPipeline (upToMicroJuvixTyped (getEntryPoint root globalOptions opts))
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)
MonoJuvix o -> do
let ppOpts =
Mono.defaultOptions
{ Mono._optShowNameIds = globalOptions ^. globalShowNameIds
}
monojuvix <- head . (^. Mono.resultModules) <$> runPipeline (upToMonoJuvix (getEntryPoint root globalOptions o))
renderStdOut (Mono.ppOut ppOpts monojuvix)
2022-04-07 10:43:17 +03:00
MiniHaskell o -> do
minihaskell <- head . (^. MiniHaskell.resultModules) <$> runPipeline (upToMiniHaskell (getEntryPoint root globalOptions o))
renderStdOut (MiniHaskell.ppOutDefault minihaskell)
Add C code generation backend (#68) * [cbackend] Adds an AST for C This should cover enough C to implement the microjuvix backend. * [cbackend] Add C serializer using language-c library We may decide to write our own serializer for the C AST but this demonstrates that the C AST is sufficient at least. * [cbackend] Declarations will always be typed * [cbackend] Add CPP support to AST * [cbackend] Rename some names for clarity * [cbackend] Add translation of InductiveDef to C * [cbackend] Add CLI for C backend * [cbackend] Add stdbool.h to file header * [cbackend] Allow Cpp and Verbatim code inline * [cbackend] Add a newline after printing C * [cbackend] Support foreign blocks * [cbackend] Add support for axioms * [cbackend] Remove code examples * [cbackend] wip FunctionDef including Expressions * [parser] Support esacping '}' inside a foreign block * [cbackend] Add support for patterns in functions * [cbackend] Add foreign C support to HelloWorld.mjuvix * hlint fixes * More hlint fixes not picked up by pre-commit * [cbackend] Remove CompileStatement from MonoJuvix * [cbackend] Add support for compile blocks * [cbackend] Move compileInfo extraction to MonoJuvixResult * [minihaskell] Fix compile block support * [chore] Remove ununsed isBackendSupported function * [chore] Remove unused imports * [cbackend] Use a Reader for pattern bindings * [cbackend] Fix compiler warnings * [cbackend] Add support for nested patterns * [cbackend] Use functions to instantiate argument names * [cbackend] Add non-exhaustive pattern error message * [cbackend] Adds test for c to WASM compile and execution * [cbackend] Add links to test dependencies in quickstart * [cbackend] Add test with inductive types and patterns * [cbackend] Fix indentation * [cbackend] Remove ExpressionTyped case https://github.com/heliaxdev/minijuvix/issues/79 * [lexer] Fix lexing of \ inside a foreign block * [cbackend] PR review fixes * [chore] Remove unused import * [cbackend] Rename CJuvix to MiniC * [cbackend] Rename MonoJuvixToC to MonoJuvixToMiniC * [cbackend] Add test for polymorphic function * [cbackend] Add module for string literals
2022-05-05 16:12:17 +03:00
MiniC o -> do
miniC <- (^. MiniC.resultCCode) <$> runPipeline (upToMiniC (getEntryPoint root globalOptions o))
say miniC
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 ()
Termination (Calls opts@CallsOptions {..}) -> do
results <- runPipeline (upToAbstract (getEntryPoint root globalOptions opts))
let topModule = head (results ^. Abstract.resultModules)
infotable = results ^. Abstract.resultTable
callMap0 = Termination.buildCallMap infotable topModule
callMap = case _callsFunctionNameFilter of
Nothing -> callMap0
Just f -> Termination.filterCallMap f callMap0
opts' = Termination.callsPrettyOptions opts
renderStdOut (Abstract.ppOut opts' callMap)
newline
Termination (CallGraph opts@CallGraphOptions {..}) -> do
results <- runPipeline (upToAbstract (getEntryPoint root globalOptions opts))
let topModule = head (results ^. Abstract.resultModules)
infotable = results ^. Abstract.resultTable
callMap = Termination.buildCallMap infotable topModule
opts' =
Abstract.defaultOptions
{ Abstract._optShowNameId = globalOptions ^. globalShowNameIds
}
completeGraph = Termination.completeCallGraph callMap
filteredGraph = maybe completeGraph (`Termination.unsafeFilterGraph` completeGraph) _graphFunctionNameFilter
rEdges = Termination.reflexiveEdges filteredGraph
recBehav = map Termination.recursiveBehaviour rEdges
App.renderStdOut (Abstract.ppOut opts' filteredGraph)
newline
forM_ recBehav $ \r -> do
let funName = r ^. Termination.recursiveBehaviourFun
funRef = Abstract.FunctionRef (Scoper.unqualifiedSymbol funName)
funInfo = HashMap.lookupDefault impossible funRef (infotable ^. Abstract.infoFunctions)
markedTerminating = funInfo ^. (Abstract.functionInfoDef . Abstract.funDefTerminating)
sopts =
Scoper.defaultOptions
{ Scoper._optShowNameId = globalOptions ^. globalShowNameIds
}
n = toAnsiText' (Scoper.ppOut sopts funName)
App.renderStdOut (Abstract.ppOut opts' r)
newline
if
| markedTerminating -> say (n <> " Terminates by assumption")
| otherwise ->
case Termination.findOrder r of
Nothing -> say (n <> " Fails the termination checking") >> embed exitFailure
Just (Termination.LexOrder k) -> say (n <> " Terminates with order " <> show (toList k))
newline
2022-01-18 14:25:42 +03:00
main :: IO ()
main = do
cli <- execParser descr >>= makeAbsPaths
runM (runAppIO (cli ^. cliGlobalOptions) (runCLI cli))