module Language.Nano.Typecheck.Types (
Nano (..)
, NanoBare
, NanoSSA
, NanoType
, Source (..)
, FunctionStatement
, mapCode
, RType (..)
, Bind (..)
, toType
, ofType
, strengthen
, bkFun
, bkAll
, Type
, TVar (..)
, TCon (..)
, tInt
, tBool
, tVoid
, tErr
, tVar
, infixOpTy
, prefixOpTy
, Annot (..)
, Fact (..)
, AnnBare
, AnnSSA
, AnnType
, AnnInfo
) where
import Text.Printf
import Data.Hashable
import Data.Maybe (fromMaybe)
import Data.Monoid hiding ((<>))
import qualified Data.HashMap.Strict as M
import Language.ECMAScript3.Syntax
import Language.ECMAScript3.Syntax.Annotations
import Language.ECMAScript3.PrettyPrint
import Language.Nano.Types
import Language.Nano.Errors
import Language.Nano.Env
import qualified Language.Fixpoint.Types as F
import Language.Fixpoint.Misc
import Language.Fixpoint.PrettyPrint
import Text.PrettyPrint.HughesPJ
import Control.Applicative
import Control.Monad.Error ()
data TVar = TV { tv_sym :: F.Symbol
, tv_loc :: SourcePos
}
deriving (Show, Ord)
instance Eq TVar where
a == b = tv_sym a == tv_sym b
instance IsLocated TVar where
srcPos = tv_loc
instance Hashable TVar where
hashWithSalt i α = hashWithSalt i $ tv_sym α
instance F.Symbolic TVar where
symbol = tv_sym
instance PP TVar where
pp = pprint . F.symbol
instance F.Symbolic a => F.Symbolic (Located a) where
symbol = F.symbol . val
data TCon
= TInt
| TBool
| TVoid
| TDef F.Symbol
deriving (Eq, Ord, Show)
data RType r
= TApp TCon [RType r] r
| TVar TVar r
| TFun [Bind r] (RType r) r
| TAll TVar (RType r)
deriving (Eq, Ord, Show, Functor)
data Bind r
= B { b_sym :: F.Symbol
, b_type :: !(RType r)
}
deriving (Eq, Ord, Show, Functor)
type Type = RType ()
toType :: RType a -> Type
toType = fmap (const ())
ofType :: (F.Reftable r) => Type -> RType r
ofType = fmap (const F.top)
bkFun :: RType r -> Maybe ([TVar], [Bind r], RType r)
bkFun t = do let (αs, t') = bkAll t
(xts, t'') <- bkArr t'
return (αs, xts, t'')
bkArr (TFun xts t _) = Just (xts, t)
bkArr _ = Nothing
bkAll :: RType a -> ([TVar], RType a)
bkAll t = go [] t
where
go αs (TAll α t) = go (α : αs) t
go αs t = (reverse αs, t)
strengthen :: F.Reftable r => RType r -> r -> RType r
strengthen (TApp c ts r) r' = TApp c ts $ r' `F.meet` r
strengthen (TVar α r) r' = TVar α $ r' `F.meet` r
strengthen t _ = t
data Nano a t = Nano { code :: !(Source a)
, specs :: !(Env t)
, defs :: !(Env t)
, consts :: !(Env t)
, quals :: ![F.Qualifier]
} deriving (Functor)
type NanoBare = Nano AnnBare Type
type NanoSSA = Nano AnnSSA Type
type NanoType = Nano AnnType Type
type FunctionStatement a = Statement a
newtype Source a = Src [FunctionStatement a]
instance Functor Source where
fmap f (Src zs) = Src (map (fmap f) zs)
instance PP t => PP (Nano a t) where
pp pgm@(Nano {code = (Src s) })
= text "********************** CODE **********************"
$+$ pp s
$+$ text "********************** SPECS *********************"
$+$ pp (specs pgm)
$+$ text "********************** DEFS *********************"
$+$ pp (defs pgm)
$+$ text "********************** CONSTS ********************"
$+$ pp (consts pgm)
$+$ text "********************** QUALS *********************"
$+$ F.toFix (quals pgm)
$+$ text "**************************************************"
instance Monoid (Nano a t) where
mempty = Nano (Src []) envEmpty envEmpty envEmpty []
mappend p1 p2 = Nano ss e e' cs qs
where
ss = Src $ s1 ++ s2
Src s1 = code p1
Src s2 = code p2
e = envFromList ((envToList $ specs p1) ++ (envToList $ specs p2))
e' = envFromList ((envToList $ defs p1) ++ (envToList $ defs p2))
cs = envFromList $ (envToList $ consts p1) ++ (envToList $ consts p2)
qs = quals p1 ++ quals p2
mapCode :: (a -> b) -> Nano a t -> Nano b t
mapCode f n = n { code = fmap f (code n) }
instance PP () where
pp _ = text ""
instance PP a => PP [a] where
pp = ppArgs brackets comma
instance PP a => PP (Maybe a) where
pp = maybe (text "Nothing") pp
instance F.Reftable r => PP (RType r) where
pp (TVar α r) = F.ppTy r $ pp α
pp (TFun xts t _) = ppArgs parens comma xts <+> text "=>" <+> pp t
pp t@(TAll _ _) = text "forall" <+> ppArgs id space αs <> text "." <+> pp t' where (αs, t') = bkAll t
pp (TApp c [] r) = F.ppTy r $ ppTC c
pp (TApp c ts r) = F.ppTy r $ parens (ppTC c <+> ppArgs id space ts)
instance F.Reftable r => PP (Bind r) where
pp (B x t) = pp x <> colon <> pp t
ppArgs p sep = p . intersperse sep . map pp
ppTC TInt = text "int"
ppTC TBool = text "boolean"
ppTC TVoid = text "void"
ppTC (TDef x) = pprint x
data Fact
= PhiVar !(Id SourcePos)
| TypInst ![Type]
deriving (Eq, Ord, Show)
data Annot b a = Ann { ann :: a, ann_fact :: [b] } deriving (Show)
type AnnBare = Annot Fact SourcePos
type AnnSSA = Annot Fact SourcePos
type AnnType = Annot Fact SourcePos
type AnnInfo = M.HashMap SourcePos [Fact]
instance HasAnnotation (Annot b) where
getAnnotation = ann
instance IsLocated (Annot a SourcePos) where
srcPos = ann
instance PP Fact where
pp (PhiVar x) = text "phi" <+> pp x
pp (TypInst ts) = text "inst" <+> pp ts
instance PP AnnInfo where
pp = vcat . (ppB <$>) . M.toList
where
ppB (x, t) = pp x <+> dcolon <+> pp t
instance (PP a, PP b) => PP (Annot b a) where
pp (Ann x ys) = text "Annot: " <+> pp x <+> pp ys
tVar :: (F.Reftable r) => TVar -> RType r
tVar = (`TVar` F.top)
tInt, tBool, tVoid, tErr :: (F.Reftable r) => RType r
tInt = TApp TInt [] F.top
tBool = TApp TBool [] F.top
tVoid = TApp TVoid [] F.top
tErr = tVoid
infixOpTy :: InfixOp -> Env t -> t
infixOpTy o g = fromMaybe err $ envFindTy ox g
where
err = errorstar $ printf "Cannot find infixOpTy %s" (ppshow ox)
ox = infixOpId o
infixOpId OpLT = builtinId "OpLT"
infixOpId OpLEq = builtinId "OpLEq"
infixOpId OpGT = builtinId "OpGT"
infixOpId OpGEq = builtinId "OpGEq"
infixOpId OpEq = builtinId "OpEq"
infixOpId OpNEq = builtinId "OpNEq"
infixOpId OpLAnd= builtinId "OpLAnd"
infixOpId OpLOr = builtinId "OpLOr"
infixOpId OpSub = builtinId "OpSub"
infixOpId OpAdd = builtinId "OpAdd"
infixOpId OpMul = builtinId "OpMul"
infixOpId OpDiv = builtinId "OpDiv"
infixOpId OpMod = builtinId "OpMod"
infixOpId o = errorstar $ "Cannot handle: infixOpId " ++ ppshow o
prefixOpTy :: PrefixOp -> Env t -> t
prefixOpTy o g = fromMaybe err $ envFindTy (prefixOpId o) g
where
err = convertError "prefixOpTy" o
prefixOpId PrefixMinus = builtinId "PrefixMinus"
prefixOpId PrefixLNot = builtinId "PrefixLNot"
prefixOpId o = errorstar $ "Cannot handle: prefixOpId " ++ ppshow o
builtinId = mkId . ("builtin_" ++)