{-# LANGUAGE RankNTypes, TypeFamilies, GeneralizedNewtypeDeriving #-}
module Text.ParserCombinators.Parsek.Position
( module Text.ParserCombinators.Parsek
, module Text.ParserCombinators.Class
, SourcePos(..)
, Parser
, getPosition
, parse
, parseFromFile
, maybePosToPos
, anyChar
) where
import Text.ParserCombinators.Class
import Text.ParserCombinators.Parsek hiding (parse,parseFromFile,Parser)
import qualified Text.ParserCombinators.Parsek as P
import Data.Bits
import Control.Monad.Fail as Fail
newtype Parser a = PP (P.Parser (Char, SourcePos) a)
deriving (Alternative, Applicative, Monad, Functor, MonadPlus, MonadFail)
instance IsParser Parser where
type SymbolOf Parser = Char
satisfy p = PP $ fst <$> satisfy (p . fst)
look = PP $ (map fst) <$> look
label lab (PP p) = PP (label lab p)
(PP p) <<|> (PP q) = PP (p <<|> q)
anyChar :: IsParser p => p (SymbolOf p)
anyChar = anySymbol
getPosition :: Parser SourcePos
getPosition = PP $ (\l -> case l of
[] -> EOF
((_,p):_) -> p) <$> look
parse :: FilePath -> Parser a -> (forall s. ParseMethod s a r) -> String -> ParseResult SourcePos r
parse file (PP p) method s = mapErrR snd $ P.parse p method (zip s (scanl updLoc (initLoc file) s))
parseFromFile :: Parser a -> (forall s. ParseMethod s a r) -> FilePath -> IO (ParseResult SourcePos r)
parseFromFile p method file = parse file p method <$> readFile file
maybePosToPos = maybe EOF id
data SourcePos = Loc {sourceName :: !FilePath, sourceLine :: !Int, sourceCol :: !Int} | EOF
deriving (Ord,Eq)
instance Show SourcePos where
show EOF = "end of file"
show (Loc f l c) = f ++ ":" ++ show l ++ ":" ++ show c
updLoc :: SourcePos -> Char -> SourcePos
updLoc (Loc f l _) '\n' = Loc f (l+1) 0
updLoc (Loc f l c) '\t' = Loc f l ((c+8) .&. complement 7)
updLoc (Loc f l c) _ = Loc f l (c+1)
updLoc EOF _ = EOF
initLoc :: FilePath -> SourcePos
initLoc p = Loc p 1 0