module Data.Parser.Grempa.Parser.Item
( It(..), getItProd, isKernelIt
, kernel
, nextSymbol
, nextItPos
, Gen, GenData(..), runGen, gen
, askItemSet
, precomputeGotos
, askGoto
) where
import Control.Applicative
import Control.Monad.Reader
import Data.List
import Data.Map(Map)
import qualified Data.Map as M
import Data.Maybe
import Data.Set(Set)
import qualified Data.Set as S
import Data.Parser.Grempa.Aux.Aux
import Data.Parser.Grempa.Grammar.Untyped
import Data.Parser.Grempa.Parser.Table
import Data.Parser.Grempa.Grammar.Token
class (Eq (i s), Ord (i s), Show (i s), Token s) => It i s where
itRId :: i s -> RId s
itProd :: i s -> ProdI
getItPos :: i s -> Int
setItPos :: i s -> Int -> i s
closure :: Set (i s) -> Set (i s)
startItem :: RId s -> i s
getItProd :: It i s => i s -> Prod s
getItProd i = rIdRule (itRId i) !! itProd i
isKernelIt :: It i s => RId s -> i s -> Bool
isKernelIt st it = pos > 0 || (itRId it == st && pos == 0)
where pos = getItPos it
kernel :: It i s => RId s -> Set (i s) -> Set (i s)
kernel st = S.filter $ isKernelIt st
nextSymbol :: It i s => i s -> Tok (Symbol s)
nextSymbol i
| pos < length prod = Tok $ prod !! pos
| otherwise = EOF
where prod = getItProd i
pos = getItPos i
goto :: (It i s, Token s) => Set (i s) -> Symbol s -> Set (i s)
goto is s = closure $ setFromJust $ S.map (nextTest s) is
where
nextTest x i
| nextSymbol i == Tok x = Just $ nextItPos i
| otherwise = Nothing
nextItPos :: It i s => i s -> i s
nextItPos i = setItPos i $ getItPos i + 1
itemSets :: (It i s, Token s) => RId s -> [RId s] -> Set (Set (i s))
itemSets rid rids = S.delete S.empty $ recTraverseG itemSets' c1
where
c1 = S.singleton $ closure $ S.singleton $ startItem rid
symbols = terminals rids ++ nonTerminals rids
itemSets' c = (c `S.union` gs, gs)
where gs = S.fromList [goto i x | i <- S.toList c, x <- symbols]
data GenData i s = GenData
{ gItemSets :: [(Set (i s), StateI)]
, gItemSetIndex :: Map (Set (i s)) StateI
, gRules :: [RId s]
, gTerminals :: [Symbol s]
, gNonTerminals :: [Symbol s]
, gSymbols :: [Symbol s]
, gStartState :: Int
, gStartRule :: RId s
, gGotos :: Map (StateI, Symbol s) StateI
} deriving Show
type Gen i s = Reader (GenData i s)
runGen :: Gen i s a -> GenData i s -> a
runGen = runReader
gen :: (It i s, Token s) => RId s -> GenData i s
gen g = GenData
{ gItemSets = items
, gItemSetIndex = itemIx
, gRules = ruless
, gTerminals = terms
, gNonTerminals = nonTerms
, gSymbols = syms
, gStartState = snd $ fromMaybe (error "gen: maybe")
$ find (S.member (startItem g) . fst) items
, gStartRule = g
, gGotos = precomputeGotos items itemIx syms
}
where items = zip (S.toList $ itemSets g ruless) [0..]
itemIx = M.fromList items
ruless = rules g
terms = terminals ruless
nonTerms = nonTerminals ruless
syms = terms ++ nonTerms
precomputeGotos :: (It i s, Token s)
=> [(Set (i s), StateI)] -> Map (Set (i s)) StateI -> [Symbol s]
-> Map (StateI, Symbol s) StateI
precomputeGotos iss isi syms = M.fromList
[((ii, sym), st) | (is, ii) <- iss
, sym <- syms
, Just st <- [findState $ goto is sym]]
where
findState = lookupItemSet iss isi
lookupItemSet :: (It i s, Token s)
=> [(Set (i s), StateI)] -> Map (Set (i s)) StateI
-> Set (i s)
-> Maybe StateI
lookupItemSet iss isi x
| S.null x = Nothing
| otherwise = case M.lookup x isi of
Nothing -> snd <$> listToMaybe (filter (S.isSubsetOf x . fst) iss)
y -> y
askItemSet :: (It i s, Token s) => Set (i s) -> Gen i s (Maybe StateI)
askItemSet x = do
iss <- asks gItemSets
isi <- asks gItemSetIndex
return $ lookupItemSet iss isi x
askGoto :: (It i s, Token s) => StateI -> Symbol s -> Gen i s (Maybe StateI)
askGoto st sym = M.lookup (st, sym) <$> asks gGotos