packages feed

fungll-combinators-0.4.1.1: src/GLL/Combinators/Visit/FUNGLL.hs

module GLL.Combinators.Visit.FUNGLL where

import GLL.Types.Grammar
import GLL.Types.BSR
import GLL.Types.DataSets
import GLL.Types.Input

import qualified Data.IntMap as IM
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.IntSet as IS
import Data.Text (pack)

type Command t  = State t (ContF t) -> State t (ContF t)
data ContF t    = ContF (Input t -> Descr t -> Command t)

type Parse_Symb t   = (Symbol t, Input t -> Slot t -> Int -> Int -> ContF t -> Command t)
type Parse_Choice t = Input t -> Nt -> Int -> ContF t -> Command t 
type Parse_Seq t    = Input t -> Nt -> [Symbol t] -> Int -> ContF t -> Command t
type Parse_Alt t    = Parse_Seq t

parser_for :: (Parseable t) => Nt -> Parse_Symb t -> Input t -> ParseResult t
parser_for x p inp = resultFromState inp (run_parse x p inp 0 emptyState)

run_parse :: Nt -> Parse_Symb t -> Input t -> Int -> 
                                State t (ContF t) -> State t (ContF t)
run_parse x p@(y,pf) inp l = pf inp (Slot x [y] []) l l counter_cont 

counter_cont :: ContF t
counter_cont = ContF cf
  where cf _ (_,_,r) s = s { successes = IM.alter updater r (successes s) } 
          where updater = maybe (Just 1) (Just . (1+))

parse_nterm :: (Ord t) => Nt -> [Parse_Seq t] -> Parse_Symb t
parse_nterm n = nterm n . foldl altOp altStart 

parse_term :: Parseable t => t -> Parse_Symb t
parse_term = term

parse_apply :: Ord t => Parse_Symb t -> Parse_Seq t
parse_apply = seqOp seqStart 

parse_seq :: Ord t => Parse_Seq t -> Parse_Symb t -> Parse_Seq t
parse_seq = seqOp

nterm :: (Ord t) => Nt -> Parse_Choice t -> Parse_Symb t
nterm n p = (Nt n, parser)
  where parser inp g l k c s 
          | null rs   = p inp n k cont_for s'
          | otherwise = compAll [ applyCF c (removePrefix len inp) (g,l,r) 
                                | r <- rs, let len = r - k ] s'
          where s' = s { grel = addCont (n,k) (g,l,c) (grel s) } 
                rs = extents (n,k) (prel s) 

        cont_for = ContF cf 
         where cf inp (_,k,r) s = 
                compAll [ applyCF c inp (g,l',r) 
                        | (g,l',c) <- conts (n,k) (grel s) ] s'
                where s' = s { prel = addExtent (n,k) r (prel s) }

term :: Parseable t => t -> Parse_Symb t
term t = (Term t, snd (predicate (pack (show t)) (matches t))) 

seqStart :: Ord t => Parse_Seq t
seqStart inp x beta l c = continue inp (Slot x [] beta, l, l, l) c

seqOp :: Ord t => Parse_Seq t -> Parse_Symb t -> Parse_Seq t
seqOp p (s,q) inp x beta l c0 = p inp x (s:beta) l c1
  where c1 = ContF c1f
         where c1f inp ((Slot _ alpha _),l,k) = q inp (Slot x (alpha++[s]) beta) l k c2
                where c2 = ContF c2f
                       where c2f inp (g,l,r) = continue inp (g,l,k,r) c0

continue :: (Ord t) => Input t -> BSR t -> ContF t -> Command t
continue inp bsr@(g@(Slot x alpha beta),l,k,r) c s 
  | hasDescr descr (uset s) = s'
  | otherwise               = applyCF c inp descr s''
  where descr = (g,l,r)
        s'  | not (null alpha) || null beta = s { bsrs = addBSR bsr (bsrs s) }
            | otherwise                     = s
        s'' = s' { uset = addDescr descr (uset s') }

altStart :: Parse_Choice t
altStart inp n l c s = s

altOp :: Parse_Choice t -> Parse_Seq t -> Parse_Choice t
altOp p q inp n l c = p inp n l c . q inp n [] l c
{- MUCH SLOWER ?
altOp p q inp n l c s = 
  let s1 = p inp n l counter_cont s
      s2 = q inp n [] l counter_cont s1
  in compAll [ applyCF c (error "cont_for assert", l, r) 
             | r <- IS.toList (IS.union (IM.keysSet (successes s1)) 
                                        (IM.keysSet (successes s2))) ] s2
-}

compAll :: [Command t] -> Command t
compAll = foldr (.) id

applyCF (ContF cf) inp a = cf inp a

{- EXTENSIONS -}

parse_lexical :: Nt -> RawParser t -> Parse_Symb t
parse_lexical n scanner = (Nt n, parser)
  where parser inp g l k c s = 
          compAll [ applyCF c (removePrefix len inp) (g, l, k + len) 
                  | prefix <- apply_scanner scanner inp 
                  , let len = length prefix ] s

{- EXPERIMENTAL -}

andNot :: (Show t) => Parse_Symb t -> Parse_Symb t -> Parse_Symb t
andNot (lnt,p) (rnt,q) = (Nt lhs_symb,parser)
  where lhs_symb = pack ("__andNot(" ++ show lnt ++","++ show rnt ++ ")")
        parser inp g l k c s = compAll [ applyCF c (removePrefix len inp) (g, l, r) 
                                       | r <- rs, let len = r - k ] 
                                       s2{successes = successes s}
          where s1 = run_parse lhs_symb (lnt,p) inp k s{successes = IM.empty}
                s2 = run_parse lhs_symb (rnt,q) inp k s1{successes = IM.empty}
                rs = IS.toList $ IS.difference (IM.keysSet (successes s1))
                                               (IM.keysSet (successes s2))


ands :: (Show t) => [Parse_Symb t] -> Parse_Symb t
ands = foldr andOp andStart

andOp :: (Show t) => Parse_Symb t -> Parse_Symb t -> Parse_Symb t
andOp (lnt,p) (rnt,q) = (Nt lhs_symb,parser)
  where lhs_symb = pack ("__and(" ++ show lnt ++","++ show rnt ++ ")")
        parser inp g l k c s = compAll [ applyCF c (removePrefix len inp) (g, l, r) 
                                       | r <- rs, let len = r - k ] s2
          where s1 = run_parse lhs_symb (lnt,p) inp k s 
                s2 = run_parse lhs_symb (rnt,q) inp k s1
                rs = IS.toList $ IS.intersection (IM.keysSet (successes s1))
                                                 (IM.keysSet (successes s2))

andStart :: Parse_Symb t
andStart = (Nt (pack "__and_unit"), parser)
  where parser inp g l k c s = applyCF c inp (g, l, k) s

predicate :: Parseable t => Nt -> (t -> Bool) -> Parse_Symb t
predicate nt p = (Nt nt, parser)
  where parser inp g l k c s =
          compAll [ applyCF c (removePrefix len inp) (g, l, k + len)   
                  | prefix <- apply_scanner (scanner_from_predicate p) inp
                  , let len = length prefix ] s

-- | 
-- The "ParseResult" datatype contains some information about a parse:
--
--  * Whether the parse was successful
--  * The number of descriptors that have been processed
--  * The number of BSR elements 
data ParseResult t = ParseResult{ bsrs_result               :: BSRs t
                                , res_success               :: Bool
                                , res_successes             :: IM.IntMap Int
                                , nr_descriptors            :: Int
                                , nr_bsrs                   :: Int
                                , error_message             :: String
                                }

matchedUpTo :: IM.IntMap Int -> Int -> Bool
matchedUpTo res r = maybe False (const True) (IM.lookup r res)

resultFromState :: Parseable t => Input t -> State t c -> ParseResult t
resultFromState inp (State uset _ _ pMap cs) =
    let usize       = sum  [ S.size s   | (l, r2s) <- IM.assocs uset
                                        , (r,s) <- IM.assocs r2s ]
        p_nodes     = sum [ IS.size ks  | (l, r2j) <- IM.assocs pMap
                                        , (r, j2s) <- IM.assocs r2j
                                        , (j, s2k) <- IM.assocs j2s
                                        , (s, ks)  <- M.assocs s2k ]
        succs = maybe 0 id (IM.lookup (inputLength inp) cs)
    in ParseResult pMap (succs > 0) cs usize p_nodes "no errors to report" 

instance Show (ParseResult t) where
    show res | res_success res = result_string
             | otherwise       = result_string ++ "\n" ++ error_message res
     where result_string = unlines $
                [   "Success             "  ++ show (res_success res)
                ,   "#Success            "  ++ show (res_successes res)
                ,   "Descriptors:        "  ++ show (nr_descriptors res)
                ,   "BSRs:               "  ++ show (nr_bsrs res)
                ]