module MagicHaskeller.TyConLib where
import qualified Data.Map as Map
import MagicHaskeller.Types
import Data.Array.IArray
import qualified Language.Haskell.TH as TH
import Data.List(nub)
type Map = Map.Map
type TyConLib = (Map TypeName TyCon, Array Kind [(TypeName,TyCon)])
defaultTCL = tyConsToTCL defaultTyCons
tyConsToTCL :: [(Kind, TypeName)] -> TyConLib
tyConsToTCL tcs
= (Map.fromListWith (\new old -> old) [ tup | k <- [0..7], tup <- tcsByK ! k ], tcsByK)
where tnsByK :: Array Kind [TypeName]
tnsByK = accumArray (flip (:)) [] (0,7) (reverse (nub tcs))
tcsByK :: Array Kind [(TypeName,TyCon)]
tcsByK = listArray (0,7) [ tnsToTCs (tnsByK ! k) | k <- [0..7] ]
tnsToTCs :: [TypeName] -> [(TypeName,TyCon)]
tnsToTCs tns = zipWith (\ i tn -> (tn, i)) [0..] tns
defaultTyCons :: [(Kind, TypeName)]
defaultTyCons = [(0, "()"), (1, "[]")] ++ [ (i, tuplename i) | i<-[2..tupleMax] ] ++ [(0, "Int"), (0, "Char"), (0, "Bool"), (0, "Integer"), (0, "Double"), (0, "Float"), (1,"Maybe"), (1,"IO"), (2,"Either"), (0,"Ordering"), (1,"Ratio"), (1,"Gen")]
tupleMax = 7
tuplename i = '(':replicate (i1) ',' ++")"
unit tcl = nameToTyCon tcl "()"
list tcl = nameToTyCon tcl "[]"
disj tcl = nameToTyCon tcl "Either"
tuple tcl n = nameToTyCon tcl (tuplename n)
nameToTyCon :: TyConLib -> String -> TyCon
nameToTyCon (fm,_) name = case Map.lookup name fm of
Nothing -> error "nameToTyCon: unknown TyCon"
Just c -> c
thTypesToTCL thts = tyConsToTCL (thTypesToTyCons thts ++ defaultTyCons)
thTypesToTyCons :: [TH.Type] -> [(Kind,TypeName)]
thTypesToTyCons thtys = [ tycon | thty <- thtys, tycon <- thTypeToTyCons 0 thty ]
thTypeToTyCons :: Kind -> TH.Type -> [(Kind,TypeName)]
thTypeToTyCons k (TH.ForallT names _cxt t) = thTypeToTyCons k t
thTypeToTyCons k (TH.AppT t u) = thTypeToTyCons (k+1) t ++ thTypeToTyCons 0 u
thTypeToTyCons 2 TH.ArrowT = []
thTypeToTyCons 1 TH.ListT = [(1, "[]")]
thTypeToTyCons _ (TH.VarT _name) = []
thTypeToTyCons k (TH.ConT qname) = [(k, show qname)]
thTypeToTyCons k (TH.TupleT i) | k == i = [(i, tuplename i)]
thTypeToTyCons k tht = error ("thTypeToTyCons :: Kind error. k = "++show k++" and tht = "++TH.pprint tht)