capnp-0.4.0.0: cmd/capnpc-haskell/Trans/PureToHaskell.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module Trans.PureToHaskell (fileToModules) where
import Data.Word
import Control.Monad (guard)
import Text.Printf (printf)
import qualified Data.Text as T
import IR.Haskell
import Trans.ToHaskellCommon
import qualified IR.Common as C
import qualified IR.Name as Name
import qualified IR.Pure as P
-- | Modules imported by all generated modules.
commonImports :: [Import]
commonImports =
[ ImportAs { importAs = "V", parts = reExp ["Data", "Vector"] }
, ImportAs { importAs = "T", parts = reExp ["Data", "Text"] }
, ImportAs { importAs = "BS", parts = reExp ["Data", "ByteString"] }
, ImportAs { importAs = "Default", parts = reExp ["Data", "Default"] }
, ImportAs { importAs = "Generics", parts = ["GHC", "Generics"] }
, ImportAs { importAs = "MonadIO", parts = ["Control", "Monad", "IO", "Class"] }
, ImportAs { importAs = "UntypedPure", parts = ["Capnp", "Untyped", "Pure"] }
, ImportAs { importAs = "Untyped", parts = ["Capnp", "Untyped"] }
, ImportAs { importAs = "Message", parts = ["Capnp", "Message"] }
, ImportAs { importAs = "Classes", parts = ["Capnp", "Classes"] }
, ImportAs { importAs = "BasicsPure", parts = ["Capnp", "Basics", "Pure" ] }
, ImportAs { importAs = "GenHelpersPure", parts = ["Capnp", "GenHelpers", "Pure"] }
]
-- | Modules imported by generated modules that use rpc.
rpcImports :: [Import]
rpcImports =
[ ImportAs { importAs = "Rpc", parts = ["Capnp", "Rpc", "Untyped"] }
, ImportAs { importAs = "Server", parts = ["Capnp", "Rpc", "Server"] }
, ImportAs { importAs = "RpcHelpers", parts = ["Capnp", "GenHelpers", "Rpc"] }
, ImportAs { importAs = "STM", parts = reExp ["Control", "Concurrent", "STM"] }
, ImportAs { importAs = "Supervisors", parts = reExp ["Supervisors"] }
]
reExp parts = ["Capnp", "GenHelpers", "ReExports"] ++ parts
-- | Whether the serialized and unserialized forms of this type
-- are the same. If not, there is a marshalling step, if so, the
-- accessors work with the decerialized form directly.
--
-- For example, this is True for Enums, basic integers, etc. but
-- False for structs, interfaces, etc.
cerialEq :: C.Type r -> Bool
cerialEq C.VoidType = True
cerialEq (C.WordType _) = True
cerialEq (C.CompositeType _) = False
cerialEq (C.PtrType _) = False
fileToModules :: P.File -> [Module]
fileToModules file =
[ fileToMainModule file
, fileToModuleAlias file
]
fileToModuleAlias :: P.File -> Module
fileToModuleAlias P.File{fileName, fileId} =
let reExport = ["Capnp", "Gen"] ++ makeModName fileName ++ ["Pure"]
in Module
{ modName = idToModule fileId ++ ["Pure"]
, modLangPragmas = []
, modExports = Just [ExportMod reExport]
, modImports = [ ImportAll { parts = reExport } ]
, modDecls = []
}
fileToMainModule :: P.File -> Module
fileToMainModule P.File{fileName, fileId, decls, reExportEnums, usesRpc} =
fixImports $ Module
{ modName = ["Capnp", "Gen"] ++ makeModName fileName ++ ["Pure"]
, modLangPragmas =
[ "DeriveGeneric"
, "DuplicateRecordFields"
, "FlexibleContexts"
, "FlexibleInstances"
, "RecordWildCards"
, "MultiParamTypeClasses"
, "TypeFamilies"
]
, modExports = Just $
[ExportGCtors (gName (rawModule fileId) name) | name <- reExportEnums]
++ concatMap (declToExport fileId) decls
, modImports =
commonImports ++ (guard usesRpc >> rpcImports)
, modDecls =
concatMap (declToDecls fileId) decls
++ concatMap (enumInstances fileId) reExportEnums
}
-- | Convert a declaration into the list of related exports we need.
-- The first argument is the id for this module.
declToExport :: Word64 -> P.Decl -> [Export]
declToExport fileId = \case
P.DataDecl P.Data{typeName} ->
[ ExportLCtors typeName ]
P.ConstDecl P.Constant { name, value=C.WordValue _ _ } ->
[ ExportGName $ gName (rawModule fileId) name ]
P.ConstDecl P.Constant { name, value=C.VoidValue } ->
[ ExportGName $ gName (rawModule fileId) name ]
P.ConstDecl P.Constant { name, value=C.PtrValue _ _ } ->
[ ExportLName name ]
P.IFaceDecl P.IFace{ name=Name.CapnpQ{local} } ->
[ ExportLCtors local
, ExportLCtors (Name.mkSub local "server_")
, ExportLName (Name.unQToLocal $ Name.UnQ $ "export_" <> Name.renderLocalQ local)
]
-- | enumInstances' generates some type class instances an enum data type.
enumInstances :: Word64 -> Name.LocalQ -> [Decl]
enumInstances thisMod name =
let rawName = gName (rawModule thisMod) name in
instance_ [] ["Classes"] "Decerialize" [TGName rawName]
[ iType "Cerial" [tuName "msg", TGName rawName] (TGName rawName)
, iValue "decerialize" [] (eStd_ "pure")
]
: instance_ [] ["Classes"] "Cerialize" [TGName rawName]
[ iValue "cerialize" [PVar "_"] (eStd_ "pure")
]
: [ instance_ [] ["Classes"] "Cerialize" [t]
[ iValue "cerialize" [] (egName ["Classes"] "cerializeBasicVec")
]
| t <- take 6 $ drop 1 $ iterate
(\t -> TApp (tgName ["V"] "Vector") [t])
(TGName rawName)
]
-- | Convert an 'IR.Pure.Decl' into a series of Haskell declarations.
declToDecls :: Word64 -> P.Decl -> [Decl]
declToDecls thisMod (P.DataDecl data_) = dataToDecls thisMod data_
declToDecls thisMod (P.ConstDecl constant) = constToDecls thisMod constant
declToDecls thisMod (P.IFaceDecl iface) = ifaceToDecls thisMod iface
dataToDecls :: Word64 -> P.Data -> [Decl]
dataToDecls thisMod data_@P.Data{firstClass} = concat $
[ dataToDataDecl thisMod data_
, dataToSimpleInstances thisMod data_
, dataToDecerialize thisMod data_
, dataToMarshal thisMod data_
]
++
[ firstClassInstances thisMod data_ | firstClass ]
-- | Get the name of a data constructor for a product type. Arguments are the
-- name of the type constructor and whether or not the type is "first class".
productVariantName :: Name.LocalQ -> Bool -> Name.LocalQ
productVariantName typeName firstClass
| firstClass = typeName
| otherwise = Name.mkSub typeName ""
-- ^ This is a group. If it's part of a union, then the union
-- will have a data constructor that is the same as typeName,
-- so we appent a ' to avoid a colision.
dataToDataDecl :: Word64 -> P.Data -> [Decl]
dataToDataDecl thisMod P.Data
{ typeName
, cerialName
, firstClass
, def
} =
let unknownCtor = Name.mkSub cerialName "unknown'" in
[ DcData Data
{ dataName = Name.localToUnQ typeName
, typeArgs = []
, derives =
["Std_.Show", "Std_.Eq", "Generics.Generic"]
, dataNewtype = False
, dataVariants =
case def of
P.Product fields ->
[ DataVariant
{ dvCtorName = Name.localToUnQ $ productVariantName typeName firstClass
, dvArgs = ARec (map (fieldToField thisMod) fields)
}
]
P.Sum variants ->
[ DataVariant
{ dvCtorName = Name.localToUnQ name
, dvArgs = case arg of
Nothing -> APos []
Just ty -> APos [typeToType thisMod ty]
}
| P.Variant{name, arg} <- variants
]
++
[ DataVariant
{ dvCtorName = Name.localToUnQ unknownCtor
, dvArgs = APos [TPrim $ C.PrimInt $ C.IntType C.Unsigned C.Sz16]
}
]
}
]
dataToSimpleInstances :: Word64 -> P.Data -> [Decl]
dataToSimpleInstances _thisMod P.Data{ typeName } =
[ instance_ [] ["Default"] "Default" [TLName typeName]
[ iValue "def" [] (egName ["GenHelpersPure"] "defaultStruct")
]
, instance_ [] ["Classes"] "FromStruct" [tgName ["Message"] "ConstMsg", TLName typeName]
[ iValue "fromStruct" [PVar "struct"] $ EBind
(EApp (egName ["Classes"] "fromStruct") [euName "struct"])
(egName ["Classes"] "decerialize")
]
]
dataToDecerialize :: Word64 -> P.Data -> [Decl]
dataToDecerialize thisMod P.Data
{ typeName
, cerialName
, firstClass
, def
} =
[ instance_ [] ["Classes"] "Decerialize" [TLName typeName]
[ iType "Cerial" [tuName "msg", TLName typeName] $
TApp (tgName (rawModule thisMod) cerialName) [tuName "msg"]
, iValue "decerialize" [PVar "raw"] $
case def of
P.Sum variants ->
variantsToDecerialize thisMod cerialName variants
P.Product fields ->
fieldsToDecerialize thisMod typeName firstClass fields
]
]
variantsToDecerialize :: Word64 -> Name.LocalQ -> [P.Variant] -> Exp
variantsToDecerialize thisMod cerialName variants =
let unknownCtor = Name.mkSub cerialName "unknown'"
fieldGetter parentName name = egName
(rawModule thisMod)
(Name.unQToLocal $ Name.getterName $ Name.mkSub parentName name)
in
EDo
[DoBind "raw" $ EApp (fieldGetter cerialName "") [euName "raw"]
]
(ECase (ELName "raw") $
[ case arg of
Nothing ->
( pgName (rawModule thisMod) name []
, EApp (eStd_ "pure") [ELName name]
)
Just type_ | cerialEq type_ ->
( pgName (rawModule thisMod) name [PVar "raw"]
, EApp (eStd_ "pure") [EApp (ELName name) [euName "raw"]]
)
Just _ ->
( pgName (rawModule thisMod) name [PVar "raw"]
, EFApp
(ELName name)
[EApp (egName ["Classes"] "decerialize") [euName "raw"]]
)
| P.Variant{name, arg} <- variants
]
++
[ ( pgName (rawModule thisMod) unknownCtor [PVar "tag"]
, EApp
(eStd_ "pure")
[EApp (ELName unknownCtor) [euName "tag"]]
)
]
)
fieldsToDecerialize :: Word64 -> Name.LocalQ -> Bool -> [P.Field] -> Exp
fieldsToDecerialize thisMod typeName firstClass fields =
let fieldGetter parentName name = egName
(rawModule thisMod)
(Name.unQToLocal $ Name.getterName $ Name.mkSub parentName name)
variantName = productVariantName typeName firstClass
in
case fields of
[] ->
EApp (eStd_ "pure") [ELName variantName]
_ ->
EFApp
(ELName variantName)
[
let getter = EApp (fieldGetter typeName name) [euName "raw"] in
if name == "union'" then
-- unions decerialize from the same type as their parents. Don't
-- do anything but pass it off.
EApp (egName ["Classes"] "decerialize") [euName "raw"]
else if cerialEq type_ then
getter
else
EBind getter (egName ["Classes"] "decerialize")
| P.Field{name, type_} <- fields
]
dataToMarshal :: Word64 -> P.Data -> [Decl]
dataToMarshal thisMod P.Data
{ typeName
, cerialName
, firstClass
, def
} =
[ instance_ [] ["Classes"] "Marshal" [TLName typeName]
[ iValue "marshalInto" [PVar "raw_", PVar "value_"] $
case def of
P.Sum variants ->
variantsToMarshal thisMod cerialName variants
P.Product fields ->
fieldsToMarshal thisMod typeName firstClass fields
]
]
variantsToMarshal :: Word64 -> Name.LocalQ -> [P.Variant] -> Exp
variantsToMarshal thisMod cerialName variants =
let unknownCtor = Name.mkSub cerialName "unknown'" in
ECase (euName "value_") $
[ let setter = Name.unQToLocal $ Name.setterName variantName
setExp = EApp (egName (rawModule thisMod) setter) [euName "raw_"]
in case arg of
Nothing ->
( PLCtor variantName []
, setExp
)
Just type_ ->
( PLCtor variantName [PVar "arg_"]
, marshalField MarshalField
{ thisMod
, into = "raw_"
, localQField = variantName
, from = "arg_"
, type_
, inUnion = True
}
)
| P.Variant{name=variantName, arg} <- variants
]
++
let setter = Name.unQToLocal $ Name.setterName unknownCtor in
[ ( PLCtor unknownCtor [PVar "tag"]
, EApp (egName (rawModule thisMod) setter) [euName "raw_", euName "tag"]
)
]
fieldsToMarshal :: Word64 -> Name.LocalQ -> Bool -> [P.Field] -> Exp
fieldsToMarshal thisMod typeName firstClass fields =
let variantName = productVariantName typeName firstClass in
ECase (euName "value_")
[ ( case fields of
-- If there are no fields, use of RecordWildCards will
-- cause an error:
[] -> PLCtor variantName []
_ -> PLRecordWildCard variantName
, EDo
[ DoE $ marshalField MarshalField
{ thisMod
, into = "raw_"
, localQField = Name.mkSub typeName fieldName
, from = fieldName
, type_
, inUnion = False
}
| P.Field{name=fieldName, type_} <- fields
]
ePureUnit
)
]
firstClassInstances :: Word64 -> P.Data -> [Decl]
firstClassInstances _thisMod P.Data{ typeName } =
[ instance_ [] ["Classes"] "Cerialize" [TLName typeName] []
, instance_ [] ["Classes"] "Cerialize" [TApp (tgName ["V"] "Vector") [TLName typeName]]
[ iValue "cerialize" [] (egName ["GenHelpersPure"] "cerializeCompositeVec")
]
] ++
-- Generate instances of Cerialize (Vector (Vector ... t)) up to some reasonable
-- nesting level. I(zenhack) can't figure out how to get a general case
-- Cerialize (Vector a) => Cerialize (Vector (Vector a)) to type check, so this
-- will have to do for now.
[ instance_ [] ["Classes"] "Cerialize" [t]
[ iValue "cerialize" [] (egName ["GenHelpersPure"] "cerializeBasicVec")
]
| t <- take 6 $ drop 2 $ iterate
(\t -> TApp (tgName ["V"] "Vector") [t])
(TLName typeName)
]
ifaceToDecls :: Word64 -> P.Interface -> [Decl]
ifaceToDecls thisMod iface =
[ ifaceClientDecl thisMod iface
, ifaceClassDecl thisMod iface
, ifaceExportFn thisMod iface
]
++
ifaceInstances thisMod iface
-- | Declare the newtype wrapper for clients of this interface.
ifaceClientDecl :: Word64 -> P.Interface -> Decl
ifaceClientDecl _thisMod P.IFace{ name=Name.CapnpQ{local=name} } =
DcData Data
{ dataName = Name.localToUnQ name
, dataNewtype = True
, dataVariants =
[ DataVariant
{ dvCtorName = Name.localToUnQ name
, dvArgs = APos [tgName ["Message"] "Client"]
}
]
, typeArgs = []
, derives =
[ "Std_.Show"
, "Std_.Eq"
, "Generics.Generic"
]
}
-- | define the *'server_ class for the interface.
ifaceClassDecl :: Word64 -> P.Interface -> Decl
ifaceClassDecl thisMod P.IFace { name=Name.CapnpQ{local=name}, methods, supers } =
DcClass
{ ctx =
TApp (tgName ["MonadIO"] "MonadIO") [tuName "m"]
:
-- Add class constraints for superclasses:
[ let superClass = pureTName thisMod fileId (Name.mkSub local "server_")
in TApp superClass [tuName "m", tuName "cap"]
| P.IFace{name=Name.CapnpQ{local, fileId}} <- supers
]
, name = Name.mkSub name "server_"
, params = ["m", "cap"]
, decls =
let mkName = mkMethodName name in
CdMinimal [ mkName name | P.Method{name} <- methods ]
: concat
[ [ CdValueDecl
(mkName methodName)
(TFn
[ tuName "cap"
, TApp
(tgName ["Server"] "MethodHandler")
[ tuName "m"
, typeToType thisMod $ C.CompositeType $ C.StructType paramType
, typeToType thisMod $ C.CompositeType $ C.StructType resultType
]
]
)
, CdValueDef DfValue
{ name = mkName methodName
, params = [PVar "_"]
, value = egName ["Server"] "methodUnimplemented"
}
]
| P.Method
{ name=methodName
, paramType
, resultType
}
<- methods
]
}
-- | Define the export_Foo function for the interface.
ifaceExportFn :: Word64 -> P.Interface -> Decl
ifaceExportFn thisMod iface@P.IFace { name=Name.CapnpQ{ local }, ancestors } =
DcValue
{ typ = TCtx
[TApp (TLName (Name.mkSub local "server_")) [tStd_ "IO", tuName "a"]]
(TFn
[ tgName ["Supervisors"] "Supervisor"
, tuName "a"
, TApp (tgName ["STM"] "STM") [TLName local]
]
)
, def = DfValue
{ name = Name.UnQ $ "export_" <> Name.renderLocalQ local
, params = [PVar "sup_", PVar "server_"]
, value = EFApp (ELName local)
[ EApp (egName ["Rpc"] "export")
[ euName "sup_"
, ERecord (egName ["Server"] "ServerOps")
[ ( "handleStop"
, ePureUnit
) -- TODO
, ( "handleCall"
, ELambda [PVar "interfaceId_", PVar "methodId_"] $
ECase (euName "interfaceId_") $
[ ( PInt (fromIntegral interfaceId)
, ECase (euName "methodId_") $
[ ( PInt i
, EApp
(egName ["Server"] "toUntypedHandler")
[ let methodName = mkMethodName ifaceName mname in
EApp
(if thisMod == ifaceMod
then euName methodName
else egName (pureModule ifaceMod) (Name.unQToLocal methodName)
)
[euName "server_"]
]
)
| (i, P.Method{name=mname}) <- zip [0..] methods
]
++
[ ( PVar "_"
, egName ["Server"] "methodUnimplemented"
)
]
)
| P.IFace
{ name = Name.CapnpQ{local=ifaceName, fileId=ifaceMod}
, interfaceId
, methods
}
<- iface:ancestors
]
++
[ ( PVar "_"
, egName ["Server"] "methodUnimplemented"
)
]
)
]
]
]
}
}
-- | Declare instances for clients for this interface.
ifaceInstances :: Word64 -> P.Interface -> [Decl]
ifaceInstances thisMod iface@P.IFace{ name=Name.CapnpQ{local=name} } =
[ instance_ [] ["Rpc"] "IsClient" [TLName name]
[ iValue "fromClient" [] (ELName name)
, iValue "toClient" [PLCtor name [PVar "client"]] (euName "client")
]
, instance_ [] ["Classes"] "FromPtr" [tuName "msg", TLName name]
[ iValue "fromPtr" [] (egName ["RpcHelpers"] "isClientFromPtr")
]
, instance_ [] ["Classes"] "ToPtr" [tuName "s", TLName name]
[ iValue "toPtr" [] (egName ["RpcHelpers"] "isClientToPtr")
]
, instance_ [] ["Classes"] "Decerialize" [TLName name]
[ iType "Cerial" [tuName "msg", TLName name] $
TApp (tgName (rawModule thisMod) name) [tuName "msg"]
, iValue "decerialize"
[ pgName (rawModule thisMod) (Name.mkSub name "newtype_") [PVar "maybeCap"]
]
(ECase (euName "maybeCap")
[ (PGCtor (std_ "Nothing") []
, EApp
(eStd_ "pure")
[ EApp (ELName name) [egName ["Message"] "nullClient"]
]
)
, (PGCtor (std_ "Just") [PVar "cap"]
, EFApp
(ELName name)
[ EApp (egName ["Untyped"] "getClient") [euName "cap"]]
)
]
)
]
, instance_ [] ["Classes"] "Cerialize" [TLName name]
[ iValue "cerialize" [PVar "msg", PLCtor name [PVar "client"]] $
EFApp
(egName (rawModule thisMod) (Name.mkSub name "newtype_"))
[ EFApp
(eStd_ "Just")
[EApp (egName ["Untyped"] "appendCap") [euName "msg", euName "client"]]
]
]
]
++
ifaceServerInstances thisMod iface
-- | Generate a reference to a type defined in a pure module given:
--
-- * The id of the module we're in (thisMod)
-- * The id of the module in which the type is defined (targetMod)
-- * The local name of the type.
pureTName :: Word64 -> Word64 -> Name.LocalQ -> Type
pureTName thisMod targetMod local
| thisMod == targetMod = TLName local
| otherwise = tgName (pureModule targetMod) local
-- | Instance declarations for this interface's client for its *'server_ class
-- and those of its ancestors.
ifaceServerInstances :: Word64 -> P.Interface -> [Decl]
ifaceServerInstances thisMod iface@P.IFace{ name=Name.CapnpQ{local=name}, ancestors } =
map go (iface:ancestors)
where
go P.IFace { name=Name.CapnpQ{local, fileId}, interfaceId, methods } =
let className = Name.mkSub local "server_"
classType = pureTName thisMod fileId className
in
-- Can't use 'instance_' here, because we don't know ahead of time what
-- module the class is in.
DcInstance
{ ctx = []
, typ =
TApp classType [tStd_ "IO", TLName name]
, defs =
[ let methodName = mkMethodName local mname in
iValue methodName [PLCtor name [PVar "client"]] $
EApp
(egName ["Rpc"] "clientMethodHandler")
[ EInt $ fromIntegral interfaceId
, EInt i
, euName "client"
]
| (i, P.Method{name=mname}) <- zip [0..] methods
]
}
-- | Generate declarations for a constant.
constToDecls :: Word64 -> P.Constant -> [Decl]
constToDecls thisMod P.Constant { name, value } = case value of
C.PtrValue ty _ ->
-- Generated code parses the corresponding constant from the raw
-- module.
[ DcValue
{ typ = typeToType thisMod (C.PtrType ty)
, def = DfValue
{ name = Name.localToUnQ name
, params = []
, value = EApp
(egName ["GenHelpersPure"] "toPurePtrConst")
[egName (rawModule thisMod) name]
}
}
]
-- For these two we just re-export the constant from the raw module, so no
-- need to do anything here:
C.WordValue _ _ -> []
C.VoidValue -> []
mkMethodName :: Name.LocalQ -> Name.UnQ -> Name.UnQ
mkMethodName typeName methodName = Name.valueName $ Name.mkSub typeName methodName
-- | Arguments to 'marshalField'
data MarshalField = MarshalField
{ thisMod :: !Word64
-- ^ The id for the module we're generating
, into :: Name.UnQ
-- ^ An variable holding the destination for the marshalled data.
, localQField :: Name.LocalQ
-- ^ The name of the field to marshal, qualified within the current module.
, from :: Name.UnQ
-- ^ A variable holding the value to marshal
, type_ :: C.Type Name.CapnpQ
, inUnion :: !Bool
-- ^ whether the parent of this field is a union
}
marshalField :: MarshalField -> Exp
marshalField MarshalField{thisMod, into, localQField, from, type_, inUnion} =
let setter = egName (rawModule thisMod) $ Name.unQToLocal (Name.setterName localQField)
getter = egName (rawModule thisMod) $ Name.unQToLocal (Name.getterName localQField)
in case type_ of
C.PtrType _ ->
EBind
(EApp
(egName ["Classes"] "cerialize")
[ EApp (egName ["Untyped"] "message") [euName "raw_"]
, euName from
]
)
(EApp setter [euName into])
C.VoidType ->
ePureUnit
C.WordType _ ->
EApp setter [euName into, euName from]
C.CompositeType _ -> EDo
(if Name.getUnQ localQField == "union'" then
-- Anonymous union; has the same Cerial as us. Just delegate.
[]
else if inUnion then
[ DoBind into $ EApp setter [euName into] ]
else
[ DoBind into $ EApp getter [euName into] ]
)
(EApp (egName ["Classes"] "marshalInto") [euName into, euName from])
fieldToField :: Word64 -> P.Field -> (Name.UnQ, Type)
fieldToField thisMod P.Field{name, type_} = (name, typeToType thisMod type_)
typeToType :: Word64 -> C.Type Name.CapnpQ -> Type
typeToType _thisMod C.VoidType =
TUnit
typeToType _thisMod (C.WordType (C.PrimWord ty)) =
TPrim ty
typeToType _thisMod (C.WordType (C.EnumType Name.CapnpQ{local, fileId})) =
-- Enums are just re-exported from the raw module, we should still
-- refer to them qualified even if they're in the file we're generated
-- from:
tgName (rawModule fileId) local
typeToType thisMod (C.CompositeType (C.StructType n)) =
nameToType thisMod n
typeToType thisMod (C.PtrType (C.PtrComposite (C.StructType n))) =
nameToType thisMod n
typeToType thisMod (C.PtrType (C.ListOf ty)) =
TApp (tgName ["V"] "Vector") [typeToType thisMod ty]
typeToType _thisMod (C.PtrType (C.PrimPtr C.PrimText)) =
tgName ["T"] "Text"
typeToType _thisMod (C.PtrType (C.PrimPtr C.PrimData)) =
tgName ["BS"] "ByteString"
typeToType _thisMod (C.PtrType (C.PrimPtr (C.PrimAnyPtr _))) =
-- TODO: distinguish different pointer types.
TApp (tStd_ "Maybe") [tgName ["UntypedPure"] "Ptr"]
typeToType thisMod (C.PtrType (C.PtrInterface n)) =
nameToType thisMod n
nameToType :: Word64 -> Name.CapnpQ -> Type
nameToType thisMod Name.CapnpQ{local, fileId}
| thisMod == fileId = TLName local
| otherwise = tgName (pureModule fileId) local
rawModule :: Word64 -> [T.Text]
rawModule modId =
["Capnp", "Gen", "ById", T.pack $ printf "X%x" modId]
pureModule :: Word64 -> [T.Text]
pureModule modId =
rawModule modId ++ ["Pure"]