Safe HaskellNone




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).


Exported types

data Field Source

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 holds t, fieldDefault = Nothing and fieldIsOptional = NotOptional.
Field with a default value.
Then fieldType holds t and fieldDefault = Just exp where exp is an expression of type t and fieldIsOptional = NotOptional.
Optional, no default value.
Then fieldType holds Maybe t, fieldDefault = Nothing and fieldIsOptional is either OptionalOmitNull or OptionalSerializeNull.

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.




fieldName :: String
fieldType :: Q Type

the type of the field, t for non-optional fields, Maybe t for optional ones.

fieldRead :: Maybe (Q Exp)

an optional custom deserialization function of type [(String, JSON.JSValue)] -> JSON.JSValue -> JSON.Result t

fieldShow :: Maybe (Q Exp)

an optional custom serialization function of type t -> (JSON.JSValue, [(String, JSON.JSValue)])

fieldExtraKeys :: [String]

a list of extra keys added by fieldShow

fieldDefault :: Maybe (Q Exp)

an optional default value of type t

fieldSerializeDefault :: Bool

whether not presented default value will be serialized

fieldConstr :: Maybe String
fieldIsOptional :: OptionalType

determines if a field is optional, and if yes, how

fieldDoc :: String
fieldPresentInForthcoming :: Bool

simpleField :: String -> Q Type -> FieldSource

Generates a simple field.

andRestArguments :: String -> FieldSource

Generate an AndRestArguments catch-all field.

withDoc :: String -> Field -> FieldSource

renameField :: String -> Field -> FieldSource

Sets the renamed constructor field.

defaultField :: Q Exp -> Field -> FieldSource

Sets the default value on a field (makes it optional with a default value).

notSerializeDefaultField :: Q Exp -> Field -> FieldSource

A defaultField which will be serialized only if it's value differs from a default value.

presentInForthcoming :: Field -> FieldSource

Mark a field as present in the forthcoming variant.

optionalField :: Field -> FieldSource

Marks a field optional (turning its base type into a Maybe).

optionalNullSerField :: Field -> FieldSource

Marks a field optional (turning its base type into a Maybe), but with Nothing serialised explicitly as null.

makeOptional :: Field -> FieldSource

Make a field optional, if it isn't already.



:: 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.

checkNonOptDef :: Monad m => Field -> m ()Source

parseFn :: Field -> Q Exp -> Q ExpSource

loadFn :: Field -> Q Exp -> Q Exp -> Q ExpSource

loadFnOpt :: Field -> Q Exp -> Q Exp -> Q ExpSource

Internal types

type SimpleField = (String, Q Type)Source

type OpCodeConstructor = (String, Q Type, String, [Field], String)Source

type LuxiConstructor = (String, [Field])Source

Helper functions

ensureLower :: String -> StringSource

ensureUpper :: String -> StringSource

toRawName :: String -> NameSource

fromRawName :: String -> NameSource

reprE :: Either String Name -> Q ExpSource

appCons :: Name -> [Exp] -> ExpSource

appConsApp :: Name -> [Exp] -> ExpSource

buildConsField :: Q Type -> StrictTypeQSource

genSaveSimpleObj :: Name -> String -> SimpleObject -> (SimpleConstructor -> Q Clause) -> Q (Dec, Dec)Source

Template code for simple raw type-equivalent ADTs

strADTDecl :: Name -> [String] -> DecSource

genToRaw :: Name -> Name -> Name -> [(String, Either String Name)] -> Q [Dec]Source

genFromRaw :: Name -> Name -> Name -> [(String, Either String Name)] -> Q [Dec]Source

declareADT :: (a -> Either String Name) -> Name -> String -> [(String, a)] -> Q [Dec]Source

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

genShowJSON :: String -> Q DecSource

genReadJSON :: String -> Q DecSource

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 -> StringSource

Transforms a CamelCase string into an_underscore_based_one.

camelCase :: String -> StringSource

constructorName :: Con -> Q NameSource

reifyConsNames :: Name -> Q [String]Source

genConstrToStr :: (String -> Q String) -> Name -> String -> Q [Dec]Source

genOpID :: Name -> String -> Q [Dec]Source

Constructor-to-string for OpCode.

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




ocfName :: String
ocfType :: PyType
ocfDefl :: Maybe PyValueEx
ocfDoc :: String

data OpCodeDescriptor Source

Transfers opcode data between the opcode description (through genOpCode) and the Python code generation functions.




ocdName :: String
ocdType :: PyType
ocdDoc :: String
ocdFields :: [OpCodeField]
ocdDescr :: String

maybeApp :: Maybe (Q Exp) -> Q Type -> Q ExpSource

pyField :: Field -> Q ExpSource

genOpCodeDictObject :: Name -> (LuxiConstructor -> Q Clause) -> (LuxiConstructor -> Q Exp) -> [LuxiConstructor] -> Q [Dec]Source



:: 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.

genAllOpFields :: String -> [OpCodeConstructor] -> (Dec, Dec)Source

genSaveOpCode :: [LuxiConstructor] -> (LuxiConstructor -> Q Clause) -> Q [Clause]Source

loadConstructor :: Name -> (Field -> Q Exp) -> [Field] -> Q ExpSource

genLoadOpCode :: [LuxiConstructor] -> (LuxiConstructor -> Q Exp) -> Q [Clause]Source

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

fieldTypeInfo :: String -> Field -> Q (Name, Strict, Type)Source

buildObject :: String -> String -> [Field] -> Q [Dec]Source

Build an object declaration.

buildAccessor :: Name -> String -> Name -> String -> Name -> String -> Field -> Q [Dec]Source

buildLens :: (Name, Name) -> (Name, Name) -> Name -> String -> Int -> (Field, Int) -> Q [Dec]Source



:: String

Name of the newly defined type

-> String

base prefix for field names; for the real and fortcoming 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.

defaultToJSArray :: DictObject a => [String] -> a -> [JSValue]Source

defaultFromJSArray :: DictObject a => [String] -> [JSValue] -> Result aSource

genArrayObjectInstance :: Name -> [Field] -> Q DecSource

genDictObject :: (Name -> Field -> Q Exp) -> (Field -> Q Exp) -> String -> [Field] -> Q [Dec]Source

genSaveObject :: String -> Q [Dec]Source

saveObjectField :: Name -> Field -> Q ExpSource

objectShowJSON :: String -> Q DecSource

genLoadObject :: String -> Q (Dec, Dec)Source

objectReadJSON :: String -> Q DecSource

Inheritable parameter tables implementation

paramTypeNames :: String -> (String, String)Source

paramFieldNames :: String -> Field -> (Name, Name)Source

paramFieldTypeInfo :: String -> Field -> VarStrictTypeQSource

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.

buildParamAllFields :: String -> [Field] -> [Dec]Source

buildPParamSerialisation :: String -> [Field] -> Q [Dec]Source

savePParamField :: Name -> Field -> Q ExpSource

fillParam :: String -> String -> [Field] -> Q [Dec]Source

Template code for exceptions

excErrMsg :: (String, Q Type)Source

Exception simple error message field.



:: String

Name of new type

-> SimpleObject

Constructor name and parameters

-> Q [Dec] 

Builds an exception type definition.

saveExcCons :: String -> [SimpleField] -> Q ClauseSource

loadExcConstructor :: Name -> String -> [SimpleField] -> Q ExpSource

genLoadExc :: Name -> String -> SimpleObject -> Q (Dec, Dec)Source

ssconfConstructorName :: String -> StringSource

Compute the ssconf constructor name from its file name.