Revision a0090487 htools/Ganeti/THH.hs

b/htools/Ganeti/THH.hs
34 34
                  , genOpID
35 35
                  , genOpCode
36 36
                  , noDefault
37
                  , genStrOfOp
38
                  , genStrOfKey
39
                  , genLuxiOp
37 40
                  ) where
38 41

  
39 42
import Control.Monad (liftM)
......
222 225
constructorName (RecC name _)    = return name
223 226
constructorName x                = fail $ "Unhandled constructor " ++ show x
224 227

  
225
-- | Builds the constructor-to-string function.
228
-- | Builds the generic constructor-to-string function.
226 229
--
227 230
-- This generates a simple function of the following form:
228 231
--
229 232
-- @
230
-- fname (ConStructorOne {}) = "CON_STRUCTOR_ONE"
231
-- fname (ConStructorTwo {}) = "CON_STRUCTOR_TWO"
233
-- fname (ConStructorOne {}) = trans_fun("ConStructorOne")
234
-- fname (ConStructorTwo {}) = trans_fun("ConStructorTwo")
232 235
-- @
233 236
--
234 237
-- This builds a custom list of name/string pairs and then uses
235 238
-- 'genToString' to actually generate the function
236
genOpID :: Name -> String -> Q [Dec]
237
genOpID name fname = do
239
genConstrToStr :: (String -> String) -> Name -> String -> Q [Dec]
240
genConstrToStr trans_fun name fname = do
238 241
  TyConI (DataD _ _ _ cons _) <- reify name
239 242
  cnames <- mapM (liftM nameBase . constructorName) cons
240
  let svalues = map (Left . deCamelCase) cnames
243
  let svalues = map (Left . trans_fun) cnames
241 244
  genToString (mkName fname) name $ zip cnames svalues
242 245

  
246
-- | Constructor-to-string for OpCode.
247
genOpID :: Name -> String -> Q [Dec]
248
genOpID = genConstrToStr deCamelCase
243 249

  
244 250
-- | OpCode parameter (field) type
245 251
type OpParam = (String, Q Type, Q Exp)
......
400 406
-- | No default type.
401 407
noDefault :: Q Exp
402 408
noDefault = conE 'Nothing
409

  
410
-- * Template code for luxi
411

  
412
-- | Constructor-to-string for LuxiOp.
413
genStrOfOp :: Name -> String -> Q [Dec]
414
genStrOfOp = genConstrToStr id
415

  
416
-- | Constructor-to-string for MsgKeys.
417
genStrOfKey :: Name -> String -> Q [Dec]
418
genStrOfKey = genConstrToStr ensureLower
419

  
420
-- | LuxiOp parameter type.
421
type LuxiParam = (String, Q Type, Q Exp)
422

  
423
-- | Generates the LuxiOp data type.
424
--
425
-- This takes a Luxi operation definition and builds both the
426
-- datatype and the function trnasforming the arguments to JSON.
427
-- We can't use anything less generic, because the way different
428
-- operations are serialized differs on both parameter- and top-level.
429
--
430
-- There are three things to be defined for each parameter:
431
--
432
-- * name
433
--
434
-- * type
435
--
436
-- * operation; this is the operation performed on the parameter before
437
--   serialization
438
--
439
genLuxiOp :: String -> [(String, [LuxiParam], Q Exp)] -> Q [Dec]
440
genLuxiOp name cons = do
441
  decl_d <- mapM (\(cname, fields, _) -> do
442
                    fields' <- mapM (\(_, qt, _) ->
443
                                         qt >>= \t -> return (NotStrict, t))
444
                               fields
445
                    return $ NormalC (mkName cname) fields')
446
            cons
447
  let declD = DataD [] (mkName name) [] decl_d [''Show, ''Read]
448
  (savesig, savefn) <- genSaveLuxiOp cons
449
  return [declD, savesig, savefn]
450

  
451
-- | Generates the \"save\" clause for entire LuxiOp constructor.
452
saveLuxiConstructor :: (String, [LuxiParam], Q Exp) -> Q Clause
453
saveLuxiConstructor (sname, fields, finfn) =
454
  let cname = mkName sname
455
      fnames = map (\(nm, _, _) -> mkName nm) fields
456
      pat = conP cname (map varP fnames)
457
      flist = map (\(nm, _, fn) -> appE fn $ varNameE nm) fields
458
      finval = appE finfn (tupE flist)
459
  in
460
    clause [pat] (normalB finval) []
461

  
462
-- | Generates the main save LuxiOp function.
463
genSaveLuxiOp :: [(String, [LuxiParam], Q Exp)] -> Q (Dec, Dec)
464
genSaveLuxiOp opdefs = do
465
  sigt <- [t| $(conT (mkName "LuxiOp")) -> JSON.JSValue |]
466
  let fname = mkName "opToArgs"
467
  cclauses <- mapM saveLuxiConstructor opdefs
468
  return $ (SigD fname sigt, FunD fname cclauses)

Also available in: Unified diff