202 lines
5.6 KiB
Idris
202 lines
5.6 KiB
Idris
module Options
|
|
|
|
import Quox.Pretty
|
|
import System
|
|
import System.Console.GetOpt
|
|
import System.File
|
|
import System.Term
|
|
import Derive.Prelude
|
|
|
|
%default total
|
|
%language ElabReflection
|
|
|
|
public export
|
|
data OutFile = File String | Console | NoOut
|
|
%name OutFile f
|
|
%runElab derive "OutFile" [Eq, Show]
|
|
|
|
public export
|
|
data Phase = Parse | Check | Erase | Scheme | End
|
|
%name Phase p
|
|
%runElab derive "Phase" [Eq, Show]
|
|
|
|
||| a list of all intermediate `Phase`s (excluding `End`)
|
|
public export %inline
|
|
allPhases : List Phase
|
|
allPhases = %runElab do
|
|
cs <- getCons $ fst !(lookupName "Phase")
|
|
traverse (check . var) $ fromMaybe [] $ init' cs
|
|
|
|
||| `Guess` is `Term` for a terminal and `NoHL` for a file
|
|
public export
|
|
data HLType = Guess | NoHL | Term | Html
|
|
%runElab derive "HLType" [Eq, Show]
|
|
|
|
public export
|
|
record Dump where
|
|
constructor MkDump
|
|
parse, check, erase, scheme : OutFile
|
|
%name Dump dump
|
|
%runElab derive "Dump" [Show]
|
|
|
|
public export
|
|
record Options where
|
|
constructor MkOpts
|
|
hlType : HLType
|
|
dump : Dump
|
|
outFile : OutFile
|
|
until : Maybe Phase
|
|
flavor : Pretty.Flavor
|
|
width : Nat
|
|
include : List String
|
|
%name Options opts
|
|
%runElab derive "Options" [Show]
|
|
|
|
export
|
|
defaultWidth : IO Nat
|
|
defaultWidth = do
|
|
w <- cast {to = Nat} <$> getTermCols
|
|
pure $ if w == 0 then 80 else w
|
|
|
|
export
|
|
defaultOpts : IO Options
|
|
defaultOpts = pure $ MkOpts {
|
|
hlType = Guess,
|
|
dump = MkDump NoOut NoOut NoOut NoOut,
|
|
outFile = Console,
|
|
until = Nothing,
|
|
flavor = Unicode,
|
|
width = !defaultWidth,
|
|
include = ["."]
|
|
}
|
|
|
|
private
|
|
data HelpType = Common | All
|
|
|
|
private
|
|
data OptAction = ShowHelp HelpType | Err String | Ok (Options -> Options)
|
|
%name OptAction act
|
|
|
|
private
|
|
toOutFile : String -> OutFile
|
|
toOutFile "" = NoOut
|
|
toOutFile "-" = Console
|
|
toOutFile f = File f
|
|
|
|
private
|
|
toPhase : String -> OptAction
|
|
toPhase str =
|
|
let lstr = toLower str in
|
|
case find (\p => toLower (show p) == lstr) allPhases of
|
|
Just p => Ok $ setPhase p
|
|
Nothing => Err "unknown phase name \{show str}\nphases: \{phaseNames}"
|
|
where
|
|
phaseNames = joinBy ", " $ map (toLower . show) allPhases
|
|
|
|
defConsole : OutFile -> OutFile
|
|
defConsole NoOut = Console
|
|
defConsole f = f
|
|
|
|
setPhase : Phase -> Options -> Options
|
|
setPhase Parse = {until := Just Parse, dump.parse $= defConsole}
|
|
setPhase Check = {until := Just Check, dump.check $= defConsole}
|
|
setPhase Erase = {until := Just Erase, dump.erase $= defConsole}
|
|
setPhase Scheme = {until := Just Scheme, dump.scheme $= defConsole}
|
|
setPhase End = id
|
|
|
|
private
|
|
toWidth : String -> OptAction
|
|
toWidth s = case parsePositive s of
|
|
Just n => Ok {width := n}
|
|
Nothing => Err "invalid width: \{show s}"
|
|
|
|
private
|
|
toHLType : String -> OptAction
|
|
toHLType str = case toLower str of
|
|
"none" => Ok {hlType := NoHL}
|
|
"term" => Ok {hlType := Term}
|
|
"html" => Ok {hlType := Html}
|
|
_ => Err "unknown highlighting type \{show str}\ntypes: term, html, none"
|
|
|
|
||| like ghc, -i '' clears the search path; -i a:b:c adds a,b,c to the end
|
|
private
|
|
dirListFlag : String -> List String -> List String
|
|
dirListFlag arg val =
|
|
if null arg then [] else val ++ toList (split (== ':') arg)
|
|
|
|
private
|
|
commonOptDescrs' : List (OptDescr OptAction)
|
|
commonOptDescrs' = [
|
|
MkOpt ['i'] ["include"]
|
|
(ReqArg (\is => Ok {include $= dirListFlag is}) "<dir>:<dir>...")
|
|
"add directories to look for source files",
|
|
MkOpt ['o'] ["output"] (ReqArg (\s => Ok {outFile := toOutFile s}) "<file>")
|
|
"output file (\"-\" for stdout, \"\" for no output)",
|
|
MkOpt ['P'] ["phase"] (ReqArg toPhase "<phase>")
|
|
"stop after the given phase"
|
|
]
|
|
|
|
private
|
|
extraOptDescrs : List (OptDescr OptAction)
|
|
extraOptDescrs = [
|
|
MkOpt [] ["unicode"] (NoArg $ Ok {flavor := Unicode})
|
|
"use unicode syntax when printing (default)",
|
|
MkOpt [] ["ascii"] (NoArg $ Ok {flavor := Ascii})
|
|
"use ascii syntax when printing",
|
|
MkOpt [] ["width"] (ReqArg toWidth "<width>")
|
|
"max output width (defaults to terminal width)",
|
|
MkOpt [] ["color", "colour"] (ReqArg toHLType "<type>")
|
|
"select highlighting type",
|
|
|
|
MkOpt [] ["dparse"] (ReqArg (\s => Ok {dump.parse := toOutFile s}) "<file>")
|
|
"dump AST",
|
|
MkOpt [] ["dcheck"] (ReqArg (\s => Ok {dump.check := toOutFile s}) "<file>")
|
|
"dump typechecker output",
|
|
MkOpt [] ["derase"] (ReqArg (\s => Ok {dump.erase := toOutFile s}) "<file>")
|
|
"dump erasure output",
|
|
MkOpt [] ["dscheme"] (ReqArg (\s => Ok {dump.scheme := toOutFile s}) "<file>")
|
|
"dump scheme output (without prelude)"
|
|
]
|
|
|
|
private
|
|
helpOptDescrs : List (OptDescr OptAction)
|
|
helpOptDescrs = [
|
|
MkOpt ['h'] ["help"] (NoArg $ ShowHelp Common) "show common options",
|
|
MkOpt [] ["help-all"] (NoArg $ ShowHelp All) "show all options"
|
|
]
|
|
|
|
commonOptDescrs = commonOptDescrs' ++ helpOptDescrs
|
|
allOptDescrs = commonOptDescrs' ++ extraOptDescrs ++ helpOptDescrs
|
|
|
|
export
|
|
usageHeader : String
|
|
usageHeader = trim """
|
|
quox [options] [file.quox ...]
|
|
rawr
|
|
"""
|
|
|
|
export
|
|
usage : List (OptDescr _) -> IO a
|
|
usage ds = do
|
|
ignore $ fPutStr stderr $ usageInfo usageHeader ds
|
|
exitSuccess
|
|
|
|
private
|
|
applyAction : Options -> OptAction -> IO Options
|
|
applyAction opts (ShowHelp Common) = usage commonOptDescrs
|
|
applyAction opts (ShowHelp All) = usage allOptDescrs
|
|
applyAction opts (Err err) = die err
|
|
applyAction opts (Ok f) = pure $ f opts
|
|
|
|
export
|
|
options : IO (String, Options, List String)
|
|
options = do
|
|
app :: args <- getArgs
|
|
| [] => die "couldn't get command line arguments"
|
|
let res = getOpt Permute allOptDescrs args
|
|
unless (null res.errors) $
|
|
die $ trim $ concat res.errors
|
|
unless (null res.unrecognized) $
|
|
die "unrecognised options: \{joinBy ", " res.unrecognized}"
|
|
opts <- foldlM applyAction !defaultOpts res.options
|
|
pure (app, opts, res.nonOptions)
|