-- © 2002 Peter Thiemann
module WASH.Utility.SimpleParser where

import Data.Char

-- very simple parser combinators: Parsec is too sophisticated!
newtype Parser a b = Parser (a -> [(b, a)])
unParser (Parser g) = g
instance Monad (Parser a) where
  return x = Parser (\ w -> [(x, w)])
  m >>=  f = let g = unParser m in
	     Parser (\ w -> [ (y, w'') | (x, w') <- g w, (y, w'') <- unParser (f x) w'])
  fail str = Parser (\ w -> [])

satisfy p = Parser (\ w -> [(x, w') | x:w' <- [w], p x])

print = satisfy isPrint
alphaNum = satisfy isAlphaNum
alpha = satisfy isAlpha
ascii = satisfy isAscii
digit = satisfy isDigit
char c = satisfy (==c)
string s = foldr (\ x p -> do { c <- char x; cs <- p; return (c:cs); }) (return "") s
oneOf cs = satisfy (`elem` cs)
noneOf cs = satisfy (not . (`elem` cs))

eof = Parser (\ w -> if null w then [((),[])] else [])
try parser = parser
p1 <|> p2 = let g1 = unParser p1
		g2 = unParser p2
	    in  Parser (\w -> g1 w ++ g2 w)

option :: x -> Parser a x -> Parser a x
option x parser = parser <|> return x

many1 p = 
  do x <- p
     xs <- many p
     return (x : xs)

many p = 
  option [] (many1 p)

manyn n p =
  if n <= 0 
  then return []
  else do x <- p
	  xs <- manyn (n-1) p
	  return (x : xs)


parseFromString :: Parser String x -> String -> Maybe x
parseFromString parser str =
  let g = unParser (parser >>= (\x -> eof >> return x)) in
  case g str of
    (x, ""): _ -> Just x
    _ -> Nothing

parserToRead :: Parser String x -> ReadS x
parserToRead parser = unParser parser
