Newer
Older
Erwan Jahier
committed
(** Time-stamp: <modified the 11/03/2009 (at 16:41) by Erwan Jahier> *)
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
(**
nb : only user nodes are expanded.
Expand nodes:
------------
if n is a node defined as follows
node n(x,y) returns(a,b);
var v1,v2;
let
v1 = x+y;
v2 = x*y;
a = v1*x;
b = v2*y;
tel
equations such as :
o1,o2 = n(i1, i2);
becomes
h1 = i1+i2;
h2 = i1*i2;
o1 = h1*i1;
o2 = h2*i2;
where h1 and h2 are fresh local vars
In other terms, we need to
- create a fresh local var for each local var of n
- take all the equations of n, and substitute
- the inputs parameters by intput args
- the outputs parameters by lhs list
- the local vars by the fresh local var names
nb : to simplify, for equations like
f.a = n(t[1], 3);
we first create fresh vars for "f.a", "t[1]", and "3"
_v1 = t[1];
_v2 = 3;
f.a = _v3;
_v3 = n(_v1,_v2);
and then we apply the transformation
Expand assertions:
-----------------
In order to deal with assertions on nodes, i.e., of the form
assert (n(i1,i2));
we first transform it into
assert_var = n(i1,i2);
assert(assert_var);
where assert_var is a fresh bool local var, and we apply the transformation
on the first equation.
*)
open Lxm
open Eff
open Predef
(********************************************************************************)
(* stuff to create fresh var names.
XXX code dupl. with Split.new_var
*)
let new_var str node_env type_eff clock_eff =
let id = Ident.of_string (Name.new_local_var str) in
(* let id = Ident.of_string (Name.new_local_var "h") in *)
let var =
{
var_name_eff = id;
var_nature_eff = SyntaxTreeCore.VarLocal;
var_number_eff = -1; (* this field is used only for i/o.
Should i rather put something sensible there ? *)
var_type_eff = type_eff;
var_clock_eff = clock_eff;
}
in
Hashtbl.add node_env.lenv_vars id var;
var
(********************************************************************************)
let get_locals node =
match node.loclist_eff with
| None -> []
| Some l -> l
let (get_node_body : Eff.local_env -> Eff.node_exp -> Eff.node_body option) =
fun node_env node ->
match node.def_eff with
| ExternEff
| AbstractEff -> None
| BodyEff node_body -> Some node_body
(********************************************************************************)
type subst = (var_info * var_info) list
Erwan Jahier
committed
let rec (substitute :
subst -> Eff.eq_info Lxm.srcflagged -> Eff.eq_info Lxm.srcflagged) =
fun s { it = (lhs,ve) ; src = lxm } ->
let lhs = List.map (subst_in_left s) lhs in
Erwan Jahier
committed
let newve = subst_in_val_exp s ve in
EvalClock.copy newve ve;
{ it = (lhs,newve) ; src = lxm }
and subst_in_left s left =
match left with
| LeftVarEff(v,lxm) -> (try LeftVarEff(List.assoc v s,lxm) with Not_found -> left)
| LeftFieldEff(left,id,t) -> LeftFieldEff(subst_in_left s left,id,t)
| LeftArrayEff(left,i, t) -> LeftArrayEff(subst_in_left s left,i, t)
| LeftSliceEff(left,si,t) -> LeftSliceEff(subst_in_left s left,si,t)
and (subst_in_val_exp : subst -> val_exp -> val_exp) =
fun s ve ->
let newve = {
ve with core =
match ve.core with
| CallByPosEff (by_pos_op, OperEff 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
| IDENT idref ->
let idref =
try
let id = Ident.of_idref idref in
let var = snd(List.find (fun (v,_) -> v.var_name_eff = id) s) in
let idref = Ident.to_idref var.var_name_eff in
idref
with Not_found -> idref
in
IDENT idref
| WITH(ve) -> WITH(subst_in_val_exp s ve)
| HAT(i,ve) -> HAT(i, subst_in_val_exp s ve)
| ARRAY(vel) -> ARRAY(List.map (subst_in_val_exp s) vel)
Erwan Jahier
committed
| WHEN(SyntaxTreeCore.Base) -> WHEN(SyntaxTreeCore.Base)
| WHEN(SyntaxTreeCore.NamedClock {src=lxm;it=(cc,cv)}) ->
let var = snd(List.find (fun (v,_) -> v.var_name_eff = cv) s) in
let cv = var.var_name_eff in
WHEN(SyntaxTreeCore.NamedClock {src=lxm;it=(cc,cv)})
| Predef _| CALL _ | PRE | ARROW | FBY | CURRENT | TUPLE
| CONCAT | STRUCT_ACCESS _ | ARRAY_ACCES _ | ARRAY_SLICE _ | MERGE _
(* | CONST _ *)
-> by_pos_op
in
CallByPosEff(Lxm.flagit by_pos_op lxm, OperEff vel)
| CallByNameEff(by_name_op, fl) ->
let fl = List.map (fun (id,ve) -> (id, subst_in_val_exp s ve)) fl in
CallByNameEff(by_name_op, fl)
}
Erwan Jahier
committed
in
EvalClock.copy newve ve;
newve
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
let mk_loc_subst = List.combine
(********************************************************************************)
(** The functions below accumulate
(1) the assertions
(2) the new equations
(3) the fresh variables
*)
type acc =
Eff.val_exp srcflagged list (* assertions *)
* (Eff.eq_info srcflagged) list (* equations *)
* Eff.var_info list (* new local vars *)
let (mk_fresh_loc : Eff.local_env -> var_info -> var_info) =
fun node_env v ->
new_var (Ident.to_string v.var_name_eff) node_env v.var_type_eff v.var_clock_eff
let (mk_input_subst: Eff.local_env -> Lxm.t -> var_info list ->
Eff.val_exp list -> acc -> subst * acc) =
fun node_env lxm vl vel acc ->
List.fold_left2
(fun (s,(a_acc,e_acc,v_acc)) v ve ->
(* we create a new var for each node argument, which is a little
bit bourrin if ever ve is a simple ident... *)
let nv = mk_fresh_loc node_env v in
let neq = [LeftVarEff(nv,lxm)],ve in
let neq = flagit neq lxm in
(v,nv)::s,(a_acc, neq::e_acc, nv::v_acc)
)
([],acc)
vl
vel
(* create fresh vars if necessary *)
let (mk_output_subst : Eff.local_env -> Lxm.t -> var_info list -> Eff.left list ->
acc -> subst * acc) =
fun node_env lxm vl leftl acc ->
List.fold_left2
(fun (s,acc) v left ->
match left with
| LeftVarEff(v2,lxm) -> (v,v2)::s, acc
| _ ->
let nv = mk_fresh_loc node_env v in
let nv_idref = Ident.to_idref nv.var_name_eff in
let nve = {
core = CallByPosEff({it=IDENT nv_idref;src = lxm },OperEff []);
typ = [nv.var_type_eff]
}
in
Erwan Jahier
committed
EvalClock.add nve [nv.var_clock_eff];
[left], nve
in
let neq = flagit neq lxm in
(* for equations of the form
x.field = n(...);
we create
- a fresh var "_v"
- define the equation "x.field = _v;"
- create the substition n_output_par/_v
*)
let (aa,ae,av) = acc in
(v,nv)::s, (aa, neq::ae, nv::av)
)
([],acc)
vl
leftl
let rec (expand_eq : Eff.local_env -> acc -> Eff.eq_info Lxm.srcflagged -> acc) =
fun node_env (asserts, eqs, locs) { src = lxm_eq ; it = eq } ->
match expand_eq_aux node_env eq with
| None -> asserts, { src = lxm_eq ; it = eq }::eqs, locs
| Some(nasserts, neqs, nlocs) ->
List.rev_append nasserts asserts,
List.rev_append neqs eqs,
List.rev_append nlocs locs
and (expand_eq_aux: Eff.local_env -> Eff.eq_info -> acc option)=
match ve.core with
| CallByPosEff( { it = Eff.CALL node ; src = lxm }, OperEff vel) ->
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
if
let nname = Ident.string_of_long2 (fst node.it.node_key_eff) in
(List.mem nname !Global.dont_expand_nodes)
then
None
else
(match get_node_body node_env node.it with
| None -> 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 fresh_locs = List.map (mk_fresh_loc node_env) node_locs in
let acc = [],[],fresh_locs in
let is,acc = mk_input_subst node_env lxm node.inlist_eff vel acc in
let os,acc = mk_output_subst node_env lxm node.outlist_eff lhs acc in
let ls = mk_loc_subst node_locs fresh_locs in
let s = List.rev_append is (List.rev_append os ls) in
let node_eqs = List.map (substitute s) node_eqs in
let subst_assert x = Lxm.flagit (subst_in_val_exp s x.it) x.src in
let asserts = List.map subst_assert asserts in
let acc = List.fold_left (expand_eq node_env) acc node_eqs in
let acc = List.fold_left (expand_assert node_env) acc asserts in
Some acc
)
| CallByPosEff (_, _)
| CallByNameEff (_, _) -> None
and (expand_assert : Eff.local_env -> acc -> val_exp srcflagged -> acc) =
fun n_env (a_acc,e_acc,v_acc) ve ->
let lxm = ve.src in
let ve = ve.it in
let clk = Ident.of_string "dummy_expand_assert", BaseEff in
let assert_var = new_var "assert" n_env Bool_type_eff clk in
let assert_eq = Lxm.flagit ([LeftVarEff(assert_var,lxm)], ve) lxm in
let assert_op = Eff.IDENT(Ident.to_idref assert_var.var_name_eff) in
let nve = {
core = CallByPosEff((Lxm.flagit assert_op lxm, OperEff []));
typ = [Bool_type_eff]
}
in
Erwan Jahier
committed
EvalClock.copy nve ve;
expand_eq n_env ((Lxm.flagit nve lxm)::a_acc, e_acc, assert_var::v_acc) assert_eq
(* exported *)
let (f : Eff.local_env -> Eff.node_exp -> Eff.node_exp) =
fun n_env n ->
match n.def_eff with
| ExternEff
| AbstractEff -> n
| BodyEff b ->
let locs = get_locals n in
let acc = List.fold_left (expand_eq n_env) ([],[],locs) b.eqs_eff in
let acc = List.fold_left (expand_assert n_env) 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 = BodyEff nb
}
in
res