-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMain.hs
More file actions
144 lines (118 loc) · 4.06 KB
/
Copy pathMain.hs
File metadata and controls
144 lines (118 loc) · 4.06 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
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
140
141
142
143
144
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use lambda-case" #-}
module Main where
import Control.Applicative
import Data.Char (digitToInt, isDigit, isSpace)
import Prelude hiding ((>>=))
-- grammer
data JsonValue
= JsonNull
| JsonBool !Bool
| JsonNumber !Int
| JsonString !String
| JsonObject ![(String, JsonValue)]
| JsonArray ![JsonValue]
| JsonValue
deriving (Show, Eq)
-- input -> Maybe (remaining input, parsed value)
newtype Parser a = Parser {parse :: String -> Maybe (a, String)}
-- need to proove parser is functor
instance Functor Parser where
-- fmap :: (a -> b) -> f a -> f b
fmap f (Parser parser1) =
Parser $ \ip -> do
(x, ip1) <- parser1 ip
Just (f x, ip1)
-- need to proove parser is applicative
instance Applicative Parser where
-- pure :: a -> f a
pure x = Parser $ \input -> Just (x, input)
-- (<*>) :: f (a -> b) -> f a -> f b
(Parser parser1) <*> (Parser parser2) =
Parser $ \input -> do
(f, input1) <- parser1 input
(a, input2) <- parser2 input1
Just (f a, input2)
-- need to proove parser is alternative
instance Alternative Parser where
-- empty :: f a
empty = Parser $ const Nothing
-- (<|>) :: f a -> f a -> f a
(Parser parser1) <|> (Parser parser2) = Parser $ \input -> do
parser1 input <|> parser2 input
satisfy :: (Char -> Bool) -> Parser Char
satisfy predicate = Parser parseIfSatisfy
where
parseIfSatisfy (x : xs) = if predicate x then Just (x, xs) else Nothing
parseIfSatisfy _ = Nothing
-- many applys parser till it fails
sepBy :: Parser a -> Parser b -> Parser [b]
sepBy sep element = (:) <$> element <*> many (sep *> element) <|> pure []
surroundedBy :: Parser a -> Parser b -> Parser a
surroundedBy p1 p2 = p2 *> p1 <* p2
charParser :: Char -> Parser Char
charParser toMatch = satisfy (== toMatch)
stringParser :: String -> Parser String
stringParser = traverse charParser
ws :: Parser String
ws = many (charParser ' ' <|> charParser '\n' <|> charParser '\r' <|> charParser '\t')
-- (*>) :: Parser Char -> Parser String -> Parser String
-- (<*) :: Parser String-> Parser Char -> Parser String
stringLiteral :: Parser String
stringLiteral = (many . satisfy) (/= '"') `surroundedBy` charParser '"'
-- (<$) :: JsonValue -> Parser String -> Parser JsonValue
jsonNull :: Parser JsonValue
jsonNull = JsonNull <$ stringParser "null"
-- (<$>) :: (String -> JsonValue) -> Parser String -> Parser JsonValue
-- take a function (convertToJsonBool) and a functor (our stringParser)
-- return a new Parser functor which return convertToJsonBool applied to output and rest of input
jsonBool :: Parser JsonValue
jsonBool = convertToJsonBool <$> (stringParser "true" <|> stringParser "false")
where
-- a function which converts output of our parser to jsonvalue
convertToJsonBool "true" = JsonBool True
convertToJsonBool "false" = JsonBool False
jsonString :: Parser JsonValue
jsonString = JsonString <$> stringLiteral
jsonNumber :: Parser JsonValue
jsonNumber = JsonNumber . read <$> (some . satisfy) isDigit
jsonArray :: Parser JsonValue
jsonArray =
JsonArray
<$> ( charParser '['
*> (elements `surroundedBy` ws)
<* charParser ']'
)
where
elements = sepBy (charParser ',' `surroundedBy` ws) jsonValue
jsonObject :: Parser JsonValue
jsonObject =
JsonObject
<$> ( charParser '{'
*> sepBy (charParser ',' `surroundedBy` ws) element `surroundedBy` ws
<* charParser '}'
)
where
element =
(\key _ val -> (key, val))
<$> stringLiteral
<*> (charParser ':' `surroundedBy` ws)
<*> jsonValue
jsonValue :: Parser JsonValue
jsonValue =
jsonNull
<|> jsonBool
<|> jsonString
<|> jsonNumber
<|> jsonArray
<|> jsonObject
parseJson :: String -> Maybe JsonValue
parseJson s = case parse jsonValue s of
Just (op, "") -> Just op
_ -> Nothing
main :: IO ()
main = do
let jsonData = "{\"a\": false, \"c\": null, \"foo\": [\"bar\",1,2,3,{}]}"
case parseJson jsonData of
Just parsedValue -> print parsedValue
Nothing -> putStrLn "Failed to parse JSON"