packages feed

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

module Parsers.Haskell.ModuleDef where


import Parsers.Haskell.ClassDef (classDef, derivingDef, instanceDef)
import Parsers.Haskell.Common   (module', token, var, varOp)
import Parsers.Haskell.DataDef  (dataDef, newtypeDef, typeDef)
import Parsers.Haskell.FnDef    (fnDef, fnSig, infixAnnotation,
                                 withinContextTupled)
import Parsers.Haskell.Type     (typeVar)

import SyntaxTrees.Haskell.FnDef     (FnDefOrSig (..))
import SyntaxTrees.Haskell.ModuleDef (ImportExportDef (..), InternalDef (..),
                                      ModuleDef (..), ModuleExport (..),
                                      ModuleExportDef (..), ModuleImport (..),
                                      ModuleImportDef (..), ModuleMember (..))

import Bookhound.Parser            (Parser)
import Bookhound.ParserCombinators (IsMatch (is), anySepBy, maybeWithin, (<|>),
                                    (|?))
import Bookhound.Parsers.Char      (comma)
import Bookhound.Parsers.String    (spacing, withinParens)


import Data.Foldable (Foldable (fold))
import Data.Maybe    (isJust)



moduleDef :: Parser ModuleDef
moduleDef = uncurry <$>
              (ModuleDef <$> (is "module" *> module')
                         <*> (moduleExport |?)
                         <*  is "where")
                         <*> withinContextTupled moduleImport internalDef



moduleExport :: Parser ModuleExport
moduleExport = ModuleExport <$> withinParens (anySepBy comma moduleExportDef)


moduleExportDef :: Parser ModuleExportDef
moduleExportDef = ModuleExportDef  <$> importExportDef <|>
                  FullModuleExport <$> (is "module" *> module')

moduleImport :: Parser ModuleImport
moduleImport = ModuleImport <$> (token (is "import") *>
                                 (isJust <$> (is "qualified" |?)))
                            <*> module'
                            <*> ((is "as" *> module') |?)
                            <*> (isJust <$> (is "hiding" |?))
                            <*> (fold <$> (defs |?))
  where
    defs = withinParens $ anySepBy comma $ maybeWithin spacing moduleImportDef


moduleImportDef :: Parser ModuleImportDef
moduleImportDef = ModuleImportDef <$> importExportDef


importExportDef :: Parser ImportExportDef
importExportDef = FullData     <$> typeVar
                               <*  withinParens (is "..")      <|>
                  FilteredData <$> typeVar
                               <*> withinParens
                                 (anySepBy comma moduleMember) <|>
                  Member       <$> moduleMember


moduleMember :: Parser ModuleMember
moduleMember = VarOpMember <$> withinParens varOp <|>
               VarMember   <$> var                <|>
               DataMember  <$> typeVar

internalDef :: Parser InternalDef
internalDef = FnDefOrSig' . Def  <$> fnDef        <|>
              FnDefOrSig' . Sig  <$> fnSig        <|>
              TypeDef'           <$> typeDef      <|>
              NewTypeDef'        <$> newtypeDef   <|>
              DataDef'           <$> dataDef      <|>
              ClassDef'          <$> classDef     <|>
              InstanceDef'       <$> instanceDef  <|>
              DerivingDef'       <$> derivingDef  <|>
              InfixFnAnnotation' <$> infixAnnotation