Add initial typechecker for AST #2
@ -9,24 +9,27 @@ typeCheckCompilationUnit classes = map (`typeCheckClass` classes) classes
|
||||
typeCheckClass :: Class -> [Class] -> Class
|
||||
typeCheckClass (Class className methods fields) classes =
|
||||
let
|
||||
-- Create a symbol table from class fields and method entries
|
||||
-- TODO: Maybe remove method entries from the symbol table?
|
||||
methodEntries = [(methodName, className) | MethodDeclaration _ methodName _ _ <- methods]
|
||||
initalSymTab = ("this", className) : methodEntries
|
||||
-- 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]
|
||||
initalSymTab = [("this", className)]
|
||||
checkedMethods = map (\method -> typeCheckMethodDeclaration method initalSymTab classes) methods
|
||||
in Class className checkedMethods fields
|
||||
|
||||
typeCheckMethodDeclaration :: MethodDeclaration -> [(Identifier, DataType)] -> [Class] -> MethodDeclaration
|
||||
typeCheckMethodDeclaration (MethodDeclaration retType name params body) classFields classes =
|
||||
typeCheckMethodDeclaration (MethodDeclaration retType name params body) symtab classes =
|
||||
let
|
||||
methodParams = [(identifier, dataType) | ParameterDeclaration dataType identifier <- params]
|
||||
initialSymtab = ("thisMeth", retType) : classFields ++ methodParams
|
||||
initialSymtab = ("thisMeth", retType) : symtab ++ methodParams
|
||||
checkedBody = typeCheckStatement body initialSymtab classes
|
||||
bodyType = getTypeFromStmt checkedBody
|
||||
in if bodyType == retType || (bodyType == "void" && retType == "void") || (bodyType == "null" && isObjectType retType) || isSubtype bodyType retType classes
|
||||
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.
|
||||
|
||||
-- ********************************** Type Checking: Expressions **********************************
|
||||
|
||||
@ -36,7 +39,6 @@ typeCheckExpression (CharacterLiteral c) _ _ = TypedExpression "char" (Character
|
||||
typeCheckExpression (BooleanLiteral b) _ _ = TypedExpression "boolean" (BooleanLiteral b)
|
||||
typeCheckExpression NullLiteral _ _ = TypedExpression "null" NullLiteral
|
||||
typeCheckExpression (Reference id) symtab classes =
|
||||
-- TODO: maybe maje exception for "this" in first lookup?
|
||||
case lookup id symtab of
|
||||
Just t -> TypedExpression t (LocalVariable id)
|
||||
Nothing ->
|
||||
@ -47,7 +49,7 @@ typeCheckExpression (Reference id) symtab classes =
|
||||
Just (Class _ _ fields) ->
|
||||
let fieldTypes = [dt | VariableDeclaration dt fieldId _ <- fields, fieldId == id]
|
||||
in case fieldTypes of
|
||||
[fieldType] -> TypedExpression fieldType (FieldVariable id)
|
||||
[fieldType] -> TypedExpression fieldType (BinaryOperation NameResolution (LocalVariable "this") (FieldVariable id))
|
||||
[] -> error $ "Field '" ++ id ++ "' not found in class '" ++ className ++ "'"
|
||||
_ -> error $ "Ambiguous reference to field '" ++ id ++ "' in class '" ++ className ++ "'"
|
||||
Nothing -> error $ "Class '" ++ className ++ "' not found for 'this'"
|
||||
@ -272,7 +274,7 @@ typeCheckStatement (Block statements) symtab classes =
|
||||
-- Initial accumulator: empty statements list, initial symbol table, empty types list
|
||||
(checkedStatements, finalSymtab, collectedTypes) = foldl processStatements ([], symtab, []) statements
|
||||
|
||||
-- Determine the block's type: unify all collected types, default to "Void" if none
|
||||
-- Determine the block's type: unify all collected types, default to "void" if none (UpperBound)
|
||||
blockType = if null collectedTypes then "void" else foldl1 unifyReturnTypes collectedTypes
|
||||
|
||||
in TypedStatement blockType (Block checkedStatements)
|
||||
|
Loading…
Reference in New Issue
Block a user