{-# LANGUAGE DeriveAnyClass #-}
-- |
-- Source position information
--
module Language.PureScript.AST.SourcePos where

import Prelude

import Codec.Serialise (Serialise)
import Control.DeepSeq (NFData)
import Data.Aeson ((.=), (.:))
import Data.Text (Text)
import GHC.Generics (Generic)
import Language.PureScript.Comments (Comment)
import Data.Aeson qualified as A
import Data.Text qualified as T
import System.FilePath (makeRelative)

-- | Source annotation - position information and comments.
type SourceAnn = (SourceSpan, [Comment])

-- | Source position information
data SourcePos = SourcePos
  { SourcePos -> Int
sourcePosLine :: Int
    -- ^ Line number
  , SourcePos -> Int
sourcePosColumn :: Int
    -- ^ Column number
  } deriving (Int -> SourcePos -> ShowS
[SourcePos] -> ShowS
SourcePos -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SourcePos] -> ShowS
$cshowList :: [SourcePos] -> ShowS
show :: SourcePos -> String
$cshow :: SourcePos -> String
showsPrec :: Int -> SourcePos -> ShowS
$cshowsPrec :: Int -> SourcePos -> ShowS
Show, SourcePos -> SourcePos -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SourcePos -> SourcePos -> Bool
$c/= :: SourcePos -> SourcePos -> Bool
== :: SourcePos -> SourcePos -> Bool
$c== :: SourcePos -> SourcePos -> Bool
Eq, Eq SourcePos
SourcePos -> SourcePos -> Bool
SourcePos -> SourcePos -> Ordering
SourcePos -> SourcePos -> SourcePos
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SourcePos -> SourcePos -> SourcePos
$cmin :: SourcePos -> SourcePos -> SourcePos
max :: SourcePos -> SourcePos -> SourcePos
$cmax :: SourcePos -> SourcePos -> SourcePos
>= :: SourcePos -> SourcePos -> Bool
$c>= :: SourcePos -> SourcePos -> Bool
> :: SourcePos -> SourcePos -> Bool
$c> :: SourcePos -> SourcePos -> Bool
<= :: SourcePos -> SourcePos -> Bool
$c<= :: SourcePos -> SourcePos -> Bool
< :: SourcePos -> SourcePos -> Bool
$c< :: SourcePos -> SourcePos -> Bool
compare :: SourcePos -> SourcePos -> Ordering
$ccompare :: SourcePos -> SourcePos -> Ordering
Ord, forall x. Rep SourcePos x -> SourcePos
forall x. SourcePos -> Rep SourcePos x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SourcePos x -> SourcePos
$cfrom :: forall x. SourcePos -> Rep SourcePos x
Generic, SourcePos -> ()
forall a. (a -> ()) -> NFData a
rnf :: SourcePos -> ()
$crnf :: SourcePos -> ()
NFData, [SourcePos] -> Encoding
SourcePos -> Encoding
forall s. Decoder s [SourcePos]
forall s. Decoder s SourcePos
forall a.
(a -> Encoding)
-> (forall s. Decoder s a)
-> ([a] -> Encoding)
-> (forall s. Decoder s [a])
-> Serialise a
decodeList :: forall s. Decoder s [SourcePos]
$cdecodeList :: forall s. Decoder s [SourcePos]
encodeList :: [SourcePos] -> Encoding
$cencodeList :: [SourcePos] -> Encoding
decode :: forall s. Decoder s SourcePos
$cdecode :: forall s. Decoder s SourcePos
encode :: SourcePos -> Encoding
$cencode :: SourcePos -> Encoding
Serialise)

displaySourcePos :: SourcePos -> Text
displaySourcePos :: SourcePos -> Text
displaySourcePos SourcePos
sp =
  Text
"line " forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (forall a. Show a => a -> String
show (SourcePos -> Int
sourcePosLine SourcePos
sp)) forall a. Semigroup a => a -> a -> a
<>
    Text
", column " forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (forall a. Show a => a -> String
show (SourcePos -> Int
sourcePosColumn SourcePos
sp))

displaySourcePosShort :: SourcePos -> Text
displaySourcePosShort :: SourcePos -> Text
displaySourcePosShort SourcePos
sp =
  String -> Text
T.pack (forall a. Show a => a -> String
show (SourcePos -> Int
sourcePosLine SourcePos
sp)) forall a. Semigroup a => a -> a -> a
<>
    Text
":" forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (forall a. Show a => a -> String
show (SourcePos -> Int
sourcePosColumn SourcePos
sp))

instance A.ToJSON SourcePos where
  toJSON :: SourcePos -> Value
toJSON SourcePos{Int
sourcePosColumn :: Int
sourcePosLine :: Int
sourcePosColumn :: SourcePos -> Int
sourcePosLine :: SourcePos -> Int
..} =
    forall a. ToJSON a => a -> Value
A.toJSON [Int
sourcePosLine, Int
sourcePosColumn]

instance A.FromJSON SourcePos where
  parseJSON :: Value -> Parser SourcePos
parseJSON Value
arr = do
    [Int
line, Int
col] <- forall a. FromJSON a => Value -> Parser a
A.parseJSON Value
arr
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Int -> SourcePos
SourcePos Int
line Int
col

data SourceSpan = SourceSpan
  { SourceSpan -> String
spanName :: String
    -- ^ Source name
  , SourceSpan -> SourcePos
spanStart :: SourcePos
    -- ^ Start of the span
  , SourceSpan -> SourcePos
spanEnd :: SourcePos
    -- ^ End of the span
  } deriving (Int -> SourceSpan -> ShowS
[SourceSpan] -> ShowS
SourceSpan -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SourceSpan] -> ShowS
$cshowList :: [SourceSpan] -> ShowS
show :: SourceSpan -> String
$cshow :: SourceSpan -> String
showsPrec :: Int -> SourceSpan -> ShowS
$cshowsPrec :: Int -> SourceSpan -> ShowS
Show, SourceSpan -> SourceSpan -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SourceSpan -> SourceSpan -> Bool
$c/= :: SourceSpan -> SourceSpan -> Bool
== :: SourceSpan -> SourceSpan -> Bool
$c== :: SourceSpan -> SourceSpan -> Bool
Eq, Eq SourceSpan
SourceSpan -> SourceSpan -> Bool
SourceSpan -> SourceSpan -> Ordering
SourceSpan -> SourceSpan -> SourceSpan
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SourceSpan -> SourceSpan -> SourceSpan
$cmin :: SourceSpan -> SourceSpan -> SourceSpan
max :: SourceSpan -> SourceSpan -> SourceSpan
$cmax :: SourceSpan -> SourceSpan -> SourceSpan
>= :: SourceSpan -> SourceSpan -> Bool
$c>= :: SourceSpan -> SourceSpan -> Bool
> :: SourceSpan -> SourceSpan -> Bool
$c> :: SourceSpan -> SourceSpan -> Bool
<= :: SourceSpan -> SourceSpan -> Bool
$c<= :: SourceSpan -> SourceSpan -> Bool
< :: SourceSpan -> SourceSpan -> Bool
$c< :: SourceSpan -> SourceSpan -> Bool
compare :: SourceSpan -> SourceSpan -> Ordering
$ccompare :: SourceSpan -> SourceSpan -> Ordering
Ord, forall x. Rep SourceSpan x -> SourceSpan
forall x. SourceSpan -> Rep SourceSpan x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SourceSpan x -> SourceSpan
$cfrom :: forall x. SourceSpan -> Rep SourceSpan x
Generic, SourceSpan -> ()
forall a. (a -> ()) -> NFData a
rnf :: SourceSpan -> ()
$crnf :: SourceSpan -> ()
NFData, [SourceSpan] -> Encoding
SourceSpan -> Encoding
forall s. Decoder s [SourceSpan]
forall s. Decoder s SourceSpan
forall a.
(a -> Encoding)
-> (forall s. Decoder s a)
-> ([a] -> Encoding)
-> (forall s. Decoder s [a])
-> Serialise a
decodeList :: forall s. Decoder s [SourceSpan]
$cdecodeList :: forall s. Decoder s [SourceSpan]
encodeList :: [SourceSpan] -> Encoding
$cencodeList :: [SourceSpan] -> Encoding
decode :: forall s. Decoder s SourceSpan
$cdecode :: forall s. Decoder s SourceSpan
encode :: SourceSpan -> Encoding
$cencode :: SourceSpan -> Encoding
Serialise)

displayStartEndPos :: SourceSpan -> Text
displayStartEndPos :: SourceSpan -> Text
displayStartEndPos SourceSpan
sp =
  Text
"(" forall a. Semigroup a => a -> a -> a
<>
  SourcePos -> Text
displaySourcePos (SourceSpan -> SourcePos
spanStart SourceSpan
sp) forall a. Semigroup a => a -> a -> a
<> Text
" - " forall a. Semigroup a => a -> a -> a
<>
  SourcePos -> Text
displaySourcePos (SourceSpan -> SourcePos
spanEnd SourceSpan
sp) forall a. Semigroup a => a -> a -> a
<> Text
")"

displayStartEndPosShort :: SourceSpan -> Text
displayStartEndPosShort :: SourceSpan -> Text
displayStartEndPosShort SourceSpan
sp =
  SourcePos -> Text
displaySourcePosShort (SourceSpan -> SourcePos
spanStart SourceSpan
sp) forall a. Semigroup a => a -> a -> a
<> Text
" - " forall a. Semigroup a => a -> a -> a
<>
  SourcePos -> Text
displaySourcePosShort (SourceSpan -> SourcePos
spanEnd SourceSpan
sp)

displaySourceSpan :: FilePath -> SourceSpan -> Text
displaySourceSpan :: String -> SourceSpan -> Text
displaySourceSpan String
relPath SourceSpan
sp =
  String -> Text
T.pack (String -> ShowS
makeRelative String
relPath (SourceSpan -> String
spanName SourceSpan
sp)) forall a. Semigroup a => a -> a -> a
<> Text
":" forall a. Semigroup a => a -> a -> a
<>
    SourceSpan -> Text
displayStartEndPosShort SourceSpan
sp forall a. Semigroup a => a -> a -> a
<> Text
" " forall a. Semigroup a => a -> a -> a
<>
    SourceSpan -> Text
displayStartEndPos SourceSpan
sp

instance A.ToJSON SourceSpan where
  toJSON :: SourceSpan -> Value
toJSON SourceSpan{String
SourcePos
spanEnd :: SourcePos
spanStart :: SourcePos
spanName :: String
spanEnd :: SourceSpan -> SourcePos
spanStart :: SourceSpan -> SourcePos
spanName :: SourceSpan -> String
..} =
    [Pair] -> Value
A.object [ Key
"name"  forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
spanName
             , Key
"start" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SourcePos
spanStart
             , Key
"end"   forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SourcePos
spanEnd
             ]

instance A.FromJSON SourceSpan where
  parseJSON :: Value -> Parser SourceSpan
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
A.withObject String
"SourceSpan" forall a b. (a -> b) -> a -> b
$ \Object
o ->
    String -> SourcePos -> SourcePos -> SourceSpan
SourceSpan     forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
      Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"  forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
      Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"start" forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
      Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"end"

internalModuleSourceSpan :: String -> SourceSpan
internalModuleSourceSpan :: String -> SourceSpan
internalModuleSourceSpan String
name = String -> SourcePos -> SourcePos -> SourceSpan
SourceSpan String
name (Int -> Int -> SourcePos
SourcePos Int
0 Int
0) (Int -> Int -> SourcePos
SourcePos Int
0 Int
0)

nullSourceSpan :: SourceSpan
nullSourceSpan :: SourceSpan
nullSourceSpan = String -> SourceSpan
internalModuleSourceSpan String
""

nullSourceAnn :: SourceAnn
nullSourceAnn :: SourceAnn
nullSourceAnn = (SourceSpan
nullSourceSpan, [])

pattern NullSourceSpan :: SourceSpan
pattern $bNullSourceSpan :: SourceSpan
$mNullSourceSpan :: forall {r}. SourceSpan -> ((# #) -> r) -> ((# #) -> r) -> r
NullSourceSpan = SourceSpan "" (SourcePos 0 0) (SourcePos 0 0)

pattern NullSourceAnn :: SourceAnn
pattern $bNullSourceAnn :: SourceAnn
$mNullSourceAnn :: forall {r}. SourceAnn -> ((# #) -> r) -> ((# #) -> r) -> r
NullSourceAnn = (NullSourceSpan, [])

nonEmptySpan :: SourceAnn -> Maybe SourceSpan
nonEmptySpan :: SourceAnn -> Maybe SourceSpan
nonEmptySpan (SourceSpan
NullSourceSpan, [Comment]
_) = forall a. Maybe a
Nothing
nonEmptySpan (SourceSpan
ss, [Comment]
_) = forall a. a -> Maybe a
Just SourceSpan
ss

widenSourceSpan :: SourceSpan -> SourceSpan -> SourceSpan
widenSourceSpan :: SourceSpan -> SourceSpan -> SourceSpan
widenSourceSpan SourceSpan
NullSourceSpan SourceSpan
b = SourceSpan
b
widenSourceSpan SourceSpan
a SourceSpan
NullSourceSpan = SourceSpan
a
widenSourceSpan (SourceSpan String
n1 SourcePos
s1 SourcePos
e1) (SourceSpan String
n2 SourcePos
s2 SourcePos
e2) =
  String -> SourcePos -> SourcePos -> SourceSpan
SourceSpan String
n (forall a. Ord a => a -> a -> a
min SourcePos
s1 SourcePos
s2) (forall a. Ord a => a -> a -> a
max SourcePos
e1 SourcePos
e2)
  where
  n :: String
n | String
n1 forall a. Eq a => a -> a -> Bool
== String
""  = String
n2
    | Bool
otherwise = String
n1

widenSourceAnn :: SourceAnn -> SourceAnn -> SourceAnn
widenSourceAnn :: SourceAnn -> SourceAnn -> SourceAnn
widenSourceAnn (SourceSpan
s1, [Comment]
_) (SourceSpan
s2, [Comment]
_) = (SourceSpan -> SourceSpan -> SourceSpan
widenSourceSpan SourceSpan
s1 SourceSpan
s2, [])