diff options
author | Tom Smeding <tom@tomsmeding.com> | 2024-02-19 23:32:09 +0100 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2024-02-19 23:32:09 +0100 |
commit | b0c81ee7def783037b514af9fdeab06f7e3bdb13 (patch) | |
tree | 78e11274cc3b4779fe06b5f30c3d8426dc36202f | |
parent | 91b62660cd522ce59ba1294eb2e6582e92f0a264 (diff) |
Show source line in parse error
-rw-r--r-- | examples/test1.hs | 4 | ||||
-rw-r--r-- | src/Parser.hs | 31 |
2 files changed, 22 insertions, 13 deletions
diff --git a/examples/test1.hs b/examples/test1.hs index 2a3a834..ea09465 100644 --- a/examples/test1.hs +++ b/examples/test1.hs @@ -12,7 +12,7 @@ g y ding = ding f (y - 2) + 7 reverse :: [a] -> [a] reverse l = let go [] acc = acc - go (x:xs) acc go xs (x:acc) 7 -> - in go l [] + go (x:xs) acc = go xs (x:acc) + in (go l [] kaas = 42 diff --git a/src/Parser.hs b/src/Parser.hs index 1746eca..76cc10e 100644 --- a/src/Parser.hs +++ b/src/Parser.hs @@ -30,6 +30,7 @@ import Control.Monad.State.Lazy import Data.Char import Data.Either (partitionEithers) import Data.Foldable +import Data.List (intercalate) import Data.List.NonEmpty (NonEmpty(..)) import Data.These @@ -58,6 +59,7 @@ data PS = PS data Context = Context { ctxFile :: FilePath + , ctxLines :: [String] -- ^ The file contents, split up in lines , ctxStack :: [String] -- ^ Stack of syntax scopes, for error reporting } deriving (Show) @@ -156,17 +158,23 @@ data ErrMsg = ErrMsg { errFile :: FilePath , errStk :: [String] , errPos :: Pos - , errMsg :: String } + , errMsg :: String + , errSourceLine :: String } deriving (Show) printErrMsg :: ErrMsg -> String -printErrMsg (ErrMsg fp stk (Pos y x) s) = - unlines (map (\descr -> "In " ++ descr ++ ":") (reverse stk)) ++ - fp ++ ":" ++ show (y + 1) ++ ":" ++ show (x + 1) ++ ": " ++ s +printErrMsg (ErrMsg fp stk (Pos y x) s srcline) = + let linenum = show (y + 1) + in intercalate "\n" $ + map (\descr -> "In " ++ descr ++ ":") (reverse stk) + ++ [fp ++ ":" ++ show (y + 1) ++ ":" ++ show (x + 1) ++ ": " ++ s + ,map (\_ -> ' ') linenum ++ " |" + ,linenum ++ " | " ++ srcline + ,map (\_ -> ' ') linenum ++ " | " ++ replicate x ' ' ++ "^"] parse :: FilePath -> String -> These [ErrMsg] (Program ()) parse fp source = - runParser pProgram (Context fp []) (PS (Pos 0 0) (Pos 0 0) source) + runParser pProgram (Context fp (lines source) []) (PS (Pos 0 0) (Pos 0 0) source) (\_ errs res -> case errs of [] -> That res _ -> These errs res) @@ -551,10 +559,11 @@ pEVarOrCon0 = pEParens0 :: FParser (Expr ()) pEParens0 = do char '(' - e <- pExpr - inlineWhite - char ')' - return e + noFail $ do + e <- pExpr <|>> (raise Error "Expected expression" >> return (ETup () [])) + inlineWhite + char ')' <|>> raise Error "Expected closing ')'" + return e data Associativity = AssocLeft | AssocRight | AssocNone deriving (Show, Eq) @@ -813,8 +822,8 @@ raise fat msg = gets psCur >>= \pos -> raiseAt pos fat msg -- | Raise an error with the given fatality and description. raiseAt :: (KnownFallible fail, FatalCtx fatal a) => Pos -> Fatality fatal -> String -> Parser fail a raiseAt pos fat msg = do - Context { ctxFile = fp , ctxStack = stk } <- ask - let err = ErrMsg fp stk pos msg + Context { ctxFile = fp , ctxStack = stk, ctxLines = srcLines } <- ask + let err = ErrMsg fp stk pos msg (srcLines !! posLine pos) case fat of Error -> dictate (pure err) Fatal -> confess (pure err) |