{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Strict            #-}
{-# LANGUAGE StrictData        #-}
module Language.Cimple.Diagnostics
  ( Diagnostics
  , HasDiagnostics (..)
  , warn
  , sloc
  ) where

import           Control.Monad.State.Strict (State)
import qualified Control.Monad.State.Strict as State
import           Data.Fix                   (foldFix)
import           Data.Text                  (Text)
import qualified Data.Text                  as Text
import           Language.Cimple.Ast        (Node)
import qualified Language.Cimple.Flatten    as Flatten
import           Language.Cimple.Lexer      (Lexeme (..), lexemeLine)

type DiagnosticsT diags a = State diags a
type Diagnostics a = DiagnosticsT [Text] a

warn
    :: (HasLocation at, HasDiagnostics diags)
    => FilePath -> at -> Text -> DiagnosticsT diags ()
warn :: forall at diags.
(HasLocation at, HasDiagnostics diags) =>
FilePath -> at -> Text -> DiagnosticsT diags ()
warn FilePath
file at
l Text
w = (diags -> diags) -> StateT diags Identity ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
State.modify (Text -> diags -> diags
forall a. HasDiagnostics a => Text -> a -> a
addDiagnostic (Text -> diags -> diags) -> Text -> diags -> diags
forall a b. (a -> b) -> a -> b
$ FilePath -> at -> Text
forall a. HasLocation a => FilePath -> a -> Text
sloc FilePath
file at
l Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
w)


class HasDiagnostics a where
    addDiagnostic :: Text -> a -> a

instance HasDiagnostics [Text] where
    addDiagnostic :: Text -> [Text] -> [Text]
addDiagnostic = (:)


class HasLocation a where
    sloc :: FilePath -> a -> Text

instance HasLocation (Lexeme text) where
    sloc :: FilePath -> Lexeme text -> Text
sloc FilePath
file Lexeme text
l = FilePath -> Text
Text.pack FilePath
file Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
Text.pack (Int -> FilePath
forall a. Show a => a -> FilePath
show (Lexeme text -> Int
forall text. Lexeme text -> Int
lexemeLine Lexeme text
l))

instance HasLocation lexeme => HasLocation (Node lexeme) where
    sloc :: FilePath -> Node lexeme -> Text
sloc FilePath
file Node lexeme
n =
        case (NodeF lexeme [lexeme] -> [lexeme]) -> Node lexeme -> [lexeme]
forall (f :: * -> *) a. Functor f => (f a -> a) -> Fix f -> a
foldFix NodeF lexeme [lexeme] -> [lexeme]
forall lexeme. NodeF lexeme [lexeme] -> [lexeme]
Flatten.lexemes Node lexeme
n of
            []  -> FilePath -> Text
Text.pack FilePath
file Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":0:0"
            lexeme
l:[lexeme]
_ -> FilePath -> lexeme -> Text
forall a. HasLocation a => FilePath -> a -> Text
sloc FilePath
file lexeme
l