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)
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
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 _ = []