Source file l2lExpandNodes.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
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
open Lxm
open Lic
let dbg = (Lv6Verbose.get_flag "en")
type local_ctx = {
init_prg : LicPrg.t;
curr_prg : LicPrg.t;
keep_node_call : Lic.node_key -> bool;
}
let new_var label str t c =
let vi = FreshName.var_info str t c in
Lv6Verbose.exe
~flag:dbg
(fun () -> Printf.printf "#EN: new_var[%s](%s)->%s%s'\n"
label str vi.var_name_eff (Lic.string_of_clock (snd c))
);
vi
let get_locals node =
match node.loclist_eff with
| None -> []
| Some l -> l
let (get_node_body : local_ctx -> Lic.node_exp -> Lic.node_body option) =
fun _lctx node ->
match node.def_eff with
| ExternLic
| AbstractLic None -> None
| AbstractLic (Some _node) -> assert false
| BodyLic node_body -> Some node_body
| MetaOpLic -> None
type new_base = clock
module IdMap = Map.Make(struct type t = Lv6Id.t let compare = compare end)
type subst = Lic.var_info IdMap.t
let (add_subst : subst -> Lv6Id.t -> Lic.var_info -> subst) =
fun s id vi -> IdMap.add id vi s
let (subst_in_id : subst -> Lv6Id.t -> Lic.var_info) =
fun s id -> IdMap.find id s
let (subst_in_id_id : subst -> Lv6Id.t -> Lv6Id.t) =
fun s id ->
try (subst_in_id s id).var_name_eff with Not_found -> id
let rec (substitute : subst * new_base ->
Lic.eq_info Lxm.srcflagged -> Lic.eq_info Lxm.srcflagged) =
fun s { it = (lhs,ve) ; src = lxm } ->
let lhs = List.map (subst_in_left s ) lhs in
let newve = subst_in_val_exp s ve in
{ it = (lhs,newve) ; src = lxm }
and subst_in_var_info (s,nb) vi =
try
let vi = subst_in_id s vi.var_name_eff in
let id,clk = vi.var_clock_eff in
{ vi with var_clock_eff = subst_in_id_id s id, subst_in_clock (s,nb) clk }
with Not_found ->
assert false
and subst_in_left s left =
match left with
| LeftVarLic(v,lxm) -> LeftVarLic(subst_in_var_info s v,lxm)
| LeftFieldLic(left,id,t) -> LeftFieldLic(subst_in_left s left,id,t)
| LeftArrayLic(left,i, t) -> LeftArrayLic(subst_in_left s left,i, t)
| LeftSliceLic(left,si,t) -> LeftSliceLic(subst_in_left s left,si,t)
and (subst_in_clock : subst * new_base -> clock -> clock) =
fun (s,new_base) clk ->
match clk with
| BaseLic -> new_base
| ClockVar i -> ClockVar i
| On ((cc,cv,ct),clk) ->
On((cc, subst_in_id_id s cv, ct), subst_in_clock (s,new_base) clk)
and (subst_in_val_exp : subst * new_base -> val_exp -> val_exp) =
fun s ve ->
let newve = {
ve with
ve_clk = List.map (subst_in_clock s) ve.ve_clk;
ve_core =
match ve.ve_core with
| CallByPosLic (by_pos_op, vel) ->
let lxm = by_pos_op.src in
let by_pos_op = by_pos_op.it in
let vel = List.map (subst_in_val_exp s) vel in
let by_pos_op = match by_pos_op with
| CONST_REF idl -> CONST_REF idl
| VAR_REF id -> VAR_REF (subst_in_id_id (fst s) id)
| WHEN(clk) -> WHEN(subst_in_clock s clk)
| HAT(i) -> HAT(i)
| PREDEF_CALL _| CALL _ | PRE | ARROW | FBY | CURRENT _ | TUPLE
| ARRAY | CONCAT | STRUCT_ACCESS _ | ARRAY_ACCES _ | ARRAY_SLICE _
| CONST _
-> by_pos_op
in
CallByPosLic(Lxm.flagit by_pos_op lxm, vel)
| CallByNameLic(by_name_op, fl) ->
let fl = List.map (fun (id,ve) -> (id, subst_in_val_exp s ve)) fl in
CallByNameLic(by_name_op, fl)
| Merge(ce,cl) ->
let cl = List.map (fun (id,ve) -> (id, subst_in_val_exp s ve)) cl in
Merge(subst_in_val_exp s ce, cl)
}
in
newve
let (mk_loc_subst:subst -> Lic.var_info list -> Lic.var_info list -> subst) =
fun s l1 l2 ->
let l = List.combine l1 l2 in
List.fold_left
(fun s (v1,v2) -> add_subst s v1.var_name_eff v2)
s l
(** The functions below accumulate
(1) the assertions
(2) the new equations
(3) the fresh variables
The fix-point is performed on nodes.
*)
type acc =
Lic.val_exp srcflagged list
* (Lic.eq_info srcflagged) list
* Lic.var_info list
let (mk_fresh_loc : string -> local_ctx -> var_info -> clock -> var_info) =
fun label _lctx v c ->
new_var label ((Lv6Id.to_string v.var_name_eff)) v.var_type_eff (fst v.var_clock_eff, c)
let rec get_new_base c_arg c_par =
match c_arg, c_par with
| _, BaseLic -> c_arg
| On(_,c_arg), On(_,c_par) -> get_new_base c_arg c_par
| _,_ -> assert false
let (mk_input_subst: local_ctx -> Lxm.t -> var_info list ->
Lic.val_exp list -> acc -> subst * acc * new_base option) =
fun lctx lxm vl vel acc ->
assert(List.length vl = List.length vel);
let s, acc, new_base_opt =
List.fold_left2
(fun (s,(a_acc,e_acc,v_acc),nbase_opt) v ve ->
let carg,cpar = match ve.ve_clk, v.var_clock_eff with
| [c1],(_,c2) -> c1,c2
| _ -> assert false
in
let new_base = get_new_base carg cpar in
let nv = mk_fresh_loc "input" lctx v carg in
let neq = [LeftVarLic(nv,lxm)],ve in
let neq = flagit neq lxm in
let nbase_opt = match nbase_opt with
| None -> Some(new_base)
| Some(b) -> assert(b=new_base); Some(b)
in
add_subst s v.var_name_eff nv,
(a_acc, neq::e_acc, nv::v_acc),
nbase_opt
)
(IdMap.empty, acc, None)
vl
vel
in
s, acc, new_base_opt
let (mk_output_subst : local_ctx -> Lxm.t -> subst -> var_info list -> Lic.left list ->
new_base option-> acc -> subst * acc * new_base) =
fun lctx lxm s vl leftl new_base_opt acc ->
assert(List.length vl = List.length leftl);
let s,acc,new_base_opt =
List.fold_left2
(fun (s,acc,new_base_opt) v left ->
match left with
| LeftVarLic(v2,_lxm) -> add_subst s v.var_name_eff v2, acc,new_base_opt
| _ ->
let clk = Lic.clock_of_left left in
let nv = mk_fresh_loc "output" lctx v clk in
let nv_id = nv.var_name_eff in
let nve = {
ve_core = CallByPosLic({it=VAR_REF nv_id;src = lxm },[]);
ve_typ = [nv.var_type_eff];
ve_clk = [snd nv.var_clock_eff];
ve_src = lxm
}
in
let neq = [left], nve in
let neq = flagit neq lxm in
let (aa,ae,av) = acc in
let new_base = get_new_base (Lic.clock_of_left left) (snd v.var_clock_eff) in
let new_base_opt =
match new_base_opt with
| Some x -> assert(x=new_base); Some x
| None -> Some new_base
in
add_subst s v.var_name_eff nv, (aa, neq::ae, nv::av), new_base_opt
)
(s,acc,new_base_opt)
vl
leftl
in
let new_base = match new_base_opt with
| Some x -> x
| None ->
raise (Lv6errors.Compile_error (
lxm, "a node ought to have at least one input or one output"))
in
s,acc,new_base
let rec (expand_eq : local_ctx * acc -> Lic.eq_info Lxm.srcflagged -> local_ctx * acc) =
fun (lctx, (asserts, eqs, locs)) { src = lxm_eq ; it = eq } ->
match expand_eq_aux lctx eq with
| lctx, None -> lctx, (asserts, { src = lxm_eq ; it = eq }::eqs, locs)
| lctx, Some(nasserts, neqs, nlocs) ->
(lctx,
(List.rev_append nasserts asserts,
List.rev_append neqs eqs,
List.rev_append nlocs locs))
and (expand_eq_aux: local_ctx -> Lic.eq_info -> local_ctx * acc option)=
fun lctx (lhs,ve) ->
match ve.ve_core with
| CallByPosLic( { it = Lic.CALL node_key ; src = lxm }, vel) ->
let lctx, node =
match LicPrg.find_node lctx.curr_prg node_key.it with
| Some node -> lctx, node
| None ->
let raw_node =
match LicPrg.find_node lctx.init_prg node_key.it with
| Some n -> n
| None ->
prerr_string (
"*** "^ (LicDump.string_of_node_key_rec false false node_key.it) ^
" not defined.\n*** Defined nodes are:"^
(String.concat ",\n"
(List.map (fun (nk,_) -> "\""^
LicDump.string_of_node_key_rec false false nk^"\"")
(LicPrg.list_nodes lctx.init_prg)))
);
flush stderr;
assert false
in
expand_node lctx raw_node
in
let node = match node.def_eff with
| AbstractLic (Some n) -> { it = n ; src = lxm }
| _ -> flagit node lxm
in
if
(lctx.keep_node_call node.it.node_key_eff)
then
lctx, None
else
(match get_node_body lctx node.it with
| None -> lctx, None
| Some node_body ->
let node_eqs = node_body.eqs_eff
and asserts = node_body.asserts_eff in
let node = node.it in
let node_locs = get_locals node in
let acc = [],[],[] in
let s,acc,new_base = mk_input_subst lctx lxm node.inlist_eff vel acc in
let s,acc,new_base = mk_output_subst lctx lxm s node.outlist_eff
lhs new_base acc in
let rec (substitute_clock : clock -> clock) =
fun c ->
match c with
| BaseLic -> new_base
| ClockVar _ -> new_base
| On(v,clk) -> On(v, substitute_clock clk)
in
let clks = List.map (fun v -> snd v.var_clock_eff) node_locs in
let fresh_locs = List.map2 (mk_fresh_loc "local" lctx) node_locs clks in
let s = mk_loc_subst s node_locs fresh_locs in
let fresh_locs =
List.map (fun v ->
let id,clk = v.var_clock_eff in
{ v with var_clock_eff =
subst_in_id_id s id, subst_in_clock (s,new_base) clk })
fresh_locs
in
let fresh_locs =
List.map
(fun v ->
let id,clk = v.var_clock_eff in
Lv6Verbose.exe
~flag:dbg
(fun () ->
Printf.printf "#EN: remplace the base clk of %s by '%s'\n"
v.var_name_eff
(Lic.string_of_clock new_base));
let clk = substitute_clock clk in
{ v with var_clock_eff = id,clk }
)
fresh_locs
in
let node_eqs = List.map (substitute (s, new_base)) node_eqs in
let subst_assert x = Lxm.flagit (subst_in_val_exp (s,new_base) x.it) x.src in
let asserts = List.map subst_assert asserts in
let acc = match acc with (a,b,c) -> (a@asserts,b@node_eqs,c@fresh_locs) in
lctx, Some acc
)
| CallByPosLic (_, _)
| Merge (_, _)
| CallByNameLic (_, _) -> lctx, None
and (expand_assert : local_ctx * acc -> val_exp srcflagged -> local_ctx * acc) =
fun (lctx, (a_acc,e_acc,v_acc)) ve ->
let lxm = ve.src in
let ve = ve.it in
let clk = Lv6Id.of_string "dummy_expand_assert", BaseLic in
let assert_var = new_var "assert" "assert" Bool_type_eff clk in
let assert_eq = Lxm.flagit ([LeftVarLic(assert_var,lxm)], ve) lxm in
let assert_op = Lic.VAR_REF(assert_var.var_name_eff) in
let nve = {
ve_core = CallByPosLic((Lxm.flagit assert_op lxm, []));
ve_typ = [Bool_type_eff];
ve_clk = [BaseLic];
ve_src = lxm
}
in
expand_eq (lctx, ((Lxm.flagit nve lxm)::a_acc, e_acc, assert_var::v_acc)) assert_eq
and (expand_node : local_ctx -> Lic.node_exp -> local_ctx * Lic.node_exp) =
fun lctx n ->
match LicPrg.find_node lctx.curr_prg n.node_key_eff with
| Some n -> lctx, n
| None ->
let lctx, exp_node =
match n.def_eff with
| ExternLic
| AbstractLic _ -> lctx, n
| BodyLic b ->
let locs = get_locals n in
let lctx,acc = List.fold_left expand_eq (lctx, ([],[],locs)) b.eqs_eff in
let lctx,acc = List.fold_left expand_assert (lctx, acc) b.asserts_eff in
let (asserts,neqs, nv) = acc in
let nb = {
eqs_eff = neqs ;
asserts_eff = asserts
}
in
let res =
{ n with
loclist_eff = Some nv;
def_eff = BodyLic nb
}
in
Lv6Verbose.exe ~flag:dbg (fun () ->
Printf.printf "#EN: '%s'\n"
(Lic.string_of_node_key n.node_key_eff));
lctx, res
| MetaOpLic -> lctx, n
in
{ lctx with curr_prg = LicPrg.add_node n.node_key_eff exp_node lctx.curr_prg },
exp_node
let (doit : Lic.node_key list -> LicPrg.t -> LicPrg.t) =
fun node_calls_to_keep inprg ->
let outprg = LicPrg.empty in
let outprg = LicPrg.fold_types LicPrg.add_type inprg outprg in
let outprg = LicPrg.fold_consts LicPrg.add_const inprg outprg in
let lctx_init = {
init_prg = inprg;
curr_prg = outprg;
keep_node_call = (fun n -> List.mem n node_calls_to_keep);
}
in
let (do_node : Lic.node_key -> Lic.node_exp -> local_ctx -> local_ctx) =
fun _nk ne lctx ->
fst (expand_node lctx ne)
in
let lctx = LicPrg.fold_nodes do_node inprg lctx_init in
let prg = lctx.curr_prg in
LicPrg.fold_nodes
(fun nk ne acc ->
if not (List.mem nk node_calls_to_keep) && not (Lic.node_is_extern ne) then
LicPrg.del_node nk acc
else
acc
)
prg
prg