-
Notifications
You must be signed in to change notification settings - Fork 0
/
Main.hs
113 lines (91 loc) · 2.89 KB
/
Main.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
module Main where
import Control.Applicative
import Data.Char
data JsonValue = JsonNull
| JsonBool Bool
| JsonNumber Integer
| JsonString String
| JsonArray [JsonValue]
| JsonObject [(String, JsonValue)]
deriving (Show, Eq)
newtype Parser a = Parser
{
runParser :: String -> Maybe (String, a)
}
instance Functor Parser where
fmap f (Parser p) =
Parser $ \input -> do
(input', x) <- p input
Just (input', f x)
instance Applicative Parser where
pure x = Parser $ \input -> Just (input, x)
(Parser p1) <*> (Parser p2) =
Parser $ \input -> do
(input', f) <- p1 input
(input'', a) <- p2 input'
Just (input'', f a)
instance Alternative Parser where
empty = Parser $ \_ -> Nothing
(Parser p1) <|> (Parser p2) =
Parser $ \input -> p1 input <|> p2 input
jsonNull :: Parser JsonValue
jsonNull = (\_ -> JsonNull) <$> stringP "null"
charP :: Char -> Parser Char
charP x = Parser f
where
f (y:ys)
| y == x = Just (ys, x)
| otherwise = Nothing
f [] = Nothing
stringP :: String -> Parser String
stringP = sequenceA . map charP
jsonBool :: Parser JsonValue
jsonBool = f <$> (stringP "true" <|> stringP "false")
where f "true" = JsonBool True
f "false" = JsonBool False
f _ = undefined
spanP :: (Char -> Bool) -> Parser String
spanP f =
Parser $ \input ->
let (token, rest) = span f input
in Just (rest, token)
notNull :: Parser [a] -> Parser [a]
notNull (Parser p) =
Parser $ \input -> do
(input', xs) <- p input
if null xs
then Nothing
else Just (input', xs)
jsonNumber :: Parser JsonValue
jsonNumber = f <$> notNull (spanP isDigit)
where f ds = JsonNumber $ read ds
stringLiteral :: Parser String
stringLiteral = charP '"' *> spanP (/= '"') <* charP '"'
jsonString :: Parser JsonValue
jsonString = JsonString <$> stringLiteral
ws :: Parser String
ws = spanP isSpace
sepBy :: Parser a -> Parser b -> Parser [b]
sepBy sep element = (:) <$> element <*> many (sep *> element) <|> pure []
jsonArray :: Parser JsonValue
jsonArray = JsonArray <$> (charP '[' *> ws *>
elements
<* ws <* charP ']')
where
elements = sepBy (ws *> charP ',' <* ws) jsonValue
jsonObject :: Parser JsonValue
jsonObject =
JsonObject <$> (charP '{' *> ws *> sepBy (ws *> charP ',' <* ws) pair <* ws <* charP '}')
where
pair =
(\key _ value -> (key, value)) <$> stringLiteral <*>
(ws *> charP ':' <* ws) <*>
jsonValue
jsonValue :: Parser JsonValue
jsonValue = jsonNull <|> jsonBool <|> jsonNumber <|> jsonString <|> jsonArray <|> jsonObject
parseFile :: FilePath -> Parser a -> IO (Maybe a)
parseFile fileName parser = do
input <- readFile fileName
return (snd <$> runParser parser input)
main :: IO ()
main = undefined