add full block type checking

This commit is contained in:

View File

@ -79,7 +79,7 @@ typeCheckMethodDeclaration (MethodDeclaration retType name params body) classFie
-- Combine class fields with method parameters to form the initial symbol table for the method
methodParams = [(dataType, identifier) | ParameterDeclaration dataType identifier <- params]
-- Ensure method parameters shadow class fields if names collide
initialSymtab = classFields ++ methodParams
initialSymtab = classFields ++ methodParams
-- Type check the body of the method using the combined symbol table
checkedBody = typeCheckStatement body initialSymtab classes
bodyType = getTypeFromStmt checkedBody
@ -265,35 +265,27 @@ typeCheckStatement (While cond stmt) symtab classes =
typeCheckStatement (Block statements) symtab classes =
let
-- Helper function to process each statement and manage the symbol table
processStatements (accSts, currentSymtab) stmt =
case stmt of
processStatements (accSts, currentSymtab, types) stmt =
let
checkedStmt = typeCheckStatement stmt currentSymtab classes
stmtType = getTypeFromStmt checkedStmt
in case stmt of
LocalVariableDeclaration (VariableDeclaration dataType identifier maybeExpr) ->
let
-- Type check the expression if it exists
checkedExpr = fmap (\expr -> typeCheckExpression expr currentSymtab classes) maybeExpr
-- Update the symbol table with the new variable
newSymtab = (dataType, identifier) : currentSymtab
newStmt = typeCheckStatement (LocalVariableDeclaration (VariableDeclaration dataType identifier checkedExpr)) newSymtab classes
in (accSts ++ [newStmt], newSymtab)
in (accSts ++ [checkedStmt], newSymtab, types)
_ ->
-- For other statements, just type check using the current symbol table
let checkedStmt = typeCheckStatement stmt currentSymtab classes
in (accSts ++ [checkedStmt], currentSymtab)
If {} -> (accSts ++ [checkedStmt], currentSymtab, if stmtType /= "Void" then types ++ [stmtType] else types)
While _ _ -> (accSts ++ [checkedStmt], currentSymtab, if stmtType /= "Void" then types ++ [stmtType] else types)
Return _ -> (accSts ++ [checkedStmt], currentSymtab, if stmtType /= "Void" then types ++ [stmtType])
_ -> (accSts ++ [checkedStmt], currentSymtab, types)
-- Fold over the list of statements starting with the initial symbol table
(checkedStatements, finalSymtab) = foldl processStatements ([], symtab) statements
-- Initial accumulator: empty statements list, initial symbol table, empty types list
(checkedStatements, finalSymtab, collectedTypes) = foldl processStatements ([], symtab, []) statements
-- Determine the type of the block by examining the types of return statements
blockType = if any isReturnStatement checkedStatements
then foldl1 unifyReturnTypes [getTypeFromStmt s | s <- checkedStatements, isReturnStatement s]
else "Void"
-- Function to check if a statement is a return statement
isReturnStatement (Return _) = True
isReturnStatement _ = False
-- Determine the block's type: unify all collected types, default to "Void" if none
blockType = if null collectedTypes then "Void" else foldl1 unifyReturnTypes collectedTypes
in TypedStatement blockType (Block checkedStatements)
@ -307,7 +299,7 @@ typeCheckStatement (Return expr) symtab classes =
Nothing -> Nothing
in case expr' of
Just e' -> TypedStatement (getTypeFromExpr e') (Return (Just e'))
Nothing -> TypedStatement "void" (Return Nothing)
Nothing -> TypedStatement "Void" (Return Nothing)
-- ********************************** Type Checking: Helpers **********************************