This repository has been archived by the owner on May 31, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpasseTypeRat.ml
388 lines (373 loc) · 13.4 KB
/
passeTypeRat.ml
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
(* Auteurs : Benjamin Coupry & Eliès Jurquet *)
(* Module de la passe de typage *)
module PasseTypeRat : Passe.Passe with type t1 = Ast.AstTds.programme and type t2 = Ast.AstType.programme =
struct
open Tds
open Exceptions
open Ast
open AstType
open Type
type t1 = AstTds.programme
type t2 = AstType.programme
(* type_trouve_exprenum : AstTds.expression -> typ list -> typ *)
(* Paramètre e : expression d'enum à typer *)
(* Paramètre enums : ensemble des types d'enums *)
(* Calcule le type d'une expression d'enum et renvoie le type calculé *)
let type_trouve_exprenum e (enums:(typ list)) =
match e with
| (AstTds.ExpressionEnum(id)) ->
begin
let predicat = fun enum ->
begin
match enum with
| TypeEnum(_, lid) -> List.exists (fun idl -> id = idl ) lid
| _ -> failwith "Erreur Interne"
end
in
match List.find_opt predicat enums with
| None -> raise (MauvaiseUtilisationIdentifiant id)
| Some r -> r
end
| _ -> failwith "Erreur interne"
(* exprenum_toint : AstTds.expression -> typ -> int *)
(* Paramètre e : expression d'enum à typer *)
(* paramètre v : type de cette expression *)
(* Calcule l'equivalent entier d'une expression d'enum *)
(* renvoie la valeur de l'enum : int *)
(* Erreur si l'enum n'est pas incluse dans son type *)
let exprenum_toint e v =
match e, v with
| AstTds.ExpressionEnum(id), TypeEnum(_, lid) ->
begin
let rec indexOf i li n =
match li with
| t::q ->
begin
if t=i then n
else indexOf i q (n+1)
end
| []-> raise (MauvaiseUtilisationIdentifiant id)
in indexOf id lid 0
end
| _ -> failwith "Erreur interne"
(* analyse_type_affectable : AstTds.affectable -> affectable * typ *)
(* Paramètre af : l'affectable à analyser *)
(* Vérifie la bonne utilisation des types et calcule le type de l'expression *)
(* renvoie un tuple de l'affectable traité et de son type *)
(* Erreur si tentative de prendre la valeur d'autre chose sur un pointeur *)
let rec analyse_type_affectable (af:AstTds.affectable) : (affectable * typ) =
match af with
| Ident info ->
begin
match info_ast_to_info info with
| InfoVar (_,t,_,_) -> (Ident info, t)
| InfoConst _ -> (Ident info, Int)
| _ -> failwith "Erreur interne : symbole non trouvé"
end
| Valeur aff ->
begin
match (analyse_type_affectable aff) with
| (naf, Pointeur tp) -> (Valeur naf, tp)
| _ -> let (_,ts) = analyse_type_affectable aff in
raise (PasUnPointeur (string_of_type ts))
end
(* analyse_type_expression : typ list -> AstTds.expression -> expression * typ *)
(* Paramètre tpEnums : la liste des types des enums *)
(* Paramètre e : l'expression à analyser *)
(* Vérifie la bonne utilisation des types et calcule le type de l'expression *)
(* renvoie un tuple de l'expression traitee et de son type *)
(* Erreur si types incompatibles *)
let rec analyse_type_expression tpEnums e =
match e with
| AstTds.AppelFonction(info, le) ->
begin
match info_ast_to_info info with
| InfoFunSurcharges(lif) ->
begin
let nlet = List.map(fun ei -> analyse_type_expression tpEnums ei) le in
let nle = List.map(fst) nlet in
let ltype = List.map(snd) nlet in
let funsigmatch = (
fun i ->
begin
match i with
| InfoFun (_, _, typeParams) -> est_compatible_list typeParams ltype
| _ -> failwith "Erreur interne"
end
) in
(*trouver la signature qui correspond*)
let signaturematch = List.find_opt (funsigmatch) lif in
match signaturematch with
(*Pas de signature trouvee*)
| None -> raise (TypesParametresInattendus([], ltype))
(*Signature trouvee*)
| Some info ->
begin
match info with
| InfoFun (_, typeret, _) -> (AppelFonction (info_to_info_ast info, nle), typeret)
| _ -> failwith "Erreur interne"
end
end
| _ -> failwith "Erreur interne."
end
| AstTds.Rationnel(e1, e2) ->
begin
let (ne1, t1) = analyse_type_expression tpEnums e1 in
let (ne2, t2) = analyse_type_expression tpEnums e2 in
if t1 = Int then
if t2 = t1 then
(Rationnel(ne1, ne2), Rat)
else
raise (TypeInattendu(t2, Int))
else
raise (TypeInattendu(t1, Int))
end
| AstTds.Numerateur(e1) ->
begin
let (ne1, t1) = analyse_type_expression tpEnums e1 in
if t1 = Rat then
(Numerateur ne1, Int)
else
raise (TypeInattendu(t1, Rat))
end
| AstTds.Denominateur(e1) ->
begin
let (ne1, t1) = analyse_type_expression tpEnums e1 in
if t1 = Rat then
(Denominateur ne1, Int)
else
raise (TypeInattendu(t1, Rat))
end
| AstTds.Ident(info) ->
begin
match info_ast_to_info info with
| InfoVar(_, t, _, _) -> (Ident info, t)
| InfoConst(_, _) -> (Ident info, Int)
| _ -> failwith("Internal error : symbol not found")
end
| AstTds.True ->
begin
(True, Bool)
end
| AstTds.False ->
begin
(False, Bool)
end
| AstTds.Entier(i) ->
begin
(Entier i, Int)
end
| AstTds.Binaire(b, e1, e2) ->
begin
let (ne1, t1) = analyse_type_expression tpEnums e1 in
let (ne2, t2) = analyse_type_expression tpEnums e2 in
match (t1, b, t2) with
| (Int, Plus, Int) ->
begin
(Binaire(PlusInt, ne1, ne2), Int)
end
| (Rat, Plus, Rat) ->
begin
(Binaire(PlusRat, ne1, ne2), Rat)
end
| (Int, Equ, Int) ->
begin
(Binaire(EquInt, ne1, ne2), Bool)
end
| (Bool, Equ, Bool) ->
begin
(Binaire(EquBool, ne1, ne2), Bool)
end
| (Int, Mult, Int) ->
begin
(Binaire(MultInt, ne1, ne2), Int)
end
| (Rat, Mult, Rat) ->
begin
(Binaire(MultRat, ne1, ne2), Rat)
end
| (Int, Inf, Int) ->
begin
(Binaire(Inf, ne1, ne2), Bool)
end
| (TypeEnum(_, _), Equ,TypeEnum(_, _)) ->
begin
(*Les deux enums doivent etre compatibles*)
if est_compatible t1 t2 then
(Binaire(EquEnum, ne1, ne2), Bool)
else
raise (TypeBinaireInattendu(b, t1, t2))
end
| _ -> raise (TypeBinaireInattendu(b, t1, t2))
end
| AstTds.Affectable a -> let (na,t) = analyse_type_affectable a in (Affectable na, t)
| AstTds.Null -> Null, Pointeur Undefined
| AstTds.New t -> New t, Pointeur t
| AstTds.Adresse info ->
begin
match info_ast_to_info info with
| InfoVar (_, t, _, _) -> (Adresse info, Pointeur t)
| _ -> failwith ("Internal error : symbol not found")
end
| AstTds.ExpressionEnum e ->
(*Trouver le type d'enum*)
let typTrouve = (type_trouve_exprenum (AstTds.ExpressionEnum e) tpEnums) in
(*Convertir l'enum en entier*)
let intCorresp = exprenum_toint (AstTds.ExpressionEnum e) typTrouve in
(ExpressionEnum (intCorresp), typTrouve )
(* analyse_type_expression : typ list -> AstTds.instruction -> instruction *)
(* Paramètre tpEnums : la liste des types des enums *)
(* Paramètre i : l'instruction à analyser *)
(* Vérifie la bonne utilisation des types*)
(* renvoie une instruction analysée *)
(* Erreur si types incompatibles *)
let rec analyse_type_instruction tpEnums i =
match i with
| AstTds.Declaration(t, e, info) ->
begin
let (ne, te) = analyse_type_expression tpEnums e in
if est_compatible te t then
begin
modifier_type_info t info;
(Declaration(ne, info))
end
else raise (TypeInattendu(te, t))
end
| AstTds.Affectation(e, affectable) ->
begin
let (af, typaf) = analyse_type_affectable affectable in
let (exp, typexp) = analyse_type_expression tpEnums e in
if est_compatible typexp typaf then
Affectation (exp, af)
else
raise (TypeInattendu(typexp, typaf))
end
| AstTds.Affichage(e) ->
begin
let (ne, te) = analyse_type_expression tpEnums e in
match te with
| Rat ->
begin
AffichageRat(ne)
end
| Int ->
begin
AffichageInt(ne)
end
| Bool ->
begin
AffichageBool(ne)
end
| _ -> failwith "Type non pris en charge."
end
| AstTds.Conditionnelle(c, b1, b2) ->
begin
let (nc, tc) = analyse_type_expression tpEnums c in
if tc = Bool then
begin
let bt1 = List.map(analyse_type_instruction tpEnums) b1 in
let bt2 = List.map(analyse_type_instruction tpEnums) b2 in
Conditionnelle(nc, bt1, bt2)
end
else raise (TypeInattendu(tc, Bool))
end
| AstTds.TantQue(c, b) ->
begin
let (nc, tc) = analyse_type_expression tpEnums c in
if tc = Bool then
begin
let bt = List.map(analyse_type_instruction tpEnums) b in
TantQue(nc, bt)
end
else raise (TypeInattendu(tc, Bool))
end
| AstTds.Empty ->
begin
Empty
end
| AstTds.Switch (expr, cl) ->
(* Analyse de l'expression comparée *)
let (nc, tc) = analyse_type_expression tpEnums expr in
(* Analyse du bloc *)
let ncl = analyse_type_listcase tpEnums tc cl in
(* Renvoie la nouvelle structure de la boucle *)
Switch(nc, ncl)
(* analyse_type_listcase : typ list -> typ -> AstTds.case list -> case list *)
(* Paramètre tpEnums : la liste des types des enums *)
(* Paramètre tc : le type de la cible du switch/case *)
(* Paramètre cl : la liste des case du switch/case *)
(* Vérifie la bonne utilisation des types *)
(* renvoie une liste de case traites *)
and analyse_type_listcase tpEnums tc cl =
List.map (analyse_type_case tpEnums tc) cl
(* analyse_type_case : typ list -> typ -> AstTds.case -> case *)
(* Paramètre tpEnums : la liste des types des enums *)
(* Paramètre tc : le type de la cible du switch/case *)
(* Paramètre case : le case du switch/case *)
(* Vérifie la bonne utilisation des types *)
(* renvoie un de case traite *)
and analyse_type_case tpEnums tc case =
match case with
| AstTds.CaseTid(s, il, b) ->
begin
let (ex,t) = (analyse_type_expression tpEnums (AstTds.ExpressionEnum(s))) in
if est_compatible t tc then CaseTid(ex,List.map(analyse_type_instruction tpEnums) il, analyse_type_break b)
else raise (TypeInattendu(t, tc))
end
| AstTds.CaseEntier(i, il, b) ->
begin
if est_compatible tc Int then CaseEntier(i, List.map(analyse_type_instruction tpEnums) il, analyse_type_break b)
else raise (TypeInattendu(Int, tc))
end
| AstTds.CaseTrue (il, b) ->
begin
if est_compatible tc Bool then CaseTrue(List.map(analyse_type_instruction tpEnums) il, analyse_type_break b)
else raise (TypeInattendu(Bool, tc))
end
| AstTds.CaseFalse (il, b) ->
begin
if est_compatible tc Bool then CaseFalse(List.map(analyse_type_instruction tpEnums) il, analyse_type_break b)
else raise (TypeInattendu(Bool, tc))
end
| AstTds.CaseDefault(il, b) ->
begin
CaseDefault(List.map(analyse_type_instruction tpEnums) il, analyse_type_break b)
end
(* analyse_type_break : AstTds.break -> break *)
(* Paramètre b : le break a analyser *)
(* fait remonter le type de break dans les passes*)
(* renvoie un break traite *)
and analyse_type_break b =
match b with
| AstTds.Break -> Break
| AstTds.Lambda -> Lambda
(* analyse_type_fonction : typ list -> AstTds.fonction -> fonction *)
(* Paramètre tpEnums : la liste des types des enums *)
(* Paramètre AstTds.Fonction : la fonction a analyser *)
(* Vérifie la bonne utilisation des types, s'assure que les parametres sont de bon type *)
(* et que le return est du type annoncé *)
(* renvoie une Fonction traitee *)
(* Erreur si types incompatibles *)
let analyse_type_fonction tpEnums (AstTds.Fonction(t, _, infoseule, lp, li, e)) =
let ltypeparam = List.map(fst) lp in
modifier_type_fonction_info t ltypeparam infoseule;
let lpt = List.map(fun (typeinfo, i) ->
begin
modifier_type_info typeinfo i;
i
end
) lp in
let lit = List.map(analyse_type_instruction tpEnums) li in
let (ne, te) = analyse_type_expression tpEnums e in
if te = t then
begin
Fonction (infoseule, lpt, lit, ne)
end
else raise (TypeInattendu(te, t))
(* analyser : t1 -> t2 *)
(* Paramètre AstTds.Programme : le programme à analyser *)
let analyser (AstTds.Programme(tpEnums,fonctions, prog)) =
let ft= List.map (analyse_type_fonction tpEnums) fonctions in
let pt = List.map (analyse_type_instruction tpEnums) prog in
Programme (ft, pt)
end