+-----------------------------------------------------------------------------
+-- Parser combinators.
+
+-- A very simple parser monad.
+newtype Parser t a = Parser { runparse :: [t] -> Either String (a, [t]) }
+
+instance Monad (Parser t) where
+ return x = Parser $ \ts -> Right (x, ts)
+ fail err = Parser $ \_ -> Left err
+ (Parser p) >>= f = Parser $ \ts -> case p ts of
+ Right (x, ts) -> runparse (f x) ts
+ Left err -> Left err
+
+-- Access to the token stream.
+peek = Parser $ \ts -> case ts of
+ t:_ -> Right (Just t, ts)
+ _ -> Right (Nothing, ts)
+
+step = Parser $ \ts -> case ts of
+ _:ts -> Right ((), ts)
+ _ -> Left "unexpected end-of-file"
+
+-- Run a parser, getting the final value out.
+parse ts p = case runparse p ts of
+ Right (x, _) -> Right x
+ Left err -> Left err
+
+-- If the current token satisfies PRED then return it; otherwise fail with
+-- ERR.
+satisfies pred err = do
+ r <- peek
+ case r of
+ Just t | pred t -> do step; return t
+ _ -> fail err
+
+-- Return the next token if there is one; otherwise fail with ERR.
+anytok err = satisfies (const True) err
+
+-- If the current character matches D then return it; otherwise fail with a
+-- suitable error.
+delim d = satisfies (\c -> c == d) ("missing " ++ [d])
+
+-- If at end of file then succeed; otherwise fail with a suitable error.
+eof = do
+ r <- peek
+ case r of
+ Nothing -> return ()
+ _ -> fail "trailing junk"
+