Refactor error reporting and add CARP_DIR check (#1033)

* compiler: refactor error reporting and add CARP_DIR check

Co-authored-by: Tim Dévé <TimDeve@users.noreply.github.com>

* set CARP_DIR in tests

Co-authored-by: Tim Dévé <TimDeve@users.noreply.github.com>
This commit is contained in:
Veit Heller 2020-11-30 15:58:25 +01:00 committed by GitHub
parent 892a972660
commit fe07a3f062
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 41 deletions

View File

@ -2,7 +2,8 @@ module Main where
import qualified System.Environment as SystemEnvironment import qualified System.Environment as SystemEnvironment
import System.Console.Haskeline (runInputT) import System.Console.Haskeline (runInputT)
import Control.Monad (foldM) import System.Exit (exitFailure)
import Control.Monad (foldM, when)
import GHC.IO.Encoding import GHC.IO.Encoding
import Data.Maybe import Data.Maybe
@ -90,12 +91,21 @@ main = do setLocaleEncoding utf8
optimize = otherOptimize otherOptions optimize = otherOptimize otherOptions
generateOnly = otherGenerateOnly otherOptions generateOnly = otherGenerateOnly otherOptions
prompt = otherPrompt 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] ++ applySettings p = p { projectCFlags = ["-D LOG_MEMORY" | logMemory] ++
["-O3 -D NDEBUG" | optimize] ["-O3 -D NDEBUG" | optimize]
++ projectCFlags p ++ projectCFlags p
, projectCore = core , projectCore = core
, projectGenerateOnly = generateOnly , projectGenerateOnly = generateOnly
, projectCarpDir = fromMaybe (projectCarpDir p) $ lookup "CARP_DIR" sysEnv , projectCarpDir = fromMaybe (projectCarpDir p) carpDir
, projectPrompt = fromMaybe (projectPrompt p) prompt , projectPrompt = fromMaybe (projectPrompt p) prompt
} }
project = applySettings defaultProject project = applySettings defaultProject
@ -120,22 +130,23 @@ main = do setLocaleEncoding utf8
loadOnce = flip loadFilesOnce loadOnce = flip loadFilesOnce
carpProfile <- configPath "profile.carp" carpProfile <- configPath "profile.carp"
hasProfile <- doesFileExist carpProfile hasProfile <- doesFileExist carpProfile
_ <- pure startingContext _ <- ifCarpDirSet
>>= load [carpProfile | hasProfile] (pure startingContext
>>= execStrs "Preload" preloads >>= load [carpProfile | hasProfile]
>>= loadOnce coreModulesToLoad >>= execStrs "Preload" preloads
>>= load argFilesToLoad >>= loadOnce coreModulesToLoad
>>= execStrs "Postload" postloads >>= load argFilesToLoad
>>= \ctx -> case execMode of >>= execStrs "Postload" postloads
Repl -> do putStrLn "Welcome to Carp 0.4.2" >>= \ctx -> case execMode of
putStrLn "This is free software with ABSOLUTELY NO WARRANTY." Repl -> do putStrLn "Welcome to Carp 0.4.2"
putStrLn "Evaluate (help) for more information." putStrLn "This is free software with ABSOLUTELY NO WARRANTY."
snd <$> runRepl ctx putStrLn "Evaluate (help) for more information."
Build -> execStr "Compiler (Build)" "(build)" ctx snd <$> runRepl ctx
Install thing -> execStr "Installation" ("(load \"" ++ thing ++ "\")") ctx Build -> execStr "Compiler (Build)" "(build)" ctx
BuildAndRun -> execStr "Compiler (Build & Run)" "(do (build) (run))" ctx Install thing -> execStr "Installation" ("(load \"" ++ thing ++ "\")") ctx
Check -> execStr "Check" "" ctx BuildAndRun -> execStr "Compiler (Build & Run)" "(do (build) (run))" ctx
-- TODO: Handle the return value from executeString and return that one to the shell Check -> execStr "Check" "" ctx)
-- TODO: Handle the return value from executeString and return that one to the shell
pure () pure ()
-- | Options for how to run the compiler. -- | Options for how to run the compiler.
data FullOptions = FullOptions data FullOptions = FullOptions

View File

@ -9,4 +9,5 @@ then
fi fi
CARP="$CARP $BUILD_OPTS --" CARP="$CARP $BUILD_OPTS --"
fi fi
export CARP_DIR=`pwd`
$CARP $CARP_OPTS "$@" $CARP $CARP_OPTS "$@"

View File

@ -1,6 +1,7 @@
module ColorText where module ColorText where
import System.Console.ANSI hiding (Blue, Red, Yellow, Green, White) import System.Console.ANSI hiding (Blue, Red, Yellow, Green, White)
import System.Exit (exitFailure)
import System.IO import System.IO
import Util import Util
@ -28,3 +29,23 @@ putStrWithColor color str =
putStrLnWithColor :: TextColor -> String -> IO () putStrLnWithColor :: TextColor -> String -> IO ()
putStrLnWithColor color str = putStrWithColor color (str ++ "\n") putStrLnWithColor color str = putStrWithColor color (str ++ "\n")
labelStr :: String -> String -> String
labelStr label str = "[" ++ label ++ "] " ++ str
emitWarning :: String -> IO ()
emitWarning str = putStrLnWithColor Blue (labelStr "WARNING" str)
emitErrorWithLabel :: String -> String -> IO ()
emitErrorWithLabel label str = putStrLnWithColor Red (labelStr label str)
emitError :: String -> IO ()
emitError str = emitErrorWithLabel "ERROR" str
emitErrorBare :: String -> IO ()
emitErrorBare str = putStrLnWithColor Red str
emitErrorAndExit :: String -> IO a
emitErrorAndExit str = do
_ <- emitError str
exitFailure

View File

@ -83,9 +83,14 @@ addCommandConfigurable path maybeArity callback doc example =
in XObj (Arr (map (tosym . intToArgName) [1..arity])) Nothing Nothing in XObj (Arr (map (tosym . intToArgName) [1..arity])) Nothing Nothing
Nothing -> XObj (Arr [(XObj (Sym (SymPath [] "") Symbol) Nothing Nothing)]) Nothing Nothing Nothing -> XObj (Arr [(XObj (Sym (SymPath [] "") Symbol) Nothing Nothing)]) Nothing Nothing
presentErrorWithLabel :: MonadIO m => String -> String -> a -> m a
presentErrorWithLabel label msg ret =
liftIO $ do emitErrorWithLabel label msg
pure ret
presentError :: MonadIO m => String -> a -> m a presentError :: MonadIO m => String -> a -> m a
presentError msg ret = presentError msg ret =
liftIO $ do putStrLnWithColor Red msg liftIO $ do emitError msg
pure ret pure ret
-- | Command for changing various project settings. -- | Command for changing various project settings.
@ -146,7 +151,7 @@ commandProjectConfig ctx [xobj@(XObj (Str key) _ _), value] = do
pure (proj { projectForceReload = forceReload }) pure (proj { projectForceReload = forceReload })
_ -> Left ("Project.config can't understand the key '" ++ key ++ "' at " ++ prettyInfoFromXObj xobj ++ ".") _ -> Left ("Project.config can't understand the key '" ++ key ++ "' at " ++ prettyInfoFromXObj xobj ++ ".")
case newProj of case newProj of
Left errorMessage -> presentError ("[CONFIG ERROR] " ++ errorMessage) (ctx, dynamicNil) Left errorMessage -> presentErrorWithLabel "CONFIG ERROR" errorMessage (ctx, dynamicNil)
Right ok -> pure (ctx {contextProj=ok}, dynamicNil) Right ok -> pure (ctx {contextProj=ok}, dynamicNil)
commandProjectConfig ctx [faultyKey, _] = commandProjectConfig ctx [faultyKey, _] =
presentError ("First argument to 'Project.config' must be a string: " ++ pretty faultyKey) (ctx, dynamicNil) presentError ("First argument to 'Project.config' must be a string: " ++ pretty faultyKey) (ctx, dynamicNil)
@ -182,7 +187,7 @@ commandProjectGetConfig ctx [xobj@(XObj (Str key) _ _)] =
_ -> Left key _ -> Left key
in pure $ case getVal ctx proj of in pure $ case getVal ctx proj of
Right val -> (ctx, Right $ xstr val) Right val -> (ctx, Right $ xstr val)
Left key -> (evalError ctx ("[CONFIG ERROR] Project.get-config can't understand the key '" ++ key) (info xobj)) Left key -> (evalError ctx (labelStr "CONFIG ERROR" ("Project.get-config can't understand the key '" ++ key)) (info xobj))
commandProjectGetConfig ctx [faultyKey] = commandProjectGetConfig ctx [faultyKey] =
presentError ("First argument to 'Project.config' must be a string: " ++ pretty faultyKey) (ctx, dynamicNil) presentError ("First argument to 'Project.config' must be a string: " ++ pretty faultyKey) (ctx, dynamicNil)

View File

@ -396,11 +396,10 @@ executeString doCatch printResult ctx input fileName =
interactiveFolder (_, context) xobj = interactiveFolder (_, context) xobj =
executeCommand context xobj executeCommand context xobj
treatErr ctx e xobj = do treatErr ctx e xobj = do
let msg = "[PARSE ERROR] " ++ e let fppl = projectFilePathPrintLength (contextProj ctx)
fppl = projectFilePathPrintLength (contextProj ctx)
case contextExecMode ctx of case contextExecMode ctx of
Check -> putStrLn (machineReadableInfoFromXObj fppl xobj ++ " " ++ msg) Check -> putStrLn (machineReadableInfoFromXObj fppl xobj ++ " " ++ e)
_ -> putStrLnWithColor Red msg _ -> emitErrorWithLabel "PARSE ERROR" e
throw CancelEvaluationException throw CancelEvaluationException
-- | Used by functions that has a series of forms to evaluate and need to fold over them (producing a new Context in the end) -- | Used by functions that has a series of forms to evaluate and need to fold over them (producing a new Context in the end)
@ -458,7 +457,7 @@ reportExecutionError ctx errorMessage =
case contextExecMode ctx of case contextExecMode ctx of
Check -> putStrLn errorMessage Check -> putStrLn errorMessage
_ -> _ ->
do putStrLnWithColor Red errorMessage do emitErrorBare errorMessage
throw CancelEvaluationException throw CancelEvaluationException
-- | Decides what to do when the evaluation fails for some reason. -- | Decides what to do when the evaluation fails for some reason.
@ -466,12 +465,12 @@ catcher :: Context -> CarpException -> IO Context
catcher ctx exception = catcher ctx exception =
case exception of case exception of
(ShellOutException message returnCode) -> (ShellOutException message returnCode) ->
do putStrLnWithColor Red ("[RUNTIME ERROR] " ++ message) do emitErrorWithLabel "RUNTIME ERROR" message
stop returnCode stop returnCode
CancelEvaluationException -> CancelEvaluationException ->
stop 1 stop 1
EvalException evalError -> EvalException evalError ->
do putStrLnWithColor Red (show evalError) do emitError (show evalError)
stop 1 stop 1
where stop returnCode = where stop returnCode =
case contextExecMode ctx of case contextExecMode ctx of

View File

@ -8,6 +8,7 @@ module Interfaces (registerInInterfaceIfNeeded,
import Data.Either (isRight) import Data.Either (isRight)
import ColorText
import Obj import Obj
import Lookup import Lookup
import Types import Types
@ -20,12 +21,18 @@ data InterfaceError = KindMismatch SymPath Ty Ty
| NonInterface SymPath | NonInterface SymPath
instance Show InterfaceError where instance Show InterfaceError where
show (KindMismatch path definitionSignature interfaceSignature) = "[INTERFACE ERROR] " ++ show path ++ ":" ++ " One or more types in the interface implementation " ++ show (KindMismatch path definitionSignature interfaceSignature) =
show definitionSignature ++ " have kinds that do not match the kinds of the types in the interface signature " ++ labelStr "INTERFACE ERROR"
show interfaceSignature ++ "\n" ++ "Types of the form (f a) must be matched by constructor types such as (Maybe a)" (show path ++ ":" ++ " One or more types in the interface implementation " ++
show (TypeMismatch path definitionSignature interfaceSignature) = "[INTERFACE ERROR] " ++ show path ++ " : " ++ show definitionSignature ++ show definitionSignature ++ " have kinds that do not match the kinds of the types in the interface signature " ++
" doesn't match the interface signature " ++ show interfaceSignature show interfaceSignature ++ "\n" ++ "Types of the form (f a) must be matched by constructor types such as (Maybe a)")
show (NonInterface path) = "[INTERFACE ERROR] " ++ show path ++ "Cant' implement the non-interface `" ++ show path ++ "`" show (TypeMismatch path definitionSignature interfaceSignature) =
labelStr "INTERFACE ERROR"
(show path ++ " : " ++ show definitionSignature ++
" doesn't match the interface signature " ++ show interfaceSignature)
show (NonInterface path) =
labelStr "INTERFACE ERROR"
(show path ++ "Cant' implement the non-interface `" ++ show path ++ "`")
-- TODO: This is currently called once outside of this module--try to remove that call and make this internal. -- TODO: This is currently called once outside of this module--try to remove that call and make this internal.
-- Checks whether a given form's type matches an interface, and if so, registers the form with the interface. -- Checks whether a given form's type matches an interface, and if so, registers the form with the interface.

View File

@ -124,10 +124,9 @@ primitiveImplements xobj ctx [x@(XObj (Sym interface@(SymPath _ _) _) _ _), inne
def = lookupInEnv impl global def = lookupInEnv impl global
in maybe notFound found def in maybe notFound found def
where (SymPath modules _) = consPath (union (contextPath ctx) prefixes) (SymPath [] name) where (SymPath modules _) = consPath (union (contextPath ctx) prefixes) (SymPath [] name)
checkInterface = let warn = do putStrWithColor Blue ("[WARNING] The interface " ++ show interface ++ " implemented by " ++ show impl ++ checkInterface = let warn = do emitWarning ("The interface " ++ show interface ++ " implemented by " ++ show impl ++
" at " ++ prettyInfoFromXObj xobj ++ " is not defined." ++ " at " ++ prettyInfoFromXObj xobj ++ " is not defined." ++
" Did you define it using `definterface`?") " Did you define it using `definterface`?")
putStrLnWithColor White "" -- To restore color for sure.
tyEnv = getTypeEnv . contextTypeEnv $ ctx tyEnv = getTypeEnv . contextTypeEnv $ ctx
in maybe warn (\_ -> pure ()) (lookupInEnv interface tyEnv) in maybe warn (\_ -> pure ()) (lookupInEnv interface tyEnv)
-- If the implementation binding doesn't exist yet, set the implements -- If the implementation binding doesn't exist yet, set the implements
@ -191,9 +190,8 @@ define hidden ctx@(Context globalEnv _ typeEnv _ proj _ _ _) annXObj =
case previousType of case previousType of
Just previousTypeUnwrapped -> Just previousTypeUnwrapped ->
unless (areUnifiable (forceTy annXObj) previousTypeUnwrapped) $ unless (areUnifiable (forceTy annXObj) previousTypeUnwrapped) $
do putStrWithColor Blue ("[WARNING] Definition at " ++ prettyInfoFromXObj annXObj ++ " changed type of '" ++ show (getPath annXObj) ++ do emitWarning ("Definition at " ++ prettyInfoFromXObj annXObj ++ " changed type of '" ++ show (getPath annXObj) ++
"' from " ++ show previousTypeUnwrapped ++ " to " ++ show (forceTy annXObj)) "' from " ++ show previousTypeUnwrapped ++ " to " ++ show (forceTy annXObj))
putStrLnWithColor White "" -- To restore color for sure.
Nothing -> pure () Nothing -> pure ()
case Meta.get "implements" previousMeta of case Meta.get "implements" previousMeta of
Just (XObj (Lst interfaces) _ _) -> Just (XObj (Lst interfaces) _ _) ->