{-# LANGUAGE CPP #-} module Floskell.Attoparsec ( Position, parseOnly ) where import qualified Data.Attoparsec.ByteString as AP import qualified Data.ByteString as B import Data.Semigroup as Sem import Data.Word ( Word8 ) data Position = Position { posLine :: !Int, posColumn :: !Int } deriving ( Eq, Ord, Show ) instance Sem.Semigroup Position where (Position l c) <> (Position l' c') = Position (l + l') (if l' > 0 then c' else c + c') instance Monoid Position where mempty = Position 0 0 #if !(MIN_VERSION_base(4,11,0)) mappend = (<>) #endif advance :: Position -> Word8 -> Position advance (Position l _) 10 = Position (l + 1) 0 advance (Position l c) _ = Position l (c + 1) position :: B.ByteString -> Position position = B.foldl' advance mempty positionAt :: B.ByteString -> B.ByteString -> Position positionAt l r = position $ B.take (B.length l - B.length r) l parseOnly :: AP.Parser a -> B.ByteString -> Either String a parseOnly p b = case AP.feed (AP.parse p b) B.empty of AP.Done _ x -> Right x AP.Fail r _ err -> Left $ parseError (positionAt b r) err AP.Partial _ -> error "impossible" where parseError (Position l c) err = err ++ ", at line " ++ show (l + 1) ++ ", column " ++ show c