Abbie's Haskell compiler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.1 KiB

  1. module Errors where
  2. import Frontend.Parser.Posn
  3. import Data.Maybe
  4. import qualified GHC.IO.Handle.FD
  5. import System.Posix.Internals (c_isatty)
  6. import GHC.IO.FD
  7. data AhcError
  8. = AhcError { errorMessage :: String
  9. , errorFilename :: String
  10. , errorInlineDesc :: Maybe String
  11. , errorBegin :: Posn
  12. , errorEnd :: Posn
  13. , errorPointers :: [ErrorPointer]
  14. }
  15. deriving (Eq, Show)
  16. emptyError :: AhcError
  17. emptyError =
  18. AhcError (error "parse errors must have a message")
  19. (error "parse errors must have a filename")
  20. Nothing
  21. (error "parse errors must have a start pos")
  22. (error "parse errors must have an end pos")
  23. []
  24. data ErrorPointer
  25. = ErrorPointer { errorPointerBegin :: Posn
  26. , errorPointerEnd :: Posn
  27. , errorPointerNote :: Maybe String
  28. , errorPointerDrawSquiggle :: Bool
  29. }
  30. deriving (Eq, Show)
  31. showAhcError :: Bool -> [String] -> AhcError -> String
  32. showAhcError color code pe = do
  33. unlines $
  34. [ bold
  35. ++ errorFilename pe
  36. ++ ":" ++ show linum ++ ":" ++ show startcol ++ ": "
  37. ++ red ++ "parse error:" ++ reset
  38. ] ++ map (render bold red sep reset) (mainPointer:errorPointers pe) ++
  39. [ padToMax "" ++ " " ++ errorMessage pe
  40. ]
  41. where
  42. linum = posnLine (errorBegin pe)
  43. startcol = posnColm (errorBegin pe)
  44. maxln = maximum [ length (show (posnLine e)) | e <- errorEnd pe:map errorPointerEnd (errorPointers pe)]
  45. (red, bold, reset, sep)
  46. | color = ("\x1b[31m", "\x1b[1m", "\x1b[0m", "\x1b[1;34m \9474 \x1b[0m")
  47. | otherwise = ("", "", "", "")
  48. padToMax x
  49. | length x < maxln = replicate (maxln - length x) ' ' ++ x
  50. | otherwise = x
  51. mainPointer = ErrorPointer (errorBegin pe) (errorEnd pe) (errorInlineDesc pe) True
  52. render bold red sep reset (ErrorPointer start end note squig) = do
  53. let
  54. linum = posnLine start
  55. startcol = posnColm start
  56. multiline = linum /= posnLine end
  57. width
  58. | multiline = 0
  59. | otherwise = max 0 (posnColm (errorEnd pe) - startcol - 1)
  60. linum' = padToMax $ show linum
  61. line = [ show linum ++ sep ++ code !! (linum - 1) | linum <- [ linum .. posnLine (errorEnd pe) ] ]
  62. padding = replicate (length linum') ' ' ++ sep
  63. padding' = replicate (length linum') ' ' ++ " "
  64. caret = replicate (startcol - 1) ' ' ++ red ++ "^"
  65. squiggle
  66. | squig = replicate width '~'
  67. | otherwise = ""
  68. init $ unlines
  69. [ padding
  70. , init (unlines line)
  71. , padding ++ caret ++ squiggle ++ reset ++ fromMaybe "" ((" " ++) <$> note)
  72. ]
  73. printParseError :: AhcError -> IO ()
  74. printParseError pe = do
  75. code <- lines <$> readFile (errorFilename pe)
  76. color <- fmap (1 ==) . c_isatty . fdFD =<< GHC.IO.Handle.FD.handleToFd GHC.IO.Handle.FD.stdout
  77. putStr $ showAhcError color code pe
  78. pointTo :: HasPosn x => x -> x -> String -> [ErrorPointer]
  79. pointTo s e msg = [ErrorPointer (startPosn s) (endPosn e) (Just msg) False]