diff options
author | tomsmeding <tom.smeding@gmail.com> | 2017-09-01 18:14:43 +0200 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2017-09-01 18:15:25 +0200 |
commit | 19c70b8eaa1126f1648b009d99092432a5c88059 (patch) | |
tree | bd4171a4d6ef5e8ae2b09e1c84bf3e2346374e97 /TypeCheck.hs | |
parent | 3d5d85e00f2a81efb62bb17f8e5db63fe5a49a61 (diff) |
Structs + typedefs
Diffstat (limited to 'TypeCheck.hs')
-rw-r--r-- | TypeCheck.hs | 99 |
1 files changed, 80 insertions, 19 deletions
diff --git a/TypeCheck.hs b/TypeCheck.hs index 922731d..2b05df1 100644 --- a/TypeCheck.hs +++ b/TypeCheck.hs @@ -1,6 +1,9 @@ +{-# LANGUAGE TupleSections #-} + module TypeCheck(typeCheck) where import Control.Monad +import Data.List import Data.Maybe import qualified Data.Map.Strict as Map @@ -10,7 +13,7 @@ import Pretty import TypeRules -data DBItem = DBVar Type | DBFunc (Maybe Type) [Type] +data DBItem = DBVar Type | DBFunc (Maybe Type) [Type] | DBType Type type TypeDB = [Map.Map Name DBItem] @@ -34,56 +37,79 @@ emptyDB = [Map.fromList ("putint", DBFunc Nothing [TInt]), ("getc", DBFunc (Just TInt) []), ("exit", DBFunc Nothing [TInt]), - ("_builtin_malloc", DBFunc (Just $ TArr TChar Nothing) [TInt])]] + ("_builtin_malloc", DBFunc (Just $ TArr TChar Nothing) [TInt]), + ("char", DBType TChar), + ("int", DBType TInt)]] withScope :: TypeDB -> (TypeDB -> a) -> a withScope db f = f (Map.empty : db) typeCheck :: Program -> Error Program -typeCheck (Program vars funcs) = do - db <- foldM registerDVar emptyDB vars - >>= \db' -> foldM registerDFunc db' funcs +typeCheck (Program tdefs vars funcs) = do + -- case topologicalSort + db <- foldM registerDTypedef emptyDB tdefs + >>= (\db' -> foldM registerDTypedefResolve db' tdefs) + >>= (\db' -> foldM registerDVar db' vars) + >>= (\db' -> foldM registerDFunc db' funcs) vars' <- mapM (annotateDVar db) vars funcs' <- mapM (annotateDFunc db) funcs - return $ Program vars' funcs' + return $ Program [] vars' funcs' + + +registerDTypedef :: TypeDB -> DTypedef -> Error TypeDB +registerDTypedef db (DTypedef n t) = case dbFind db n of + Nothing -> return $ dbSet db n (DBType t) + Just _ -> Left $ "Duplicate top-level name '" ++ n ++ "'" +registerDTypedefResolve :: TypeDB -> DTypedef -> Error TypeDB +registerDTypedefResolve db (DTypedef n t) = do + t' <- resolveType db t + return $ dbSet db n (DBType t') registerDVar :: TypeDB -> DVar -> Error TypeDB registerDVar db (DVar t n _) = case dbFind db n of - Nothing -> return $ dbSet db n (DBVar t) + Nothing -> do + t' <- resolveType db t + return $ dbSet db n (DBVar t') Just _ -> Left $ "Duplicate top-level name '" ++ n ++ "'" registerDFunc :: TypeDB -> DFunc -> Error TypeDB registerDFunc db (DFunc rt n al _) = case dbFind db n of - Nothing -> return $ dbSet db n (DBFunc rt (map fst al)) + Nothing -> do + rt' <- sequence $ fmap (resolveType db) rt + al' <- forM al $ \(at,an) -> (,an) <$> resolveType db at + return $ dbSet db n (DBFunc rt' (map fst al')) Just _ -> Left $ "Duplicate top-level name '" ++ n ++ "'" annotateDVar :: TypeDB -> DVar -> Error DVar annotateDVar db (DVar toptype name expr) = do + toptype' <- resolveType db toptype expr' <- annotateExpr db expr when (isNothing (typeof expr')) $ Left $ "Cannot assign void value in global declaration of " ++ name let typ = fromJust $ typeof expr' - if canCoerce typ toptype - then return $ DVar toptype name expr' + if canCoerce typ toptype' + then return $ DVar toptype' name expr' else Left $ "Cannot assign a value of type " ++ pretty typ ++ - " to a variable of type " ++ pretty toptype + " to a variable of type " ++ pretty toptype' data State = State {stDfunc :: DFunc, stLoopDepth :: Int} deriving Show annotateDFunc :: TypeDB -> DFunc -> Error DFunc annotateDFunc db dfunc@(DFunc rettype name arglist block) = do - when (name == "main" && rettype /= Just TInt) $ + rettype' <- sequence $ fmap (resolveType db) rettype + arglist' <- forM arglist $ \(at,an) -> (,an) <$> resolveType db at + when (name == "main" && rettype' /= Just TInt) $ Left $ "Function 'main' should return an int" - let db' = foldl registerArg db arglist + db' <- foldM registerArg db arglist' block' <- annotateBlock (State dfunc 0) db' block - return $ DFunc rettype name arglist block' + return $ DFunc rettype' name arglist' block' where - registerArg :: TypeDB -> (Type, Name) -> TypeDB - registerArg db' (t, n) = dbSet db' n (DBVar t) + registerArg :: TypeDB -> (Type, Name) -> Error TypeDB + registerArg db' (t, n) = dbSet db' n . DBVar <$> resolveType db' t annotateBlock :: State -> TypeDB -> Block -> Error Block annotateBlock state db (Block sts) = @@ -93,16 +119,17 @@ annotateBlock state db (Block sts) = annotateStatement :: State -> TypeDB -> Statement -> Error (TypeDB, Statement) annotateStatement _ db (SDecl toptype name expr) = do + toptype' <- resolveType db toptype expr' <- annotateExpr db expr when (isNothing (typeof expr')) $ Left $ "Cannot assign void value in declaration of " ++ name when (isJust (dbFindTop db name)) $ Left $ "Duplicate declaration of variable " ++ name let typ = fromJust $ typeof expr' - if canCoerce typ toptype - then return $ (dbSet db name (DBVar toptype), SDecl toptype name expr') + if canCoerce typ toptype' + then return $ (dbSet db name (DBVar toptype'), SDecl toptype' name expr') else Left $ "Cannot assign a value of type " ++ pretty typ ++ - " to a variable of type " ++ pretty toptype + " to a variable of type " ++ pretty toptype' annotateStatement _ db (SAs ae expr) = do ae' <- annotateAsExpr db ae expr' <- annotateExpr db expr @@ -182,6 +209,7 @@ annotateExpr db (ELit lit@(LVar n) _) = case dbFind db n of Nothing -> Left $ "Use of undeclared variable " ++ n ++ " in expression" Just (DBVar t) -> return $ ELit lit (Just t) Just (DBFunc _ _) -> Left $ "Cannot use function " ++ n ++ " in expression" + Just (DBType _) -> Left $ "Cannot use type " ++ n ++ " as value in expression" annotateExpr db (ELit (LCall n as) _) = do as' <- mapM (annotateExpr db) as case dbFind db n of @@ -200,17 +228,38 @@ annotateExpr db (ELit (LCall n as) _) = do " but value of type " ++ pretty (fromJust $ typeof arg) ++ " was given" return $ ELit (LCall n as') mrt + Just (DBType t) -> case as of + [a] -> annotateExpr db (ECast t a) + _ -> Left $ "Cannot call type " ++ pretty t ++ " as function with " ++ + show (length as) ++ " arguments" annotateExpr _ (ELit lit@(LStr s) _) = return $ ELit lit (Just $ TArr TChar (Just $ fromIntegral $ length s)) +annotateExpr db (ELit (LStruct ms) _) = do + ms' <- forM ms $ \(n,e) -> (n,) <$> annotateExpr db e + types <- forM ms' $ \(n,e) -> case typeof e of + Nothing -> Left $ "Use of void value in struct literal item '" ++ n ++ "'" + Just t -> return t + return $ ELit (LStruct ms') (Just $ TStruct $ zip types (map fst ms')) annotateExpr db (ESubscript arr sub _) = do arr' <- annotateExpr db arr sub' <- annotateExpr db sub + when (isNothing (typeof sub')) $ + Left $ "Use of void value as subscripted expression" let subtyp = fromJust (typeof sub') when (subtyp /= TInt) $ Left $ "Type of array subscript should be int, but is " ++ pretty subtyp case fromJust (typeof arr') of TArr et _ -> return $ ESubscript arr' sub' (Just et) _ -> Left $ "Subscripted expression is not an array: " ++ pretty arr +annotateExpr db (EGet st n _) = do + st' <- annotateExpr db st + case typeof st' of + Nothing -> Left $ "Use of void value as dot-indexed expression" + Just stt@(TStruct ms) -> case find ((==n) . snd) ms of + Nothing -> Left $ "Struct of type " ++ pretty stt ++ + " has no member named '" ++ n ++ "'" + Just (t, _) -> return $ EGet st' n (Just t) + Just stt -> Left $ "Use of non-struct type " ++ pretty stt ++ " as dot-indexed expression" annotateExpr db (ECast t e) = do e' <- annotateExpr db e let typ = fromJust (typeof e') @@ -232,6 +281,7 @@ annotateAsExpr db (AEVar n _) = case dbFind db n of Nothing -> Left $ "Use of undeclared variable " ++ n ++ " in assignment expression" Just (DBVar t) -> return $ AEVar n (Just t) Just (DBFunc _ _) -> Left $ "Cannot use function " ++ n ++ " in assignment expression" + Just (DBType _) -> Left $ "Cannot use type " ++ n ++ " as variable in assignment expression" annotateAsExpr db (AESubscript ae expr _) = do ae' <- annotateAsExpr db ae expr' <- annotateExpr db expr @@ -243,3 +293,14 @@ annotateAsExpr db (AESubscript ae expr _) = do TArr t _ -> return $ AESubscript ae' expr' (Just t) t -> Left $ "Indexed expression '" ++ pretty ae ++ "' has non-array type " ++ pretty t ++ " in assignment expression" + + +resolveType :: TypeDB -> Type -> Error Type +resolveType _ TInt = return TInt +resolveType _ TChar = return TChar +resolveType db (TArr t sz) = liftM (\t' -> TArr t' sz) $ resolveType db t +resolveType db (TStruct ms) = TStruct <$> mapM (\(t,n) -> liftM (,n) $ resolveType db t) ms +resolveType db (TName n) = case dbFind db n of + Nothing -> Left $ "Type name '" ++ n ++ "' not defined" + Just (DBType t) -> return t + Just _ -> Left $ "Name '" ++ n ++ "' used as type is not a type" |