-- | A very simple representation of collections of warnings.
-- Warnings have a position (so they can be ordered), and their
-- 'Pretty'-instance produces a human-readable string.
module Language.Futhark.Warnings
  ( Warnings,
    anyWarnings,
    singleWarning,
    singleWarning',
    listWarnings,
  )
where

import Data.List (sortOn)
import Data.Monoid
import Futhark.Util.Console (inYellow)
import Futhark.Util.Loc
import Futhark.Util.Pretty
import Language.Futhark.Core (locStr, prettyStacktrace)
import Prelude

-- | The warnings produced by the compiler.  The 'Show' instance
-- produces a human-readable description.
newtype Warnings = Warnings [(SrcLoc, [SrcLoc], Doc)]

instance Semigroup Warnings where
  Warnings [(SrcLoc, [SrcLoc], Doc)]
ws1 <> :: Warnings -> Warnings -> Warnings
<> Warnings [(SrcLoc, [SrcLoc], Doc)]
ws2 = [(SrcLoc, [SrcLoc], Doc)] -> Warnings
Warnings forall a b. (a -> b) -> a -> b
$ [(SrcLoc, [SrcLoc], Doc)]
ws1 forall a. Semigroup a => a -> a -> a
<> [(SrcLoc, [SrcLoc], Doc)]
ws2

instance Monoid Warnings where
  mempty :: Warnings
mempty = [(SrcLoc, [SrcLoc], Doc)] -> Warnings
Warnings forall a. Monoid a => a
mempty

instance Pretty Warnings where
  ppr :: Warnings -> Doc
ppr (Warnings []) = forall a. Monoid a => a
mempty
  ppr (Warnings [(SrcLoc, [SrcLoc], Doc)]
ws) =
    [Doc] -> Doc
stack forall a b. (a -> b) -> a -> b
$ Doc -> [Doc] -> [Doc]
punctuate Doc
line forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall {a}. Located a => (a, [a], Doc) -> Doc
onWarning forall a b. (a -> b) -> a -> b
$ forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Loc -> (String, Int)
rep forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a} {b} {c}. Located a => (a, b, c) -> Loc
wloc) [(SrcLoc, [SrcLoc], Doc)]
ws
    where
      wloc :: (a, b, c) -> Loc
wloc (a
x, b
_, c
_) = forall a. Located a => a -> Loc
locOf a
x
      rep :: Loc -> (String, Int)
rep Loc
NoLoc = (String
"", Int
0)
      rep (Loc Pos
p Pos
_) = (Pos -> String
posFile Pos
p, Pos -> Int
posCoff Pos
p)
      onWarning :: (a, [a], Doc) -> Doc
onWarning (a
loc, [], Doc
w) =
        String -> Doc
text (String -> String
inYellow (String
"Warning at " forall a. [a] -> [a] -> [a]
++ forall a. Located a => a -> String
locStr a
loc forall a. [a] -> [a] -> [a]
++ String
":"))
          Doc -> Doc -> Doc
</> Int -> Doc -> Doc
indent Int
2 Doc
w
      onWarning (a
loc, [a]
locs, Doc
w) =
        String -> Doc
text
          ( String -> String
inYellow
              ( String
"Warning at\n"
                  forall a. [a] -> [a] -> [a]
++ Int -> [String] -> String
prettyStacktrace Int
0 (forall a b. (a -> b) -> [a] -> [b]
map forall a. Located a => a -> String
locStr (a
loc forall a. a -> [a] -> [a]
: [a]
locs))
              )
          )
          Doc -> Doc -> Doc
</> Int -> Doc -> Doc
indent Int
2 Doc
w

-- | True if there are any warnings in the set.
anyWarnings :: Warnings -> Bool
anyWarnings :: Warnings -> Bool
anyWarnings (Warnings [(SrcLoc, [SrcLoc], Doc)]
ws) = Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(SrcLoc, [SrcLoc], Doc)]
ws

-- | A single warning at the given location.
singleWarning :: SrcLoc -> Doc -> Warnings
singleWarning :: SrcLoc -> Doc -> Warnings
singleWarning SrcLoc
loc = SrcLoc -> [SrcLoc] -> Doc -> Warnings
singleWarning' SrcLoc
loc []

-- | A single warning at the given location, but also with a stack
-- trace (sort of) to the location.
singleWarning' :: SrcLoc -> [SrcLoc] -> Doc -> Warnings
singleWarning' :: SrcLoc -> [SrcLoc] -> Doc -> Warnings
singleWarning' SrcLoc
loc [SrcLoc]
locs Doc
problem = [(SrcLoc, [SrcLoc], Doc)] -> Warnings
Warnings [(SrcLoc
loc, [SrcLoc]
locs, Doc
problem)]

-- | Exports Warnings into a list of (location, problem).
listWarnings :: Warnings -> [(SrcLoc, Doc)]
listWarnings :: Warnings -> [(SrcLoc, Doc)]
listWarnings (Warnings [(SrcLoc, [SrcLoc], Doc)]
ws) = forall a b. (a -> b) -> [a] -> [b]
map (\(SrcLoc
loc, [SrcLoc]
_, Doc
doc) -> (SrcLoc
loc, Doc
doc)) [(SrcLoc, [SrcLoc], Doc)]
ws