module Text.EasyJson.Parser where
import Control.Applicative
import Control.Monad.Identity
import qualified Data.HashMap.Strict as H
import Data.Monoid
import Data.Text (Text, pack, unpack)
import qualified Data.Text as T
import qualified Data.Vector as V
import Text.Parsec hiding (many, (<|>))
import Text.EasyJson.AST
type ParserState = ()
type Parser = ParsecT String ParserState Identity
sstring :: String -> Parser String
sstring = lexeme . string
schar :: Char -> Parser Char
schar = lexeme . char
lexeme :: Parser a -> Parser a
lexeme p = p <* spaces
pJson :: Parser Json
pJson = choice [Number <$> pNumber, String <$> pString,
false, true, null, array, object] where
enclose l r p = between (schar l) (schar r) $ p `sepEndBy` schar ','
array = Array . V.fromList <$> enclose '[' ']' pJson
object = Object . H.fromList <$> enclose '{' '}' keyval
keyval = (,) <$> pString <*> (schar ':' *> pJson)
false = sstring "false" >> return (Bool False)
true = sstring "true" >> return (Bool True)
null = sstring "null" *> return Null
pNumber :: Parser Double
pNumber = lexeme $ fmap read $ do
first <- many1 digit
option first $ do
dot <- char '.'
rest <- many1 digit
return $ first <> [dot] <> rest
pString :: Parser Text
pString = lexeme $ do
start <- char '"' <|> char '\''
loop start []
where
loop stop acc = do
option (pack $ reverse acc) $ anyChar >>= \case
c | c == stop -> return $ pack $ reverse acc
'\\' -> anyChar >>= \case
'n' -> add '\n'
'r' -> add '\r'
't' -> add '\r'
'b' -> add '\r'
'\\' -> add '\\'
'"' -> add '"'
'\'' -> add '\''
c -> unexpected $ "Unrecognized escape sequence: \\" <> [c]
c -> add c
where add c = loop stop (c : acc)
parseIt :: String -> Either ParseError Json
parseIt = parse (pJson <* eof) ""