{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
module HaskellWorks.Data.Json.Internal.Backend.Standard.Token.Tokenize
( IsChar(..)
, JsonToken(..)
, ParseJson(..)
) where
import Control.Applicative
import Data.Bits
import Data.Char
import Data.Word
import Data.Word8
import HaskellWorks.Data.Char.IsChar
import HaskellWorks.Data.Json.Internal.Token.Types
import HaskellWorks.Data.Parser ((<?>))
import qualified Data.Attoparsec.ByteString.Char8 as BC
import qualified Data.Attoparsec.Combinator as AC
import qualified Data.Attoparsec.Types as T
import qualified Data.ByteString as BS
import qualified HaskellWorks.Data.Parser as P
hexDigitNumeric :: P.Parser t u => T.Parser t Int
hexDigitNumeric = do
c <- P.satisfyChar (\c -> '0' <= c && c <= '9')
return $ ord c - ord '0'
hexDigitAlphaLower :: P.Parser t u => T.Parser t Int
hexDigitAlphaLower = do
c <- P.satisfyChar (\c -> 'a' <= c && c <= 'z')
return $ ord c - ord 'a' + 10
hexDigitAlphaUpper :: P.Parser t u => T.Parser t Int
hexDigitAlphaUpper = do
c <- P.satisfyChar (\c -> 'A' <= c && c <= 'Z')
return $ ord c - ord 'A' + 10
hexDigit :: P.Parser t u => T.Parser t Int
hexDigit = hexDigitNumeric <|> hexDigitAlphaLower <|> hexDigitAlphaUpper
class ParseJson t s d where
parseJsonTokenString :: T.Parser t (JsonToken s d)
parseJsonToken :: T.Parser t (JsonToken s d)
parseJsonTokenBraceL :: T.Parser t (JsonToken s d)
parseJsonTokenBraceR :: T.Parser t (JsonToken s d)
parseJsonTokenBracketL :: T.Parser t (JsonToken s d)
parseJsonTokenBracketR :: T.Parser t (JsonToken s d)
parseJsonTokenComma :: T.Parser t (JsonToken s d)
parseJsonTokenColon :: T.Parser t (JsonToken s d)
parseJsonTokenWhitespace :: T.Parser t (JsonToken s d)
parseJsonTokenNull :: T.Parser t (JsonToken s d)
parseJsonTokenBoolean :: T.Parser t (JsonToken s d)
parseJsonTokenDouble :: T.Parser t (JsonToken s d)
parseJsonToken =
parseJsonTokenString <|>
parseJsonTokenBraceL <|>
parseJsonTokenBraceR <|>
parseJsonTokenBracketL <|>
parseJsonTokenBracketR <|>
parseJsonTokenComma <|>
parseJsonTokenColon <|>
parseJsonTokenWhitespace <|>
parseJsonTokenNull <|>
parseJsonTokenBoolean <|>
parseJsonTokenDouble
instance ParseJson BS.ByteString String Double where
parseJsonTokenBraceL = P.string "{" >> return JsonTokenBraceL
parseJsonTokenBraceR = P.string "}" >> return JsonTokenBraceR
parseJsonTokenBracketL = P.string "[" >> return JsonTokenBracketL
parseJsonTokenBracketR = P.string "]" >> return JsonTokenBracketR
parseJsonTokenComma = P.string "," >> return JsonTokenComma
parseJsonTokenColon = P.string ":" >> return JsonTokenColon
parseJsonTokenNull = P.string "null" >> return JsonTokenNull
parseJsonTokenDouble = JsonTokenNumber <$> P.rational
parseJsonTokenString = do
_ <- P.string "\""
value <- many (verbatimChar <|> escapedChar <|> escapedCode)
_ <- P.string "\""
return $ JsonTokenString value
where
verbatimChar = P.satisfyChar (BC.notInClass "\"\\") <?> "invalid string character"
escapedChar = do
_ <- P.string "\\"
( P.char '"' >> return '"' ) <|>
( P.char 'b' >> return '\b' ) <|>
( P.char 'n' >> return '\n' ) <|>
( P.char 'f' >> return '\f' ) <|>
( P.char 'r' >> return '\r' ) <|>
( P.char 't' >> return '\t' ) <|>
( P.char '\\' >> return '\\' ) <|>
( P.char '\'' >> return '\'' ) <|>
( P.char '/' >> return '/' )
escapedCode = do
_ <- P.string "\\u"
a <- hexDigit
b <- hexDigit
c <- hexDigit
d <- hexDigit
return $ chr $ a `shift` 24 .|. b `shift` 16 .|. c `shift` 8 .|. d
parseJsonTokenWhitespace = do
_ <- AC.many1' $ BC.choice [P.string " ", P.string "\t", P.string "\n", P.string "\r"]
return JsonTokenWhitespace
parseJsonTokenBoolean = true <|> false
where true = P.string "true" >> return (JsonTokenBoolean True)
false = P.string "false" >> return (JsonTokenBoolean False)
instance ParseJson BS.ByteString BS.ByteString Double where
parseJsonTokenBraceL = P.string "{" >> return JsonTokenBraceL
parseJsonTokenBraceR = P.string "}" >> return JsonTokenBraceR
parseJsonTokenBracketL = P.string "[" >> return JsonTokenBracketL
parseJsonTokenBracketR = P.string "]" >> return JsonTokenBracketR
parseJsonTokenComma = P.string "," >> return JsonTokenComma
parseJsonTokenColon = P.string ":" >> return JsonTokenColon
parseJsonTokenNull = P.string "null" >> return JsonTokenNull
parseJsonTokenDouble = JsonTokenNumber <$> P.rational
parseJsonTokenString = do
_ <- P.string "\""
value <- many (verbatimChar <|> escapedChar <|> escapedCode)
_ <- P.string "\""
return $ JsonTokenString $ BS.pack value
where
word :: Word8 -> T.Parser BS.ByteString Word8
word w = P.satisfy (== w)
verbatimChar :: T.Parser BS.ByteString Word8
verbatimChar = P.satisfy (\w -> w /= _quotedbl && w /= _backslash)
escapedChar :: T.Parser BS.ByteString Word8
escapedChar = do
_ <- P.string "\\"
( word _quotedbl >> return _quotedbl ) <|>
( word _b >> return 0x08 ) <|>
( word _n >> return _lf ) <|>
( word _f >> return _np ) <|>
( word _r >> return _cr ) <|>
( word _t >> return _tab ) <|>
( word _backslash >> return _backslash ) <|>
( word _quotesingle >> return _quotesingle ) <|>
( word _slash >> return _slash )
escapedCode :: T.Parser BS.ByteString Word8
escapedCode = do
_ <- P.string "\\u"
a <- hexDigit
b <- hexDigit
c <- hexDigit
d <- hexDigit
return $ fromIntegral $ a `shift` 24 .|. b `shift` 16 .|. c `shift` 8 .|. d
parseJsonTokenWhitespace = do
_ <- AC.many1' $ BC.choice [P.string " ", P.string "\t", P.string "\n", P.string "\r"]
return JsonTokenWhitespace
parseJsonTokenBoolean = true <|> false
where
true = P.string "true" >> return (JsonTokenBoolean True)
false = P.string "false" >> return (JsonTokenBoolean False)