module EventLoop.Json(JSONMember(..), JSONMessage(..), retrieve, retrieveError, FromJSON(..), JSONAble(..), stringToJsonObject) where
import Data.Char (isDigit, isLower, isUpper)
import FPPrac
data JSONMember = JSONMember [Char] JSONMessage
data JSONMessage = JSONNumber Number
| JSONString [Char]
| JSONBool Bool
| JSONObject [JSONMember]
| JSONArray [JSONMessage]
retrieve :: [Char] -> [JSONMember] -> Maybe JSONMessage
retrieve search [] = Nothing
retrieve search ((JSONMember name member):list) | search == name = Just member
| otherwise = retrieve search list
retrieveError :: [Char] -> [JSONMember] -> JSONMessage
retrieveError search members = case (retrieve search members) of
Nothing -> error ("Could not find " ++ search ++ " in JSON members")
Just result -> result
class FromJSON a where
fromJsonMessage :: JSONMessage -> a
instance Show JSONMessage where
show (JSONNumber n) = show n
show (JSONString s) = "\"" ++ s ++ "\""
show (JSONBool bool) | bool = "true"
| otherwise = "false"
show (JSONObject (r:rs)) = "{" ++ rows ++ "}"
where
rows = foldl insertComma (show r) (map show rs)
show (JSONArray []) = "[]"
show (JSONArray (x:xs)) = "[" ++ list ++ "]"
where
list = foldl insertComma (show x) (map show xs)
insertComma :: [Char] -> [Char] -> [Char]
insertComma a b = a ++ "," ++ b
instance Show JSONMember where
show (JSONMember name m) = "\"" ++ name ++ "\": " ++ (show m)
class JSONAble a where
toJsonMessage :: a -> JSONMessage
data Grammer = O | R
type Rest = [Char]
stringToJsonObject :: [Char] -> JSONMessage
stringToJsonObject string = snd $ parse O string (JSONObject [])
errorMsg :: [Char] -> [Char] -> [Char]
errorMsg exp act = "Fault at parsing, expected '" ++ exp ++ "' but found '" ++ act ++ "'"
parse :: Grammer -> Rest -> JSONMessage -> (Rest, JSONMessage)
parse O [] _ = error (errorMsg "something" "premature end (start of message)")
parse O (c1:cs) (JSONObject rows) | c1 == '{' = result
| otherwise = error (errorMsg "{" [c1])
where
((c1':cs'), object) = parse R cs (JSONObject rows)
result | c1' == '}' = (cs', object)
| otherwise = error (errorMsg "}" [c1'])
parse R [] _ = error (errorMsg "something" "premature end (reading a row)")
parse R (t:ts) (JSONObject rows) = object
where
((r:rs), rowName) | t == '"' = parseWord ts
| otherwise = error (errorMsg "\"" [t])
rs' | r == ':' = rs
| otherwise = error (errorMsg ":" [r])
((r'':rs''), var2) = parseVariable rs'
rows' = rows ++ [(JSONMember rowName var2)]
object | r'' == '}' = ((r'':rs''), JSONObject rows')
| r'' == ',' = parse R rs'' (JSONObject rows')
| otherwise = error (errorMsg "',' or '}'" [r''])
parseVariable :: Rest -> (Rest, JSONMessage)
parseVariable [] = error (errorMsg "something" "premature end")
parseVariable [c1] = error (errorMsg "longer variable" (c1:" and premature end"))
parseVariable (c1:c2:cs) | c1 == '"' && ((isLower c2) || (isUpper c2)) = (r1, JSONString word)
| isDigit c1 = (r2, JSONNumber (read number))
| otherwise = error (errorMsg "\"" [c1])
where
(r1, word) = parseWord (c2:cs)
(r2, number) = parseNumber (c1:c2:cs)
parseWord :: Rest -> (Rest, [Char])
parseWord [] = error (errorMsg "something" "premature end")
parseWord (c1:cs) | (isLower c1) || (isDigit c1) || (isUpper c1) = (r1, c1:result')
| c1 == '"' = (cs, [])
| otherwise = error (errorMsg "letter or number" [c1])
where
(r1, result') = parseWord cs
parseNumber :: Rest -> (Rest, [Char])
parseNumber [] = error (errorMsg "something" "premature end")
parseNumber (c1:cs) | isDigit c1 || c1 == '.' = (r1, c1:result')
| c1 == ',' || c1 == '}' = (c1:cs, [])
| otherwise = error (errorMsg "number" [c1])
where
(r1, result') = parseNumber cs