-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson-parser.hs
More file actions
63 lines (53 loc) · 1.95 KB
/
Copy pathjson-parser.hs
File metadata and controls
63 lines (53 loc) · 1.95 KB
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
module JSON.Parser (parse) where
import qualified Text.ParserCombinators.Parsec as P
import Text.ParserCombinators.Parsec hiding (parse, string)
import Control.Monad (void)
import Prelude hiding (null)
data Value = String String
| Number Double
| Object [(Value,Value)] -- an association list -- only a `String` is valid as the index `Value`
| Array [Value] -- not limited to identical primitive datatypes
| Boolean Bool -- either `True` or `False`
| Null
deriving Show
parse :: String -> Maybe Value
parse = eitherToMaybe . P.parse (jsonValue <* eof) ""
where
eitherToMaybe (Right x) = Just x
eitherToMaybe (Left _) = Nothing
string :: Parser Value
string = String <$> betweenQuotes (many notQuote)
where
notQuote = satisfy (/= '"')
betweenQuotes = lexeme . between (char '"') (char '"')
number :: Parser Value
number = lexeme $ do
sign <- option "" (P.string "-")
int <- P.string "0" <|> ((:) <$> oneOf ['1'..'9'] <*> many digit)
frac <- option "" ((:) <$> char '.' <*> many1 digit)
return $ Number $ read (sign ++ int ++ frac)
object :: Parser Value
object = Object <$> betweenCurlyBrackets members
where
betweenCurlyBrackets = between (lexeme $ char '{') (lexeme $ char '}')
members = pair `sepBy` char ','
pair = do
key <- string
void $ lexeme $ char ':'
value <- jsonValue
return (key, value)
array :: Parser Value
array = Array <$> betweenSquareBrackets (jsonValue `sepBy` char ',')
where
betweenSquareBrackets = between (lexeme $ char '[') (lexeme $ char ']')
boolean :: Parser Value
boolean = Boolean <$> (true <|> false)
where
true = True <$ (lexeme $ P.string "true")
false = False <$ (lexeme $ P.string "false")
null :: Parser Value
null = Null <$ (lexeme $ P.string "null")
jsonValue :: Parser Value
jsonValue = spaces *> choice [number, string, boolean, null, array, object]
lexeme :: Parser a -> Parser a
lexeme p = p <* spaces