My omnium-gatherom of scripts and source code.
at main 97 lines 3.0 kB view raw
1module Main where 2 3import Control.Applicative 4import Data.Char 5 6{- Abstract Syntax Tree -} 7data JsonValue = JsonNull 8 | JsonBool Bool 9 | JsonNumber Integer -- no support for floats 10 | JsonString String -- no support for escaping 11 | JsonArray [JsonValue] 12 | JsonObject [(String, JsonValue)] 13 deriving (Show, Eq) 14 15-- NOTE: no proper error reporting 16newtype Parser a = Parser { runParser :: String -> Maybe (String, a) } 17 18instance Functor Parser where 19 fmap f (Parser p) = Parser $ \input -> do 20 (input', x) <- p input 21 Just (input', f x) 22 23instance Applicative Parser where 24 pure :: a -> Parser a 25 pure x = Parser . (Just .) . flip (,) 26 27 (<*>) :: Parser (a -> b) -> Parser a -> Parser b 28 (Parser p1) <*> (Parser p2) = Parser $ \input -> do 29 (input', f) <- p1 input 30 (input'', a) <- p2 input' 31 Just (input'', f a) 32 33instance Alternative Parser where 34 empty :: Parser a 35 empty = Parser $ const Nothing 36 (<|>) :: Parser a -> Parser a -> Parser a 37 (Parser p1) <|> (Parser p2) = Parser $ \input -> p1 input <|> p2 input 38 39spanP :: (Char -> Bool) -> Parser String 40spanP f = Parser $ \input -> let (token, rest) = span f input in Just (rest, token) 41 42notNull :: Parser [a] -> Parser [a] 43notNull (Parser p) = Parser $ \input -> do 44 (input', xs) <- p input 45 if null xs then Nothing else Just (input', xs) 46 47charP :: Char -> Parser Char 48charP x = Parser f 49 where 50 f (y:ys) | y == x = Just (ys, x) 51 | otherwise = Nothing 52 f [] = Nothing 53 54stringP :: String -> Parser String 55stringP = sequenceA . map charP 56 57ws :: Parser String 58ws = spanP isSpace 59 60sepBy :: Parser a -> Parser b -> Parser [b] 61sepBy sep element = (:) <$> element <*> (many (sep *> element)) <|> pure [] 62 63jsonNull :: Parser JsonValue 64jsonNull = const JsonNull <$> stringP "null" 65 66jsonBool :: Parser JsonValue 67jsonBool = f <$> (stringP "true" <|> stringP "false") 68 where 69 f "true" = JsonBool True 70 f "false" = JsonBool False 71 f _ = undefined 72 73jsonNumber :: Parser JsonValue 74jsonNumber = f <$> notNull (spanP isDigit) 75 where f ds = JsonNumber $ read ds 76 77stringLiteral :: Parser String 78stringLiteral = charP '"' *> spanP (/= '"') <* charP '"' 79 80jsonString :: Parser JsonValue 81jsonString = JsonString <$> stringLiteral 82 83jsonArray :: Parser JsonValue 84jsonArray = JsonArray <$> (charP '[' *> ws *> elements <* ws <* charP ']') 85 where elements = sepBy (ws *> charP ',' <* ws) jsonValue 86 87jsonObject :: Parser JsonValue 88jsonObject = JsonObject <$> (charP '{' *> ws *> sepBy (ws *> charP ',' <* ws) pair <* ws <* charP '}') 89 where pair = (\key _ value -> (key, value)) <$> stringLiteral <*> (ws *> charP ':' <* ws) <*> jsonValue 90 91jsonValue :: Parser JsonValue 92jsonValue = jsonNull <|> jsonBool <|> jsonNumber <|> jsonString <|> jsonArray <|> jsonObject 93 94parseFile :: FilePath -> Parser a -> IO (Maybe a) 95parseFile filename parser = do 96 input <- readFile filename 97 return (snd <$> runParser parser input)