{-# LANGUAGE OverloadedStrings #-} module Salak.Types.Value where import Control.Monad.Writer import Data.Attoparsec.Text import qualified Data.PQueue.Min as Q import Data.Scientific (Scientific) import Data.Text (Text) import qualified Data.Text as T import Data.Time import Salak.Types.Selector type Priority = Int data RefText = RRef [Selector] | RVal !Text deriving (Eq, Show) data Value = VStr !Priority !Text | VRef !Priority ![RefText] | VNum !Priority !Scientific | VBool !Priority !Bool | VZTime !Priority !TimeZone !LocalTime | VLTime !Priority !LocalTime | VDay !Priority !Day | VHour !Priority !TimeOfDay deriving Eq instance Ord Value where compare a b = compare (getPriority a) (getPriority b) instance Show Value where show v = let (a,b,c) = typeOfV v in c <> ":" <> b <> "#" <> show a newVStr :: Text -> Priority -> Value newVStr v i = g4 $ g3 $ go v where go v' = let (a,b) = T.break (=='$') v' in if T.null b then [RVal a] else RVal a : g2 b (parse ref b) g2 _ (Done x r) = r : go x g2 b _ = [RVal b] g3 (RVal a:RVal b:cs) = g3 $ RVal (a <> b) :cs g3 (RVal a:bs) = if T.null a then g3 bs else RVal a: g3 bs g3 (RRef a:bs) = RRef a : g3 bs g3 [] = [] g4 [RVal a] = VStr i a g4 x = VRef i x ref :: Parser RefText ref = RRef <$> do _ <- char '$' _ <- char '{' r <- exprs _ <- char '}' return r typeOfV :: Value -> (Priority, String, String) typeOfV (VStr a b) = (a, "Str", show b) typeOfV (VRef a b) = (a, "Ref", show b) typeOfV (VNum a b) = (a, "Num", show b) typeOfV (VBool a b) = (a, "Bool", show b) typeOfV (VZTime a b c) = (a, "ZonedTime", show (ZonedTime c b)) typeOfV (VLTime a b) = (a, "LocalTime", show b) typeOfV (VDay a b) = (a, "Day", show b) typeOfV (VHour a b) = (a, "TimeOfDay", show b) getPriority :: Value -> Priority getPriority x = let (a,_,_) = typeOfV x in a getType :: Value -> String getType x = let (_,b,_) = typeOfV x in b getV :: Value -> String getV x = let (_,_,b) = typeOfV x in b type QV = Q.MinQueue Value getQ :: QV -> Maybe Value getQ = Q.getMin nullQ :: QV -> Bool nullQ = Q.null insertQ :: Value -> QV -> QV insertQ = Q.insert replaceQ :: Monad m => String -> Priority -> QV -> QV -> WriterT [String] m QV replaceQ s i nq q = do let nq' = Q.filter ((==i) . getPriority) nq (a,b) = Q.partition ((==i) . getPriority) q go v = tell $ (\vi -> "#" <> show i <> " " <> vi) <$> v if a == nq' then return q else case getQ nq' of Just v -> do go [(if Q.null a then "Add " else "Mod ") ++ s] return $ Q.insert v b _ -> do unless (Q.null a) $ go ["Del " ++ s] return b