{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE KindSignatures #-} module GHCJS.DOM.Debug.Internal ( DomHasCallStack , debugEnabled , cachedStacks , cacheStack , lookupStack , getElementStack ) where import Control.Monad (void) import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Map (Map) import qualified Data.Map as M (insert, size, lookup) import Data.IORef (atomicModifyIORef', IORef, newIORef, readIORef) import GHC.Stack (SrcLoc, CallStack, callStack, getCallStack, HasCallStack) import GHC.Exts (Constraint) import System.IO.Unsafe (unsafePerformIO) import Text.Read (readMaybe) import GHCJS.DOM.Types (Element(..), MonadDOM, ToJSString, JSString) import GHCJS.DOM.Element (setAttribute, getAttribute) #ifdef GHCJS_DOM_DEBUG type DomHasCallStack = (HasCallStack :: Constraint) debugEnabled :: Bool debugEnabled = True #else type DomHasCallStack = (() :: Constraint) debugEnabled :: Bool debugEnabled = False #endif cachedStacks :: IORef (Map String Int, Map Int [(String, SrcLoc)]) cachedStacks = unsafePerformIO $ newIORef (mempty, mempty) {-# NOINLINE cachedStacks #-} lookupStack :: MonadIO m => Int -> m (Maybe [(String, SrcLoc)]) lookupStack n = do (_, intToStack) <- liftIO $ readIORef cachedStacks return $ M.lookup n intToStack getElementStack :: MonadDOM m => Element -> m (Maybe [(String, SrcLoc)]) getElementStack e = getAttribute e ("hs-creator" :: JSString) >>= \case Just a -> case readMaybe a of Just n -> lookupStack n Nothing -> return Nothing Nothing -> return Nothing cacheStack :: MonadIO m => [(String, SrcLoc)] -> m Int cacheStack cs = do let csString = show cs liftIO $ atomicModifyIORef' cachedStacks $ \(stackToInt, intToStack) -> case M.lookup csString stackToInt of Just n -> ((stackToInt, intToStack), n) Nothing -> let n = M.size stackToInt in ((M.insert csString n stackToInt, M.insert n cs intToStack), n)