module Lang.Hask.ValConcrete where

import FP
import Lang.Hask.Semantics
import Literal
import DataCon

data CVal   =
    CBot
  | CLit Literal
  | CData (Data  )
  | CDataAny DataCon
  | CFunClo (FunClo  )
  | CThunkClo (ThunkClo  )
  | CForced (Forced  )
  | CRef (Ref  )
  | CRefAny
  | CKonClo (KonClo  )
  | CKonMemoClo (KonMemoClo  )
  deriving (Eq, Ord)
makePrisms ''CVal
makePrettySum ''CVal
 :: P CVal
 = P

data OCVal   = Pos (CVal  ) | Neg (CVal  )
  deriving (Eq, Ord)
makePrettySum ''OCVal

discreteE :: (Ord b) => Prism (CVal  ) b -> OCVal   -> ConstructiveClassical b
discreteE l (Pos v) = case view l v of
  Just x -> Constructive $ single x
  Nothing -> Constructive empty
discreteE l (Neg v) = case view l v of
  Just x -> Classical $ \ x' -> x /= x'
  Nothing -> Classical $ const True

instance Neg (OCVal  ) where
  neg :: OCVal   -> OCVal  
  neg (Pos v) = Neg v
  neg (Neg v) = Pos v

instance (Ord , Ord ) => Val   ConstructiveClassical OCVal where
  botI :: OCVal  
  botI = Pos CBot

  litI :: Literal -> OCVal  
  litI = Pos . CLit

  litTestE :: Literal -> OCVal   -> ConstructiveClassical Bool
  litTestE l (Pos (CLit l')) 
    | l == l' = Constructive $ single True
    | otherwise = Constructive $ single False
  litTestE _ (Pos _) = Constructive empty
  litTestE l (Neg (CLit l')) 
    | l == l' = Constructive $ single False
    | otherwise = Constructive $ fromList [False, True]
  litTestE _ (Neg _) = Constructive $ fromList [False, True]

  dataI :: Data   -> OCVal  
  dataI = Pos . CData

  dataAnyI :: DataCon -> OCVal  
  dataAnyI = Pos . CDataAny

  dataE :: OCVal   -> ConstructiveClassical (Data  )
  dataE (Pos (CData d)) = Constructive $ single d
  dataE (Pos (CDataAny con)) = Classical $ \ d -> dataCon d == con
  dataE (Pos _) = Constructive empty
  dataE (Neg (CData d)) = Classical $ \ d' -> d /= d'
  dataE (Neg (CDataAny con)) = Classical $ \ d -> dataCon d /= con
  dataE (Neg _) = Classical $ const True

  funCloI :: FunClo   -> OCVal  
  funCloI = Pos . CFunClo

  funCloE :: OCVal   -> ConstructiveClassical (FunClo  )
  funCloE = discreteE cFunCloL

  thunkCloI :: ThunkClo   -> OCVal  
  thunkCloI = Pos . CThunkClo

  thunkCloE :: OCVal   -> ConstructiveClassical (ThunkClo  )
  thunkCloE = discreteE cThunkCloL

  forcedI :: Forced   -> OCVal  
  forcedI = Pos . CForced

  forcedE :: OCVal   -> ConstructiveClassical (Forced  )
  forcedE = discreteE cForcedL

  refI :: Ref   -> OCVal  
  refI = Pos . CRef

  refAnyI :: OCVal  
  refAnyI = Pos CRefAny

  refE :: OCVal   -> ConstructiveClassical (Ref  )
  refE (Pos (CRef r)) = Constructive $ single r
  refE (Pos CRefAny) = Classical $ const True
  refE (Pos _) = Constructive empty
  refE (Neg (CRef r)) = Classical $ \ r' -> r /= r'
  refE (Neg CRefAny) = Constructive empty
  refE (Neg _) = Classical $ const True

  konCloI :: KonClo   -> OCVal  
  konCloI = Pos . CKonClo

  konCloE :: OCVal   -> ConstructiveClassical (KonClo  )
  konCloE = discreteE cKonCloL

  konMemoCloI :: KonMemoClo   -> OCVal  
  konMemoCloI = Pos . CKonMemoClo

  konMemoCloE :: OCVal   -> ConstructiveClassical (KonMemoClo  )
  konMemoCloE = discreteE cKonMemoCloL