on 9b0c310 help sign in
elk/src/Reporting/Region.hs
122 lines 2.7 kB history raw
1{-# LANGUAGE OverloadedStrings #-}
2module Reporting.Region where
4import Data.Aeson ((.=))
5import qualified Data.Aeson as Json
6import qualified Text.Parsec.Pos as Parsec
8import Elm.Utils ((|>))
11data Region = Region
12 { start :: Position
13 , end :: Position
14 }
15 deriving (Show)
18data Position = Position
19 { line :: Int
20 , column :: Int
21 }
22 deriving (Show)
25fromSourcePos :: Parsec.SourcePos -> Position
26fromSourcePos sourcePos =
27 Position
28 (Parsec.sourceLine sourcePos)
29 (Parsec.sourceColumn sourcePos)
32merge :: Region -> Region -> Region
33merge (Region start _) (Region _ end) =
34 Region start end
37-- TO STRING
39toString :: Region -> String
40toString (Region start end) =
41 case line start == line end of
42 False ->
43 "between lines " ++ show (line start)
44 ++ " and " ++ show (line end)
46 True ->
47 "on line " ++ show (line end) ++ ", column "
48 ++ show (column start) ++ " to " ++ show (column end)
51-- EXTRACT REGION from SOURCE with LINE NUMBERS
53select :: Region -> String -> String
54select (Region start end) source =
55 let
56 relevantLines =
57 lines source
58 |> drop (line start)
59 |> take (line end - line start)
60 in
61 case relevantLines of
62 [] ->
63 error "something has gone badly wrong with reporting source locations"
65 [theLine] ->
66 let
67 lineNumber = show (line start) ++ "|"
68 in
69 lineNumber
70 ++ theLine
71 ++ "\n"
72 ++ replicate (column start + length lineNumber) ' '
73 ++ replicate (column end - column start) '^'
74 ++ "\n"
76 firstLine : rest ->
77 let
78 filteredFirstLine =
79 replicate (column start) ' ' ++ drop (column start) firstLine
81 filteredLastLine =
82 take (column end) (last rest)
84 focusedRelevantLines =
85 filteredFirstLine : init rest ++ [filteredLastLine]
87 lineNumbersWidth =
88 length (show (line end))
90 numberedLines =
91 zipWith
92 (addLineNumber lineNumbersWidth)
93 [line start .. line end]
94 focusedRelevantLines
95 in
96 unlines numberedLines
99addLineNumber :: Int -> Int -> String -> String
100addLineNumber width n line =
101 let
102 number = show n
103 in
104 replicate (width - length number) ' ' ++ number ++ "|" ++ line
107-- JSON
109instance Json.ToJSON Region where
110 toJSON (Region start end) =
111 Json.object
112 [ "start" .= start
113 , "end" .= end
114 ]
117instance Json.ToJSON Position where
118 toJSON (Position line column) =
119 Json.object
120 [ "line" .= line
121 , "column" .= column
122 ]