diff --git a/src/Typecheck.hs b/src/Typecheck.hs index b03155a..0be409f 100644 --- a/src/Typecheck.hs +++ b/src/Typecheck.hs @@ -2,7 +2,6 @@ module Typecheck where import Data.List (find) import Data.Maybe import Ast -import Debug.Trace (trace) typeCheckCompilationUnit :: CompilationUnit -> CompilationUnit typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes @@ -10,13 +9,12 @@ typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes typeCheckClass :: Class -> [Class] -> Class typeCheckClass (Class className methods fields) classes = let - -- Fields dont need to be added to the symtab because they are looked upon automatically under this if its not a declared local variable - -- TODO: Maybe remove method entries from the symbol table? I dont think we need them but if yes the next line would be - -- initalSymTab = ("this", className) : methodEntries - -- methodEntries = [(methodName, className) | MethodDeclaration _ methodName _ _ <- methods] + -- Fields and methods dont need to be added to the symtab because they are looked upon automatically under "this" + -- if its not a declared local variable. Also shadowing wouldnt be possible then. initalSymTab = [("this", className)] checkedMethods = map (\method -> typeCheckMethodDeclaration method initalSymTab classes) methods - in Class className checkedMethods fields + checkedFields = map (\field -> typeCheckVariableDeclaration field initalSymTab classes) fields + in Class className checkedMethods checkedFields typeCheckMethodDeclaration :: MethodDeclaration -> [(Identifier, DataType)] -> [Class] -> MethodDeclaration typeCheckMethodDeclaration (MethodDeclaration retType name params body) symtab classes = @@ -29,8 +27,24 @@ typeCheckMethodDeclaration (MethodDeclaration retType name params body) symtab c then MethodDeclaration retType name params checkedBody else error $ "Method Declaration: Return type mismatch in method " ++ name ++ ": expected " ++ retType ++ ", found " ++ bodyType --- TODO: It could be that TypeCheckVariableDeclaration is missing. If it comes up -> just check wether the type is correct. The maybe expression needs to be --- checked as well. Also if its a class type, check wether the class exists. +typeCheckVariableDeclaration :: VariableDeclaration -> [(Identifier, DataType)] -> [Class] -> VariableDeclaration +typeCheckVariableDeclaration (VariableDeclaration dataType identifier maybeExpr) symtab classes = + let + -- Ensure the type is valid (either a primitive type or a valid class name) + validType = dataType `elem` ["int", "boolean", "char"] || isUserDefinedClass dataType classes + -- Ensure no redefinition in the same scope + redefined = any ((== identifier) . snd) symtab + -- Type check the initializer expression if it exists + checkedExpr = fmap (\expr -> typeCheckExpression expr symtab classes) maybeExpr + exprType = fmap getTypeFromExpr checkedExpr + in case (validType, redefined, exprType) of + (False, _, _) -> error $ "Type '" ++ dataType ++ "' is not a valid type for variable '" ++ identifier ++ "'" + (_, True, _) -> error $ "Variable '" ++ identifier ++ "' is redefined in the same scope" + (_, _, Just t) + | t == "null" && isObjectType dataType -> VariableDeclaration dataType identifier checkedExpr + | t /= dataType -> error $ "Type mismatch in declaration of '" ++ identifier ++ "': expected " ++ dataType ++ ", found " ++ t + | otherwise -> VariableDeclaration dataType identifier checkedExpr + (_, _, Nothing) -> VariableDeclaration dataType identifier checkedExpr -- ********************************** Type Checking: Expressions **********************************