1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-04 06:23:13 +03:00
juvix/app/GlobalOptions.hs
Jan Mas Rovira 2d36a65324
Make compile targets a subcommand instead of a flag (#2700)
# Changes
The main goal of this pr is to remove the `--target` flag for `juvix
compile` and use subcommands instead. The targets that are relevant to
normal users are found in `juvix compile --help`. Targets that are
relevant only to developers are found in `juvix dev compile --help`.

Below I list some of the changes in more detail.
## Compile targets for user-facing languages
- `juvix compile native`
- `juvix compile wasi`. I wasn't sure how to call this: `wasm`,
`wasm32-wasi`, etc. In the end I thought `wasi` was short and accurate,
but we can change it.
- `juvix compile vampir`
- `juvix compile anoma`
- `juvix compile cairo`
## *New* compile targets for internal languages
See `juvix dev compile --help`.

1. `dev compile core` has the same behaviour as `dev core
from-concrete`. The `dev core from-concrete` is redundant at the moment.
2. `dev compile tree` compiles to Tree and prints the InfoTable to the
output file wihout any additional checks.
3. `dev compile reg` compiles to Reg and prints the InfoTable to the
output file wihout any additional checks.
4. `dev compile asm` compiles to Asm and prints the InfoTable to the
output file wihout any additional checks.
5. 4. `dev compile casm` compiles to Asm and prints the Result to the
output file wihout any additional checks. TODO: should the Result be
printed or something else? At the moment the Result lacks a pretty
instance.
6. 
## Optional input file
1. The input file for commands that expect a .juvix file as input is now
optional. If the argument is ommited, he main file given in the
package.yaml will be used. This applies to the following commands:
   1. `juvix compile [native|wasi|geb|vampir|anoma|cairo]`
   8.  `juvix dev compile [core|reg|tree|casm|asm]`
   1. `juvix html`
   3. `juvix markdown`.
   4. `juvix dev internal [typecheck|pretty]`.
   5. `juvix dev [parse|scope]`
   7. `juvix compile [native|wasi|geb|vampir|anoma|cairo]`
   9. note that `juvix format` has not changed its behaviour.

## Refactor some C-like compiler flags
Both `juvix compile native` and `juvix compile wasi` support `--only-c`
(`-C`), `--only-preprocess` (`-E`), `--only-assemble` (`-S`). I propose
to deviate from the `gcc` style and instead use a flag with a single
argument:
- `--cstage [source|preprocess|assembly|exec(default)]`. I'm open to
suggestions. For now, I've kept the legacy flags but marked them as
deprecated in the help message.

## Remove code duplication
I've tried to reduce code duplication. This is sometimes in tension with
code readability so I've tried to find a good balance. I've tried to
make it so we don't have to jump to many different files to understand
what a single command is doing. I'm sure there is still room for
improvement.

## Other refactors
I've implemented other small refactors that I considered improved the
quality of the code.

## TODO/Future work
We should refactor commands (under `compile dev`) which still use
`module Commands.Extra.Compile` and remove it.
2024-04-09 13:29:07 +02:00

216 lines
6.8 KiB
Haskell

module GlobalOptions
( module GlobalOptions,
module Juvix.Data.Effect.TaggedLock,
)
where
import CommonOptions
import Juvix.Compiler.Core.Options qualified as Core
import Juvix.Compiler.Internal.Pretty.Options qualified as Internal
import Juvix.Compiler.Pipeline
import Juvix.Compiler.Pipeline.Root
import Juvix.Data.Effect.TaggedLock
import Juvix.Data.Error.GenericError qualified as E
import Juvix.Data.Field
data GlobalOptions = GlobalOptions
{ _globalNoColors :: Bool,
_globalShowNameIds :: Bool,
_globalBuildDir :: Maybe (AppPath Dir),
_globalOnlyErrors :: Bool,
_globalStdin :: Bool,
_globalNoTermination :: Bool,
_globalNoPositivity :: Bool,
_globalNoCoverage :: Bool,
_globalNoStdlib :: Bool,
_globalUnrollLimit :: Int,
_globalFieldSize :: Maybe Natural,
_globalOffline :: Bool
}
deriving stock (Eq, Show)
makeLenses ''GlobalOptions
instance CanonicalProjection GlobalOptions Internal.Options where
project g =
Internal.defaultOptions
{ Internal._optShowNameIds = g ^. globalShowNameIds
}
instance CanonicalProjection GlobalOptions E.GenericOptions where
project GlobalOptions {..} =
E.GenericOptions
{ E._showNameIds = _globalShowNameIds
}
instance CanonicalProjection GlobalOptions Core.CoreOptions where
project GlobalOptions {..} =
Core.CoreOptions
{ Core._optCheckCoverage = not _globalNoCoverage,
Core._optUnrollLimit = _globalUnrollLimit,
Core._optFieldSize = fromMaybe defaultFieldSize _globalFieldSize,
Core._optOptimizationLevel = defaultOptimizationLevel,
Core._optInliningDepth = defaultInliningDepth
}
defaultGlobalOptions :: GlobalOptions
defaultGlobalOptions =
GlobalOptions
{ _globalNoColors = False,
_globalShowNameIds = False,
_globalOnlyErrors = False,
_globalNoTermination = False,
_globalBuildDir = Nothing,
_globalStdin = False,
_globalNoPositivity = False,
_globalNoCoverage = False,
_globalNoStdlib = False,
_globalUnrollLimit = defaultUnrollLimit,
_globalFieldSize = Nothing,
_globalOffline = False
}
-- | Get a parser for global flags which can be hidden or not depending on
-- the input boolean
parseGlobalFlags :: Parser GlobalOptions
parseGlobalFlags = do
_globalNoColors <-
switch
( long "no-colors"
<> help "Disable ANSI formatting"
)
_globalBuildDir <-
optional
( parseBuildDir
( long "internal-build-dir"
<> help "Directory for compiler internal output"
)
)
_globalStdin <-
switch
( long "stdin"
<> help "Read from Stdin"
)
_globalOnlyErrors <-
switch
( long "only-errors"
<> help "Only print errors in a uniform format (used by juvix-mode)"
)
_globalNoTermination <-
switch
( long "no-termination"
<> help "Disable termination checking"
)
_globalNoPositivity <-
switch
( long "no-positivity"
<> help "Disable positivity checking for inductive types"
)
_globalNoCoverage <-
switch
( long "no-coverage"
<> help "Disable coverage checking for patterns"
)
_globalNoStdlib <-
switch
( long "no-stdlib"
<> help "Do not use the standard library"
)
_globalFieldSize <-
option
fieldSizeOpt
( long "field-size"
<> value Nothing
<> help "Field type size [cairo,small,11] (default: small)"
)
_globalUnrollLimit <-
option
(fromIntegral <$> naturalNumberOpt)
( long "unroll"
<> value defaultUnrollLimit
<> help ("Recursion unrolling limit (default: " <> show defaultUnrollLimit <> ")")
)
_globalOffline <-
switch
( long "offline"
<> help "Disable access to network resources"
)
_globalShowNameIds <-
switch
( long "show-name-ids"
<> help "[DEV] Show the unique number of each identifier when pretty printing"
)
return GlobalOptions {..}
parseBuildDir :: Mod OptionFields (Prepath Dir) -> Parser (AppPath Dir)
parseBuildDir m = do
_pathPath <-
option
somePreDirOpt
( metavar "BUILD_DIR"
<> action "directory"
<> m
)
pure AppPath {_pathIsInput = False, ..}
entryPointFromGlobalOptionsPre ::
(Members '[TaggedLock, EmbedIO] r) =>
Root ->
Prepath File ->
GlobalOptions ->
Sem r EntryPoint
entryPointFromGlobalOptionsPre root premainFile opts = do
mainFile <- liftIO (prepathToAbsFile (root ^. rootInvokeDir) premainFile)
entryPointFromGlobalOptions root mainFile opts
entryPointFromGlobalOptions ::
(Members '[TaggedLock, EmbedIO] r) =>
Root ->
Path Abs File ->
GlobalOptions ->
Sem r EntryPoint
entryPointFromGlobalOptions root mainFile opts = do
mabsBuildDir :: Maybe (Path Abs Dir) <- liftIO (mapM (prepathToAbsDir cwd) optBuildDir)
pkg <- readPackageRootIO root
let def :: EntryPoint
def = defaultEntryPoint pkg root mainFile
return
def
{ _entryPointNoTermination = opts ^. globalNoTermination,
_entryPointNoPositivity = opts ^. globalNoPositivity,
_entryPointNoCoverage = opts ^. globalNoCoverage,
_entryPointNoStdlib = opts ^. globalNoStdlib,
_entryPointUnrollLimit = opts ^. globalUnrollLimit,
_entryPointGenericOptions = project opts,
_entryPointBuildDir = maybe (def ^. entryPointBuildDir) (CustomBuildDir . Abs) mabsBuildDir,
_entryPointOffline = opts ^. globalOffline,
_entryPointFieldSize = fromMaybe defaultFieldSize $ opts ^. globalFieldSize
}
where
optBuildDir :: Maybe (Prepath Dir)
optBuildDir = fmap (^. pathPath) (opts ^. globalBuildDir)
cwd = root ^. rootInvokeDir
entryPointFromGlobalOptionsNoFile :: (Members '[EmbedIO, TaggedLock] r, MonadIO (Sem r)) => Root -> GlobalOptions -> Sem r EntryPoint
entryPointFromGlobalOptionsNoFile root opts = do
mabsBuildDir :: Maybe (Path Abs Dir) <- mapM (prepathToAbsDir cwd) optBuildDir
pkg <- readPackageRootIO root
let def :: EntryPoint
def = defaultEntryPointNoFile pkg root
return
def
{ _entryPointNoTermination = opts ^. globalNoTermination,
_entryPointNoPositivity = opts ^. globalNoPositivity,
_entryPointNoCoverage = opts ^. globalNoCoverage,
_entryPointNoStdlib = opts ^. globalNoStdlib,
_entryPointUnrollLimit = opts ^. globalUnrollLimit,
_entryPointGenericOptions = project opts,
_entryPointBuildDir = maybe (def ^. entryPointBuildDir) (CustomBuildDir . Abs) mabsBuildDir,
_entryPointOffline = opts ^. globalOffline,
_entryPointFieldSize = fromMaybe defaultFieldSize $ opts ^. globalFieldSize
}
where
optBuildDir :: Maybe (Prepath Dir)
optBuildDir = fmap (^. pathPath) (opts ^. globalBuildDir)
cwd = root ^. rootInvokeDir