summaryrefslogtreecommitdiff
path: root/Parsers.hs
blob: 54d85a5455f193ae9dbe5cb6b6e0f72b94a7fd0c (plain)
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
module Parsers where

-- Parsec is for casuals

import Control.Applicative (Alternative(..), liftA2)
import Control.Monad (MonadPlus(..), guard)
import Data.Maybe (catMaybes)

newtype Parser t a =
  Parser { parse :: [t] -> Maybe ([t], a) }

instance Semigroup a => Semigroup (Parser t a) where
  (<>) = liftA2 (<>)

instance Monoid a => Monoid (Parser t a) where
  mempty = pure mempty

instance Functor (Parser t) where
  fmap f (Parser p) = Parser $ fmap (fmap f) . p

instance Applicative (Parser t) where
  pure = result

  p <*> q = Parser $ \ inp -> do
    (inp', f) <- parse p inp
    parse (f <$> q) inp'

instance Monad (Parser t) where
  return = pure

  p >>= f = Parser $ \ inp -> do
    (inp', x) <- parse p inp
    parse (f x) inp'

instance Alternative (Parser t) where
  empty = flunk

  (<|>) = alt

-----------------------------------------------------------------------------

flunk :: Parser t a
flunk = Parser $ \ _ -> Nothing

result :: a -> Parser t a
result x = Parser $ \ inp -> Just (inp, x)

peek :: Parser t a -> Parser t a
peek p = Parser $ \ inp -> do
  (_, x) <- parse p inp
  return (inp, x)

anyToken :: Parser t t
anyToken = Parser $ \ inp -> case inp of
  t:ts -> Just (ts, t)
  _    -> Nothing

eof :: Parser t ()
eof = Parser $ \ inp -> case inp of
  [] -> Just ([], ())
  _  -> Nothing

infixl 3 `alt`
alt :: Parser t a -> Parser t a -> Parser t a
alt (Parser p) (Parser q) = Parser $ \ inp -> p inp <|> q inp

-----------------------------------------------------------------------------

phrase :: Parser t a -> Parser t a
phrase = (<* eof)

recover :: a -> Parser t a -> Parser t a
recover x p = p <|> pure x

optional :: Parser t a -> Parser t (Maybe a)
optional = recover Nothing . fmap Just

assert :: (a -> Bool) -> Parser t a -> Parser t a
assert f p = do
  x <- p
  guard $ f x
  return x

satisfy :: (t -> Bool) -> Parser t t
satisfy f = assert f anyToken

token :: Eq t => t -> Parser t t
token t = satisfy (==t)

list :: Eq t => [t] -> Parser t [t]
list = traverse token

mult :: Parser t a -> Parser t [a]
mult = many

mult1 :: Parser t a -> Parser t [a]
mult1 = some

exactly :: Int -> Parser t a -> Parser t [a]
exactly i = sequence . replicate i

atLeast :: Int -> Parser t a -> Parser t [a]
atLeast i p = exactly i p <> mult p

atMost :: Int -> Parser t a -> Parser t [a]
atMost i = fmap catMaybes . exactly i . optional

between :: Int -> Int -> Parser t a -> Parser t [a]
between x y p = exactly (min x y) p <> atMost (abs $ x - y) p

stopAt :: Parser t a -> Parser t [t]
stopAt p = go
  where
    p' = ([] <$ peek p)
    go = p' <|> liftA2 (:) anyToken go

stopAfter :: Parser t a -> Parser t ([t], a)
stopAfter p = (,) <$> stopAt p <*> p

stopIf :: Parser t a -> Parser t [t]
stopIf p = stopAt $ () <$ p <|> eof