{-# LANGUAGE BangPatterns, RankNTypes, TypeFamilies, FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Lexer.Inchworm.Source
( Source (..), Range(..), Location (..)
, Sequence (..)
, makeListSourceIO)
where
import Data.IORef
import Data.Maybe
import qualified Data.List as List
import Prelude hiding (length)
class Sequence is where
type Elem is
length :: is -> Int
instance Sequence [a] where
type Elem [a] = a
length = List.length
data Source m loc input
= Source
{
sourceSkip :: (Elem input -> Bool) -> m ()
, sourceTry :: forall a. m (Maybe a) -> m (Maybe a)
, sourcePull :: (Elem input -> Bool)
-> m (Maybe (Range loc, Elem input))
, sourcePulls :: forall s
. Maybe Int
-> (Int -> Elem input -> s -> Maybe s)
-> s
-> m (Maybe (Range loc, input))
, sourceBumpLoc :: Elem input -> loc -> loc
, sourceRemaining :: m (loc, input)
}
makeListSourceIO
:: forall i loc. Eq i
=> loc
-> (i -> loc -> loc)
-> [i]
-> IO (Source IO loc [i])
makeListSourceIO loc00 bumpLoc cs0
= do refLoc <- newIORef loc00
refSrc <- newIORef cs0
return $ Source
(skipListSourceIO refLoc refSrc)
(tryListSourceIO refLoc refSrc)
(pullListSourceIO refLoc refSrc)
(pullsListSourceIO refLoc refSrc)
(bumpLoc)
(remainingSourceIO refLoc refSrc)
where
skipListSourceIO refLoc refSrc fPred
= do
loc0 <- readIORef refLoc
cc0 <- readIORef refSrc
let eat !loc !cc
= case cc of
[]
-> do writeIORef refLoc loc
writeIORef refSrc []
return ()
c : cs
| fPred c
-> eat (bumpLoc c loc) cs
| otherwise
-> do writeIORef refLoc loc
writeIORef refSrc (c : cs)
return ()
eat loc0 cc0
tryListSourceIO refLoc refSrc comp
= do loc <- readIORef refLoc
cc <- readIORef refSrc
mx <- comp
case mx of
Just i
-> return (Just i)
Nothing
-> do writeIORef refLoc loc
writeIORef refSrc cc
return Nothing
pullListSourceIO refLoc refSrc fPred
= do locFirst <- readIORef refLoc
cc <- readIORef refSrc
case cc of
[]
-> return Nothing
c : cs
| fPred c
-> do writeIORef refLoc (bumpLoc c locFirst)
writeIORef refSrc cs
return $ Just (Range locFirst locFirst, c)
| otherwise
-> return Nothing
pullsListSourceIO
:: IORef loc -> IORef [i]
-> Maybe Int -> (Int -> i -> s -> Maybe s)
-> s -> IO (Maybe (Range loc, [i]))
pullsListSourceIO refLoc refSrc mLenMax work s0
= do lFirst <- readIORef refLoc
cc0 <- readIORef refSrc
let eat !ix !(mlPrev :: Maybe loc) !(lHere :: loc) !cc !acc !s
| Just mx <- mLenMax
, ix >= mx
= return (ix, mlPrev, lHere, cc, reverse acc)
| otherwise
= case cc of
[]
-> return (ix, mlPrev, lHere, cc, reverse acc)
c : cs
-> case work ix c s of
Nothing -> return (ix, mlPrev, lHere, cc, reverse acc)
Just s' -> eat (ix + 1) (Just lHere) (bumpLoc c lHere)
cs (c : acc) s'
(len, mlPrev, lEnd, cc', acc)
<- eat 0 Nothing lFirst cc0 [] s0
case len of
0 -> return Nothing
_ -> do writeIORef refLoc lEnd
writeIORef refSrc cc'
let lFinal = fromMaybe lFirst mlPrev
return $ Just (Range lFirst lFinal, acc)
remainingSourceIO
:: IORef loc -> IORef [i]
-> IO (loc, [i])
remainingSourceIO refLoc refSrc
= do loc <- readIORef refLoc
src <- readIORef refSrc
return (loc, src)
data Range loc
= Range !loc !loc
deriving Show
data Location
= Location
!Int
!Int
deriving Show
{-# SPECIALIZE INLINE
makeListSourceIO
:: Location
-> (Char -> Location -> Location)
-> [Char]
-> IO (Source IO Location [Char])
#-}