-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathchapter7-parsing.hs
139 lines (100 loc) · 4.54 KB
/
chapter7-parsing.hs
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
module Parsing where
import Control.Applicative -- Otherwise you can't do the Applicative instance.
import Control.Monad
import Data.Char
infixr 5 +++
newtype Parser a = P (String -> [(a, String)])
instance Functor Parser where
fmap = liftM
instance Applicative Parser where
pure = return
(<*>) = ap
instance Monad Parser where
return v = P (\inp -> [(v,inp)])
p >>= f = P (\inp ->
case parse p inp of
[(v, out)] -> parse (f v) out
[] -> [])
instance Alternative Parser where
(<|>) = mplus
empty = mzero
instance MonadPlus Parser where
mzero = P (\inp -> [])
p `mplus` q = P (\inp -> case parse p inp of
[] -> parse q inp
[(v,out)] -> [(v,out)])
-- Basic parser
parse :: Parser a -> String -> [(a, String)]
parse (P p) inp = p inp
failure :: Parser a
failure = mzero
item :: Parser Char
item = P (\inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)])
(+++) :: Parser a -> Parser a -> Parser a
p +++ q = p `mplus` q
sat :: (Char -> Bool) -> Parser Char
sat p = do x <- item
if p x then return x else failure
digit :: Parser Char
digit = sat isDigit
lower :: Parser Char
lower = sat isLower
upper :: Parser Char
upper = sat isUpper
letter :: Parser Char
letter = sat isAlpha
alphanum :: Parser Char
alphanum = sat isAlphaNum
char :: Char -> Parser Char
char x = sat (== x)
string :: String -> Parser String
string [] = return []
string (x:xs) = do char x
string xs
return (x:xs)
many' :: Parser a -> Parser [a]
many' p = many1 p +++ return []
many1 :: Parser a -> Parser [a]
many1 p = do v <- p
vs <- many' p
return (v:vs)
ident :: Parser String
ident = do x <- lower
xs <- many' alphanum
return (x:xs)
nat :: Parser Int
nat = do xs <- many1 digit
return (read xs)
int :: Parser Int
int = (do char '-'
n <- nat
return (-n))
+++ nat
space :: Parser ()
space = do many' (sat isSpace)
return ()
comment :: Parser ()
comment = do string "--"
many' (sat (/= '\n'))
return ()
expr :: Parser Int
expr = do n <- natural
ns <- many'
(do symbol "-"
natural)
return (foldl (-) n ns)
token :: Parser a -> Parser a
token p = do space
v <- p
space
return v
identifier :: Parser String
identifier = token ident
natural :: Parser Int
natural = token nat
integer :: Parser Int
integer = token int
symbol :: String -> Parser String
symbol xs = token (string xs)