Add initial typechecker for AST #2
@ -2,7 +2,6 @@ module Typecheck where
|
|||||||
import Data.List (find)
|
import Data.List (find)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Ast
|
import Ast
|
||||||
import Debug.Trace (trace)
|
|
||||||
|
|
||||||
typeCheckCompilationUnit :: CompilationUnit -> CompilationUnit
|
typeCheckCompilationUnit :: CompilationUnit -> CompilationUnit
|
||||||
typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes
|
typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes
|
||||||
@ -10,13 +9,12 @@ typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes
|
|||||||
typeCheckClass :: Class -> [Class] -> Class
|
typeCheckClass :: Class -> [Class] -> Class
|
||||||
typeCheckClass (Class className methods fields) classes =
|
typeCheckClass (Class className methods fields) classes =
|
||||||
let
|
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
|
-- Fields and methods dont need to be added to the symtab because they are looked upon automatically under "this"
|
||||||
-- TODO: Maybe remove method entries from the symbol table? I dont think we need them but if yes the next line would be
|
-- if its not a declared local variable. Also shadowing wouldnt be possible then.
|
||||||
-- initalSymTab = ("this", className) : methodEntries
|
|
||||||
-- methodEntries = [(methodName, className) | MethodDeclaration _ methodName _ _ <- methods]
|
|
||||||
initalSymTab = [("this", className)]
|
initalSymTab = [("this", className)]
|
||||||
checkedMethods = map (\method -> typeCheckMethodDeclaration method initalSymTab classes) methods
|
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 -> [(Identifier, DataType)] -> [Class] -> MethodDeclaration
|
||||||
typeCheckMethodDeclaration (MethodDeclaration retType name params body) symtab classes =
|
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
|
then MethodDeclaration retType name params checkedBody
|
||||||
else error $ "Method Declaration: Return type mismatch in method " ++ name ++ ": expected " ++ retType ++ ", found " ++ bodyType
|
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
|
typeCheckVariableDeclaration :: VariableDeclaration -> [(Identifier, DataType)] -> [Class] -> VariableDeclaration
|
||||||
-- checked as well. Also if its a class type, check wether the class exists.
|
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 **********************************
|
-- ********************************** Type Checking: Expressions **********************************
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user