module Patrol.Type.Stacktrace where

import qualified Data.Aeson as Aeson
import qualified Data.Map as Map
import qualified Data.Text as Text
import qualified GHC.Stack as Stack
import qualified Patrol.Extra.Aeson as Aeson
import qualified Patrol.Type.Frame as Frame

-- | <https://develop.sentry.dev/sdk/event-payloads/types/#stacktrace>
data Stacktrace = Stacktrace
  { Stacktrace -> [Frame]
frames :: [Frame.Frame],
    Stacktrace -> Map Text Text
registers :: Map.Map Text.Text Text.Text
  }
  deriving (Stacktrace -> Stacktrace -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Stacktrace -> Stacktrace -> Bool
$c/= :: Stacktrace -> Stacktrace -> Bool
== :: Stacktrace -> Stacktrace -> Bool
$c== :: Stacktrace -> Stacktrace -> Bool
Eq, Int -> Stacktrace -> ShowS
[Stacktrace] -> ShowS
Stacktrace -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Stacktrace] -> ShowS
$cshowList :: [Stacktrace] -> ShowS
show :: Stacktrace -> String
$cshow :: Stacktrace -> String
showsPrec :: Int -> Stacktrace -> ShowS
$cshowsPrec :: Int -> Stacktrace -> ShowS
Show)

instance Aeson.ToJSON Stacktrace where
  toJSON :: Stacktrace -> Value
toJSON Stacktrace
stacktrace =
    [Pair] -> Value
Aeson.intoObject
      [ forall a. ToJSON a => String -> a -> Pair
Aeson.pair String
"frames" forall a b. (a -> b) -> a -> b
$ Stacktrace -> [Frame]
frames Stacktrace
stacktrace,
        forall a. ToJSON a => String -> a -> Pair
Aeson.pair String
"registers" forall a b. (a -> b) -> a -> b
$ Stacktrace -> Map Text Text
registers Stacktrace
stacktrace
      ]

empty :: Stacktrace
empty :: Stacktrace
empty =
  Stacktrace
    { frames :: [Frame]
frames = [],
      registers :: Map Text Text
registers = forall k a. Map k a
Map.empty
    }

fromCallStack :: Stack.CallStack -> Stacktrace
fromCallStack :: CallStack -> Stacktrace
fromCallStack =
  let intoFrame :: String -> SrcLoc -> Frame
intoFrame String
string SrcLoc
srcLoc =
        (SrcLoc -> Frame
Frame.fromSrcLoc SrcLoc
srcLoc)
          { function :: Text
Frame.function = String -> Text
Text.pack String
string
          }
   in forall a b c. (a -> b -> c) -> b -> a -> c
flip [Frame] -> Map Text Text -> Stacktrace
Stacktrace forall k a. Map k a
Map.empty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry String -> SrcLoc -> Frame
intoFrame) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. CallStack -> [(String, SrcLoc)]
Stack.getCallStack