1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
--- ----------------------------------------------------------------------------
--- This module provides some simple parser combinators.
---
--- @author  Jan Tikovsky (with changes by Niels Bunkenburg)
--- @version May 2021
--- ----------------------------------------------------------------------------
module ParserComb where

data Parser tok a = Parser { runParser :: [tok] -> Either String ([tok], a) }

instance Alternative (Parser tok) where
  empty = Parser $ const (Left "empty parser")
  l <|> r = Parser $ \ts -> case runParser l ts of
                              Left         _ -> runParser r ts
                              Right (ts', x) -> Right (ts', x)

instance Functor (Parser tok) where
  fmap f (Parser g) = Parser $ \ts -> case g ts of
                                        Left s -> Left s
                                        Right (ts', x) -> Right (ts', f x)

instance Applicative (Parser tok) where
  pure = return
  af <*> ax = af >>= \f -> fmap f ax

instance Monad (Parser tok) where
  return x = Parser $ \ts -> Right (ts, x)

  (Parser p) >>= f = Parser $ \ts -> case p ts of
    Left         e -> Left e
    Right (ts', x) -> runParser (f x) ts'

eof :: Parser tok a
eof = Parser $ \_ -> Left "Unexpected end-of-file"

unexpected :: Show tok => tok -> Parser tok a
unexpected t = Parser $ \_ -> Left $ "Unexpected token " ++ show t

terminal :: (Eq tok, Show tok) => tok -> Parser tok ()
terminal tok = Parser $ \tokens -> case tokens of
  []               -> (runParser eof) []
  t:ts | tok == t  -> Right (ts, ())
       | otherwise -> (runParser (unexpected t)) ts