packages feed

nirum-0.1.0: src/Nirum/Constructs/Service.hs

{-# LANGUAGE OverloadedStrings #-}
module Nirum.Constructs.Service ( Method ( Method
                                         , methodAnnotations
                                         , methodDocs
                                         , methodName
                                         , parameters
                                         , returnType
                                         )
                                , Parameter(Parameter)
                                , Service(Service, methods)
                                ) where

import qualified Data.Text as T

import Nirum.Constructs (Construct(toCode))
import Nirum.Constructs.Annotation (AnnotationSet)
import Nirum.Constructs.Declaration ( Declaration(name, docs)
                                    , Docs
                                    , toCodeWithPrefix
                                    )
import Nirum.Constructs.DeclarationSet (DeclarationSet, toList)
import Nirum.Constructs.Name (Name)
import Nirum.Constructs.TypeExpression (TypeExpression)

-- | 'Method' parameter.
data Parameter = Parameter Name TypeExpression (Maybe Docs)
                 deriving (Eq, Ord, Show)

instance Construct Parameter where
    toCode (Parameter name' typeExpr docs') =
        T.concat [ toCode typeExpr
                 , " "
                 , toCode name'
                 , ","
                 , toCodeWithPrefix "\n" docs'
                 ]

instance Declaration Parameter where
    name (Parameter name' _ _) = name'
    docs (Parameter _ _ docs') = docs'

-- | 'Service' method.
data Method = Method { methodName :: Name
                     , parameters :: DeclarationSet Parameter
                     , returnType :: TypeExpression
                     , errorType  :: Maybe TypeExpression
                     , methodDocs :: Maybe Docs
                     , methodAnnotations :: AnnotationSet
                     } deriving (Eq, Ord, Show)

instance Construct Method where
    toCode method@Method { parameters = params
                         , errorType = error'
                         , methodDocs = docs'
                         , methodAnnotations = annotationSet'
                         } =
        T.concat $ [ toCode annotationSet'
                   , toCode $ returnType method
                   , " "
                   , toCode $ methodName method
                   , " ("
                   , toCodeWithPrefix "\n  " docs'
                   ] ++ case (docs', params') of
                            (Nothing, []) -> []
                            (Just _, []) -> ["\n"]
                            (Nothing, [p@(Parameter _ _ Nothing)]) ->
                                [T.dropWhileEnd (== ',') $ toCode p]
                            _ -> [ "\n"
                                 , T.intercalate "\n" $ map indentedCode params'
                                 , "\n"
                                 ]
                   ++ [")"]
                   ++ case error' of
                          Nothing -> []
                          Just e -> [" throws ", toCode e]
                   ++ [","]
      where
        params' :: [Parameter]
        params' = toList params
        indentedCode :: Construct a => a -> T.Text
        indentedCode c = T.concat [ "  "
                                  , T.intercalate "\n  " $ T.lines (toCode c)
                                  ]

instance Declaration Method where
    name = methodName
    docs = methodDocs

-- | RPC service.
data Service =
    Service { methods :: DeclarationSet Method } deriving (Eq, Ord, Show)