1{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE TupleSections #-}
5{-# OPTIONS_GHC -fno-warn-orphans #-}
8-- Copyright : (c) 2015 Brendan Hay
9-- License : Mozilla Public License, v. 2.0.
10-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
11-- Stability : provisional
12-- Portability : non-portable (GHC extensions)
14module Gen.Syntax where
16import Control.Lens hiding (iso, mapping, op, pre,
18import Data.Foldable (foldr')
20import qualified Data.HashMap.Strict as Map
22import Data.Semigroup ((<>))
24import Data.Text (Text)
25import qualified Data.Text as Text
26import Data.Text.Manipulate
31import Language.Haskell.Exts.Build
32import Language.Haskell.Exts.SrcLoc
33import Language.Haskell.Exts.Syntax hiding (Int)
35apiTypes :: Service s r -> Id -> Method -> [Type]
36apiTypes s r m = map sing ps ++ qs ++ [end]
38 ps = filter (not . Text.null)
39 $ Text.split (== '/') (_svcServicePath s)
40 <> Text.split (== '/') (_mPath m)
42 -- FIXME: order by _mParameterOrder
43 qs = map param (Map.toList (_svcParameters s))
44 ++ map param (Map.toList (_mParameters m))
47 -- FIXME: types, many/repeated
48 let t = literal (_prmLiteral p)
50 in case _prmLocation p of
51 Path -> TyApp (TyApp (tycon "Capture") n) t
52 Query -> TyApp (TyApp (tycon "QueryParam") n) t
54 end = TyApp (TyApp meth typ) res
56 meth = TyCon . unqual . Text.unpack $ Text.toTitle (_mMethod m)
58 res = maybe (tycon "()") (tycon . Free) (_mResponse m)
60 -- method (titlecase) '[JSON] (responsetype)
62objDecl :: Id -> Pre -> Map Local Solved -> AST Decl
63objDecl n p rs = DataDecl noLoc arity [] d [] [conDecl d p rs] <$> derivings n
67 arity | Map.size rs == 1 = NewType
68 | otherwise = DataType
70conDecl :: Name -> Pre -> Map Local Solved -> QualConDecl
71conDecl n p rs = QualConDecl noLoc [] [] body
73 body = case Map.toList rs of
75 [x] -> RecDecl n [field internal x]
76 xs -> RecDecl n (map (field (strict . internal)) xs)
78 field f (l, v) = ([fname p l], f (_type v))
80ctorSig :: Id -> Map Local Solved -> Decl
81ctorSig n rs = TypeSig noLoc [cname n] ts
83 ts = foldr' TyFun (TyCon (UnQual (dname n))) ps
84 ps = parameters (Map.elems rs)
86ctorDecl :: Id -> Pre -> Map Local Solved -> Decl
87ctorDecl n p rs = sfun noLoc c ps (UnGuardedRhs rhs) noBinds
92 rhs | Map.null rs = var d
93 | otherwise = RecConstr (UnQual d) $
94 map (uncurry (fieldUpdate p)) (Map.toList rs)
96 ps = map (pname p) . Map.keys $ Map.filter (view required) rs
98fieldUpdate :: Pre -> Local -> Solved -> FieldUpdate
99fieldUpdate p l s = FieldUpdate (UnQual (fname p l)) rhs
101 rhs | s ^. required = v
102 | Just x <- s ^. defaulted = str x
103 | Just x <- iso (_type s) = infixApp x "#" v
104 | otherwise = var (name "Nothing")
108lensSig :: Id -> Pre -> Local -> Solved -> Decl
109lensSig n p l s = TypeSig noLoc [lname p l] $
110 TyApp (TyApp (tycon "Lens'") (tycon n))
113lensDecl :: Pre -> Local -> Solved -> Decl
114lensDecl p l s = sfun noLoc (lname p l) [] (UnGuardedRhs rhs) noBinds
120 app (app (var "lens") (var f))
121 (paren (lamE noLoc [pvar "s", pvar "a"]
122 (RecUpdate (var "s") [FieldUpdate (UnQual f) (var "a")])))
124derivings :: Id -> AST [Deriving]
125derivings k = map ((,[]) . unqual . drop 1 . show) <$> derive k
127parameters :: [Solved] -> [Type]
128parameters = map (external . _type) . filter (view required)
130external, internal :: TType -> Type
131external = internal . \case
132 TMaybe t@TList {} -> t
137 TMaybe t -> TyApp (tycon "Maybe") (internal t)
138 TEither a b -> TyApp (TyApp (tycon "Either") (internal a)) (internal b)
139 TList t -> TyList (internal t)
142literal :: Lit -> Type
146 Time -> tycon "UTCTime"
147 Nat -> tycon "Natural"
148 Float -> tycon "Float"
149 Double -> tycon "Double"
150 Byte -> tycon "Word8"
151 UInt32 -> tycon "Word32"
152 UInt64 -> tycon "Word64"
153 Int32 -> tycon "Int32"
154 Int64 -> tycon "Int64"
156mapping :: TType -> Exp -> Exp
157mapping t e = infixE e "." (go t)
160 TMaybe x@(TList {}) -> var "_Default" : go x
161 TMaybe x -> nest (go x)
162 x -> maybeToList (iso x)
165 nest (x:xs) = [app (var "mapping") (infixE x "." xs)]
167iso :: TType -> Maybe Exp
169 TList {} -> Just (var "_Coerce")
172strict :: Type -> Type
173strict = TyBang BangedTy . \case
174 t@TyApp{} -> TyParen t
178sing = TyCon . unqual . Text.unpack . flip mappend "\"" . mappend "\""
181tycon = TyCon . unqual . Text.unpack . idToText
183unqual :: String -> QName
184unqual = UnQual . name
186infixE :: Exp -> QOp -> [Exp] -> Exp
188infixE l o (r:rs) = infixE (infixApp l o r) o rs
191str = strE . Text.unpack
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list