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