Safe Haskell | None |
---|
Ganeti.THH
Contents
Description
TemplateHaskell helper for Ganeti Haskell code.
As TemplateHaskell require that splices be defined in a separate module, we combine all the TemplateHaskell functionality that HTools needs in this module (except the one for unittests).
Synopsis
- data Field = Field {
- fieldName :: Text
- fieldType :: Q Type
- fieldRead :: Maybe (Q Exp)
- fieldShow :: Maybe (Q Exp)
- fieldExtraKeys :: [Text]
- fieldDefault :: Maybe (Q Exp)
- fieldSerializeDefault :: Bool
- fieldConstr :: Maybe Text
- fieldIsOptional :: OptionalType
- fieldDoc :: Text
- fieldPresentInForthcoming :: Bool
- simpleField :: String -> Q Type -> Field
- andRestArguments :: String -> Field
- withDoc :: String -> Field -> Field
- renameField :: String -> Field -> Field
- defaultField :: Q Exp -> Field -> Field
- notSerializeDefaultField :: Q Exp -> Field -> Field
- presentInForthcoming :: Field -> Field
- optionalField :: Field -> Field
- optionalNullSerField :: Field -> Field
- makeOptional :: Field -> Field
- customField :: Name -> Name -> [String] -> Field -> Field
- declareLADT :: Name -> String -> [(String, String)] -> Q [Dec]
- declareILADT :: String -> [(String, Int)] -> Q [Dec]
- declareIADT :: String -> [(String, Name)] -> Q [Dec]
- declareSADT :: String -> [(String, Name)] -> Q [Dec]
- makeJSONInstance :: Name -> Q [Dec]
- deCamelCase :: String -> String
- genOpID :: Name -> String -> Q [Dec]
- genOpLowerStrip :: String -> Name -> String -> Q [Dec]
- genAllConstr :: (String -> String) -> Name -> String -> Q [Dec]
- genAllOpIDs :: Name -> String -> Q [Dec]
- data OpCodeField = OpCodeField {}
- data OpCodeDescriptor = OpCodeDescriptor {}
- genOpCode :: String -> [OpCodeConstructor] -> Q [Dec]
- genStrOfOp :: Name -> String -> Q [Dec]
- genStrOfKey :: Name -> String -> Q [Dec]
- genLuxiOp :: String -> [LuxiConstructor] -> Q [Dec]
- buildObject :: String -> String -> [Field] -> Q [Dec]
- buildObjectWithForthcoming :: String -> String -> [Field] -> Q [Dec]
- buildObjectSerialisation :: String -> [Field] -> Q [Dec]
- buildParam :: String -> String -> [Field] -> Q [Dec]
- excErrMsg :: (String, Q Type)
- genException :: String -> SimpleObject -> Q [Dec]
- ssconfConstructorName :: String -> String
Exported types
Serialised field data type describing how to generate code for the field.
Each field has a type, which isn't captured in the type of the data type,
but is saved in the Q
monad in fieldType
.
Let t
be a type we want to parametrize the field with. There are the
following possible types of fields:
- Mandatory with no default.
- Then
fieldType
holdst
,fieldDefault = Nothing
andfieldIsOptional = NotOptional
. - Field with a default value.
- Then
fieldType
holdst
andfieldDefault = Just exp
whereexp
is an expression of typet
andfieldIsOptional = NotOptional
. - Optional, no default value.
- Then
fieldType
holdsMaybe t
,fieldDefault = Nothing
andfieldIsOptional
is eitherOptionalOmitNull
orOptionalSerializeNull
.
Optional fields with a default value are prohibited, as their main intention is to represent the information that a request didn't contain the field data.
Custom (de)serialization:
Field can have custom (de)serialization functions that are stored in
fieldRead
and fieldShow
. If they aren't provided, the default is to use
readJSON
and showJSON
for the field's type t
. If they are provided,
the type of the contained deserializing expression must be
[(String, JSON.JSValue)] -> JSON.JSValue -> JSON.Result t
where the first argument carries the whole record in the case the deserializing function needs to process additional information.
The type of the contained serializing experssion must be
t -> (JSON.JSValue, [(String, JSON.JSValue)])
where the result can provide extra JSON fields to include in the output
record (or just return []
if they're not needed).
Note that for optional fields the type appearing in the custom functions
is still t
. Therefore making a field optional doesn't change the
functions.
There is also a special type of optional field AndRestArguments
which
allows to parse any additional arguments not covered by other fields. There
can be at most one such special field and it's type must be
Map String JSON.JSValue
. See also andRestArguments
.
Constructors
Field | |
Fields
|
simpleField :: String -> Q Type -> Field Source #
Generates a simple field.
andRestArguments :: String -> Field Source #
Generate an AndRestArguments catch-all field.
renameField :: String -> Field -> Field Source #
Sets the renamed constructor field.
defaultField :: Q Exp -> Field -> Field Source #
Sets the default value on a field (makes it optional with a default value).
notSerializeDefaultField :: Q Exp -> Field -> Field Source #
A defaultField which will be serialized only if it's value differs from a default value.
presentInForthcoming :: Field -> Field Source #
Mark a field as present in the forthcoming variant.
optionalField :: Field -> Field Source #
Marks a field optional (turning its base type into a Maybe).
optionalNullSerField :: Field -> Field Source #
Marks a field optional (turning its base type into a Maybe), but
with Nothing
serialised explicitly as null.
makeOptional :: Field -> Field Source #
Make a field optional, if it isn't already.
Arguments
:: Name | The name of the read function |
-> Name | The name of the show function |
-> [String] | The name of extra field keys |
-> Field | The original field |
-> Field | Updated field |
Sets custom functions on a field.
Internal types
Helper functions
Template code for simple raw type-equivalent ADTs
declareLADT :: Name -> String -> [(String, String)] -> Q [Dec] Source #
declareILADT :: String -> [(String, Int)] -> Q [Dec] Source #
declareIADT :: String -> [(String, Name)] -> Q [Dec] Source #
declareSADT :: String -> [(String, Name)] -> Q [Dec] Source #
makeJSONInstance :: Name -> Q [Dec] Source #
Generates a JSON instance for a given type.
This assumes that the nameToRaw and nameFromRaw functions
have been defined as by the declareSADT
function.
Template code for opcodes
deCamelCase :: String -> String Source #
Transforms a CamelCase string into an_underscore_based_one.
genOpLowerStrip :: String -> Name -> String -> Q [Dec] Source #
Strips Op
from the constructor name, converts to lower-case
and adds a given prefix.
genAllConstr :: (String -> String) -> Name -> String -> Q [Dec] Source #
Builds a list with all defined constructor names for a type.
vstr :: String vstr = [...]
Where the actual values of the string are the constructor names
mapped via trans_fun
.
genAllOpIDs :: Name -> String -> Q [Dec] Source #
Generates a list of all defined opcode IDs.
Python code generation
data OpCodeField Source #
data OpCodeDescriptor Source #
Transfers opcode data between the opcode description (through
genOpCode
) and the Python code generation functions.
Constructors
OpCodeDescriptor | |
Arguments
:: String | Type name to use |
-> [OpCodeConstructor] | Constructor name and parameters |
-> Q [Dec] |
Generates the OpCode data type.
This takes an opcode logical definition, and builds both the datatype and the JSON serialisation out of it. We can't use a generic serialisation since we need to be compatible with Ganeti's own, so we have a few quirks to work around.
Template code for luxi
genStrOfOp :: Name -> String -> Q [Dec] Source #
Constructor-to-string for LuxiOp.
genStrOfKey :: Name -> String -> Q [Dec] Source #
Constructor-to-string for MsgKeys.
genLuxiOp :: String -> [LuxiConstructor] -> Q [Dec] Source #
Generates the LuxiOp data type.
This takes a Luxi operation definition and builds both the datatype and the function transforming the arguments to JSON. We can't use anything less generic, because the way different operations are serialized differs on both parameter- and top-level.
There are two things to be defined for each parameter:
- name
- type
Objects functionality
buildObject :: String -> String -> [Field] -> Q [Dec] Source #
Build an object declaration.
buildObjectWithForthcoming Source #
Arguments
:: String | Name of the newly defined type |
-> String | base prefix for field names; for the real and forthcoming variant, with base prefix will be prefixed with "real" and forthcoming, respectively. |
-> [Field] | List of fields in the real version |
-> Q [Dec] |
Build an object that can have a forthcoming variant. This will create 3 data types: two objects, prefixed by Real and Forthcoming, respectively, and a sum type of those. The JSON representation of the latter will be a JSON object, dispatching on the "forthcoming" key.
buildObjectSerialisation :: String -> [Field] -> Q [Dec] Source #
Generates an object definition: data type and its JSON instance.
Inheritable parameter tables implementation
buildParam :: String -> String -> [Field] -> Q [Dec] Source #
Build a parameter declaration.
This function builds two different data structures: a filled one, in which all fields are required, and a partial one, in which all fields are optional. Due to the current record syntax issues, the fields need to be named differrently for the two structures, so the partial ones get a P suffix. Also generate a default value for the partial parameters.
Template code for exceptions
Arguments
:: String | Name of new type |
-> SimpleObject | Constructor name and parameters |
-> Q [Dec] |
Builds an exception type definition.
ssconfConstructorName :: String -> String Source #
Compute the ssconf constructor name from its file name.