mirror of
https://github.com/carp-lang/Carp.git
synced 2024-09-19 01:18:40 +03:00
208 lines
6.8 KiB
Haskell
208 lines
6.8 KiB
Haskell
module Main where
|
|
|
|
import ColorText
|
|
import Control.Monad (foldM, when)
|
|
import Data.Maybe
|
|
import Eval
|
|
import GHC.IO.Encoding
|
|
import Info
|
|
import Obj
|
|
import Options.Applicative
|
|
import Path
|
|
import Project
|
|
import Repl
|
|
import StartingEnv
|
|
import System.Console.Haskeline (runInputT)
|
|
import qualified System.Environment as SystemEnvironment
|
|
import System.Exit (exitFailure)
|
|
import Types
|
|
import Util
|
|
|
|
defaultProject :: Project
|
|
defaultProject =
|
|
Project
|
|
{ projectTitle = "Untitled",
|
|
projectIncludes = [],
|
|
projectCFlags = case platform of
|
|
Windows ->
|
|
[ "-D_CRT_SECURE_NO_WARNINGS"
|
|
]
|
|
_ ->
|
|
[ "-fPIC",
|
|
"-g",
|
|
"-std=c99",
|
|
-- , "-pedantic"
|
|
"-D_DEFAULT_SOURCE",
|
|
"-Wall",
|
|
"-Werror",
|
|
"-Wno-unused-variable",
|
|
"-Wno-self-assign"
|
|
],
|
|
projectLibFlags = case platform of
|
|
Windows -> []
|
|
_ -> ["-lm"],
|
|
projectFiles = [],
|
|
projectAlreadyLoaded = [],
|
|
projectEchoC = False,
|
|
projectLibDir = "libs",
|
|
projectCarpDir = ".",
|
|
projectOutDir = "out",
|
|
projectDocsDir = "docs",
|
|
projectDocsLogo = "",
|
|
projectDocsPrelude = "",
|
|
projectDocsURL = "",
|
|
projectDocsGenerateIndex = True,
|
|
projectDocsStyling = "carp_style.css",
|
|
projectBalanceHints = True,
|
|
projectPrompt = case platform of
|
|
MacOS -> "鲤 "
|
|
_ -> "> ",
|
|
projectCarpSearchPaths = [],
|
|
projectPrintTypedAST = False,
|
|
projectCompiler = case platform of
|
|
Windows -> "clang-cl.exe"
|
|
_ -> "clang",
|
|
projectTarget = Native,
|
|
projectCore = True,
|
|
projectEchoCompilationCommand = False,
|
|
projectCanExecute = False,
|
|
projectFilePathPrintLength = FullPath,
|
|
projectGenerateOnly = False,
|
|
projectForceReload = False,
|
|
projectPkgConfigFlags = [],
|
|
projectCModules = [],
|
|
projectLoadStack = [],
|
|
projectPreproc = []
|
|
}
|
|
|
|
-- | Starting point of the application.
|
|
main :: IO ()
|
|
main = do
|
|
setLocaleEncoding utf8
|
|
args <- SystemEnvironment.getArgs
|
|
sysEnv <- SystemEnvironment.getEnvironment
|
|
fullOpts <- execParser $ Options.Applicative.info (parseFull <**> helper) fullDesc
|
|
let execMode = optExecMode fullOpts
|
|
otherOptions = optOthers fullOpts
|
|
argFilesToLoad = optFiles fullOpts
|
|
logMemory = otherLogMemory otherOptions
|
|
core = not $ otherNoCore otherOptions
|
|
profile = not $ otherNoProfile otherOptions
|
|
optimize = otherOptimize otherOptions
|
|
generateOnly = otherGenerateOnly otherOptions
|
|
prompt = otherPrompt otherOptions
|
|
carpDir = lookup "CARP_DIR" sysEnv
|
|
ifCarpDirSet comp =
|
|
case carpDir of
|
|
Just _ -> comp
|
|
Nothing -> do
|
|
emitWarning "The environment variable `CARP_DIR` is not set."
|
|
if core
|
|
then emitErrorAndExit "Cannot use core libraries without `CARP_DIR` being set (if you want to provide your own, use `--no-core`)."
|
|
else comp
|
|
applySettings p =
|
|
p
|
|
{ projectCFlags =
|
|
["-D LOG_MEMORY" | logMemory]
|
|
++ ["-O3 -D NDEBUG" | optimize]
|
|
++ projectCFlags p,
|
|
projectCore = core,
|
|
projectGenerateOnly = generateOnly,
|
|
projectCarpDir = fromMaybe (projectCarpDir p) carpDir,
|
|
projectPrompt = fromMaybe (projectPrompt p) prompt
|
|
}
|
|
project = applySettings defaultProject
|
|
noArray = False
|
|
startingContext =
|
|
Context
|
|
(startingGlobalEnv noArray)
|
|
Nothing
|
|
(TypeEnv startingTypeEnv)
|
|
[]
|
|
project
|
|
""
|
|
execMode
|
|
[]
|
|
coreModulesToLoad = if core then coreModules (projectCarpDir project) else []
|
|
execStr :: String -> String -> Context -> IO Context
|
|
execStr i s ctx = executeString True False ctx s i
|
|
execStrs :: String -> [String] -> Context -> IO Context
|
|
execStrs i strs ctx = foldM (\ctx' str' -> execStr i str' ctx') ctx strs
|
|
preloads = optPreload fullOpts
|
|
postloads = optPostload fullOpts
|
|
load = flip loadFiles
|
|
loadOnce = flip loadFilesOnce
|
|
carpProfile <- configPath "profile.carp"
|
|
hasProfile <- doesFileExist carpProfile
|
|
_ <-
|
|
ifCarpDirSet
|
|
( pure startingContext
|
|
>>= load [carpProfile | hasProfile && profile]
|
|
>>= execStrs "Preload" preloads
|
|
>>= loadOnce coreModulesToLoad
|
|
>>= load argFilesToLoad
|
|
>>= execStrs "Postload" postloads
|
|
>>= \ctx -> case execMode of
|
|
Repl -> do
|
|
putStrLn "Welcome to Carp 0.5.3"
|
|
putStrLn "This is free software with ABSOLUTELY NO WARRANTY."
|
|
putStrLn "Evaluate (help) for more information."
|
|
snd <$> runRepl ctx
|
|
Build -> execStr "Compiler (Build)" "(build)" ctx
|
|
Install thing -> execStr "Installation" ("(load \"" ++ thing ++ "\")") ctx
|
|
BuildAndRun -> execStr "Compiler (Build & Run)" "(do (build) (run))" ctx
|
|
Check -> execStr "Check" "" ctx
|
|
)
|
|
-- TODO: Handle the return value from executeString and return that one to the shell
|
|
pure ()
|
|
|
|
-- | Options for how to run the compiler.
|
|
data FullOptions = FullOptions
|
|
{ optExecMode :: ExecutionMode,
|
|
optOthers :: OtherOptions,
|
|
optPreload :: [String],
|
|
optPostload :: [String],
|
|
optFiles :: [FilePath]
|
|
}
|
|
deriving (Show)
|
|
|
|
parseFull :: Parser FullOptions
|
|
parseFull =
|
|
FullOptions
|
|
<$> parseExecMode
|
|
<*> parseOther
|
|
<*> many (strOption (long "eval-preload" <> metavar "CODE" <> help "Eval CODE after loading config and before FILES"))
|
|
<*> many (strOption (long "eval-postload" <> metavar "CODE" <> help "Eval CODE after loading FILES"))
|
|
<*> parseFiles
|
|
|
|
data OtherOptions = OtherOptions
|
|
{ otherNoCore :: Bool,
|
|
otherNoProfile :: Bool,
|
|
otherLogMemory :: Bool,
|
|
otherOptimize :: Bool,
|
|
otherGenerateOnly :: Bool,
|
|
otherPrompt :: Maybe String
|
|
}
|
|
deriving (Show)
|
|
|
|
parseOther :: Parser OtherOptions
|
|
parseOther =
|
|
OtherOptions
|
|
<$> switch (long "no-core" <> help "Don't load Core.carp")
|
|
<*> switch (long "no-profile" <> help "Don't load profile.carp")
|
|
<*> switch (long "log-memory" <> help "Log memory allocations")
|
|
<*> switch (long "optimize" <> help "Optimized build")
|
|
<*> switch (long "generate-only" <> help "Stop after generating the C code")
|
|
<*> optional (strOption (long "prompt" <> help "Set REPL prompt"))
|
|
|
|
parseExecMode :: Parser ExecutionMode
|
|
parseExecMode =
|
|
flag' Check (long "check" <> help "Check project")
|
|
<|> flag' Build (short 'b' <> help "Build project")
|
|
<|> flag' BuildAndRun (short 'x' <> help "Build an run project")
|
|
<|> Install <$> strOption (short 'i' <> help "Install built product")
|
|
<|> pure Repl
|
|
|
|
parseFiles :: Parser [FilePath]
|
|
parseFiles = many (argument str (metavar "FILES..."))
|