Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / THH / PyType.hs @ 6897a51e

History | View | Annotate | Download (3.9 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| PyType helper for Ganeti Haskell code.
4

    
5
-}
6

    
7
{-
8

    
9
Copyright (C) 2013 Google Inc.
10

    
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation; either version 2 of the License, or
14
(at your option) any later version.
15

    
16
This program is distributed in the hope that it will be useful, but
17
WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
General Public License for more details.
20

    
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
02110-1301, USA.
25

    
26
-}
27
module Ganeti.THH.PyType
28
  ( PyType(..)
29
  , pyType
30
  , pyOptionalType
31
  ) where
32

    
33
import Control.Applicative
34
import Control.Monad
35
import Data.List (intercalate)
36
import Language.Haskell.TH
37
import Language.Haskell.TH.Syntax (Lift(..))
38

    
39
import Ganeti.PyValue
40

    
41

    
42
-- | Represents a Python encoding of types.
43
data PyType
44
    = PTMaybe PyType
45
    | PTApp PyType [PyType]
46
    | PTOther String
47
    | PTAny
48
    | PTDictOf
49
    | PTListOf
50
    | PTNone
51
    | PTObject
52
    | PTOr
53
    | PTSetOf
54
    | PTTupleOf
55
  deriving (Show, Eq, Ord)
56

    
57
-- TODO: We could use th-lift to generate this instance automatically.
58
instance Lift PyType where
59
  lift (PTMaybe x)   = [| PTMaybe x |]
60
  lift (PTApp tf as) = [| PTApp tf as |]
61
  lift (PTOther i)   = [| PTOther i |]
62
  lift PTAny         = [| PTAny |]
63
  lift PTDictOf      = [| PTDictOf |]
64
  lift PTListOf      = [| PTListOf |]
65
  lift PTNone        = [| PTNone |]
66
  lift PTObject      = [| PTObject |]
67
  lift PTOr          = [| PTOr |]
68
  lift PTSetOf       = [| PTSetOf |]
69
  lift PTTupleOf     = [| PTTupleOf |]
70

    
71
instance PyValue PyType where
72
  showValue (PTMaybe x)   = ptApp (ht "Maybe") [x]
73
  showValue (PTApp tf as) = ptApp (showValue tf) as
74
  showValue (PTOther i)   = ht i
75
  showValue PTAny         = ht "Any"
76
  showValue PTDictOf      = ht "DictOf"
77
  showValue PTListOf      = ht "ListOf"
78
  showValue PTNone        = ht "None"
79
  showValue PTObject      = ht "Object"
80
  showValue PTOr          = ht "Or"
81
  showValue PTSetOf       = ht "SetOf"
82
  showValue PTTupleOf     = ht "TupleOf"
83

    
84
ht :: String -> String
85
ht = ("ht.T" ++)
86

    
87
ptApp :: String -> [PyType] -> String
88
ptApp name ts = name ++ "(" ++ intercalate ", " (map showValue ts) ++ ")"
89

    
90
-- | Converts a Haskell type name into a Python type name.
91
pyTypeName :: Name -> PyType
92
pyTypeName name =
93
  case nameBase name of
94
                "()"                -> PTNone
95
                "Map"               -> PTDictOf
96
                "Set"               -> PTSetOf
97
                "ListSet"           -> PTSetOf
98
                "Either"            -> PTOr
99
                "GenericContainer"  -> PTDictOf
100
                "JSValue"           -> PTAny
101
                "JSObject"          -> PTObject
102
                str                 -> PTOther str
103

    
104
-- | Converts a Haskell type into a Python type.
105
pyType :: Type -> Q PyType
106
pyType t | not (null args)  = PTApp `liftM` pyType fn `ap` mapM pyType args
107
  where (fn, args) = pyAppType t
108
pyType (ConT name)          = return $ pyTypeName name
109
pyType ListT                = return PTListOf
110
pyType (TupleT 0)           = return PTNone
111
pyType (TupleT _)           = return PTTupleOf
112
pyType typ                  = fail $ "unhandled case for type " ++ show typ
113

    
114
-- | Returns a type and its type arguments.
115
pyAppType :: Type -> (Type, [Type])
116
pyAppType = g []
117
  where
118
    g as (AppT typ1 typ2) = g (typ2 : as) typ1
119
    g as typ              = (typ, as)
120

    
121
-- | @pyType opt typ@ converts Haskell type @typ@ into a Python type,
122
-- where @opt@ determines if the converted type is optional (i.e.,
123
-- Maybe).
124
pyOptionalType :: Bool -> Type -> Q PyType
125
pyOptionalType True  typ = PTMaybe <$> pyType typ
126
pyOptionalType False typ = pyType typ