packages feed

chalkboard-1.9.0.15: Graphics/ChalkBoard/Expr.hs

{-# LANGUAGE TypeFamilies, GADTs #-}
module Graphics.ChalkBoard.Expr where
	
--import Control.Applicative
import Graphics.ChalkBoard.Types -- hiding (Alpha)
import qualified Graphics.ChalkBoard.Types as Ty
import Graphics.ChalkBoard.Core as C
import Data.Reify.Graph
import Data.Reify
import Control.Applicative as AF
import qualified Data.Traversable as T
import qualified Data.Foldable as F
import Data.Monoid
import Data.Maybe
import qualified Data.List as L
import Control.Monad

-- All the functions in our first order language.
data Expr s 
	= Choose s s s
	| O_Bool Bool
	| O_RGB RGB
	| O_RGBA RGBA -- (Ty.Alpha RGB)
	| O_Pair s s 			-- (a,b)
	| O_Fst s
	| O_Snd s
	| Lit R
	| Var Int
	| OrBool		-- the || function
	| Alpha UI s		-- O_Alpha?
	| ScaleAlpha UI s			-- RGBA -> RGBA
	| UnAlpha s
	deriving Show

newtype E = E (Expr E)
	deriving Show

data ExprType = BOOL_Ty | RGB_Ty | RGBA_Ty	-- we seems to have this all over
	deriving (Show, Eq)

exprTypeE :: E -> Maybe ExprType
exprTypeE (E e) = exprType e

exprType :: Expr E -> Maybe ExprType
exprType (Choose _ a b)     = getFirst (First (exprTypeE a) `mappend` (First (exprTypeE b)))
exprType (O_Bool {})        = return BOOL_Ty
exprType (O_RGB {})         = return RGB_Ty
exprType (O_RGBA {}) 	    = return RGBA_Ty
exprType (Alpha {})	    = return RGBA_Ty
exprType (UnAlpha {})	    = return RGB_Ty
exprType (ScaleAlpha {})    = return RGBA_Ty
exprType _                  = Nothing

exprUnifyE :: E -> ExprType -> [(Int,ExprType)]
exprUnifyE (E e) = exprUnify e

-- exprUnify :: what the expected result type is, and does it unify
exprUnify :: Expr E -> ExprType -> [(Int,ExprType)]
exprUnify (Choose a b c) ty = L.nub (exprUnifyE a ty ++ exprUnifyE b ty ++ exprUnifyE c BOOL_Ty)
exprUnify (O_Bool {}) BOOL_Ty = []
exprUnify (O_RGB {}) RGB_Ty = []
exprUnify (O_RGBA {}) RGBA_Ty = []
exprUnify (Alpha _ e) RGBA_Ty = exprUnifyE e RGB_Ty
exprUnify (UnAlpha e) RGB_Ty = exprUnifyE e RGBA_Ty
exprUnify (ScaleAlpha _ e) RGBA_Ty = exprUnifyE e RGBA_Ty
exprUnify (Var i) ty = [(i,ty)]
exprUnify other ty = error $ "exprUnify" ++ show (other,ty)


-- evaluate to a normal form (constant folding, really)
evalExprE :: Expr E -> Maybe (Expr E)
-- already values
evalExprE e@(Var {}) 		= return e
evalExprE e@(O_Bool {}) 	= return e
evalExprE e@(O_RGB {}) 	= return e
evalExprE e@(O_RGBA {}) 	= return e
-- try some evaluation, please.
evalExprE (Choose a b c) = 
	case liftM unE $ evalE c of
	  Just (O_Bool True)  -> liftM unE $ evalE a
	  Just (O_Bool False) -> liftM unE $ evalE b
	  other -> Nothing
evalExprE (Alpha a e) = 
	case liftM unE $ evalE e of
	    Just (O_RGB c) -> return $ O_RGBA (C.withAlpha c a)
	    other -> Nothing
evalExprE other = Nothing

unE :: E -> Expr E
unE (E e) = e

evalE :: E -> Maybe E
evalE (E e) = liftM E (evalExprE e)

-- The generic plubing for our Expr datatype.				-- 

instance MuRef E where
  type DeRef E = Expr
  mapDeRef f (E e) = T.traverse f e


instance T.Traversable Expr where
	traverse f (Choose a b c) 	= Choose <$> f a <*> f b <*> f c
	traverse f (Alpha c e) 		= Alpha c <$> f e
	traverse f (UnAlpha e) 		= UnAlpha <$> f e
	traverse f (ScaleAlpha c e) 	= ScaleAlpha c <$> f e
	traverse f (O_Bool v)		= pure $ O_Bool v
	traverse f (O_RGB v)		= pure $ O_RGB v
	traverse f (Lit r)		= pure $ Lit r
	traverse f (Var i)		= pure $ Var i
	traverse f (O_RGBA v)		= pure $ O_RGBA v
	-- TODO
	
instance F.Foldable Expr where
	foldMap f (Choose a b c) = mconcat [f a, f b, f c]
	--- TODO
	
instance Functor Expr where
	fmap f (Choose a b c) = Choose (f a) (f b) (f c)
	--- TODO