Add bidirectional type checker, lambda lifter.

This commit is contained in:
Martin Fredin 2023-02-18 14:49:33 +01:00
parent 2fa30faa87
commit ac3f222753
22 changed files with 2440 additions and 577 deletions

View file

@ -1,245 +1,135 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
module TypeChecker.TypeCheckerIr (
module TypeChecker.TypeCheckerIr,
) where
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.State
import Data.Char (isDigit)
import Data.Functor.Identity (Identity)
import Data.Map (Map)
import Data.Set (Set)
import Data.String qualified
import Grammar.Print
import Prelude
import Prelude qualified as C (Eq, Ord, Read, Show)
module TypeChecker.TypeCheckerIr
( module Grammar.Abs
, module TypeChecker.TypeCheckerIr
) where
newtype Ctx = Ctx {vars :: Map Ident Type}
deriving (Show)
import Data.String (IsString)
import Grammar.Abs (Character (..), Lit (..), TVar (..))
import Grammar.Print
import Prelude
import qualified Prelude as C (Eq, Ord, Read, Show)
data Env = Env
{ count :: Int
, nextChar :: Char
, sigs :: Map Ident (Maybe Type)
, constructors :: Map Ident Type
, takenTypeVars :: Set Ident
}
deriving (Show)
newtype Program' t = Program [Def' t]
deriving (C.Eq, C.Ord, C.Show, C.Read)
type Error = String
type Subst = Map Ident Type
type Infer = StateT Env (ReaderT Ctx (ExceptT Error Identity))
newtype Program = Program [Def]
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Data = Data Ident [Constructor]
deriving (Show, Eq, Ord, Read)
data Constructor = Constructor Ident Type
deriving (Show, Eq, Ord, Read)
newtype TVar = MkTVar Ident
deriving (Show, Eq, Ord, Read)
data Def' t = DBind (Bind' t)
| DData (Data' t)
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Type
= TLit Ident
| TVar TVar
| TData Ident [Type]
| TFun Type Type
| TAll TVar Type
| TData Ident [Type]
deriving (Show, Eq, Ord, Read)
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Exp
= EId Ident
| ELit Lit
| ELet Bind ExpT
| EApp ExpT ExpT
| EAdd ExpT ExpT
| EAbs Ident ExpT
| ECase ExpT [Branch]
deriving (C.Eq, C.Ord, C.Read, C.Show)
data Data' t = Data t [Inj' t]
deriving (C.Eq, C.Ord, C.Show, C.Read)
type ExpT = (Exp, Type)
data Branch = Branch (Pattern, Type) ExpT
deriving (C.Eq, C.Ord, C.Read, C.Show)
data Pattern = PVar Id | PLit (Lit, Type) | PInj Ident [Pattern] | PCatch | PEnum Ident
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Def = DBind Bind | DData Data
deriving (C.Eq, C.Ord, C.Read, C.Show)
type Id = (Ident, Type)
data Inj' t = Inj Ident t
deriving (C.Eq, C.Ord, C.Show, C.Read)
newtype Ident = Ident String
deriving (C.Eq, C.Ord, C.Show, C.Read, Data.String.IsString)
deriving (C.Eq, C.Ord, C.Show, C.Read, IsString)
data Lit = LInt Integer | LChar Char
deriving (Show, Eq, Ord, Read)
data Pattern' t
= PVar (Id' t) -- TODO should be Ident
| PLit (Lit, t) -- TODO should be Lit
| PCatch
| PEnum Ident
| PInj Ident [Pattern' t] -- TODO should be (Pattern' t, t)
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Bind = Bind Id [Id] ExpT
data Exp' t
= EVar Ident
| EInj Ident
| ELit Lit
| ELet (Bind' t) (ExpT' t)
| EApp (ExpT' t) (ExpT' t)
| EAdd (ExpT' t) (ExpT' t)
| EAbs Ident (ExpT' t)
| ECase (ExpT' t) [Branch' t]
deriving (C.Eq, C.Ord, C.Show, C.Read)
type Id' t = (Ident, t)
type ExpT' t = (Exp' t, t)
data Bind' t = Bind (Id' t) [Id' t] (ExpT' t)
deriving (C.Eq, C.Ord, C.Show, C.Read)
data Branch' t = Branch (Pattern' t, t) (ExpT' t)
deriving (C.Eq, C.Ord, C.Show, C.Read)
instance Print Ident where
prt _ (Ident str) = doc . showString $ str
prt i (Ident s) = prt i s
instance Print [Def] where
prt _ [] = concatD []
prt _ (x : xs) = concatD [prt 0 x, doc (showString "\n\n"), prt 0 xs]
instance Print Data where
prt i = \case
Data type_ constructors -> prPrec i 0 (concatD [doc (showString "data"), prt 0 type_, doc (showString "where"), doc (showString "{"), prt 0 constructors, doc (showString "}")])
instance Print Constructor where
prt i = \case
Constructor uident type_ -> prPrec i 0 (concatD [prt 0 uident, doc (showString ":"), prt 0 type_])
instance Print [Constructor] where
prt _ [] = concatD []
prt _ [x] = concatD [prt 0 x]
prt _ (x : xs) = concatD [prt 0 x, prt 0 xs]
instance Print Def where
prt i (DBind bind) = prt i bind
prt i (DData d) = prt i d
instance Print Program where
instance Print t => Print (Program' t) where
prt i (Program sc) = prPrec i 0 $ prt 0 sc
instance Print Bind where
prt i (Bind (name, t) args rhs) =
prPrec i 0 $
concatD
[ prt 0 name
, doc $ showString ":"
, prt 0 t
, doc $ showString "\n"
, prt 0 name
, prtIdPs 0 args
, doc $ showString "="
, prt 0 rhs
]
instance Print t => Print (Bind' t) where
prt i (Bind sig@(name, _) parms rhs) = prPrec i 0 $ concatD
[ prtSig sig
, prt 0 name
, prtIdPs 0 parms
, doc $ showString "="
, prt 0 rhs
]
instance Print [Bind] where
prt _ [] = concatD []
prt _ [x] = concatD [prt 0 x]
prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), doc (showString "\n"), prt 0 xs]
prtSig :: Print t => Id' t -> Doc
prtSig (name, t) = concatD [ prt 0 name
, doc $ showString ":"
, prt 0 t
, doc $ showString ";"
]
prtIdPs :: Int -> [Id] -> Doc
prtIdPs i = prPrec i 0 . concatD . map (prtIdP i)
instance Print t => Print (ExpT' t) where
prt i (e, t) = concatD [ doc $ showString "("
, prt i e
, doc $ showString ","
, prt i t
, doc $ showString ")"
]
prtId :: Int -> Id -> Doc
prtId i (name, t) =
prPrec i 0 $
concatD
[ doc $ showString "("
, prt 0 name
, doc $ showString ":"
, prt 0 t
, doc $ showString ")"
]
instance Print t => Print [Bind' t] where
prt _ [] = concatD []
prt _ [x] = concatD [prt 0 x]
prt _ (x:xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs]
prtIdP :: Int -> Id -> Doc
prtIdP i (name, t) =
prPrec i 0 $
concatD
[ doc $ showString "("
, prt 0 name
, doc $ showString ":"
, prt 0 t
, doc $ showString ")"
]
prtIdPs :: Print t => Int -> [Id' t] -> Doc
prtIdPs i = prPrec i 0 . concatD . map (prt i)
instance Print Exp where
prt i = \case
EId n -> prPrec i 3 $ concatD [prt 0 n]
ELit lit -> prPrec i 3 $ concatD [prt 0 lit]
ELet bs e ->
prPrec i 3 $
concatD
[ doc $ showString "let"
, prt 0 bs
, doc $ showString "in"
, prt 0 e
]
EApp e1 e2 ->
prPrec i 2 $
concatD
[ prt 2 e1
, prt 3 e2
]
EAdd e1 e2 ->
prPrec i 1 $
concatD
[ doc $ showString "@"
, prt 1 e1
, doc $ showString "+"
, prt 2 e2
]
EAbs n e ->
prPrec i 0 $
concatD
[ doc $ showString "λ"
, prt 0 n
, doc $ showString "."
, prt 0 e
]
ECase exp injs ->
prPrec
i
0
( concatD
[ doc (showString "case")
, prt 0 exp
, doc (showString "of")
, doc (showString "{")
, prt 0 injs
, doc (showString "}")
, doc (showString ":")
]
)
instance Print t => Print (Id' t) where
prt i (name, t) = concatD [ doc $ showString "("
, prt i name
, doc $ showString ","
, prt i t
, doc $ showString ")"
]
instance Print ExpT where
prt i (e, t) = concatD [doc $ showString "(", prt i e, doc (showString ":"), prt i t, doc $ showString ")"]
instance Print Branch where
prt i = \case
Branch (init, t) exp -> prPrec i 0 (concatD [prt 0 init, doc (showString ":"), prt 0 t, doc (showString "=>"), prt 0 exp])
instance Print Pattern where
prt i = \case
PVar lident -> prPrec i 0 (concatD [prtId 0 lident])
PLit (lit, typ) -> prPrec i 0 (concatD [doc $ showString "(", prt 0 lit, doc $ showString ",", prt 0 typ, doc $ showString ")"])
PInj uident patterns -> prPrec i 0 (concatD [prt 0 uident, prt 0 patterns])
PCatch -> prPrec i 0 (concatD [doc (showString "_")])
PEnum p -> prt i p
instance Print [Branch] where
prt _ [] = concatD []
prt _ [x] = concatD [prt 0 x]
prt _ (x : xs) = concatD [prt 0 x, doc (showString ";"), prt 0 xs]
instance Print TVar where
prt i (MkTVar id) = prt i id
instance Print Type where
prt i = \case
TLit uident -> prPrec i 2 (concatD [prt 0 uident])
TVar tvar@(MkTVar (Ident iden)) ->
if all isDigit iden
then prPrec i 2 (concatD [prt 0 $ TVar (MkTVar (Ident ("a" <> iden)))])
else prPrec i 2 (concatD [prt 0 tvar])
TAll tvar type_ -> prPrec i 1 (concatD [doc (showString "forall"), prt 0 tvar, doc (showString "."), prt 0 type_])
TData ident types -> prPrec i 1 (concatD [prt 0 ident, prt 0 types])
TFun type_1 type_2 -> prPrec i 0 (concatD [prt 1 type_1, doc (showString "->"), prt 0 type_2])
instance Print Lit where
prt i = \case
LInt n -> prPrec i 0 (concatD [prt 0 n])
LChar c -> prPrec i 0 (concatD [prt 0 c])
instance Print t => Print (Exp' t) where
prt i = \case
EVar name -> prPrec i 3 $ prt 0 name
EInj name -> prPrec i 3 $ prt 0 name
ELit lit -> prPrec i 3 $ prt 0 lit
ELet b e -> prPrec i 3 $ concatD
[ doc $ showString "let"
, prt 0 b
, doc $ showString "in"
, prt 0 e
]
EApp e1 e2 -> prPrec i 2 $ concatD
[ prt 2 e1
, prt 3 e2
]
EAdd e1 e2 -> prPrec i 1 $ concatD
[ prt 1 e1
, doc $ showString "+"
, prt 2 e2
]
EAbs v e -> prPrec i 0 $ concatD
[ doc $ showString "\\"