{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Tshark.TH (
declarePrefixedColumns
, genExplicitRecord
, genRecordFrom
, genRecordFromHeaders
, genRecHashable
)
where
import Tshark.Fields
import Control.Arrow (first, second)
import qualified Data.Text as T
import Data.Word (Word16, Word32, Word64)
import GHC.TypeLits
import Language.Haskell.TH
import Net.IP
-- import Language.Haskell.TH.Syntax
import Data.Vinyl ()
import Language.Haskell.TH.Syntax (Q, sequenceQ)
-- for ( (:->)())
import Frames.Col ()
-- ((:->))
import Frames
import Frames.TH hiding (rowTypeName, tablePrefix)
-- import Frames
import Control.Monad (foldM)
import Data.Char (toLower)
import Data.Map (mapWithKey, toList)
import qualified Data.Map as Map
import Data.Proxy (Proxy(..))
import Frames.Utils
-- WARN the behavior here differs from Frames
declarePrefixedColumns :: Text -> FieldDescriptions -> DecsQ
declarePrefixedColumns prefix fields = do
foldM toto mempty (toList fields)
where
-- acc ++
toto acc (colName, field) = do
-- Note: Frames.declarePrefixedColumn doesn't prefix the colName but the accessors !
-- expects colName lensPrefix type
t <- declarePrefixedColumn (prefix <> colName) prefix (tfieldColType field)
return $ acc ++ t
-- TODO search frames.TH
-- Generates a '[ ]
-- la solution est dans tableTypesText'
-- Generate a FieldRec
-- TODO rename
genRecordFrom :: String -> FieldDescriptions -> DecsQ
genRecordFrom = genRecordFromHeaders ""
-- rename to explicit / upstream
-- ici on presuppose que les colonnes existrent deja en fait ?
genRecordFromHeaders :: String -> String -> FieldDescriptions -> DecsQ
genRecordFromHeaders tablePrefix rowTypeName fields = genExplicitRecord tablePrefix rowTypeName converted
where
converted = map (\(name, field) -> (name, tfieldColType field)) (toList fields)
-- mergedFields :: [(String, Name)]
-- FieldDescriptions
-- tablePrefix here consists in the lenses but not the actual column names
genExplicitRecord :: String -> String -> [(Text, Name)] -> Q [Dec]
genExplicitRecord tablePrefix rowTypeName fields = do
(colTypes, colDecs) <- second concat . unzip
<$> mapM (uncurry mkColDecs) headers
-- let recTy = TySynD (mkName rowTypeName) [] (recDec colTypes)
let recTy = TySynD (mkName rowTypeName) [] (qqDec colTypes)
return [recTy]
where
-- colTypes = map (\(name, field) -> (name, colType field)) fields
-- TODO headers
-- headers :: [(Text, Type)]
headers = zip colNames (repeat (ConT ''T.Text))
-- colNames :: [Text]
colNames = map fst fields
mkColDecs colNm colTy = do
let safeName = T.unpack (sanitizeTypeName colNm)
mColNm <- lookupTypeName (tablePrefix ++ safeName)
case mColNm of
Just n -> pure (ConT n, [])
Nothing -> colDec (T.pack tablePrefix) rowTypeName colNm (Right colTy)
genRecHashable :: String -> FieldDescriptions -> DecsQ
genRecHashable prefix fields = genRecordFrom prefix (Map.filter tfieldHashable fields)
-- inspired from recDec
qqDec :: [Type] -> Type
qqDec = go
where go [] = PromotedNilT
go (t:cs) = AppT (AppT PromotedConsT t) (go cs)
-- TODO make public in Frames
-- table
-- mkColDecs :: T.Text -> Either (String -> Q [Dec]) Type -> Q (Type, [Dec])
-- mkColDecs colNm colTy = do
-- let tablePrefix = ""
-- let rowTypeName = "toto"
-- let safeName = tablePrefix ++ (T.unpack . sanitizeTypeName $ colNm)
-- mColNm <- lookupTypeName safeName
-- case mColNm of
-- Just n -> pure (ConT n, []) -- Column's type was already defined
-- Nothing -> colDec (T.pack tablePrefix) rowTypeName colNm colTy
-- | Generate a column type.
-- recDecExplicit :: [(T.Text, Q Type)] -> Q Type
-- recDecExplicit = appT [t|Record|] . go
-- where go [] = return PromotedNilT
-- go ((n,t):cs) =
-- [t|($(litT $ strTyLit (T.unpack n)) :-> $t) ': $(go cs) |]
-- TODO pass on rowTypeName
-- myRowGen :: String -> [(T.Text, TsharkFieldDesc)] -> DecsQ
-- myRowGen rowName fields = do
-- rowType <- recDecExplicit tfields
-- -- let recTy = TySynD (mkName rowTypeName) [] (recDec colTypes)
-- let recTy = TySynD (mkName rowName) [] rowType
-- colDecs <- concat <$> mapM (uncurry $ colDecExplicit (T.pack tablePrefix)) headers
-- return [recTy]
-- where
-- tfields = map (\(colName, fullField) -> (colName, colType fullField)) fields
--
--myRow :: [(T.Text, TsharkFieldDesc)] -> RowGen a
--myRow fields = RowGen [] "" "|" "HostCols" []
-- where
-- --
-- tfields = map (\(colName, fullField) -> (colName, colType fullField)) fields
-- type CommonColumns = [Bool, Int, Double, T.Text]
-- rowGen :: FilePath -> RowGen CommonColumns
-- myColumnUniverse :: String -> FieldDescriptions -> Q [Dec]
-- myColumnUniverse rowTypeName fields = do
-- let colTys = map (\(_name, x) -> colType x) fields
-- colTypes <- tySynD (mkName rowTypeName) [] (promotedTypeList colTys)
-- -- colTypes <- sequenceQ colTys
-- -- f <- sequenceA (colTypes)
-- return [colTypes]
-- -- return $ tySynD colTys
-- -- where
-- -- colTypes :: Q Type
promotedTypeList :: [Q Type] -> Q Type
promotedTypeList [] = promotedNilT
promotedTypeList (t:ts) = [t| $promotedConsT $t $(promotedTypeList ts) |]