Revision 53664e15
b/htools/Ganeti/THH.hs | ||
---|---|---|
43 | 43 |
|
44 | 44 |
import qualified Text.JSON as JSON |
45 | 45 |
|
46 |
-- * Helper functions |
|
47 |
|
|
46 | 48 |
-- | Ensure first letter is lowercase. |
47 | 49 |
-- |
48 | 50 |
-- Used to convert type name to function prefix, e.g. in @data Aa -> |
... | ... | |
51 | 53 |
ensureLower [] = [] |
52 | 54 |
ensureLower (x:xs) = toLower x:xs |
53 | 55 |
|
56 |
-- | Helper for quoted expressions. |
|
57 |
varNameE :: String -> Q Exp |
|
58 |
varNameE = varE . mkName |
|
59 |
|
|
60 |
-- | showJSON as an expression, for reuse. |
|
61 |
showJSONE :: Q Exp |
|
62 |
showJSONE = varNameE "showJSON" |
|
63 |
|
|
54 | 64 |
-- | ToString function name. |
55 | 65 |
toStrName :: String -> Name |
56 | 66 |
toStrName = mkName . (++ "ToString") . ensureLower |
... | ... | |
62 | 72 |
-- | Converts a name to it's varE/litE representations. |
63 | 73 |
-- |
64 | 74 |
reprE :: Either String Name -> Q Exp |
65 |
reprE (Left name) = litE (StringL name) |
|
66 |
reprE (Right name) = varE name |
|
75 |
reprE = either stringE varE |
|
76 |
|
|
77 |
-- * Template code for simple string-equivalent ADTs |
|
67 | 78 |
|
68 | 79 |
-- | Generates a data type declaration. |
69 | 80 |
-- |
... | ... | |
183 | 194 |
JSON.Ok s' -> $(varE (fromStrName name)) s' |
184 | 195 |
JSON.Error e -> |
185 | 196 |
JSON.Error $ "Can't parse string value for type " ++ |
186 |
$(litE (StringL name)) ++ ": " ++ e
|
|
197 |
$(stringE name) ++ ": " ++ e
|
|
187 | 198 |
|] |
188 | 199 |
return $ FunD (mkName "readJSON") [Clause [VarP s] (NormalB body) []] |
189 | 200 |
|
... | ... | |
198 | 209 |
readJ <- genReadJSON base |
199 | 210 |
return [InstanceD [] (AppT (ConT ''JSON.JSON) (ConT name)) (readJ:showJ)] |
200 | 211 |
|
212 |
-- * Template code for opcodes |
|
213 |
|
|
201 | 214 |
-- | Transforms a CamelCase string into an_underscore_based_one. |
202 | 215 |
deCamelCase :: String -> String |
203 | 216 |
deCamelCase = |
... | ... | |
282 | 295 |
-> Q Exp |
283 | 296 |
saveField fvar (fname, qt, _) = do |
284 | 297 |
t <- qt |
285 |
let showJ = varE (mkName "showJSON") |
|
286 |
fnexp = litE (stringL fname) |
|
298 |
let fnexp = stringE fname |
|
287 | 299 |
fvare = varE fvar |
288 | 300 |
(if isOptional t |
289 | 301 |
then [| case $fvare of |
290 |
Just v' -> [( $fnexp, $showJ v')] |
|
302 |
Just v' -> [( $fnexp, $showJSONE v')]
|
|
291 | 303 |
Nothing -> [] |
292 | 304 |
|] |
293 |
else [| [( $fnexp, $showJ $fvare )] |]) |
|
305 |
else [| [( $fnexp, $showJSONE $fvare )] |])
|
|
294 | 306 |
|
295 | 307 |
-- | Generates the \"save\" clause for an entire opcode constructor. |
296 | 308 |
-- |
... | ... | |
307 | 319 |
let pat = conP cname (map varP fnames) |
308 | 320 |
let felems = map (uncurry saveField) (zip fnames fields) |
309 | 321 |
-- now build the OP_ID serialisation |
310 |
opid = [| [( $(litE (stringL "OP_ID")), |
|
311 |
$(varE (mkName "showJSON")) |
|
312 |
$(litE . stringL . deCamelCase $ sname) )] |] |
|
322 |
opid = [| [( $(stringE "OP_ID"), |
|
323 |
$showJSONE $(stringE . deCamelCase $ sname) )] |] |
|
313 | 324 |
flist = listE (opid:felems) |
314 | 325 |
-- and finally convert all this to a json object |
315 |
flist' = [| $(varE (mkName "makeObj")) (concat $flist) |]
|
|
326 |
flist' = [| $(varNameE "makeObj") (concat $flist) |]
|
|
316 | 327 |
clause [pat] (normalB flist') [] |
317 | 328 |
|
318 | 329 |
-- | Generates the main save opcode function. |
... | ... | |
339 | 350 |
t <- qt |
340 | 351 |
defa <- qdefa |
341 | 352 |
-- these are used in all patterns below |
342 |
let objvar = varE (mkName "o")
|
|
343 |
objfield = litE (StringL fname)
|
|
353 |
let objvar = varNameE "o"
|
|
354 |
objfield = stringE fname
|
|
344 | 355 |
bexp <- if isOptional t |
345 |
then [| $((varE (mkName "maybeFromObj"))) $objvar $objfield |]
|
|
356 |
then [| $((varNameE "maybeFromObj")) $objvar $objfield |]
|
|
346 | 357 |
else case defa of |
347 | 358 |
AppE (ConE dt) defval | dt == 'Just -> |
348 | 359 |
-- but has a default value |
349 |
[| $(varE (mkName "fromObjWithDefault"))
|
|
360 |
[| $(varNameE "fromObjWithDefault")
|
|
350 | 361 |
$objvar $objfield $(return defval) |] |
351 | 362 |
ConE dt | dt == 'Nothing -> |
352 |
[| $(varE (mkName "fromObj")) $objvar $objfield |]
|
|
363 |
[| $(varNameE "fromObj") $objvar $objfield |]
|
|
353 | 364 |
s -> fail $ "Invalid default value " ++ show s ++ |
354 | 365 |
", expecting either 'Nothing' or a 'Just defval'" |
355 | 366 |
return (fvar, BindS (VarP fvar) bexp) |
... | ... | |
371 | 382 |
opid = mkName "op_id" |
372 | 383 |
st1 <- bindS (varP objname) [| liftM JSON.fromJSObject |
373 | 384 |
(JSON.readJSON $(varE arg1)) |] |
374 |
st2 <- bindS (varP opid) [| $(varE (mkName "fromObj"))
|
|
375 |
$(varE objname) $(litE (stringL "OP_ID")) |]
|
|
385 |
st2 <- bindS (varP opid) [| $(varNameE "fromObj")
|
|
386 |
$(varE objname) $(stringE "OP_ID") |]
|
|
376 | 387 |
-- the match results (per-constructor blocks) |
377 | 388 |
mexps <- mapM (uncurry loadConstructor) opdefs |
378 | 389 |
fails <- [| fail $ "Unknown opcode " ++ $(varE opid) |] |
Also available in: Unified diff