sugar-0.0.1: src/Sugar/Types.hs
{-# LANGUAGE TupleSections, DeriveGeneric, OverloadedStrings, CPP #-}
module Sugar.Types
( Sugar(..)
, Wrap(..)
, Note
, readSugarMay
, sugarTextMay
, sugarMapAsIxMap
, reservedChars
, FromSugar(..)
, ToSugar(..)
) where
import Data.Text (Text)
import Data.Map (Map)
import Data.Maybe (mapMaybe)
import Data.Text.Conversions (ToText(..), fromText, unUTF8, decodeConvertText, UTF8(..))
import Data.String (IsString(..))
import Data.Word (Word8,Word16,Word32,Word64)
import Data.Int (Int8,Int16,Int32,Int64)
import GHC.Generics (Generic)
import Safe (readMay)
import qualified Data.Map as Map
import qualified Data.Serialize as Serialize
import qualified Data.Store as Store ()
import qualified Data.ByteString as BS
import qualified Data.Text as T
---
data Sugar
= Sugar'Unit Note
| Sugar'Text Text Note
| Sugar'List [Sugar] Wrap Note
| Sugar'Map [(Sugar,Sugar)] Note
deriving (Eq, Show, Generic)
data Wrap
= Wrap'Square
| Wrap'Paren
deriving (Eq, Show, Generic)
type Note = Maybe [Sugar]
--
sugarTextMay :: Sugar -> Maybe Text
sugarTextMay (Sugar'Text t _) = Just t
sugarTextMay _ = Nothing
readSugarMay :: Read a => Sugar -> Maybe a
readSugarMay (Sugar'Text t _) = readMay $ T.unpack t
readSugarMay _ = Nothing
sugarMapAsIxMap :: [(Sugar,Sugar)] -> Map (Int, Sugar) Sugar
sugarMapAsIxMap = Map.fromList . zipWith (\i (k,v) -> ((i,k),v)) [0..]
sugarShow :: Show a => a -> Sugar
sugarShow s = Sugar'Text (T.pack $ show s) Nothing
reservedChars :: [Char]
reservedChars = ['\"','[',']','<','>','(',')','{','}',';']
--
instance Ord Sugar where
compare (Sugar'Unit x) (Sugar'Unit y) = compare x y
compare Sugar'Unit{} _ = GT
compare _ Sugar'Unit{} = LT
compare (Sugar'Text x0 x1) (Sugar'Text y0 y1) = compare x0 y0 `mappend` compare x1 y1
compare Sugar'Text{} _ = GT
compare _ Sugar'Text{} = LT
compare (Sugar'List x0 _ x1) (Sugar'List y0 _ y1) = compare x0 y0 `mappend` compare x1 y1
compare Sugar'List{} _ = GT
compare _ Sugar'List{} = LT
compare (Sugar'Map x0 x1) (Sugar'Map y0 y1) = compare x0 y0 `mappend` compare x1 y1
instance Serialize.Serialize Sugar where
get = do
tag <- Serialize.getWord8
go tag
where
go :: Word8 -> Serialize.Get Sugar
go 0 = Sugar'Unit <$> Serialize.get
go 1 = Sugar'Text <$> getSerializedText <*> Serialize.get
go 2 = Sugar'List <$> Serialize.get <*> Serialize.get <*> Serialize.get
go 3 = Sugar'Map <$> Serialize.get <*> Serialize.get
go _ = fail "No matching Sugar value"
getSerializedText :: Serialize.Get Text
getSerializedText = do
txt <- (decodeConvertText . UTF8) <$> (Serialize.get :: Serialize.Get BS.ByteString)
maybe (fail "Cannot deserialize text as UTF8") pure txt
put (Sugar'Unit note) = do
Serialize.put (0 :: Word8)
Serialize.put note
put (Sugar'Text txt note) = do
Serialize.put (1 :: Word8)
Serialize.put (unUTF8 $ fromText txt :: BS.ByteString)
Serialize.put note
put (Sugar'List xs w note) = do
Serialize.put (2 :: Word8)
Serialize.put xs
Serialize.put w
Serialize.put note
put (Sugar'Map m note) = do
Serialize.put (3 :: Word8)
Serialize.put m
Serialize.put note
instance Serialize.Serialize Wrap where
instance IsString Sugar where
fromString str = Sugar'Text (toText str) Nothing
class FromSugar a where
parseSugar :: Sugar -> Maybe a
instance FromSugar a => FromSugar [a] where
parseSugar (Sugar'List xs _ _) = mapM parseSugar xs
parseSugar _ = Nothing
instance FromSugar a => FromSugar (Maybe a) where
parseSugar (Sugar'Unit _) = Just Nothing
parseSugar s = (return . Just) =<< parseSugar s
instance (FromSugar a, Ord a, FromSugar b) => FromSugar (Map a b) where
parseSugar (Sugar'Map m _) = Just $ Map.fromList $
mapMaybe
(\(s,v) -> (,) <$> parseSugar s <*> parseSugar v)
m
parseSugar _ = Nothing
instance FromSugar Text where
parseSugar (Sugar'Text t _) = Just t
parseSugar _ = Nothing
instance FromSugar Bool where
parseSugar (Sugar'Text "#t" _) = Just True
parseSugar (Sugar'Text "#f" _) = Just False
parseSugar _ = Nothing
instance FromSugar Integer where parseSugar = readSugarMay
instance FromSugar Int where parseSugar = readSugarMay
instance FromSugar Int8 where parseSugar = readSugarMay
instance FromSugar Int16 where parseSugar = readSugarMay
instance FromSugar Int32 where parseSugar = readSugarMay
instance FromSugar Int64 where parseSugar = readSugarMay
instance FromSugar Word where parseSugar = readSugarMay
instance FromSugar Word8 where parseSugar = readSugarMay
instance FromSugar Word16 where parseSugar = readSugarMay
instance FromSugar Word32 where parseSugar = readSugarMay
instance FromSugar Word64 where parseSugar = readSugarMay
instance FromSugar Float where parseSugar = readSugarMay
instance FromSugar Double where parseSugar = readSugarMay
class ToSugar a where
toSugar :: a -> Sugar
instance ToSugar () where
toSugar () = Sugar'Unit Nothing
instance ToSugar Text where
toSugar t = Sugar'Text t Nothing
-- TODO: Will conflict with a String instance (aka [Char])
instance ToSugar a => ToSugar [a] where
toSugar xs = Sugar'List (map toSugar xs) Wrap'Square Nothing
instance ToSugar a => ToSugar (Maybe a) where
toSugar Nothing = Sugar'Unit Nothing
toSugar (Just a) = toSugar a
instance (ToSugar a, ToSugar b) => ToSugar (Map a b) where
toSugar m = Sugar'Map (map (\(k,v) -> (toSugar k, toSugar v)) $ Map.toList m) Nothing
instance (ToSugar a, ToSugar b) => ToSugar (a,b) where
toSugar (a,b) = Sugar'List [toSugar a, toSugar b] Wrap'Paren Nothing
instance (ToSugar a, ToSugar b, ToSugar c) => ToSugar (a,b,c) where
toSugar (a,b,c) = Sugar'List [toSugar a, toSugar b, toSugar c] Wrap'Paren Nothing
instance ToSugar Bool where
toSugar s = toSugar (if s then "#t" else "#f" :: Text)
instance ToSugar Integer where toSugar = sugarShow
instance ToSugar Int where toSugar = sugarShow
instance ToSugar Int8 where toSugar = sugarShow
instance ToSugar Int16 where toSugar = sugarShow
instance ToSugar Int32 where toSugar = sugarShow
instance ToSugar Int64 where toSugar = sugarShow
instance ToSugar Word where toSugar = sugarShow
instance ToSugar Word8 where toSugar = sugarShow
instance ToSugar Word16 where toSugar = sugarShow
instance ToSugar Word32 where toSugar = sugarShow
instance ToSugar Word64 where toSugar = sugarShow
instance ToSugar Float where toSugar = sugarShow
instance ToSugar Double where toSugar = sugarShow