NLinker icon

Task to implement JSON parser

NLinker | PRO | 11/20/19 06:17:36 PM UTC | 0 ⭐ | 12904 👁️ | Never ⏰ | []
Haskell |

4.93 KB

|

None

|

0 👍

/

0 👎

Astyanax task
https://repl.it/@astynax/ParserCombinators
-------------
 
import Data.Char (isDigit, isSpace)
-- No more imports should be here!
 
-- ******** Types ***********
 
newtype Parser a = Parser
  { runParser
    :: String
    -- ^ parser's input
    -> Maybe -- parsing can fail
       ( a
       -- ^ parsed value
       , String
       -- ^ rest of input
       )
  }
 
instance Functor Parser where
  fmap = error "fmap: implement me!"
  
instance Applicative Parser where
  pure  = error "pure: implement me!"
  {- 
  > runParser (pure 42) "asd"
  Just (42, "asd")
  > runParser (pure 42) ""
  Just (42, "")
  -}
  
  -- Hint: (<*>) :: Parser (a -> b) -> Parser a -> Parser b
  (<*>) = error "(<*>): implement me!"
 
-- ********* Elementary parsers ************
 
{-
> runParser anyChar "ab"
Just ('a', "b")
> runParser anyChar "a"
Just ('a', "")
> runParser anyChar ""
Nothing
-}
anyChar :: Parser Char
anyChar = Parser $ \s ->
  case s of
    (x:xs) -> Just (x, xs)
    _      -> Nothing
 
{-
> runParser (satisfy (== 'a') anyChar) "abc"
Just ('a', "bc")
> runParser (satisfy isSpace anyChar) " a "
Just (' ', "a ")
> runParser (satisfy isSpace anyChar) "xyz"
Nothing
> runParser (satisfy isSpace anyChar) ""
Nothing
-}
satisfy :: (a -> Bool) -> Parser a -> Parser a
satisfy pred p = Parser $ \s ->
  case runParser p s of
    Just (x, xs) | pred x -> Just (x, xs)
    _                     -> Nothing
 
{-
> runParser (char '1') "123"
Just ('1', "23")
-}
char :: Char -> Parser Char
char c = satisfy (== c) anyChar
 
{-
> runParser eof "asd"
Nothing
> runParser eof ""
Just ((), "")
-}
eof :: Parser ()
eof = Parser $ \s ->
  case s of
    [] -> Just ((), "")
    _  -> Nothing
 
-- ********* Combinators ***********
{-
> runParser (char 'a' <|> char 'b') "a"
Just ('a', "")
> runParser (char 'a' <|> char 'b') "b"
Just ('b', "")
> runParser (char 'a' <|> char 'b') "c"
Nothing
-}
(<|>) :: Parser a -> Parser a -> Parser a
p1 <|> p2 = error "(<|>): implement me!"
 
{-
> runParser (many $ char '.') ".abc"
Just (".", "abc")
> runParser (many $ char '.') ".....abc"
Just (".....", "abc")
> runParser (many $ char '.') "abc"
Just ("", "abc")
-}
many :: Parser a -> Parser [a]
many p = many1 p <|> pure []
 
{-
> runParser (many1 $ char '.') ".abc"
Just (".", "abc")
> runParser (many1 $ char '.') ".....abc"
Just (".....", "abc")
> runParser (many1 $ char '.') "abc"
Nothing
-}
many1 :: Parser a -> Parser [a]
many1 p = (:) <$> p <*> many p
 
{-
> runParser (between (char '{') (char '}') (many anyChar)) "{}asd"
Just ("", "asd")
> runParser (between (char '{') (char '}') (many anyChar)) "{as}d"
Just ("as", "d")
> runParser (between (char '{') (char '}') (many anyChar)) "{asd"
Nothing
-}
between :: Parser a -> Parser b -> Parser c -> Parser c
between p1 p2 p = p1 *> p <* p2
 
{-
> runParser (sepBy (char ',') (satisfy isDigit anyChar)) "1,2,3,a"
Just ("123", ",a")
> runParser (sepBy (char ',') (satisfy isDigit anyChar)) "1"
Just ("1", "")
> runParser (sepBy (char ',') (satisfy isDigit anyChar)) ""
Just ("", "")
-}
sepBy :: Parser a -> Parser b -> Parser [b]
sepBy s p = error "sepBy: implement me!"
 
-- ********* Combined parsers **********
 
{-
> runParser (string "foo") "fo"
Nothing
> runParser (string "foo") "foobar"
Just ("foo", "bar")
-}
string :: String -> Parser String
string = error "string: implement me!"
 
-- *********** Simple JSON parser *****************
-- * incomplete(!), i.e. w/o any advanced stuff like special char escaping, spaces, etc
 
data JSON
  = JNull
  | JBool Bool
  | JNum Int
  | JString String
  | JArray [JSON]
  | JObject [(String, JSON)]
  deriving (Show)
 
quotedString :: Parser String
quotedString = between (char '"') (char '"') $ many (satisfy (/= '"') anyChar)
 
jnull, jbool, jnum, jstring, jarray, jobject, json :: Parser JSON
json    = jnull <|> jbool <|> jnum <|> jstring <|> jarray <|> jobject
jnull   = JNull <$ string "null"
jbool   = JBool <$> ((True <$ string "true") <|> (False <$ string "false"))
jnum    = error "jnum: implement me!"
jstring = JString <$> quotedString
jarray  = JArray <$> between (char '[') (char ']') (sepBy (char ',') json)
jobject = JObject <$> between (char '{') (char '}')
   (sepBy (char ',') $ (,) <$> quotedString <* char ':' <*> json)
 
-- ************** Some tests
 
main :: IO ()
main = do
  putStrLn "These ones should parse something"
  print $ runParser jnull "null"
  print $ runParser jbool "true"
  print $ runParser jnum "123"
  print $ runParser jstring "\"abc\""
  print $ runParser jarray "[]"
  print $ runParser jarray "[null]"
  print $ runParser jarray "[true,false]"
  print $ runParser jobject "{}"
  print $ runParser jobject "{\"a\":null}"
  print $ runParser (json <* eof) "{\"a\":[1,null,false,\"foo\",{}],\"b\":true}"
  putStrLn "This one should fail:"
  print $ runParser (json <* eof) "{\"a\":[1,null,false,\"foo\",{}],\"b\":true}blabla"

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎