{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Dino.Types
  ( module Dino.Types
  , Inspectable
  ) where
import Dino.Prelude
import Data.Type.Equality ((:~:) (..), TestEquality (..))
import Data.Typeable (cast)
import Type.Reflection (typeRep)
import Dino.AST (Inspectable)
type family BuiltIn a :: Bool where
  BuiltIn [a]    = 'True
  BuiltIn (a, b) = 'True
  BuiltIn a      = 'False
data DinoTypeRep a where
  ListType  :: DinoTypeRep a -> DinoTypeRep [a]
  PairType  :: DinoTypeRep a -> DinoTypeRep b -> DinoTypeRep (a, b)
  OtherType :: (BuiltIn a ~ 'False, DinoType a) => DinoTypeRep a
  
  
  
  
  
  
  
  
  
  
withType :: DinoTypeRep a -> (DinoType a => b) -> b
withType (ListType t)   b = withType t b
withType (PairType t u) b = withType t $ withType u b
withType OtherType      b = b
listTypeElem :: DinoTypeRep [a] -> DinoTypeRep a
listTypeElem (ListType t) = t
  
instance TestEquality DinoTypeRep where
  testEquality :: forall t u. DinoTypeRep t -> DinoTypeRep u -> Maybe (t :~: u)
  testEquality t u = withType t $ withType u $
    testEquality (typeRep @t) (typeRep @u)
    
    
class (Eq a, Show a, Typeable a, Inspectable a) => DinoType a where
  dinoTypeRep :: DinoTypeRep a
  default dinoTypeRep :: (BuiltIn a ~ 'False) => DinoTypeRep a
  dinoTypeRep = OtherType
instance DinoType ()
instance DinoType Bool
instance DinoType Rational
instance DinoType Int
instance DinoType Integer
instance DinoType Float
instance DinoType Double
instance DinoType Text
instance DinoType a => DinoType (Maybe a)
instance DinoType a => DinoType [a] where
  dinoTypeRep = ListType dinoTypeRep
instance (DinoType a, DinoType b) => DinoType (a, b) where
  dinoTypeRep = PairType dinoTypeRep dinoTypeRep
data Dinamic where
  Dinamic :: DinoType a => a -> Dinamic
fromDinamic :: DinoType a => Dinamic -> Maybe a
fromDinamic (Dinamic a) = cast a