module HappyDot.Parser where
import Control.Monad.Trans.State
import Data.Char
import Data.Maybe
consumeWhile :: (Char -> Bool) -> State (String, Int) String
consumeWhile f = do
(str, ln) <- get
let (x,r) = span f str
ln' = ln + (length $ filter (=='\n') x)
put $ (r, ln')
return x
consumeOnce :: (Char -> Bool) -> State (String, Int) String
consumeOnce f = do
(str, ln) <- get
case str of
(c:cs) -> if f c then put (cs, ln + if c == '\n' then 1 else 0) >> return [c] else return ""
[] -> return ""
consumeQuotedString :: State (String, Int) (Either String String)
consumeQuotedString = do
str <- consumeWhile (\c -> not $ c `elem` "\\\"\n")
(cs, ln) <- get
case cs of
'\\':'\n':ss -> do
put (ss, ln+1)
str1 <- consumeQuotedString
return $ fmap (str ++) str1
'\\':'"':ss -> do
put (ss, ln)
str1 <- consumeQuotedString
return $ str1 >>= \s1 -> return (str ++ ('"':s1))
'\"':ss -> do
put (ss, ln)
return $ Right str
'\n':ss -> do
put (ss, ln+1)
return $ Left "String was open when newline was found. Either close the string with a \" or add a \\ to the end of the line to continue the string on the next line."
'\\':c:ss -> do
put (ss, ln)
str1 <- consumeQuotedString
return $ str1 >>= \s1 -> return (str ++ ('\\':c:s1))
[] -> return $ Right str
consumeProcessing = do
(s0, ln) <- get
case s0 of
'<':'?':cs -> do
put (cs, ln)
consumeProcessing'
_ -> return []
consumeProcessing' = do
t <- consumeWhile (/='?')
(s1, ln) <- get
case s1 of
'?':'>':cs -> do
put (cs, ln)
return $ '<':'?':(t ++ "?>")
c:cs -> do
put (cs, ln)
consumeProcessing'
[] -> do
return []
consumeComment = do
consumeWhile (/='*')
(str, ln) <- get
case str of
('*':'/':str') -> put (str', ln)
(_:str') -> do
put (str', ln)
consumeComment
consumeXMLComment = do
consumeWhile (/='-')
(str, ln) <- get
case str of
('-':'-':'>':str') -> put (str', ln)
(_:str') -> do
put (str', ln)
consumeXMLComment
consumeSomeString strings = do
str <- get
let ss = filter isJust $ map
(\(s,r) ->
do
str' <- spanStr s str
return (r, str'))
strings
if null ss then return Nothing
else let Just (r, str') = head ss in put str' >> return (Just r)
consumeTag = do
tag <- consumeWhile (/='>')
consumeOnce (=='>')
return tag
spanStr [] str = Just str
spanStr _ [] = Nothing
spanStr (p:pattern) (s:str)
| p == s = spanStr pattern str
| otherwise = Nothing