packages feed

demangler-1.3.2.0: src/Demangler/Context.hs

{-# LANGUAGE TemplateHaskell #-}
module Demangler.Context
  (
    Context
  , Coord
  , newDemangling
  , contextFindOrAdd
  , contextStr
  , WithContext
  , addContext
  , withContext
  , contextData
  , withContextForTemplateArg
  , isTemplateArgContext
  , sayableConstraints
  )
where

import           Data.Sequence ( (|>) )
import qualified Data.Sequence as Seq
import           Data.Text ( Text )
import qualified Language.Haskell.TH as TH

import Text.Sayable


-- | The Context provides a persistent information and collection over a set of
-- demangling calls.  This allows for additional efficiency in memory storage.

-- Note that it can be observed that the stored data here is identifiers, and
-- therefore there are 64 initial characters ('A-Za-z0-9_' + 1 bucket for all
-- others).  This might lead to the use of an Array of Seq or an IntMap of Seq.
-- Both of these were tested in both single and batched mode against
-- approximately 13,000 demanglings: there was no significant different between
-- those more complicated forms and this simple Seq in either time, memory
-- consumption, or garbage collection, so this simplest form is sufficient.

data Context = Context (Seq.Seq Text)

-- | Return an initial Context useable for calls to 'demangle'.

newDemangling :: Context
newDemangling = Context mempty

type Coord = Int


contextFindOrAdd :: Text -> Context -> (Coord, Context)
contextFindOrAdd s c@(Context l) =
  case Seq.elemIndexL s l of
    Just n -> (n, c)
    Nothing -> (Seq.length l, Context $ l |> s)

contextStr :: WithContext a -> Coord -> Text
contextStr (WC _ _ (Context l)) i = l `Seq.index` i

data SayingElement = DefaultSay | SayingTemplateArg

data WithContext a = WC  SayingElement a Context

addContext :: a -> Context -> WithContext a
addContext = WC DefaultSay

withContext :: WithContext a -> b -> WithContext b
withContext (WC s _ c) d = WC s d c

withContextForTemplateArg :: WithContext a -> b -> WithContext b
withContextForTemplateArg (WC _ _ c) d = WC SayingTemplateArg d c

isTemplateArgContext :: WithContext a -> Bool
isTemplateArgContext (WC SayingTemplateArg _ _) = True
isTemplateArgContext _ = False

contextData :: WithContext a -> a
contextData (WC _ d _) = d

sayableConstraints :: TH.Name -> TH.PredQ
sayableConstraints forTy = do
  let rTy = TH.ConT forTy
  wctxt <- [t|WithContext|]
  sayableSubConstraints $ do ofType forTy
                             paramTH rTy
                             subElemFilter (not
                                            . (`elem` [ "Context"
                                                      , "Bool"
                                                      , "Natural"
                                                      , "Float"
                                                      ])
                                             . TH.nameBase)
                             subWrapper wctxt
                             tagVar "saytag"