type Type = String 

data Class = Class(Type, [FieldDecl], [MethodDecl]) 

data FieldDecl = FieldDecl(Type, String) 

data MethodDecl = Method(Type, String,[(Type,String)], Stmt) 

data Stmt = If(Expr, Stmt , Maybe Stmt)
          | While( Expr , Stmt )
          | Block([Stmt])
          | Empty
          | Return( Maybe Expr )
          | TypedStmt(Stmt, Type)
          deriving (Show)

data Expr = One
       | T
       | TypedExpr(Expr, Type)
     deriving (Show)


typecheckStmt (If(be, ifs, Nothing)) symtab cls =
  let
    bexp = typecheckExpr be symtab cls
    ifstmt = typecheckStmt ifs symtab cls
  in
    if ((getTypeFromExpr bexp) == "boolean") then
      TypedStmt(If(bexp, ifstmt, Nothing), getTypeFromStmt ifstmt)
    else                  
     error "boolean expected"

typecheckStmt (If(be, ifs, Just elses)) symtab cls =
  let
    bexp = typecheckExpr be symtab cls
    ifstmt = typecheckStmt ifs symtab cls
    elsestmt = typecheckStmt elses symtab cls
  in
    if ((getTypeFromExpr bexp) == "boolean") then
      if (getTypeFromStmt ifstmt) == (getTypeFromStmt elsestmt) then
        TypedStmt(If(bexp, ifstmt, Just elsestmt), getTypeFromStmt elsestmt)
      else    
        error "if und else unterschiedlich"
    else                  
     error "boolean expected"

typecheckStmt Empty symtab cls = TypedStmt(Empty, "void")

typecheckStmt (Return(Nothing)) symtab cls = TypedStmt(Return(Nothing), "void")
typecheckStmt (Return(Just e)) symtab cls = 
  let
    typedexpr = typecheckExpr e symtab cls
  in
    TypedStmt(Return (Just typedexpr), getTypeFromExpr(typedexpr))

typecheckExpr:: Expr -> [(String, Type)] -> [Class] -> Expr
typecheckExpr T symtab cls = TypedExpr(T, "boolean")
typecheckExpr One symtab cls = TypedExpr(One, "integer")

getTypeFromExpr (TypedExpr(_, typ)) = typ

getTypeFromStmt (TypedStmt(_, typ)) = typ

erste = typecheckStmt (If (T, Empty, Nothing)) [] []

zweite = typecheckStmt (If (One, Empty, Nothing)) [] []

dritte = typecheckStmt (If (T, Empty, Just Empty)) [] []

vierte = typecheckStmt (If (T, Empty, Just (Return (Just One)))) [] []

fuenfte = typecheckStmt (If (T, Return (Just One), Just (Return (Just One)))) [] []
