module Parsing ( Parser,parse, success,failure,sat,pmap,char,digit, (+++),(<:>),(>*>),(>->),(<-<), oneOrMore,zeroOrMore ) {---------------------- 2010-11-25 dave Final Refactored Parser including (i) A new type for the Parser, but no export of the constructor (ii) Parser as an instance of Monad. What has not been done: rewrite the definitions of the parser combinators to use the monadic operations (do etc). ----------------------} where import Data.Maybe import Data.Char ------------------ data Parser a = P(String -> Maybe (a,String)) parse :: Parser a -> String -> Maybe(a,String) parse (P p) s = p s instance Monad Parser where (>>=) = (>*>) return = success ------------------- -- Basic Parsers, dependent on internal structure -- -- success and fail failure = P $ \s -> Nothing success a = P $ \s -> Just (a,s) -- Parse any single character item = P $ \s -> case s of [] -> Nothing (c:cs) -> Just (c,cs) -- (+++) parse either using p or else using q infixr 5 +++ (+++) :: Parser a -> Parser a -> Parser a p +++ q = P $ \s -> listToMaybe [ x | Just x <- [parse p s, parse q s]] -- (p >*> f) parse using p to produce a. -- Then parse using f a infixl 1 >*> (>*>) :: Parser a -> (a -> Parser b) -> Parser b p >*> f = P $ \s -> case parse p s of Just(a,s') -> parse (f a) s' _ -> Nothing ----------------------------------------------- -- Parsers below do not depend on the internal -- representation of Parser -- sat p parse a single character satisfying p sat :: (Char -> Bool) -> Parser Char sat p = item >*> \c -> if p c then success c else failure char c = sat (==c) digit = sat isDigit -- pmap modifies the result of a parser pmap :: (a -> b) -> Parser a -> Parser b pmap f p = p >*> success . f p >-> q = p >*> \_ -> q -- equivalent to monadic op: >> p <-< q = p >*> \a -> q >-> success a (<:>):: Parser a -> Parser [a] -> Parser [a] p <:> q = p >*> \a -> pmap (a:) q oneOrMore, zeroOrMore :: Parser a -> Parser [a] oneOrMore p = p <:> zeroOrMore p zeroOrMore p = oneOrMore p +++ success []