-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeCheckerFJ.hs
More file actions
191 lines (179 loc) · 7.6 KB
/
TypeCheckerFJ.hs
File metadata and controls
191 lines (179 loc) · 7.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
module TypeCheckerFJ where
import UtilitiesFJ;;
import DataTypesFJ;;
-- check type of an expression
typeCheck :: Exp -> ClassTable -> Context -> Either Exception Type
-- T-Var
typeCheck (Variable x) cTable context =
case lookupContext x context of
Nothing -> Left (VariableNotFoundException ("Variable " ++ x ++ " not found!"))
Just t -> Right t
;;
-- T-Invk
typeCheck (MethodInv e0 mname params) cTable context =
let c0 = typeCheck e0 cTable context in
case c0 of
Left e -> Left e
Right (TypeDecl c0') ->
case tryGetClass c0' cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ c0' ++ " not found!"))
Just c' ->
let types = mtype c' mname cTable in
case types of
Left e' -> Left e'
Right (types', retType) ->
case checkTypeAndNumberOfParams types' params cTable context of
Left e'' -> Left e''
Right _ -> Right retType
;;
-- T-Field
typeCheck (FieldAccess e f) cTable context =
let t = typeCheck e cTable context in
case t of
Left e -> Left e
Right (TypeDecl t') ->
let c = tryGetClass t' cTable in
case c of
Nothing -> Left (ClassNotFoundException ("Class " ++ t' ++ " not found!"))
Just c' ->
let fds = fields c' cTable in
let idx = isInFields f fds 0 in
case idx of
Nothing -> Left (FieldNotFoundException ("Field " ++ f ++ " not found!"))
Just idx' -> Right (fst (fds !! idx'))
;;
-- T-New
typeCheck (New cname params) cTable context =
let c = tryGetClass cname cTable in
case c of
Nothing -> Left (ClassNotFoundException ("Class " ++ cname ++ " not found!"))
Just c' ->
let fds = map (fst) (fields c' cTable) in
case checkTypeAndNumberOfParams fds params cTable context of
Left e -> Left e
Right _ -> Right (TypeDecl cname)
;;
-- T-Cast
typeCheck (Cast cname exp) cTable context =
let t = typeCheck exp cTable context in
case t of
Left e -> Left e
Right t' ->
let tt = fromType t' in
case tryGetClass tt cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ tt ++ " not found!"))
Just c ->
case tryGetClass cname cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ cname ++ " not found!"))
Just c' ->
-- T-UpCast
case subtype c c' cTable of
Nothing -> Left (TypeException "Types are not well formed!")
Just b ->
if b
then Right (TypeDecl cname)
else
-- T-DownCast
case subtype c' c cTable of
Nothing -> Left (TypeException "Types are not well formed!")
Just b' ->
if b'
then Right (TypeDecl cname)
else Left (TypeException "Types are not compatible!")
;;
-- check if a method is well-formed
typeCheckMethod :: Method -> Class -> ClassTable -> Either Exception ()
typeCheckMethod (MethodDecl retType mName params exp) c cTable =
let context = (map (\(x, y) -> (y, x)) params) ++ [("this", TypeDecl (className c))] in
if allDifferent (map (fst) context)
then
case typeCheck exp cTable context of
Left e -> Left e
Right t ->
let tt = fromType t in
case tryGetClass tt cTable of
Nothing -> Left (ClassNotFoundException ("Type " ++ tt ++ " not found!"))
Just r' ->
let ttt = fromType retType in
case tryGetClass ttt cTable of
Nothing -> Left (ClassNotFoundException ("Type " ++ ttt ++ " not found!"))
Just retType' ->
case subtype r' retType' cTable of
Nothing -> Left (TypeException "Types are not well formed!")
Just b ->
if b
then Right ()
else Left (TypeException "Effective and declared return types are not compatible!")
else Left (DuplicateVariableException ("There are two params with the same name in method " ++ mName ++ "!"))
;;
-- check all methods in a class
checkAllMethods :: MDS -> Class -> ClassTable -> Either Exception ()
checkAllMethods [] _ _ = Right ();;
checkAllMethods (m:mds) c cTable =
case typeCheckMethod m c cTable of
Left e -> Left e
_ -> checkAllMethods mds c cTable
;;
-- check if a class is well-formed
typeCheckClass :: Class -> ClassTable -> Either Exception ()
typeCheckClass c cTable =
let cname = className c in
let fname = classFather c in
if checkClassName cname cTable
then
case tryGetClass fname cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ fname ++ " does not exist!"))
_ ->
if goToObj c cTable [] then
let fds = fields c cTable in
if allDifferent (map (snd) fds)
then
case checkFieldsType fds cTable of
Left ex -> Left ex
_ ->
let mds = methods c cTable in
if allDifferent (map (methodName) (classMethods c)) -- overrided allowed
then
if checkOverride mds
then
case checkAllMethods mds c cTable of
Left e -> Left e
_ -> Right ()
else Left (OverrideException "Methods with same name do not share same signature!")
else Left (DuplicateMethodException ("There are two methods with the same name in class " ++ cname ++ "!"))
else Left (DuplicateFieldException ("There are two fields with the same name in class " ++ cname ++ "!"))
else Left (TypeException "Cyclic dependency between two types!")
else Left (DuplicateClassException ("There are two classes with the same name: " ++ cname ++ "!"))
;;
-- typecheck the entire program
typeCheckProg :: ClassTable -> ClassTable -> Either Exception ()
typeCheckProg [] _ = Right ();;
typeCheckProg (c:cs) cTable =
case typeCheckClass c cTable of
Left e -> Left e
_ -> typeCheckProg cs cTable
;;
-- check the number and the type of parameter of a function (also contructor) invocation
checkTypeAndNumberOfParams :: [Type] -> [Exp] -> ClassTable -> Context -> Either Exception Bool
checkTypeAndNumberOfParams [] [] _ _ = Right True;;
checkTypeAndNumberOfParams ts [] _ _ = Left (MismatchParamsException "Params does not match!");;
checkTypeAndNumberOfParams [] params _ _ = Left (MismatchParamsException "Params does not match!");;
checkTypeAndNumberOfParams (tf:ts) (p:params) cTable context =
let tf' = fromType tf in
case tryGetClass tf' cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ tf' ++ " not found!"))
Just c' ->
case typeCheck p cTable context of
Left e -> Left e
Right p' ->
let tp = fromType p' in
case tryGetClass tp cTable of
Nothing -> Left (ClassNotFoundException ("Class " ++ tp ++ " not found!"))
Just c ->
case subtype c c' cTable of
Nothing -> Left (MismatchParamsException "Type of params does not match!")
Just b ->
if b
then checkTypeAndNumberOfParams ts params cTable context
else Left (MismatchParamsException "Type of params does not match!")
;;