{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleInstances, DeriveFunctor #-} {-# OPTIONS_GHC -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- | -- Module : Language.Haskell.Exts.Annotated.Parser -- Copyright : (c) Niklas Broberg 2004-2009 -- (c) Michael Sloan 2013 -- License : BSD-style (see the file LICENSE.txt) -- -- Maintainer : Niklas Broberg, d00nibro@chalmers.se -- Stability : stable -- Portability : portable -- -- Annotated parser for Haskell with extensions. -- ----------------------------------------------------------------------------- module Language.Haskell.Exts.Parser ( -- * General parsing Parseable(parse, parseWithMode, parseWithComments) , ParseMode(..), defaultParseMode, ParseResult(..), fromParseResult -- * Parsing of specific AST elements -- ** Modules , parseModule, parseModuleWithMode, parseModuleWithComments -- ** Expressions , parseExp, parseExpWithMode, parseExpWithComments -- ** Statements , parseStmt, parseStmtWithMode, parseStmtWithComments -- ** Patterns , parsePat, parsePatWithMode, parsePatWithComments -- ** Declarations , parseDecl, parseDeclWithMode, parseDeclWithComments -- ** Types , parseType, parseTypeWithMode, parseTypeWithComments -- ** Imports , parseImportDecl, parseImportDeclWithMode, parseImportDeclWithComments -- * Non-greedy parsers , NonGreedy(..) , ListOf(..), unListOf -- ** Module head parsers , getTopPragmas , PragmasAndModuleName(..) , PragmasAndModuleHead(..) , ModuleHeadAndImports(..) ) where import Data.Data hiding (Fixity) import Language.Haskell.Exts.Fixity import Language.Haskell.Exts.Syntax import Language.Haskell.Exts.Comments import Language.Haskell.Exts.InternalParser import Language.Haskell.Exts.ParseMonad import Language.Haskell.Exts.SrcLoc instance Parseable (Decl SrcSpanInfo) where parser = normalParser mparseDecl instance Parseable (Exp SrcSpanInfo) where parser = normalParser mparseExp instance Parseable (Module SrcSpanInfo) where parser = normalParser mparseModule instance Parseable (Pat SrcSpanInfo) where parser = normalParser mparsePat instance Parseable (Stmt SrcSpanInfo) where parser = normalParser mparseStmt instance Parseable (Type SrcSpanInfo) where parser = normalParserNoFixity mparseType instance Parseable (ImportDecl SrcSpanInfo) where parser = normalParserNoFixity mparseImportDecl normalParser :: AppFixity a => P (a SrcSpanInfo) -> Maybe [Fixity] -> P (a SrcSpanInfo) normalParser p Nothing = p normalParser p (Just fixs) = p >>= \ast -> applyFixities fixs ast `atSrcLoc` noLoc normalParserNoFixity :: P (a SrcSpanInfo) -> Maybe [Fixity] -> P (a SrcSpanInfo) normalParserNoFixity p _ = p -- Type-specific functions -- | Parse of a string, which should contain a complete Haskell module, using 'defaultParseMode'. parseModule :: String -> ParseResult (Module SrcSpanInfo) parseModule = parse -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode'. parseModuleWithMode :: ParseMode -> String -> ParseResult (Module SrcSpanInfo) parseModuleWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseModuleWithComments :: ParseMode -> String -> ParseResult (Module SrcSpanInfo, [Comment]) parseModuleWithComments = parseWithComments -- | Parse of a string containing a Haskell expression, using 'defaultParseMode'. parseExp :: String -> ParseResult (Exp SrcSpanInfo) parseExp = parse -- | Parse of a string containing a Haskell expression, using an explicit 'ParseMode'. parseExpWithMode :: ParseMode -> String -> ParseResult (Exp SrcSpanInfo) parseExpWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseExpWithComments :: ParseMode -> String -> ParseResult (Exp SrcSpanInfo, [Comment]) parseExpWithComments = parseWithComments -- | Parse of a string containing a Haskell pattern, using 'defaultParseMode'. parsePat :: String -> ParseResult (Pat SrcSpanInfo) parsePat = parse -- | Parse of a string containing a Haskell pattern, using an explicit 'ParseMode'. parsePatWithMode :: ParseMode -> String -> ParseResult (Pat SrcSpanInfo) parsePatWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parsePatWithComments :: ParseMode -> String -> ParseResult (Pat SrcSpanInfo, [Comment]) parsePatWithComments = parseWithComments -- | Parse of a string containing a Haskell top-level declaration, using 'defaultParseMode'. parseDecl :: String -> ParseResult (Decl SrcSpanInfo) parseDecl = parse -- | Parse of a string containing a Haskell top-level declaration, using an explicit 'ParseMode'. parseDeclWithMode :: ParseMode -> String -> ParseResult (Decl SrcSpanInfo) parseDeclWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseDeclWithComments :: ParseMode -> String -> ParseResult (Decl SrcSpanInfo, [Comment]) parseDeclWithComments = parseWithComments -- | Parse of a string containing a Haskell type, using 'defaultParseMode'. parseType :: String -> ParseResult (Type SrcSpanInfo) parseType = parse -- | Parse of a string containing a Haskell type, using an explicit 'ParseMode'. parseTypeWithMode :: ParseMode -> String -> ParseResult (Type SrcSpanInfo) parseTypeWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseTypeWithComments :: ParseMode -> String -> ParseResult (Type SrcSpanInfo, [Comment]) parseTypeWithComments = parseWithComments -- | Parse of a string containing a Haskell statement, using 'defaultParseMode'. parseStmt :: String -> ParseResult (Stmt SrcSpanInfo) parseStmt = parse -- | Parse of a string containing a Haskell type, using an explicit 'ParseMode'. parseStmtWithMode :: ParseMode -> String -> ParseResult (Stmt SrcSpanInfo) parseStmtWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseStmtWithComments :: ParseMode -> String -> ParseResult (Stmt SrcSpanInfo, [Comment]) parseStmtWithComments = parseWithComments -- | Parse of a string containing a Haskell statement, using 'defaultParseMode'. parseImportDecl :: String -> ParseResult (ImportDecl SrcSpanInfo) parseImportDecl = parse -- | Parse of a string containing a Haskell type, using an explicit 'ParseMode'. parseImportDeclWithMode :: ParseMode -> String -> ParseResult (ImportDecl SrcSpanInfo) parseImportDeclWithMode = parseWithMode -- | Parse of a string containing a complete Haskell module, using an explicit 'ParseMode', retaining comments. parseImportDeclWithComments :: ParseMode -> String -> ParseResult (ImportDecl SrcSpanInfo, [Comment]) parseImportDeclWithComments = parseWithComments -- Non-greedy parsers (should use ng- prefixed parses exported by InternalParser) -- | Non-greedy parse of a string starting with a series of top-level option pragmas. getTopPragmas :: String -> ParseResult [ModulePragma SrcSpanInfo] getTopPragmas = fmap (unListOf . unNonGreedy) . parse instance Parseable (NonGreedy (ListOf (ModulePragma SrcSpanInfo))) where parser = nglistParserNoFixity ngparseModulePragmas nglistParserNoFixity :: P ([a SrcSpanInfo], [SrcSpan], SrcSpanInfo) -> Maybe [Fixity] -> P (NonGreedy (ListOf (a SrcSpanInfo))) nglistParserNoFixity f = fmap (NonGreedy . toListOf) . normalParserNoFixity f -- | Type intended to be used with 'Parseable', with instances that implement a -- non-greedy parse of the module name, including top-level pragmas. This -- means that a parse error that comes after the module header won't be -- returned. If the 'Maybe' value is 'Nothing', then this means that there was -- no module header. data PragmasAndModuleName l = PragmasAndModuleName l [ModulePragma l] (Maybe (ModuleName l)) deriving (Eq,Ord,Show,Typeable,Data) instance Parseable (NonGreedy (PragmasAndModuleName SrcSpanInfo)) where parser _ = do ((pragmas, pss, pl), mn) <- ngparsePragmasAndModuleName let l = combSpanMaybe (pl <** pss) (fmap ann mn) return $ NonGreedy $ PragmasAndModuleName l pragmas mn -- Type intended to be used with 'Parseable', with instances that -- implement a non-greedy parse of the module name, including -- top-level pragmas. This means that a parse error that comes -- after the module header won't be returned. If the 'Maybe' value -- is 'Nothing', this means that there was no module head. -- -- Note that the 'ParseMode' matters for this due to the 'MagicHash' -- changing the lexing of identifiers to include \"#\". data PragmasAndModuleHead l = PragmasAndModuleHead l [ModulePragma l] (Maybe (ModuleHead l)) deriving (Eq,Ord,Show,Typeable,Data) instance Parseable (NonGreedy (PragmasAndModuleHead SrcSpanInfo)) where parser _ = do ((pragmas, pss, pl), mh) <- ngparsePragmasAndModuleHead let l = combSpanMaybe (pl <** pss) (fmap ann mh) return $ NonGreedy $ PragmasAndModuleHead l pragmas mh -- Type intended to be used with 'Parseable', with instances that -- implement a non-greedy parse of the module head, including -- top-level pragmas, module name, export list, and import -- list. This means that if a parse error that comes after the -- imports won't be returned. If the 'Maybe' value is 'Nothing', -- this means that there was no module head. -- -- Note that the 'ParseMode' matters for this due to the 'MagicHash' -- changing the lexing of identifiers to include \"#\". data ModuleHeadAndImports l = ModuleHeadAndImports l [ModulePragma l] (Maybe (ModuleHead l)) [ImportDecl l] deriving (Eq,Ord,Show,Typeable,Data) instance Parseable (NonGreedy (ModuleHeadAndImports SrcSpanInfo)) where parser _ = do ((pragmas, pss, pl), mh, mimps) <- ngparseModuleHeadAndImports let l = (pl <** pss) `combSpanMaybe` (fmap ann mh) `combSpanMaybe` (fmap (\(_, iss, il) -> il <** iss) mimps) imps = maybe [] (\(x, _, _) -> x) mimps return $ NonGreedy $ ModuleHeadAndImports l pragmas mh imps -- | Instances of 'Parseable' for @NonGreedy a@ will only consume the input -- until @a@ is fully parsed. This means that parse errors that come later -- in the input will be ignored. It's also more efficient, as it's fully lazy -- in the remainder of the input: -- -- >>> parse (unlines ("module A where" : "main =" : repeat "blah")) :: ParseResult PragmasAndModuleHead -- ParseOk (NonGreedy {unNonGreedy = PragmasAndModuleHead [] (ModuleName "A",Nothing,Nothing)}) -- -- (this example uses the simplified AST) newtype NonGreedy a = NonGreedy { unNonGreedy :: a } deriving (Eq,Ord,Show,Typeable,Data) instance Functor NonGreedy where fmap f (NonGreedy x) = NonGreedy (f x) -- | @ListOf a@ stores lists of the AST type @a@, along with a 'SrcSpanInfo', -- in order to provide 'Parseable' instances for lists. These instances are -- provided when the type is used as a list in the syntax, and the same -- delimiters are used in all of its usages. Some exceptions are made: data ListOf a = ListOf SrcSpanInfo [a] deriving (Eq,Ord,Show,Typeable,Data,Functor) unListOf :: ListOf a -> [a] unListOf (ListOf _ xs) = xs -- It's safe to forget about the previous SrcSpanInfo 'srcInfoPoints', -- as long as they are created with (presently) are all created with -- 'noInfoSpan' ('nIS'), '(<^^>)', or '(<++>)', all of which have -- empty 'srcInfoPoints'. Ideally, the parsers would return better -- types, but this works. toListOf :: ([a], [SrcSpan], SrcSpanInfo) -> ListOf a toListOf (xs, ss, l) = ListOf (infoSpan (srcInfoSpan l) ss) xs