packages feed

polyglot-0.1.1.0: src/Parsers/Haskell/Type.hs

module Parsers.Haskell.Type where


import Bookhound.Parser              (Parser)
import Bookhound.ParserCombinators   (IsMatch (is), multipleSepBy, (<|>),
                                      (|+))
import Bookhound.Parsers.Char        (comma, dot, lower, upper)
import Bookhound.Parsers.Collections (tupleOf)
import Bookhound.Parsers.String      (maybeWithinParens, withinParens,
                                      withinSquareBrackets)

import Parsers.Haskell.Common   (ident, notReserved, qClass, qTerm')
import SyntaxTrees.Haskell.Type (AnyKindedType (..), ClassConstraint (..),
                                 QTypeCtor (QTypeCtor), QTypeVar (QTypeVar),
                                 Type (..), TypeCtor (..), TypeParam (..),
                                 TypeVar (..))

typeParam :: Parser TypeParam
typeParam = TypeParam <$> notReserved (ident lower)

typeVar :: Parser TypeVar
typeVar = TypeVar  <$> ident upper <|>
          UnitType <$ is "()"

typeCtor :: Parser TypeCtor
typeCtor = TypeCtor  <$> ident upper <|>
           Arrow     <$  is "(->)"   <|>
           TupleType <$  is "(,)"    <|>
           ListType  <$  is "[]"

anyKindedType :: Parser AnyKindedType
anyKindedType = TypeValue <$> type'     <|>
                TypeFn    <$> qTypeCtor


classConstraints :: Parser Type -> Parser [ClassConstraint]
classConstraints typeParser =
  tupleOf (classConstraint typeParser)
  <|> pure <$> maybeWithinParens (classConstraint typeParser)


classConstraint :: Parser Type -> Parser ClassConstraint
classConstraint typeParser = ClassConstraint <$> qClass <*> (typeParser |+)



type' :: Parser Type
type' = typeScope <|> classScope <|> type'' <|> maybeWithinParens (type'')
  where
    type'' = arrow <|> typeApply <|> elem'

    typeApply = CtorTypeApply   <$> typeCtor' <*> (typeApplyElem |+) <|>
                ParamTypeApply  <$> typeParam <*> (typeApplyElem |+) <|>
                NestedTypeApply <$> withinParens typeApply <*> (typeApplyElem |+)

    arrow = CtorTypeApply (QTypeCtor Nothing Arrow)
            <$> multipleSepBy (is "->") arrowElem
    tuple = CtorTypeApply (QTypeCtor Nothing TupleType)
            <$> (withinParens $ multipleSepBy comma type'')
    list  = CtorTypeApply (QTypeCtor Nothing ListType)
            <$> (pure <$> withinSquareBrackets type'')

    typeCtor'  = qTypeCtor <|> QTypeCtor Nothing <$> typeCtor
    typeVar'   = TypeVar'   <$> (qTypeVar <|> QTypeVar Nothing <$> typeVar)
    typeParam' = TypeParam' <$> typeParam

    typeScope = TypeScope <$> (is "forall" *> (typeParam |+) <* dot)
                          <*> (classScope <|> type'')
    classScope = ClassScope <$> (classConstraints' <* (is "=>"))
                            <*> type''

    classConstraints' = classConstraints
                        (elem' <|> withinParens (arrow <|> typeApply))


    typeApplyElem = elem' <|> withinParens (arrow <|> typeApply)
    arrowElem     = typeApply <|> elem' <|> withinParens arrow

    elem' = typeVar' <|> typeParam' <|> tuple <|> list <|>
            withinParens (typeScope <|> classScope)

qTypeVar :: Parser QTypeVar
qTypeVar = uncurry QTypeVar <$> qTerm' TypeVar

qTypeCtor :: Parser QTypeCtor
qTypeCtor = uncurry QTypeCtor <$> qTerm' TypeCtor