--------------------------------------------------------------------- -- -- | UxADT -- -- @Data\/UxADT.hs@ -- -- A library that supports a universal, cross-platform embedded -- representation for algebraic data type (ADT) values. -- -- Web: uxadt.org -- Version: 0.0.16.0 -- -- ---------------------------------------------------------------- -- {-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-} module Data.UxADT where import Data.Ratio import Data.Data import Text.JSON import Control.Monad.State ---------------------------------------------------------------- -- | UxADT Data type definition. type Variable = String type Constructor = String data UxADT = V Variable | B Bool | R Rational | CH Char -- For internal use only. | S String | C Constructor [UxADT] | L [UxADT] | None deriving (Show, Eq) ---------------------------------------------------------------- -- | Conversion from arbitrary algebraic data type values to -- UxADT values. uxadt :: Data a => a -> UxADT uxadt x = let -- Helper function for conversion from lists. mkCons :: [UxADT] -> UxADT mkCons [CH c, S cs] = S $ c:cs mkCons [CH c, L []] = S $ c:"" mkCons [x, L xs] = L $ x:xs mkCons _ = None rep = dataTypeRep (constrType $ toConstr x) ty = dataTypeName $ dataTypeOf x in if ty == "Prelude.Bool" then B (case show (toConstr x) of "True" -> True ; "False" -> False) else if rep == IntRep then R (toRational (read (show (toConstr x)) :: Integer)) else if rep == FloatRep then R (toRational (read (show (toConstr x)) :: Float)) else if ty == "Prelude.Double" then R (toRational (read (show (toConstr x)) :: Double)) else if ty == "GHC.Real.Ratio" then R $ (\[R n, R d] -> (numerator n) % (numerator d)) [i | i <- gmapQ uxadt x] else if ty == "Prelude.[]" then case (show (toConstr x)) of "(:)" -> mkCons (gmapQ uxadt x) "[]" -> L [] else if ty == "Prelude.(,)" then L (gmapQ uxadt x) else if ty == "Prelude.Char" then CH $ head (drop 1 (show (toConstr x))) else C (show (toConstr x)) (gmapQ uxadt x) ---------------------------------------------------------------- -- | Useful synonym. toUxADT :: Data a => a -> UxADT toUxADT = uxadt ---------------------------------------------------------------- -- | Conversion to an algebraic data type value from a UxADT -- value. fromUxADT :: Data a => [DataType] -> UxADT -> a fromUxADT tys u = let constrByName :: String -> [DataType] -> Constr constrByName c' ts = head [c | t <- ts, c <- dataTypeConstrs t, showConstr c == c'] nxt :: Data a => State [UxADT] a nxt = do {(u:us) <- get; put us; return (fromUxADT tys u)} in case u of B b -> fromConstr (constrByName (show b) [dataTypeOf True]) R r -> let nxt :: Data a => State [Integer] a nxt = do {(n:ns) <- get; put ns; return (fromConstr (toConstr n))} in evalState (fromConstrM nxt (constrByName ":%" [dataTypeOf r])) [numerator r, denominator r] CH c -> fromConstr (toConstr c) S "" -> fromConstr (constrByName "[]" [dataTypeOf [()]]) S (c:cs) -> evalState (fromConstrM nxt (constrByName "(:)" [dataTypeOf [()]])) [CH c, S cs] C c [] -> fromConstr (constrByName c tys) C c us -> evalState (fromConstrM nxt (constrByName c tys)) us L [] -> fromConstr (constrByName "[]" [dataTypeOf [()]]) L (u:us) -> evalState (fromConstrM nxt (constrByName "(:)" [dataTypeOf [()]])) [u, L us] _ -> error "UxADT value cannot be converted to native Haskell value." ---------------------------------------------------------------- -- | Translations between the native UxADT representation and a -- native JSON representation. instance JSON UxADT where showJSON u = case u of B b -> JSBool b R r -> JSRational True r S s -> JSString $ toJSString s C c us -> makeObj [(c, showJSON us)] L us -> JSArray (map showJSON us) _ -> JSNull readJSON j = case j of JSBool b -> Ok $ B b JSRational True r -> Ok $ R $ r JSString s -> Ok $ S $ fromJSString s JSObject o -> case fromJSObject o of [(c, js)] -> case readJSONs js of Ok us -> Ok $ C c us _ -> Error "JSON not a value UxADT value." _ -> Error "JSON not a value UxADT value." JSArray js -> case readJSONs j of Ok us -> Ok $ L us _ -> Error "JSON not a value UxADT value." _ -> Error "JSON not a value UxADT value." --eof