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
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
(** TYPE/BINDING CHECK : main
-------------------------------------------------------------
Cette passe a essentiellement pour but de donner un
type effectif aux différents items syntaxiques du
programme (lets, expressions).
Conjointement, elle résout les "bindings" des identificateurs :
- toute référence à un identificateur est identifiée
de manière UNIQUE par son ident (décoré de son info source)
On utilise trois tables :
- une table GLOBALE de binding "ident -> ident_info"
- une table "dynamique" de scoping "string -> ident_info"
- une table de typage des exp "val_exp -> type_eff"
------------------------------------------------------------*)
open Lexeme;;
open LutErrors;;
open Format;;
open Syntaxe;;
open CkIdentInfo;;
let type_error lxm get expect = (
let msg = sprintf "type error, get (%s) while (%s) was expected"
(CkTypeEff.list_to_string get) (CkTypeEff.list_to_string expect) in
raise (Compile_error (lxm, msg))
)
let arity_error lxm get expect = (
let msg = sprintf "arity error, get %d while %d was expected"
get expect in
raise (Compile_error (lxm, msg))
)
let rec check_var_decl (env : CheckEnv.t) (i, t, vopt,range_opt) =
let tdecl = (CkTypeEff.of_texp t) in
(match vopt with
| None -> ()
| Some e -> (
let tcalc = check_exp env e in
if CkTypeEff.lifts_to tcalc tdecl then () else
type_error i.src [tcalc] [tdecl]
)
);
(match range_opt with
| None -> ()
| Some (low, high) ->
let tlow = check_exp env low
and thigh= check_exp env high in
if(CkTypeEff.lifts_to tlow tdecl) then
if (CkTypeEff.lifts_to thigh tdecl) then ()
else ( type_error i.src [thigh] [tdecl] )
else ( type_error i.src [tlow] [tdecl] )
);
(i,tdecl)
and
check_erun_var_decl
(env : CheckEnv.t)
(i, topt, vopt)
(txpc)
=
(
let teff = match topt with
| Some t ->
let tf = (CkTypeEff.of_texp t) in
if(CkTypeEff.lifts_to txpc tf) then tf
else ( type_error i.src [txpc] [tf] )
| None -> txpc
in
let _ = (
match vopt with
| None -> ()
| Some e -> (
let tcalc = check_exp env e in
if(CkTypeEff.lifts_to tcalc teff) then ()
else ( type_error i.src [tcalc] [teff] )
)
) in
(i,teff)
)
and
check_run_var_decl
(env : CheckEnv.t)
(id)
(txpc)
=
(
let _ = match (CheckEnv.nature_of_ident env id) with
| Support_var -> ()
| _ -> (
raise (Compile_error (id.src,"identifier "^id.it^" not allowed as run result"))
) in
let tf = CheckEnv.type_of_ident env id in
let teff = if(CkTypeEff.lifts_to tf txpc) then txpc
else ( type_error id.src [tf] [txpc])
in
(id,teff)
)
and
check_exp
(env : CheckEnv.t)
(e : Syntaxe.val_exp) =
(
let rec_call e = ( check_exp env e) in
let rec_list_call el = ( List.map rec_call el) in
let e_teff = (
match e.it with
TRUE_n -> CkTypeEff.boolean
| FALSE_n -> CkTypeEff.boolean
| ICONST_n _id -> CkTypeEff.integer
| RCONST_n _id -> CkTypeEff.real
| IDENT_n id -> (
match (CheckEnv.nature_of_ident env id) with
Macro_ident (_, _prof) -> (
let msg = sprintf "arity error, get a macro where a scalar was expected" in
raise (Compile_error (e.src, msg))
)
| _ -> CheckEnv.type_of_ident env id
)
| PRE_n id -> (
match (CheckEnv.nature_of_ident env id) with
Support_var
| Formal_param -> (
let te = CheckEnv.type_of_ident env id in
try (
CkTypeEff.lift_ref te
) with Failure _ -> (
let msg = sprintf
"type error, get (%s) while ('a ref) was expected"
(CkTypeEff.to_string te)
in
raise (Compile_error (e.src, msg))
)
) |
_ -> (
raise (Compile_error (e.src,
"identifier "^id.it^" not allowed as pre argument"))
)
)
| FBY_n (e1,e2) -> (
let tel = rec_list_call [e1;e2] in
match_type_profile tel CkTypeEff.prof_tt_t e.src
)
| LOOP_n (_,e1) -> (
let tel = rec_list_call [e1] in
match_type_profile tel CkTypeEff.prof_t_t e.src
)
| LOOPI_n (min, max, e1) -> (
let tel = rec_list_call [min;max;e1] in
match_type_profile tel CkTypeEff.prof_iit_t e.src
)
| LOOPA_n (av, Some ec, e1) -> (
let tel = rec_list_call [av;ec;e1] in
match_type_profile tel CkTypeEff.prof_iit_t e.src
)
| LOOPA_n (av, None, e1) -> (
let tel = rec_list_call [av;e1] in
match_type_profile tel CkTypeEff.prof_it_t e.src
)
| ASSERT_n (_, c, e1) -> (
let tel = rec_list_call [c;e1] in
match_type_profile tel CkTypeEff.prof_bt_t e.src
)
| CALL_n (id, elst) -> (
match (CheckEnv.nature_of_ident env id) with
| Macro_ident (None , prof) -> (
let tel = rec_list_call elst in
match_type_profile tel prof e.src
)
| Macro_ident (Some _ , prof) -> (
let tel = rec_list_call elst in
match_type_profile tel prof e.src
)
| External_func (_lio, _eio, prof) -> (
let tel = rec_list_call elst in
match_type_profile tel prof e.src
)
| _ -> (
raise (Compile_error (e.src,
"identifier "^id.it^" cannot be used as a function"))
)
)
| CHOICE_n clist -> (
let check_one_choice = ( function
(e, None) -> (
let t = check_exp env e in
let _ = match_type_profile [t] CkTypeEff.prof_t_t e.src in
()
) |
(e, Some w) -> (
let te = check_exp env e in
let tw = check_exp env w.it in
let _ = match_type_profile [te;tw] CkTypeEff.prof_tw_t w.src in
()
)
) in
List.iter check_one_choice clist ;
CkTypeEff.trace
)
| PRIO_n plist -> (
let check_one_prio e = (
let t = check_exp env e in
let _ = match_type_profile [t] CkTypeEff.prof_t_t e.src in
()
) in
List.iter check_one_prio plist ;
CkTypeEff.trace
)
| PARA_n plist -> (
let check_one_para e = (
let t = check_exp env e in
let _ = match_type_profile [t] CkTypeEff.prof_t_t e.src in
()
) in
List.iter check_one_para plist ;
CkTypeEff.trace
)
| EXIST_n (tidlst, e1) -> (
let checked_ids = List.map (check_var_decl env) tidlst in
let rkey = CheckEnv.add_support_vars env checked_ids in
let res = check_exp env e1 in
CheckEnv.restore env rkey ;
res
)
| ERUN_n (varlst, edef, e1) -> (
let expected_types = (
match edef.it with
| CALL_n (id, elst) -> (
match (CheckEnv.nature_of_ident env id) with
| Node_ident (_, prof) -> (
let tel = rec_list_call elst in
match_run_type_profile tel prof e.src
)
| External_func (_lio, _eio, prof) -> (
let tel = rec_list_call elst in
[ match_type_profile tel prof e.src ]
)
| _ -> (
raise (Compile_error
(e.src, "identifier "^id.it^" cannot be used in run statement"))
)
)
| _ -> raise (Compile_error
(edef.src, "only node calls are supported in run statement"))
) in
let checked_ids = List.map2 (check_erun_var_decl env) varlst expected_types in
CheckEnv.set_exp_type env edef (CkTypeEff.get_data_tuple expected_types);
let rkey = CheckEnv.add_support_vars env checked_ids in
let res = check_exp env e1 in
CheckEnv.restore env rkey ;
res
)
| RUN_n (idlst, edef, e1opt) -> (
let expected_types = (
match edef.it with
| CALL_n (id, elst) -> (
match (CheckEnv.nature_of_ident env id) with
| Node_ident (_, prof) -> (
let tel = rec_list_call elst in
match_run_type_profile tel prof e.src
)
| External_func (_lio, _eio, prof) -> (
let tel = rec_list_call elst in
[ match_type_profile tel prof e.src ]
)
| _ -> (
raise (Compile_error (e.src,
"identifier "^id.it^" cannot be used in run statement"))
)
)
| _ -> raise (Compile_error
(edef.src, "only node calls are supported in run statement"))
) in
let checked_ids = List.map2 (check_run_var_decl env) idlst expected_types in
CheckEnv.set_exp_type env edef (CkTypeEff.get_data_tuple expected_types);
match e1opt with
| Some e1 ->
let rkey = CheckEnv.add_support_vars env checked_ids in
let res = check_exp env e1 in
CheckEnv.restore env rkey ;
res
| None -> CkTypeEff.trace
)
| LET_n (li, e1) -> (
let tres = check_let env li in
let rkey = CheckEnv.add_let env li tres li.lti_ident in
let res = check_exp env e1 in
CheckEnv.restore env rkey ;
res
)
| RAISE_n id -> (
match (CheckEnv.nature_of_ident env id) with
Const_ident -> (
let t = CheckEnv.type_of_ident env id in
if (t = CkTypeEff.except) then (
CkTypeEff.trace
) else (
type_error id.src [t] [CkTypeEff.except]
)
) | _ -> (
raise (Compile_error (e.src,
"identifier "^id.it^" not allowed as raise argument"))
)
)
| EXCEPT_n (xlst, e1) -> (
let f i = (
CheckEnv.add_local_cst env i (CkTypeEff.except)
) in
let ekeyl = List.map f xlst in
let res = check_exp env e1 in
List.iter (CheckEnv.restore env) ekeyl ;
res
)
| CATCH_n (id, e1, e2opt) -> (
let id_type = ( match (CheckEnv.nature_of_ident env id) with
Const_ident -> (
CheckEnv.type_of_ident env id
) | _ -> (
raise (Compile_error (e.src,
"identifier "^id.it^" not allowed as catch argument"))
)
) in
match e2opt with
None -> (
let tel = (id_type)::(rec_list_call [e1]) in
match_type_profile tel CkTypeEff.prof_et_t e.src
) |
Some e2 -> (
let tel = (id_type)::(rec_list_call [e1;e2]) in
match_type_profile tel CkTypeEff.prof_ett_t e.src
)
)
| TRAP_n (id, e1, e2opt) -> (
let ekey =
CheckEnv.add_local_cst env id (CkTypeEff.except)
in
let _id_type = ( match (CheckEnv.nature_of_ident env id) with
Const_ident -> (
CheckEnv.type_of_ident env id
) | _ -> assert false
) in
let res = (
match e2opt with
None -> (
let tel = (CkTypeEff.except)::(rec_list_call [e1]) in
match_type_profile tel CkTypeEff.prof_et_t e.src
) |
Some e2 -> (
let tel = (CkTypeEff.except)::(rec_list_call [e1;e2]) in
match_type_profile tel CkTypeEff.prof_ett_t e.src
)
) in
CheckEnv.restore env ekey ;
res
)
| TRY_n (e1, e2opt ) -> (
match e2opt with
None -> (
let tel = rec_list_call [e1] in
match_type_profile tel CkTypeEff.prof_t_t e.src
) |
Some e2 -> (
let tel = rec_list_call [e1;e2] in
match_type_profile tel CkTypeEff.prof_tt_t e.src
)
)
) in
CheckEnv.set_exp_type env e e_teff;
e_teff
)
and match_type_profile tel prof lxm = (
try (
match CkTypeEff.match_prof tel prof with
| [t] -> t
| _ -> assert false
) with _ ->
type_error lxm tel (CkTypeEff.params_of_prof prof)
)
and match_run_type_profile tel prof lxm = (
try (
CkTypeEff.match_prof tel prof
) with _ ->
type_error lxm tel (CkTypeEff.params_of_prof prof)
)
and check_let
(env : CheckEnv.t)
(li : Syntaxe.let_info) =
(
let lxm = li.lti_ident.src in
match (li.lti_def) with
Some exp -> (
let rkey = CheckEnv.add_formal_params env li.lti_inputs in
let tcalc = check_exp env exp in
let tcalc = try CkTypeEff.lift_ref tcalc with Failure _ -> tcalc in
let res = (
match li.lti_type with
Some te -> (
let tdecl = (CkTypeEff.of_texp te) in
if(CkTypeEff.lifts_to tcalc tdecl) then ( tdecl)
else ( type_error lxm [tcalc] [tdecl] )
) | None -> ( tcalc)
) in
CheckEnv.restore env rkey ;
res
) |
None -> (
assert false
)
) and check_extern
(_env : CheckEnv.t)
(li : Syntaxe.let_info) =
(
let lxm = li.lti_ident.src in
match (li.lti_def) with
Some _exp -> (
assert false
) |
None -> (
match li.lti_type with
| Some te -> (
let res = CkTypeEff.of_texp te in
Verbose.exe ~level:3
(fun () -> Printf.printf "CheckType.check_extern \"%s\", return type \"%s\"\n"
li.lti_ident.it
(CkTypeEff.to_string res));
res
)
| None -> raise ( Compile_error (lxm,
"external profiles must be fully declared")
)
)
)
let check_node
(env : CheckEnv.t)
(ni : Syntaxe.node_info) =
(
let lxm = ni.ndi_ident.src in
let ins = List.map (check_var_decl env) ni.ndi_inputs in
let outs = List.map (check_var_decl env) ni.ndi_outputs in
let rkey = CheckEnv.add_support_profile env ins outs in
let tcalc = check_exp env ni.ndi_def in
let zeprof = if(CkTypeEff.lifts_to tcalc CkTypeEff.trace) then (
let teff_of_param = function (_, t) -> t in
let tins = List.map teff_of_param ins in
let touts = List.map teff_of_param outs in
CkTypeEff.get_prof tins touts
) else (
type_error lxm [tcalc] [CkTypeEff.trace]
) in
CheckEnv.restore env rkey ;
zeprof
)
let check_pack
(libs: string list option)
(p : Syntaxe.package) = (
let env0 = CheckEnv.copy LutPredef.lutin_env in
let env = match libs with
| None -> env0
| Some ll -> CheckEnv.add_libs env0 ll
in
let check_def_item =
function
LetDef s -> (
let m = (Util.hfind p.pck_lettab s.it) in
let tres = check_let env m in
ignore (CheckEnv.add_let env m tres m.lti_ident)
)
| ExternDef x -> (
let m = (Util.hfind p.pck_lettab x.it) in
let tres = check_extern env m in
ignore (CheckEnv.add_extern env m tres m.lti_ident)
)
| NodeDef s -> (
let n = (Util.hfind p.pck_nodetab s.it) in
let nprof = check_node env n in
ignore (CheckEnv.add_node env n nprof n.ndi_ident)
)
| ExceptDef s -> (
ignore (CheckEnv.add_global_cst env s (CkTypeEff.except))
)
in
List.iter check_def_item p.pck_deflist ;
env
)