type-machine-0.1.0.0: benchmarks/runtime/Gen.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wno-missing-export-lists #-}
module Gen where
import Control.Monad (forM)
import Control.Monad.Writer.Strict
import Data.Extensible
import Data.Map.Strict (fromList)
import Language.Haskell.TH hiding (Type)
import qualified Language.Haskell.TH as TH
import SuperRecord
import TypeMachine
import TypeMachine.Type (Type (Type))
genWithFieldCount :: Int -> Q [Dec]
genWithFieldCount n = do
tm <- genTMRecord n
superr <- genSuperrecord n
extensible <- genExtensible n
return $ tm ++ superr ++ extensible
withNFields :: Int -> String -> (Int -> Q TH.Type) -> TM Type
withNFields n fieldPrefix getType = do
fields <- forM [0 .. n - 1] $ \i -> do
let fieldName = fieldPrefix ++ show i
fieldType <- lift $ getType i
return (fieldName, (Bang NoSourceUnpackedness SourceStrict, fieldType))
return (Type (TH.mkName "_") (fromList fields) [])
genTMRecord :: Int -> Q [Dec]
genTMRecord n = do
let tyName = "RecordTM" ++ show n
recDef <- type_ tyName $ withNFields n ("field" ++ show n ++ "_") (const [t|Int|])
builder <- genTMRecordBuilder tyName n
sumF <- genTMRecordSum tyName n
return $ recDef ++ builder ++ sumF
genTMRecordBuilder :: String -> Int -> Q [Dec]
genTMRecordBuilder tyName fieldCount =
return
[ PragmaD $ InlineP (mkName fName) NoInline FunLike AllPhases
, FunD
(mkName fName)
[Clause [] (NormalB constructorApp) []]
]
where
constructorApp = foldl (\f arg -> AppE f (LitE $ IntegerL $ fromIntegral arg)) (ConE $ mkName tyName) [0 .. fieldCount - 1]
fName = "mk" ++ tyName
genTMRecordSum :: String -> Int -> Q [Dec]
genTMRecordSum tyName fieldCount = do
body_ <- foldl (\rest arg -> [|$rest + $(varE arg)|]) [|0|] fieldVarNames
sig <- sigD (mkName fName) [t|$(conT $ mkName tyName) -> Int|]
return
[ sig
, PragmaD $ InlineP (mkName fName) NoInline FunLike AllPhases
, FunD (mkName fName) [Clause [pattern_] (NormalB body_) []]
]
where
pattern_ = ConP (mkName tyName) [] (VarP <$> fieldVarNames)
fieldVarNames = mkName . ("f" ++) . show <$> [0 .. fieldCount - 1]
fName = "sum" ++ tyName
----------
genSuperrecord :: Int -> Q [Dec]
genSuperrecord n = do
let tyName = "SuperRRecord" ++ show n
recDef <- genSuperrecordType tyName n
builder <- genSuperrecordBuilder tyName n
sum_ <- genSuperrecordSum tyName n
return $ recDef : builder ++ sum_
genSuperrecordType :: String -> Int -> Q Dec
genSuperrecordType tyName fCount = do
fields <- forM [0 .. fCount - 1] $ \i -> do
let fName = getSuperrecordFieldName fCount i
[t|$(return $ LitT $ StrTyLit fName) := Int|]
ty <- foldr (\arg rest -> [t|$(return arg) ': $rest|]) (return PromotedNilT) fields
return $ TySynD (mkName tyName) [] ty
getSuperrecordFieldName :: Int -> Int -> String
getSuperrecordFieldName fCount idx = "fSR" ++ show fCount ++ "_" ++ show idx
genSuperrecordBuilder :: String -> Int -> Q [Dec]
genSuperrecordBuilder tyName fCount = do
body_ <-
foldr
( \arg rest ->
let label = LabelE $ getSuperrecordFieldName fCount arg
in [|$(return label) := ($(litE $ IntegerL $ fromIntegral arg) :: Int) & $rest|]
)
[|rnil|]
[0 .. fCount - 1]
sig <- sigD fName [t|SuperRecord.Record $(conT $ mkName tyName)|]
return
[ sig
, PragmaD $ InlineP fName NoInline FunLike AllPhases
, FunD fName [Clause [] (NormalB body_) []]
]
where
fName = mkName $ "mk" ++ tyName
genSuperrecordSum :: String -> Int -> Q [Dec]
genSuperrecordSum tyName fCount = do
body_ <-
foldl
( \rest arg ->
let fieldLabel = labelE $ getSuperrecordFieldName fCount arg
fieldGetter = [|get $fieldLabel $(varE rVar)|]
in [|$rest + $fieldGetter|]
)
[|0|]
[0 .. fCount - 1]
sig <- sigD fName [t|SuperRecord.Record $(conT $ mkName tyName) -> Int|]
return
[ sig
, PragmaD $ InlineP fName NoInline FunLike AllPhases
, FunD fName [Clause [VarP rVar] (NormalB body_) []]
]
where
rVar = mkName "r"
fName = mkName $ "sum" ++ tyName
--------------
genExtensible :: Int -> Q [Dec]
genExtensible n = do
let tyName = "ExtensibleRecord" ++ show n
recTy <- genExtensibleType tyName n
builder <- genExtensibleBuilder tyName n
sum_ <- genExtensibleSum tyName n
return $ recTy ++ builder ++ sum_
getExtensibleFieldName :: Int -> Int -> String
getExtensibleFieldName fCount idx = "fE" ++ show fCount ++ "_" ++ show idx
genExtensibleType :: String -> Int -> Q [Dec]
genExtensibleType tyName fCount = do
f <- mkField (unwords fieldNames)
fields <- forM fieldNames $ \fName -> do [t|$(return $ LitT $ StrTyLit fName) Data.Extensible.:> Int|]
fieldsTy <- foldr (\arg rest -> [t|$(return arg) ': $rest|]) (return PromotedNilT) fields
let fieldsTyName = mkName $ tyName ++ "Fields"
ty <- [t|Data.Extensible.Record $(conT fieldsTyName)|]
return $
f
++ [ TySynD fieldsTyName [] fieldsTy
, TySynD (mkName tyName) [] ty
]
where
fieldNames = getExtensibleFieldName fCount <$> [0 .. fCount - 1]
genExtensibleBuilder :: String -> Int -> Q [Dec]
genExtensibleBuilder tyName fCount = do
body_ <-
foldr
( \arg rest ->
let label = LabelE $ getExtensibleFieldName fCount arg
in [|$(return label) @= (($(litE $ IntegerL $ fromIntegral arg)) :: Int) <: $rest|]
)
[|emptyRecord|]
[0 .. fCount - 1]
sig <- sigD fName [t|$(conT $ mkName tyName)|]
return
[ sig
, PragmaD $ InlineP fName NoInline FunLike AllPhases
, FunD fName [Clause [] (NormalB body_) []]
]
where
fName = mkName $ "mk" ++ tyName
genExtensibleSum :: String -> Int -> Q [Dec]
genExtensibleSum tyName fCount = do
body_ <-
foldl
( \rest arg ->
let fieldLabel = labelE $ getExtensibleFieldName fCount arg
fieldGetter = [|$(varE rVar) ^. $fieldLabel|]
in [|$rest + $fieldGetter|]
)
[|0|]
[0 .. fCount - 1]
sig <- sigD fName [t|$(conT $ mkName tyName) -> Int|]
return
[ sig
, PragmaD $ InlineP fName NoInline FunLike AllPhases
, FunD fName [Clause [VarP rVar] (NormalB body_) []]
]
where
rVar = mkName "r"
fName = mkName $ "sum" ++ tyName