2022-04-27 14:04:03 -04:00
|
|
|
|
module Main
|
2021-07-07 07:11:39 -04:00
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
import Quox.Syntax as Q
|
|
|
|
|
import Quox.Definition as Q
|
|
|
|
|
import Quox.Untyped.Syntax as U
|
2023-11-27 01:39:17 -05:00
|
|
|
|
import Quox.Parser
|
2023-10-20 11:42:01 -04:00
|
|
|
|
import Quox.Untyped.Erase
|
2023-10-24 17:52:19 -04:00
|
|
|
|
import Quox.Untyped.Scheme
|
2023-11-27 01:39:17 -05:00
|
|
|
|
import Quox.Pretty
|
2023-10-20 11:42:01 -04:00
|
|
|
|
import Options
|
2021-07-20 16:05:19 -04:00
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
import System
|
|
|
|
|
import System.File
|
2023-11-27 01:39:17 -05:00
|
|
|
|
import Data.IORef
|
2023-03-31 13:31:29 -04:00
|
|
|
|
import Control.Eff
|
2021-07-20 16:05:19 -04:00
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
%default total
|
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
%hide Doc.(>>=)
|
|
|
|
|
%hide Core.(>>=)
|
|
|
|
|
|
|
|
|
|
|
2023-10-24 17:52:19 -04:00
|
|
|
|
private
|
|
|
|
|
die : HasIO io => (opts : LayoutOpts) -> Doc opts -> io a
|
|
|
|
|
die opts err = do
|
|
|
|
|
ignore $ fPutStr stderr $ render opts err
|
|
|
|
|
exitFailure
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
2023-11-05 09:47:52 -05:00
|
|
|
|
private
|
|
|
|
|
hlFor : HLType -> OutFile -> HL -> Highlight
|
|
|
|
|
hlFor Guess Console = highlightSGR
|
|
|
|
|
hlFor Guess _ = noHighlight
|
|
|
|
|
hlFor NoHL _ = noHighlight
|
|
|
|
|
hlFor Term _ = highlightSGR
|
|
|
|
|
hlFor Html _ = highlightHtml
|
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
runPretty : Options -> OutFile -> Eff Pretty a -> a
|
|
|
|
|
runPretty opts file act =
|
|
|
|
|
runPrettyWith Outer opts.flavor (hlFor opts.hlType file) 2 act
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
2023-05-14 13:58:46 -04:00
|
|
|
|
private
|
2023-10-20 11:42:01 -04:00
|
|
|
|
record State where
|
|
|
|
|
constructor MkState
|
|
|
|
|
seen : IORef SeenSet
|
|
|
|
|
defs : IORef Q.Definitions
|
|
|
|
|
ns : IORef Mods
|
|
|
|
|
suf : IORef NameSuf
|
|
|
|
|
%name Main.State state
|
2023-05-14 13:58:46 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-10-20 11:42:01 -04:00
|
|
|
|
newState : HasIO io => io State
|
|
|
|
|
newState = pure $ MkState {
|
|
|
|
|
seen = !(newIORef empty),
|
|
|
|
|
defs = !(newIORef empty),
|
|
|
|
|
ns = !(newIORef [<]),
|
|
|
|
|
suf = !(newIORef 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private
|
2023-11-01 07:56:27 -04:00
|
|
|
|
data Error =
|
|
|
|
|
ParseError String Parser.Error
|
|
|
|
|
| FromParserError FromParser.Error
|
|
|
|
|
| EraseError Erase.Error
|
|
|
|
|
| WriteError FilePath FileError
|
|
|
|
|
| NoMain
|
|
|
|
|
| MultipleMains (List Id)
|
2023-10-20 11:42:01 -04:00
|
|
|
|
%hide FromParser.Error
|
|
|
|
|
%hide Erase.Error
|
|
|
|
|
%hide Lexer.Error
|
|
|
|
|
%hide Parser.Error
|
|
|
|
|
|
2023-11-01 07:56:27 -04:00
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
private
|
|
|
|
|
loadError : Loc -> FilePath -> FileError -> Error
|
|
|
|
|
loadError loc file err = FromParserError $ LoadError loc file err
|
|
|
|
|
|
2023-10-24 17:52:19 -04:00
|
|
|
|
private
|
|
|
|
|
prettyError : {opts : LayoutOpts} -> Error -> Eff Pretty (Doc opts)
|
|
|
|
|
prettyError (ParseError file e) = prettyParseError file e
|
|
|
|
|
prettyError (FromParserError e) = FromParser.prettyError True e
|
|
|
|
|
prettyError (EraseError e) = Erase.prettyError True e
|
2023-11-01 07:56:27 -04:00
|
|
|
|
prettyError NoMain = pure "no #[main] function given"
|
|
|
|
|
prettyError (MultipleMains xs) =
|
|
|
|
|
pure $ sep ["multiple #[main] functions given:",
|
|
|
|
|
separateLoose "," !(traverse prettyId xs)]
|
2023-10-24 17:52:19 -04:00
|
|
|
|
prettyError (WriteError file e) = pure $
|
|
|
|
|
hangSingle 2 (text "couldn't write file \{file}:") (pshow e)
|
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
private
|
|
|
|
|
dieError : Options -> Error -> IO a
|
|
|
|
|
dieError opts e =
|
|
|
|
|
die (Opts opts.width) $
|
|
|
|
|
runPretty ({outFile := Console} opts) Console $
|
|
|
|
|
prettyError e
|
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
private
|
|
|
|
|
data CompileTag = OPTS | STATE
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
Compile : List (Type -> Type)
|
|
|
|
|
Compile =
|
|
|
|
|
[Except Error,
|
|
|
|
|
ReaderL STATE State, ReaderL OPTS Options,
|
|
|
|
|
LoadFile, IO]
|
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
private covering
|
2023-10-20 11:42:01 -04:00
|
|
|
|
runCompile : Options -> State -> Eff Compile a -> IO (Either Error a)
|
|
|
|
|
runCompile opts state act =
|
|
|
|
|
fromIOErr $ runEff act $ with Union.(::)
|
|
|
|
|
[handleExcept (\e => ioLeft e),
|
|
|
|
|
handleReaderConst state,
|
|
|
|
|
handleReaderConst opts,
|
|
|
|
|
handleLoadFileIOE loadError ParseError state.seen opts.include,
|
|
|
|
|
liftIO]
|
|
|
|
|
|
2023-05-14 13:58:46 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-10-20 11:42:01 -04:00
|
|
|
|
data StopTag = STOP
|
2023-05-14 13:58:46 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-10-20 11:42:01 -04:00
|
|
|
|
CompileStop : List (Type -> Type)
|
|
|
|
|
CompileStop = FailL STOP :: Compile
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
withEarlyStop : Has (FailL STOP) fs => Eff fs () -> Eff (fs - FailL STOP) ()
|
|
|
|
|
withEarlyStop = ignore . runFailAt STOP
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
stopHere : Has (FailL STOP) fs => Eff fs ()
|
|
|
|
|
stopHere = failAt STOP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
data ConsoleChannel = COut | CErr
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
data OpenFile = OConsole ConsoleChannel | OFile String File | ONone
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
rethrowFile : String -> Either FileError a -> Eff Compile a
|
|
|
|
|
rethrowFile f = rethrow . mapFst (WriteError f)
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
toOutFile : OpenFile -> OutFile
|
|
|
|
|
toOutFile (OConsole _) = Console
|
|
|
|
|
toOutFile (OFile f _) = File f
|
|
|
|
|
toOutFile ONone = NoOut
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
private
|
|
|
|
|
withFileC : String -> (OpenFile -> Eff Compile a) -> Eff Compile a
|
|
|
|
|
withFileC f act =
|
|
|
|
|
withFile f WriteTruncate pure (Prelude.map Right . act . OFile f) >>=
|
|
|
|
|
rethrowFile f
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
withOutFile : ConsoleChannel -> OutFile ->
|
|
|
|
|
(OpenFile -> Eff Compile a) -> Eff Compile a
|
|
|
|
|
withOutFile _ (File f) act = withFileC f act
|
|
|
|
|
withOutFile ch Console act = act $ OConsole ch
|
|
|
|
|
withOutFile _ NoOut act = act ONone
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
outputStr : OpenFile -> Lazy String -> Eff Compile ()
|
|
|
|
|
outputStr ONone _ = pure ()
|
|
|
|
|
outputStr (OConsole COut) str = putStr str
|
|
|
|
|
outputStr (OConsole CErr) str = fPutStr stderr str >>= rethrowFile "<stderr>"
|
|
|
|
|
outputStr (OFile f h) str = fPutStr h str >>= rethrowFile f
|
2023-10-24 17:52:19 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
outputDocs : OpenFile ->
|
|
|
|
|
({opts : LayoutOpts} -> Eff Pretty (List (Doc opts))) ->
|
|
|
|
|
Eff Compile ()
|
|
|
|
|
outputDocs file docs = do
|
2023-10-24 17:52:19 -04:00
|
|
|
|
opts <- askAt OPTS
|
2023-11-27 01:39:17 -05:00
|
|
|
|
for_ (runPretty opts (toOutFile file) docs) $ \x =>
|
|
|
|
|
outputStr file $ render (Opts opts.width) x
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
outputDoc : OpenFile ->
|
|
|
|
|
({opts : LayoutOpts} -> Eff Pretty (Doc opts)) -> Eff Compile ()
|
|
|
|
|
outputDoc file doc = outputDocs file $ singleton <$> doc
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
liftFromParser : Eff FromParserIO a -> Eff Compile a
|
2023-10-20 11:42:01 -04:00
|
|
|
|
liftFromParser act =
|
|
|
|
|
runEff act $ with Union.(::)
|
2023-12-06 19:35:39 -05:00
|
|
|
|
[handleExcept $ \err => throw $ FromParserError err,
|
2023-10-20 11:42:01 -04:00
|
|
|
|
handleStateIORef !(asksAt STATE defs),
|
|
|
|
|
handleStateIORef !(asksAt STATE ns),
|
2023-11-03 12:45:02 -04:00
|
|
|
|
handleStateIORef !(asksAt STATE suf),
|
|
|
|
|
\g => send g]
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
liftErase : Q.Definitions -> Eff Erase a -> Eff Compile a
|
2023-10-20 11:42:01 -04:00
|
|
|
|
liftErase defs act =
|
|
|
|
|
runEff act
|
2023-12-06 19:35:39 -05:00
|
|
|
|
[handleExcept $ \err => throw $ EraseError err,
|
2023-10-20 11:42:01 -04:00
|
|
|
|
handleStateIORef !(asksAt STATE suf)]
|
|
|
|
|
|
2023-10-24 17:52:19 -04:00
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
liftScheme : Eff Scheme a -> Eff Compile (a, List Id)
|
2023-11-01 07:56:27 -04:00
|
|
|
|
liftScheme act = do
|
|
|
|
|
runEff [|MkPair act (getAt MAIN)|]
|
|
|
|
|
[handleStateIORef !(newIORef empty),
|
|
|
|
|
handleStateIORef !(newIORef [])]
|
|
|
|
|
|
2023-10-24 17:52:19 -04:00
|
|
|
|
|
2023-11-01 07:56:27 -04:00
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
Step : Type -> Type -> Type
|
|
|
|
|
Step i o = OpenFile -> i -> Eff Compile o
|
|
|
|
|
|
|
|
|
|
-- private
|
|
|
|
|
-- processFile : String -> Eff Compile ()
|
|
|
|
|
-- processFile file = withEarlyStop $ do
|
|
|
|
|
-- Just ast <- loadFile noLoc file
|
|
|
|
|
-- | Nothing => pure ()
|
|
|
|
|
-- -- putErrLn "checking \{file}"
|
|
|
|
|
-- when (!(asksAt OPTS until) == Just Parse) $ do
|
|
|
|
|
-- lift $ outputStr $ show ast
|
|
|
|
|
-- stopHere
|
|
|
|
|
-- defList <- liftFromParser $ concat <$> traverse fromPTopLevel ast
|
|
|
|
|
-- outputDocStopIf Check $
|
|
|
|
|
-- traverse (uncurry Q.prettyDef) defList
|
|
|
|
|
-- let defs = SortedMap.fromList defList
|
|
|
|
|
-- erased <- liftErase defs $
|
|
|
|
|
-- traverse (\(x, d) => (x,) <$> eraseDef defs x d) defList
|
|
|
|
|
-- outputDocStopIf Erase $
|
|
|
|
|
-- traverse (uncurry U.prettyDef) erased
|
|
|
|
|
-- (scheme, mains) <- liftScheme $ map catMaybes $
|
|
|
|
|
-- traverse (uncurry defToScheme) erased
|
|
|
|
|
-- outputDocStopIf Scheme $
|
|
|
|
|
-- intersperse empty <$> traverse prettySexp scheme
|
2023-11-05 09:47:52 -05:00
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
|
private
|
2023-11-27 01:39:17 -05:00
|
|
|
|
step : {default CErr console : ConsoleChannel} ->
|
|
|
|
|
Phase -> OutFile -> Step i o -> i -> Eff CompileStop o
|
|
|
|
|
step phase file act x = do
|
2023-11-01 07:56:27 -04:00
|
|
|
|
opts <- askAt OPTS
|
2023-11-27 01:39:17 -05:00
|
|
|
|
res <- lift $ withOutFile console file $ \h => act h x
|
|
|
|
|
when (opts.until == Just phase) stopHere
|
|
|
|
|
pure res
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
parse : Step String PFile
|
|
|
|
|
parse h file = do
|
|
|
|
|
Just ast <- loadFile noLoc file
|
|
|
|
|
| Nothing => pure []
|
|
|
|
|
outputStr h $ show ast
|
|
|
|
|
pure ast
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
check : Step PFile (List Q.NDefinition)
|
|
|
|
|
check h decls =
|
|
|
|
|
map concat $ for decls $ \decl => do
|
|
|
|
|
defs <- liftFromParser $ fromPTopLevel decl
|
|
|
|
|
outputDocs h $ traverse (\(x, d) => prettyDef x d) defs
|
|
|
|
|
pure defs
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
erase : Step (List Q.NDefinition) (List U.NDefinition)
|
|
|
|
|
erase h defList =
|
|
|
|
|
for defList $ \(x, def) => do
|
|
|
|
|
def <- liftErase defs $ eraseDef defs x def
|
|
|
|
|
outputDoc h $ U.prettyDef x def
|
|
|
|
|
pure (x, def)
|
|
|
|
|
where defs = SortedMap.fromList defList
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
scheme : Step (List U.NDefinition) (List Sexp, Id)
|
|
|
|
|
scheme h defs = do
|
|
|
|
|
sexps' <- for defs $ \(x, d) => do
|
|
|
|
|
(msexp, mains) <- liftScheme $ defToScheme x d
|
|
|
|
|
outputDoc h $ maybe (sayErased x) prettySexp msexp
|
|
|
|
|
pure (msexp, mains)
|
|
|
|
|
bitraverse (pure . catMaybes) (oneMain . concat) $ unzip sexps'
|
|
|
|
|
where
|
|
|
|
|
sayErased : {opts : LayoutOpts} -> Name -> Eff Pretty (Doc opts)
|
|
|
|
|
sayErased x = pure $ hsep [";;", prettyName x, "erased"]
|
|
|
|
|
|
|
|
|
|
oneMain : List Id -> Eff Compile Id
|
|
|
|
|
oneMain [m] = pure m
|
|
|
|
|
oneMain [] = throw NoMain
|
|
|
|
|
oneMain ms = throw $ MultipleMains ms
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
output : Step (List Sexp, Id) ()
|
|
|
|
|
output h (sexps, main) =
|
|
|
|
|
lift $ outputDocs h $ do
|
|
|
|
|
res <- traverse prettySexp sexps
|
2023-11-01 07:56:27 -04:00
|
|
|
|
runner <- makeRunMain main
|
|
|
|
|
pure $ text Scheme.prelude :: res ++ [runner]
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
private covering
|
|
|
|
|
processFile : String -> Eff Compile ()
|
|
|
|
|
processFile file = withEarlyStop $ pipeline !(askAt OPTS) file where
|
|
|
|
|
pipeline : Options -> String -> Eff CompileStop ()
|
|
|
|
|
pipeline opts =
|
|
|
|
|
step Parse opts.dump.parse Main.parse >=>
|
|
|
|
|
step Check opts.dump.check Main.check >=>
|
|
|
|
|
step Erase opts.dump.erase Main.erase >=>
|
|
|
|
|
step Scheme opts.dump.scheme Main.scheme >=>
|
|
|
|
|
step End opts.outFile Main.output {console = COut}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export covering
|
2023-03-31 13:31:29 -04:00
|
|
|
|
main : IO ()
|
|
|
|
|
main = do
|
2023-10-20 11:42:01 -04:00
|
|
|
|
(_, opts, files) <- options
|
|
|
|
|
case !(runCompile opts !newState $ traverse_ processFile files) of
|
|
|
|
|
Right () => pure ()
|
2023-11-27 01:39:17 -05:00
|
|
|
|
Left e => dieError opts e
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
2023-03-31 13:31:29 -04:00
|
|
|
|
|
|
|
|
|
-----------------------------------
|
2023-05-14 13:58:46 -04:00
|
|
|
|
{-
|
2021-07-20 16:05:19 -04:00
|
|
|
|
|
2022-04-11 08:09:37 -04:00
|
|
|
|
private
|
2022-04-11 15:58:33 -04:00
|
|
|
|
text : PrettyOpts -> List String
|
2022-04-11 08:09:37 -04:00
|
|
|
|
text _ =
|
|
|
|
|
["",
|
|
|
|
|
#" ___ ___ _____ __ __"#,
|
|
|
|
|
#"/ _ `/ // / _ \\ \ /"#,
|
|
|
|
|
#"\_, /\_,_/\___/_\_\"#,
|
|
|
|
|
#" /_/"#,
|
|
|
|
|
""]
|
2022-03-06 19:19:26 -05:00
|
|
|
|
|
2023-11-27 01:39:17 -05:00
|
|
|
|
-- ["",
|
|
|
|
|
-- #" __ _ _ _ _____ __"#,
|
|
|
|
|
-- #"/ _` | || / _ \ \ /"#,
|
|
|
|
|
-- #"\__, |\_,_\___/_\_\"#,
|
|
|
|
|
-- #" |_|"#,
|
|
|
|
|
-- ""]
|
|
|
|
|
|
2022-04-11 08:09:37 -04:00
|
|
|
|
private
|
2022-04-11 15:58:33 -04:00
|
|
|
|
qtuwu : PrettyOpts -> List String
|
2022-04-11 08:09:37 -04:00
|
|
|
|
qtuwu opts =
|
|
|
|
|
if opts.unicode then
|
|
|
|
|
[#" ___,-´⎠ "#,
|
|
|
|
|
#"(·`──´ ◡ -´⎠"#,
|
2023-02-26 04:58:47 -05:00
|
|
|
|
#" \/\/──´⎞/`──´ "#,
|
|
|
|
|
#" ⎜⎟───,-₎ ⎞ "#,
|
|
|
|
|
#" ⎝⎠ (‾‾) ⎟ "#,
|
2022-04-11 08:09:37 -04:00
|
|
|
|
#" (‾‾‾) ⎟ "#]
|
|
|
|
|
else
|
|
|
|
|
[#" ___,-´/ "#,
|
|
|
|
|
#"(.`--´ u -´/"#,
|
|
|
|
|
#" \/\/--´|/`--´ "#,
|
2023-02-26 04:58:47 -05:00
|
|
|
|
#" ||---,-, \ "#,
|
|
|
|
|
#" `´ (--) | "#,
|
2022-04-11 08:09:37 -04:00
|
|
|
|
#" (---) | "#]
|
|
|
|
|
|
|
|
|
|
private
|
2022-04-11 15:58:33 -04:00
|
|
|
|
join1 : PrettyOpts -> String -> String -> String
|
2022-04-11 08:09:37 -04:00
|
|
|
|
join1 opts l r =
|
|
|
|
|
if opts.color then
|
|
|
|
|
" " <+> show (colored Green l) <+> " " <+> show (colored Magenta r)
|
|
|
|
|
else
|
|
|
|
|
" " <+> l <+> " " <+> r
|
|
|
|
|
|
|
|
|
|
export
|
2022-04-11 15:58:33 -04:00
|
|
|
|
banner : PrettyOpts -> String
|
2022-04-11 08:09:37 -04:00
|
|
|
|
banner opts = unlines $ zipWith (join1 opts) (qtuwu opts) (text opts)
|
2023-05-14 13:58:46 -04:00
|
|
|
|
-}
|