Renamer done.

It renames bound variables to numbers, converts let to lambda, and
removes all variables from binds
This commit is contained in:
sebastianselander 2023-02-14 16:44:38 +01:00
parent 53314551f5
commit 6218efac20
9 changed files with 158 additions and 175 deletions

View file

@ -14,12 +14,12 @@ EAbs. Exp ::= "\\" Ident "." Exp ;
CInt. Const ::= Integer ;
CStr. Const ::= String ;
TMono. Type1 ::= UIdent ;
TPoly. Type1 ::= LIdent ;
TMono. Type ::= "Mono" Ident ;
TPoly. Type ::= "Poly" Ident ;
TArrow. Type ::= Type "->" Type1 ;
token UIdent (upper (letter | digit | '_')*) ;
token LIdent (lower (letter | digit | '_')*) ;
-- token Upper (upper (letter | digit | '_')*) ;
-- token Lower (lower (letter | digit | '_')*) ;
separator Bind ";" ;
separator Ident " ";

View file

@ -31,12 +31,10 @@ executable language
Grammar.Print
Grammar.Skel
Grammar.ErrM
-- LambdaLifter
TypeChecker.TypeChecker
TypeChecker.TypeCheckerIr
-- Renamer.Renamer
-- Renamer.RenamerIr
-- Interpreter
Renamer.Renamer
Renamer.RenamerIr
hs-source-dirs: src

View file

@ -1,4 +1,3 @@
add x = \y. x+y;
main = (\z. z+z) ((add 4) 6);

View file

@ -6,6 +6,7 @@ import Grammar.Print (printTree)
import System.Environment (getArgs)
import System.Exit (exitFailure, exitSuccess)
import TypeChecker.TypeChecker (typecheck)
import Renamer.Renamer (rename)
main :: IO ()
main = getArgs >>= \case
@ -17,12 +18,11 @@ main = getArgs >>= \case
putStrLn "SYNTAX ERROR"
putStrLn err
exitFailure
Right prg -> case typecheck prg of
Right prg -> case rename prg of
Right prg -> do
putStrLn "TYPE CHECK SUCCESSFUL"
putStrLn . show $ prg
putStrLn "RENAME SUCCESSFUL"
putStrLn $ printTree prg
Left err -> do
putStrLn "TYPE CHECK ERROR"
putStrLn "FAILED RENAMING"
putStrLn . show $ err
exitFailure

View file

@ -1,90 +1,101 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE LambdaCase, OverloadedRecordDot, OverloadedStrings #-}
module Renamer.Renamer (rename) where
import Control.Applicative (Applicative (liftA2))
import Control.Monad.Except (MonadError (throwError))
import Control.Monad.RWS (MonadState, gets, modify)
import Control.Monad.State (StateT, evalStateT)
import Renamer.RenamerIr
import Control.Monad.State
import Control.Monad.Except
import Control.Monad.Reader
import Data.Functor.Identity (Identity, runIdentity)
import Data.Set (Set)
import qualified Data.Set as Set
import Grammar.Abs
import Grammar.ErrM (Err)
import Grammar.Print (printTree)
import qualified Renamer.RenamerIr as R
import qualified Data.Set as S
import Data.Map (Map)
import qualified Data.Map as M
import Renamer.RenamerIr
import qualified Grammar.Abs as Old
data Cxt = Cxt
{ uniques :: [(Ident, R.Unique)]
, nextUnique :: R.Unique
type Rename = StateT Ctx (ExceptT Error Identity)
data Ctx = Ctx { count :: Integer
, sig :: Set Ident
}
, env :: Map Ident Integer}
initCxt :: Cxt
initCxt = Cxt
{ uniques = []
, nextUnique = R.Unique 0
run :: Rename a -> Either Error a
run = runIdentity . runExceptT . flip evalStateT initCtx
initCtx :: Ctx
initCtx = Ctx { count = 0
, sig = mempty
}
, env = mempty }
newtype Rn a = Rn { runRn :: StateT Cxt Err a }
deriving (Functor, Applicative, Monad, MonadState Cxt, MonadError String)
rename :: Old.Program -> Either Error RProgram
rename = run . renamePrg
rename :: Program -> Err R.Program
rename p = evalStateT (runRn $ renameProgram p) initCxt
renamePrg :: Old.Program -> Rename RProgram
renamePrg (Old.Program xs) = do
xs' <- mapM renameBind xs
return $ RProgram xs'
renameProgram :: Program -> Rn R.Program
renameProgram (Program ds (Main e)) = do
ds' <- mapM renameDef ds
e' <- renameExp e
pure $ R.Program ds' (R.Main e')
renameBind :: Old.Bind -> Rename RBind
renameBind (Old.Bind i args e) = do
insertSig i
e' <- renameExp (makeLambda (reverse args) e)
return $ RBind i e'
where
makeLambda :: [Ident] -> Old.Exp -> Old.Exp
makeLambda [] e = e
makeLambda (x:xs) e = makeLambda xs (Old.EAbs x e)
renameDef :: Def -> Rn R.Def
renameDef = \case
DExp x t _ xs e -> do
newSig x
xs' <- mapM newUnique xs
e' <- renameExp e
let e'' = foldr ($) e' . zipWith R.EAbs xs' $ fromTree t
pure . R.DBind $ R.Bind x t e''
renameExp :: Exp -> Rn R.Exp
renameExp :: Old.Exp -> Rename RExp
renameExp = \case
EId x -> R.EId <$> findBind x
EInt i -> pure $ R.EInt i
EApp e e1 -> liftA2 R.EApp (renameExp e) $ renameExp e1
EAdd e e1 -> liftA2 R.EAdd (renameExp e) $ renameExp e1
EAbs x t e -> do
x' <- newUnique x
e' <- renameExp e
pure $ R.EAbs x' t e'
findBind :: Ident -> Rn R.Name
findBind x = lookupUnique x >>= \case
Just u -> pure $ R.Nu u
Nothing -> gets (Set.member x . sig) >>= \case
False -> throwError ("Unbound variable " ++ printTree x)
True -> pure $ R.Ni x
Old.EId i -> do
st <- get
case M.lookup i st.env of
Just n -> return $ RBound n i
Nothing -> case S.member i st.sig of
True -> return $ RFree i
False -> throwError $ UnboundVar (show i)
newUnique :: Ident -> Rn R.Unique
newUnique x = do
u <- gets nextUnique
modify $ \env -> env { nextUnique = succ u
, uniques = (x, u) : env.uniques
}
pure u
Old.EConst c -> return $ RConst c
newSig :: Ident -> Rn ()
newSig x = modify $ \cxt -> cxt { sig = Set.insert x cxt.sig}
Old.EAnn e t -> flip RAnn t <$> renameExp e
lookupUnique :: Ident -> Rn (Maybe R.Unique)
lookupUnique x = lookup x <$> gets uniques
Old.EApp e1 e2 -> RApp <$> renameExp e1 <*> renameExp e2
fromTree :: Type -> [Type]
fromTree = fromTree' []
Old.EAdd e1 e2 -> RAdd <$> renameExp e1 <*> renameExp e2
fromTree' :: [Type] -> Type -> [Type]
fromTree' acc = \case
TFun t t1 -> acc ++ [t] ++ fromTree t1
other -> other : acc
-- Convert let-expressions to lambdas
Old.ELet i e1 e2 -> renameExp (Old.EApp (Old.EAbs i e2) e1)
Old.EAbs i e -> do
n <- cnt
ctx <- get
insertEnv i n
re <- renameExp e
return $ RAbs n i re
-- | Get current count and increase it by one
cnt :: Rename Integer
cnt = do
st <- get
put (Ctx { count = succ st.count
, sig = st.sig
, env = st.env })
return st.count
insertEnv :: Ident -> Integer -> Rename ()
insertEnv i n = do
c <- get
put ( Ctx { env = M.insert i n c.env , sig = c.sig , count = c.count} )
insertSig :: Ident -> Rename ()
insertSig i = do
c <- get
put ( Ctx { sig = S.insert i c.sig , env = c.env , count = c.count } )
data Error = UnboundVar String
instance Show Error where
show (UnboundVar str) = "Unbound variable: " <> str

View file

@ -1,84 +1,51 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
module Renamer.RenamerIr where
module Renamer.RenamerIr (module Grammar.Abs, RExp (..), RBind (..), RProgram (..)) where
import Grammar.Abs (Ident, Type (..))
import Grammar.Abs (
Bind (..),
Const (..),
Ident (..),
Program (..),
Type (..),
)
import Grammar.Print
data RProgram = RProgram [RBind]
deriving (Eq, Show, Read, Ord)
data Program = Program [Def] Main
data RBind = RBind Ident RExp
deriving (Eq, Show, Read, Ord)
data RExp
= RAnn RExp Type
| RBound Integer Ident
| RFree Ident
| RConst Const
| RApp RExp RExp
| RAdd RExp RExp
| RAbs Integer Ident RExp
deriving (Eq, Ord, Show, Read)
newtype Main = Main Exp
deriving (Eq, Ord, Show, Read)
newtype Def = DBind Bind
deriving (Eq, Ord, Show, Read)
data Name = Nu Unique | Ni Ident deriving (Ord, Show, Eq, Read)
newtype Unique = Unique Int deriving (Enum, Eq, Read, Ord)
instance Show Unique where show (Unique i) = "x" ++ show i
data Exp
= EId Name
| EInt Integer
| EApp Exp Exp
| EAdd Exp Exp
| EAbs Unique Type Exp
deriving (Eq, Ord, Show, Read)
data Bind = Bind Ident Type Exp
deriving (Eq, Ord, Show, Read)
instance Print Program where
instance Print RProgram where
prt i = \case
Program defs main -> prPrec i 0 (concatD [prt 0 defs, prt 0 main])
RProgram defs -> prPrec i 0 (concatD [prt 0 defs])
instance Print Def where
prt i (DBind b) = prPrec i 0 $ concatD [prt 0 b, doc (showString ";")]
instance Print Bind where
instance Print RBind where
prt i = \case
Bind x t e -> prPrec i 0 $ concatD
RBind x e ->
prPrec i 0 $
concatD
[ prt 0 x
, doc (showString ":")
, prt 0 t
, doc (showString "=")
, prt 0 e]
instance Print [Def] where
prt _ [] = concatD []
prt _ (x:xs) = concatD [prt 0 x, prt 0 xs]
instance Print Main where
prt i = \case
Main exp -> prPrec i 0 $ concatD
[ doc (showString "main")
, doc (showString "=")
, prt 0 exp
, doc (showString ";")
, prt 0 e
]
instance Print Exp where
instance Print RExp where
prt i = \case
EId u -> prPrec i 3 (concatD [prt 0 u])
EInt n -> prPrec i 3 (concatD [prt 0 n])
EApp e e1 -> prPrec i 2 (concatD [prt 2 e, prt 3 e1])
EAdd e e1 -> prPrec i 1 (concatD [prt 1 e, doc (showString "+"), prt 2 e1])
EAbs u t e -> prPrec i 0 (concatD [doc (showString "\\"), prt 0 u, doc (showString ":"), prt 0 t, doc (showString "."), prt 0 e])
instance Print Name where
prt _ = \case
Ni i -> prt 0 i
Nu u -> prt 0 u
instance Print Unique where
prt _ = doc . showString . show
RBound n _ -> prPrec i 3 (concatD [prt 0 ("var" ++ show n)])
RFree id -> prPrec i 3 (concatD [prt 0 id])
RConst n -> prPrec i 3 (concatD [prt 0 n])
RApp e e1 -> prPrec i 2 (concatD [prt 2 e, prt 3 e1])
RAdd e e1 -> prPrec i 1 (concatD [prt 1 e, doc (showString "+"), prt 2 e1])
RAbs u id e -> prPrec i 0 (concatD [doc (showString "\\"), prt 0 ("var" ++ show u), doc (showString "."), prt 0 e])

View file

@ -76,8 +76,8 @@ inferExp = \case
return infT
Old.EConst c -> case c of
(Old.CInt i) -> return (TMono $ UIdent "Int")
(Old.CStr s) -> return (TMono $ UIdent "String")
(Old.CInt i) -> return (TMono "Int")
(Old.CStr s) -> return (TMono "String")
Old.EAdd e1 e2 -> do
let int = TMono "Int"

View file

@ -1,14 +1,19 @@
{-# LANGUAGE LambdaCase #-}
module TypeChecker.TypeCheckerIr (module Grammar.Abs, Exp) where
module TypeChecker.TypeCheckerIr where
import Grammar.Abs (Program(..), Ident(..), Bind(..), Const(..), Type(..), UIdent(..), LIdent(..))
import Renamer.RenamerIr
data Exp
= EAnn Exp Type
| EId Ident Type
| EConst Const Type
| EApp Exp Exp Type
| EAdd Exp Exp Type
| EAbs Ident Exp Type
data TProgram = TProgram [TBind]
data TBind = TBind Ident Type TExp
data TExp
= TAnn TExp Type
| TBound Integer Ident Type
| TFree Ident Type
| TConst Const Type
| TApp TExp TExp Type
| TAdd TExp TExp Type
| TAbs Integer Ident TExp Type
deriving (Eq, Ord, Show, Read)

View file

@ -1 +1,4 @@
main = 3;
letters = let x = 1
in let y = 2
in let z = 3
in x + y + z