Revision 12e8358c htools/Ganeti/THH.hs
b/htools/Ganeti/THH.hs | ||
---|---|---|
56 | 56 |
import Control.Monad (liftM) |
57 | 57 |
import Data.Char |
58 | 58 |
import Data.List |
59 |
import Data.Maybe (fromMaybe) |
|
59 | 60 |
import qualified Data.Set as Set |
60 | 61 |
import Language.Haskell.TH |
61 | 62 |
|
... | ... | |
106 | 107 |
customField readfn showfn field = |
107 | 108 |
field { fieldRead = Just (varE readfn), fieldShow = Just (varE showfn) } |
108 | 109 |
|
110 |
-- | Computes the record name for a given field, based on either the |
|
111 |
-- string value in the JSON serialisation or the custom named if any |
|
112 |
-- exists. |
|
109 | 113 |
fieldRecordName :: Field -> String |
110 | 114 |
fieldRecordName (Field { fieldName = name, fieldConstr = alias }) = |
111 |
maybe (camelCase name) id alias
|
|
115 |
fromMaybe (camelCase name) alias
|
|
112 | 116 |
|
113 | 117 |
-- | Computes the preferred variable name to use for the value of this |
114 | 118 |
-- field. If the field has a specific constructor name, then we use a |
... | ... | |
145 | 149 |
|
146 | 150 |
-- * Common field declarations |
147 | 151 |
|
152 |
-- | Timestamp fields description. |
|
148 | 153 |
timeStampFields :: [Field] |
149 | 154 |
timeStampFields = |
150 | 155 |
[ defaultField [| 0::Double |] $ simpleField "ctime" [t| Double |] |
151 | 156 |
, defaultField [| 0::Double |] $ simpleField "mtime" [t| Double |] |
152 | 157 |
] |
153 | 158 |
|
159 |
-- | Serial number fields description. |
|
154 | 160 |
serialFields :: [Field] |
155 | 161 |
serialFields = |
156 | 162 |
[ renameField "Serial" $ simpleField "serial_no" [t| Int |] ] |
157 | 163 |
|
164 |
-- | UUID fields description. |
|
158 | 165 |
uuidFields :: [Field] |
159 | 166 |
uuidFields = [ simpleField "uuid" [t| String |] ] |
160 | 167 |
|
... | ... | |
196 | 203 |
fromRawName :: String -> Name |
197 | 204 |
fromRawName = mkName . (++ "FromRaw") . ensureLower |
198 | 205 |
|
199 |
-- | Converts a name to it's varE/litE representations. |
|
200 |
-- |
|
206 |
-- | Converts a name to it's varE\/litE representations. |
|
201 | 207 |
reprE :: Either String Name -> Q Exp |
202 | 208 |
reprE = either stringE varE |
203 | 209 |
|
... | ... | |
286 | 292 |
-- |
287 | 293 |
-- * /name/FromRaw, which (monadically) converts from a raw type to the type |
288 | 294 |
-- |
289 |
-- Note that this is basically just a custom show/read instance, |
|
295 |
-- Note that this is basically just a custom show\/read instance,
|
|
290 | 296 |
-- nothing else. |
291 | 297 |
declareADT :: Name -> String -> [(String, Name)] -> Q [Dec] |
292 | 298 |
declareADT traw sname cons = do |
... | ... | |
388 | 394 |
-- fname (ConStructorTwo {}) = trans_fun("ConStructorTwo") |
389 | 395 |
-- @ |
390 | 396 |
-- |
391 |
-- This builds a custom list of name/string pairs and then uses |
|
392 |
-- 'genToRaw' to actually generate the function |
|
397 |
-- This builds a custom list of name\/string pairs and then uses
|
|
398 |
-- 'genToRaw' to actually generate the function.
|
|
393 | 399 |
genConstrToStr :: (String -> String) -> Name -> String -> Q [Dec] |
394 | 400 |
genConstrToStr trans_fun name fname = do |
395 | 401 |
cnames <- reifyConsNames name |
... | ... | |
487 | 493 |
sigt <- [t| $(conT (mkName "OpCode")) -> JSON.JSValue |] |
488 | 494 |
return $ (SigD fname sigt, FunD fname cclauses) |
489 | 495 |
|
496 |
-- | Generates load code for a single constructor of the opcode data type. |
|
490 | 497 |
loadConstructor :: String -> [Field] -> Q Exp |
491 | 498 |
loadConstructor sname fields = do |
492 | 499 |
let name = mkName sname |
... | ... | |
496 | 503 |
fstmts' = fstmts ++ [NoBindS (AppE (VarE 'return) cval)] |
497 | 504 |
return $ DoE fstmts' |
498 | 505 |
|
506 |
-- | Generates the loadOpCode function. |
|
499 | 507 |
genLoadOpCode :: [(String, [Field])] -> Q (Dec, Dec) |
500 | 508 |
genLoadOpCode opdefs = do |
501 | 509 |
let fname = mkName "loadOpCode" |
... | ... | |
604 | 612 |
ser_decls <- buildObjectSerialisation sname fields |
605 | 613 |
return $ declD:ser_decls |
606 | 614 |
|
615 |
-- | Generates an object definition: data type and its JSON instance. |
|
607 | 616 |
buildObjectSerialisation :: String -> [Field] -> Q [Dec] |
608 | 617 |
buildObjectSerialisation sname fields = do |
609 | 618 |
let name = mkName sname |
... | ... | |
615 | 624 |
[rdjson, shjson] |
616 | 625 |
return $ savedecls ++ [loadsig, loadfn, instdecl] |
617 | 626 |
|
627 |
-- | Generates the save object functionality. |
|
618 | 628 |
genSaveObject :: (Name -> Field -> Q Exp) |
619 | 629 |
-> String -> [Field] -> Q [Dec] |
620 | 630 |
genSaveObject save_fn sname fields = do |
... | ... | |
636 | 646 |
return [SigD tdname tdsigt, FunD tdname [tclause], |
637 | 647 |
SigD fname sigt, ValD (VarP fname) (NormalB cclause) []] |
638 | 648 |
|
649 |
-- | Generates the code for saving an object's field, handling the |
|
650 |
-- various types of fields that we have. |
|
639 | 651 |
saveObjectField :: Name -> Field -> Q Exp |
640 | 652 |
saveObjectField fvar field |
641 | 653 |
| fisOptional = [| case $(varE fvar) of |
... | ... | |
651 | 663 |
nameE = stringE (fieldName field) |
652 | 664 |
fvarE = varE fvar |
653 | 665 |
|
666 |
-- | Generates the showJSON clause for a given object name. |
|
654 | 667 |
objectShowJSON :: String -> Q Dec |
655 | 668 |
objectShowJSON name = do |
656 | 669 |
body <- [| JSON.showJSON . $(varE . mkName $ "save" ++ name) |] |
657 | 670 |
return $ FunD (mkName "showJSON") [Clause [] (NormalB body) []] |
658 | 671 |
|
672 |
-- | Generates the load object functionality. |
|
659 | 673 |
genLoadObject :: (Field -> Q (Name, Stmt)) |
660 | 674 |
-> String -> [Field] -> Q (Dec, Dec) |
661 | 675 |
genLoadObject load_fn sname fields = do |
... | ... | |
674 | 688 |
return $ (SigD funname sigt, |
675 | 689 |
FunD funname [Clause [VarP arg1] (NormalB (DoE fstmts')) []]) |
676 | 690 |
|
691 |
-- | Generates code for loading an object's field. |
|
677 | 692 |
loadObjectField :: Field -> Q (Name, Stmt) |
678 | 693 |
loadObjectField field = do |
679 | 694 |
let name = fieldVariable field |
... | ... | |
693 | 708 |
|
694 | 709 |
return (fvar, BindS (VarP fvar) bexp) |
695 | 710 |
|
711 |
-- | Builds the readJSON instance for a given object name. |
|
696 | 712 |
objectReadJSON :: String -> Q Dec |
697 | 713 |
objectReadJSON name = do |
698 | 714 |
let s = mkName "s" |
... | ... | |
742 | 758 |
fill_decls <- fillParam sname field_pfx fields |
743 | 759 |
return $ [declF, declP] ++ ser_decls_f ++ ser_decls_p ++ fill_decls |
744 | 760 |
|
761 |
-- | Generates the serialisation for a partial parameter. |
|
745 | 762 |
buildPParamSerialisation :: String -> [Field] -> Q [Dec] |
746 | 763 |
buildPParamSerialisation sname fields = do |
747 | 764 |
let name = mkName sname |
... | ... | |
753 | 770 |
[rdjson, shjson] |
754 | 771 |
return $ savedecls ++ [loadsig, loadfn, instdecl] |
755 | 772 |
|
773 |
-- | Generates code to save an optional parameter field. |
|
756 | 774 |
savePParamField :: Name -> Field -> Q Exp |
757 | 775 |
savePParamField fvar field = do |
758 | 776 |
checkNonOptDef field |
... | ... | |
765 | 783 |
, Match (ConP 'Just [VarP actualVal]) |
766 | 784 |
(NormalB normalexpr) [] |
767 | 785 |
] |
786 |
|
|
787 |
-- | Generates code to load an optional parameter field. |
|
768 | 788 |
loadPParamField :: Field -> Q (Name, Stmt) |
769 | 789 |
loadPParamField field = do |
770 | 790 |
checkNonOptDef field |
... | ... | |
785 | 805 |
$(varNameE $ "f_" ++ fname) |
786 | 806 |
$(varNameE $ "p_" ++ fname) |]) [] |
787 | 807 |
|
808 |
-- | Builds a function that executes the filling of partial parameter |
|
809 |
-- from a full copy (similar to Python's fillDict). |
|
788 | 810 |
fillParam :: String -> String -> [Field] -> Q [Dec] |
789 | 811 |
fillParam sname field_pfx fields = do |
790 | 812 |
let fnames = map (\fd -> field_pfx ++ fieldRecordName fd) fields |
Also available in: Unified diff