{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE GADTs #-} module Laborantin.Query.Interpret (toTExpr) where import Laborantin.Types import Control.Applicative ((<$>),(<*>)) import Laborantin.Query import Data.Text (Text) import Data.Maybe (fromMaybe) import Data.Time (UTCTime) type Param = Maybe ParameterValue data TTyp a where TTBool :: TTyp Bool TTNum :: TTyp Rational TTString :: TTyp Text TTParam :: TTyp (Text,Param) TTUTCTime :: TTyp UTCTime data IError = IError deriving (Show) -- carries the type of a TExpr data ATExpr = forall a . TExpr a ::: TTyp a instance Show ATExpr where show (expr ::: ty) = show expr toTExpr :: TExpr Bool -> UExpr -> (TExpr Bool) toTExpr expr = fromMaybe expr . toTExpr' toTExpr' :: UExpr -> Maybe (TExpr Bool) toTExpr' u = case interpret u of Right (expr ::: TTBool) -> Just expr _ -> Nothing interpret :: UExpr -> Either IError ATExpr interpret UScName = Right (ScName ::: TTString) interpret UScStatus = Right (ScStatus ::: TTString) interpret UScTimestamp = Right (ScTimestamp ::: TTUTCTime) interpret (UScParam a) = Right (ScParam a ::: TTParam) interpret (UB a) = Right (B a ::: TTBool) interpret (UT a) = Right (T a ::: TTUTCTime) interpret (UN a) = Right (N a ::: TTNum) interpret (US a) = Right (S a ::: TTString) interpret (UAnd a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTBool, y ::: TTBool) -> Right (And x y ::: TTBool) _ -> error "expecting 'boolean' for And clause" interpret (UOr a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTBool, y ::: TTBool) -> Right (Or x y ::: TTBool) _ -> error "expecting 'boolean' for Or clause" interpret (UPlus a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Plus x y ::: TTNum) _ -> error "expecting 'number' for Plus operator" interpret (UMinus a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Times x (TBind "0 - x" (\n -> N (0 - n)) y) ::: TTNum) _ -> error "expecting 'number' for Minus operator" interpret (UTimes a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Times x y ::: TTNum) _ -> error "expecting 'number' for Times operator" interpret (UDiv a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Times x (TBind "1/x" (\n -> N (1/n)) y) ::: TTNum) _ -> error "expecting 'number' for Div operator" interpret (UEq a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Eq x y ::: TTBool) (x ::: TTString, y ::: TTString) -> Right (Eq x y ::: TTBool) (x ::: TTBool, y ::: TTBool) -> Right (Eq x y ::: TTBool) (x ::: TTUTCTime, y ::: TTUTCTime) -> Right (Eq x y ::: TTBool) (x ::: TTParam, y ::: TTString) -> Right (Eq (SCoerce x) y ::: TTBool) (x ::: TTString, y ::: TTParam) -> Right (Eq x (SCoerce y) ::: TTBool) (x ::: TTParam, y ::: TTNum) -> Right (Eq (NCoerce x) y ::: TTBool) (x ::: TTNum, y ::: TTParam) -> Right (Eq x (NCoerce y) ::: TTBool) (x ::: TTParam, y ::: TTParam) -> Right (Eq x y ::: TTBool) _ -> error "type mismatch for equality check" interpret (UGt a b) = do vals <- ((,) <$> interpret a <*> interpret b) case vals of (x ::: TTNum, y ::: TTNum) -> Right (Gt x y ::: TTBool) (x ::: TTUTCTime, y ::: TTUTCTime) -> Right (Gt x y ::: TTBool) (x ::: TTParam, y ::: TTNum) -> Right (Gt (NCoerce x) y ::: TTBool) (x ::: TTNum, y ::: TTParam) -> Right (Gt x (NCoerce y) ::: TTBool) (x ::: TTParam, y ::: TTParam) -> Right (Gt (NCoerce x) (NCoerce y) ::: TTBool) _ -> error "type mismatch for comparison" interpret (UGte a b) = interpret (UOr (UGt a b) (UEq a b)) interpret (ULt a b) = interpret (UNot (UGte a b)) interpret (ULte a b) = interpret (UNot (UGt a b)) interpret (UContains a b) = do val <- interpret a case val of (x ::: TTNum) -> Right (Contains x (L $ ttnums b) ::: TTBool) (x ::: TTUTCTime) -> Right (Contains x (L $ ttutcs b) ::: TTBool) (x ::: TTString) -> Right (Contains x (L $ ttstrs b) ::: TTBool) (x ::: TTParam) -> Right ((Or (Contains (SilentSCoerce x) (L $ ttstrs b)) (Contains (SilentNCoerce x) (L $ ttnums b))) ::: TTBool) _ -> error "interpretation unsupported for 'in'" interpret (UL as) = do -- TODO evaluate non-heterogeneous lists error "cannot safely evaluate list which may be heterogeneous" interpret (UNot x) = do val <- interpret x case val of (x ::: TTBool) -> Right (Not x ::: TTBool) _ -> error "expecting 'boolean' for Not clause" ttnums :: UExpr -> [TExpr Rational] ttnums (UL xs) = map (\(UN x) -> N x) (filter match xs) where match (UN _) = True match _ = False ttnums _ = [] ttstrs :: UExpr -> [TExpr Text] ttstrs (UL xs) = map (\(US x) -> S x) (filter match xs) where match (US _) = True match _ = False ttstrs _ = [] ttutcs :: UExpr -> [TExpr UTCTime] ttutcs (UL xs) = map (\(UT x) -> T x) (filter match xs) where match (UT _) = True match _ = False ttutcs _ = []