{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE InstanceSigs #-} module Types where import Syntax import Data.List import Control.Applicative import Debug.Trace --------------------------- -- TYPES FOR TransformeR -- --------------------------- class RefTy t where tyOK :: t -> Bool data RecTy = RecTy [(Label, Ty)] -- labeled fields deriving (Show, Eq) data Ty = NumTy (Number, Number) -- lower and upper bound | CatTy [Category] -- set of catagories deriving (Show, Eq) type Label = String type Gamma = [(Name, Either RecTy Ty)] -- type environment mapsTo g l t = (l, t) : g --------------------- -- FORMATION RULES -- --------------------- instance RefTy Ty where tyOK (NumTy (n1, n2)) = n1 <= n2 tyOK (CatTy cs) = isSet cs instance RefTy RecTy where tyOK (RecTy lts) = all tyOK taus && isSet ls where (ls, taus) = unzip lts --------------------- -- SUBTYPING RULES -- --------------------- instance Ord TransTy where TransTy rtauIn rtauOut <= TransTy rtauIn' rtauOut' = rtauIn == rtauIn' && rtauOut <= rtauOut' instance Ord RecTy where RecTy lts <= RecTy lts' = (length lts == length lts') && labs == labs' && all id (zipWith (<=) taus taus') where (labs, taus) = unzip lts (labs', taus') = unzip lts' instance Ord Ty where NumTy (lb, ub) <= NumTy (lb', ub') = lb' <= lb && ub <= ub' CatTy cs <= CatTy cs' = all (\c -> elem c cs') cs ------------------------- -- TYPE SYSTEM/CHECKER -- ------------------------- data TransTy = TransTy RecTy RecTy deriving (Show, Eq) tyTrans :: Transformation -> TransTy tyTrans (TRANS arg sigIn sigOut b) | tyOK tauIn && tyOK tauOut && tau' <= tauOut = TransTy tauIn tauOut | otherwise = undefined where (Left tau', _) = ty [(arg, Left tauIn)] b tauOut = tySig sigOut tauIn = tySig sigIn readSig :: Sig -> [(Name, Ty)] readSig (Sig sig) = map (\(l, s) -> (l, tyDes s)) sig where tyDes (INTERVAL lb ub) = NumTy (lb, ub) tyDes (SET ns) = CatTy ns tySig :: Sig -> RecTy tySig = RecTy . readSig ty :: Gamma -> Expression -> (Either RecTy Ty, Gamma) ty gamma exp = let ty' (PROJ e l) = (Right fTau, gamma') where (rTau, gamma') = ty gamma e Just fTau = lookup l rTauR Left (RecTy rTauR) = rTau ty' (OP opr es) | tyOK tauOut = (Right tauOut, gamma') where tauOut = tyJoin opr taus (gamma', taus) = foldl tyNext (gamma, []) es tyNext (g, tau) e = let (t, g) = ty gamma e in (g, t:tau) ty' (LIT (NUM n)) = (Right $ NumTy (n, n), gamma) ty' (LIT (CAT c)) = (Right $ CatTy [c], gamma) ty' (LIT (MAP fvs)) = (ty' . REC) $ map (\(f, v) -> (f, LIT v)) fvs ty' (REC fields) | tyOK tauRec = (Left tauRec, gamma') | otherwise = undefined where tauRec = RecTy taus (taus, gamma') = foldl tyNext ([], gamma) fields tyNext (taus, g) (l, e) = let (Right t, g') = ty g e in (taus ++ [(l,t)], g') ty' (VAR x) = let Just tau = lookup x gamma in (tau, gamma) ty' (MUTATE x l e) = (Left tau', mapsTo gamma' x (Left tau')) where Just (Left (RecTy lts))= lookup x gamma (Right sigma, gamma') = ty' e tau' = if elem l $ map fst lts then RecTy $ map (\(l', t) -> if l == l' then (l, sigma) else (l, t)) lts else RecTy $ lts ++ [(l, sigma)] ty' (SEQ e1 e2) = ty gamma' e2 where (_, gamma') = ty' e1 ty' (ASSIGN x e) = (t, mapsTo gamma' x t) where (t, gamma') = ty' e in ty' exp ----------------------------- -- RULES FOR JOINING TYPES -- ----------------------------- tyJoin SUM [Right (NumTy (lb1, ub1)), Right (NumTy (lb2, ub2))] | lb1 <= ub1 && lb2 <= ub2 = NumTy (lb1 + lb2, ub1 + ub2) | otherwise = undefined tyJoin CONCAT [Right (CatTy cs1), Right (CatTy cs2)] | isSet cs1 && isSet cs2 = CatTy . nub $ cs1 ++ cs2 | otherwise = undefined tyJoin _ _ = undefined ---------------------------- -- Mother's little helper -- ---------------------------- isSet xs = length xs == length (nub xs)