Source file gen_reduce.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
open Tools
open Location
open Ident
open Model
exception Anomaly of string
type error_desc =
| UnsupportedContainer of string
| UnsupportedType of string
| RecordNotFound
| NotSupportedType of string
[@@deriving show {with_path = false}]
let emit_error (desc : error_desc) =
let str = Format.asprintf "%a@." pp_error_desc desc in
raise (Anomaly str)
let storage_lident : lident = dumloc "_s"
let storage_var : mterm = mk_mterm (Mvarlocal storage_lident) Tstorage
let operations_lident : lident = dumloc "_ops"
let operations_type : type_ = Tcontainer (Toperation, Collection)
let operations_var : mterm = mk_mterm (Mvarlocal operations_lident) operations_type
let operations_init : mterm = mk_mterm (Marray []) operations_type
let operations_storage_type : type_ = Ttuple [Tcontainer (Toperation, Collection); Tstorage]
let operations_storage_var : mterm = mk_mterm (Mtuple [operations_var; storage_var]) operations_storage_type
let rec simplify (mt : mterm) : mterm =
match mt.node with
| Mletin ([let_id], init, _, {node = (Mvarlocal var_id); _}, _)
| Mletin ([let_id], init, _, {node = (Mtuple [{node = Mvarlocal var_id; _}]); _}, _) when String.equal (unloc let_id) (unloc var_id) -> simplify init
| Mletin (ids, init, _, {node = (Mtuple tuples); _}, _) when
(
let cmp_lidents (ids1 : lident list) (ids2 : lident list) : bool = List.fold_left2 (fun accu x y -> accu && String.equal (unloc x) (unloc y)) true ids1 ids2 in
let tuples_ids, continue = List.fold_right (fun (x : mterm) (tuples_ids, continue) ->
match x.node with
| Mvarlocal id -> id::tuples_ids, continue
| _ -> tuples_ids, false) tuples ([], true) in
if (not continue) || List.compare_lengths ids tuples_ids <> 0
then false
else cmp_lidents ids tuples_ids)
-> simplify init
| _ -> map_mterm simplify mt
let is_fail (t : mterm) (e : mterm option) : bool =
match t.node , e with
| Mfail _, None -> true
| _ -> false
type s_red = {
with_ops : bool;
subs: (ident * type_) list;
}
type ctx_red = {
local_fun_types : (ident * type_) list;
vars: (ident * type_) list;
target: mterm option;
}
let rec compute_side_effect_aux (ctx : ctx_red)(accu : (ident * type_) list) (mt : mterm) : (ident * type_) list =
match mt.node with
| Massign (_, a, _b) ->
let id : ident = unloc a in
let type_ = List.assoc_opt id ctx.vars in
(match type_ with
| Some v ->
if List.mem (id, v) accu
then accu
else (id, v)::accu
| None -> accu)
| _ -> fold_term (compute_side_effect_aux ctx) accu mt
let compute_side_effect (ctx : ctx_red) (mt : mterm) =
compute_side_effect_aux ctx [] mt
let compute_side_effect_for_list (ctx : ctx_red) (l : mterm list) : (ident * type_) list =
List.fold_left (fun accu x ->
compute_side_effect_aux ctx accu x
) [] l
let rec process_non_empty_list_term (ctx : ctx_red) (s : s_red) (mts : mterm list) : mterm * s_red =
let split_last_list l : 'a * 'a list =
let rec split_last_list_rec accu l =
match l with
| [] -> assert false
| t::[] -> (t, (List.rev accu))
| t::l -> split_last_list_rec (t::accu) l
in
split_last_list_rec [] l
in
let last, list = split_last_list mts in
let last, s = process_mtern ctx s last in
List.fold_right (fun x (accu, s) ->
let x, s = process_mtern ctx s x in
match x with
| { node = Massign (op, id, value); _} ->
let type_ = value.type_ in
let value =
let var = mk_mterm (Mvarlocal id) type_ in
match op with
| ValueAssign -> value
| PlusAssign -> mk_mterm (Mplus (var, value)) type_
| MinusAssign -> mk_mterm (Mminus (var, value)) type_
| MultAssign -> mk_mterm (Mmult (var, value)) type_
| DivAssign -> mk_mterm (Mdiv (var, value)) type_
| AndAssign -> mk_mterm (Mand (var, value)) type_
| OrAssign -> mk_mterm (Mor (var, value)) type_
in
mk_mterm (Mletin ([id], value, Some value.type_, accu, None)) accu.type_, s
| {type_ = Ttuple (Tcontainer(Toperation, Collection)::Tstorage::l); _} ->
mk_mterm (Mletin ([storage_lident; operations_lident] @ (List.fold_left (fun accu _x -> (dumloc "_")::accu) [] l), x, Some x.type_, accu, None)) accu.type_, s
| {type_ = Ttuple (Tstorage::l); _} ->
let lidents : lident list = (List.mapi (fun i _x ->
if i < List.length s.subs
then dumloc (List.nth s.subs i |> fst)
else (dumloc "_")) l) in
mk_mterm (Mletin ([storage_lident] @ lidents, x, Some x.type_, accu, None)) accu.type_, s
| {type_ = Ttuple (Tcontainer(Toperation, Collection)::l); _} ->
mk_mterm (Mletin ([operations_lident] @ (List.fold_left (fun accu _x -> (dumloc "_")::accu) [] l), x, Some x.type_, accu, None)) x.type_, s
| {type_ = Tstorage; _} ->
mk_mterm (Mletin ([storage_lident], x, Some x.type_, accu, None)) accu.type_, s
| {type_ = Tcontainer (Toperation, Collection); _} ->
mk_mterm (Mletin ([operations_lident], x, Some x.type_, accu, None)) accu.type_, s
| _ ->
merge_seq x accu, s
) list (last, s)
and process_mtern (ctx : ctx_red) (s : s_red) (mt : mterm) : mterm * s_red =
let get_type (ctx : ctx_red) (id : ident) : type_ =
List.assoc id ctx.local_fun_types
in
match mt.node with
| Mset (an, l, col, value) ->
let col, s = process_mtern ctx s col in
let value, s = process_mtern ctx s value in
mk_mterm (Mset (an, l, col, value)) Tstorage, s
| Maddasset (an, arg) ->
let arg, s = process_mtern ctx s arg in
mk_mterm (Maddasset (an, arg)) Tstorage, s
| Maddfield (an, fn, col, arg) ->
let col, s = process_mtern ctx s col in
let arg, s = process_mtern ctx s arg in
mk_mterm (Maddfield (an, fn, col, arg)) Tstorage, s
| Mremoveasset (an, arg) ->
let arg, s = process_mtern ctx s arg in
mk_mterm (Mremoveasset (an, arg)) Tstorage, s
| Mremovefield (an, fn, col, arg) ->
let col, s = process_mtern ctx s col in
let arg, s = process_mtern ctx s arg in
mk_mterm (Mremovefield (an, fn, col, arg)) Tstorage, s
| Mclearasset an ->
mk_mterm (Mclearasset an) Tstorage, s
| Mclearfield (an, fn, col) ->
let col, s = process_mtern ctx s col in
mk_mterm (Mclearfield (an, fn, col)) Tstorage, s
| Mreverseasset an ->
mk_mterm (Mreverseasset an) Tstorage, s
| Mreversefield (an, fn, col) ->
let col, s = process_mtern ctx s col in
mk_mterm (Mreversefield (an, fn, col)) Tstorage, s
| Maddshallow (an, args) ->
mk_mterm (Maddshallow (an, storage_var::args)) Tstorage, s
| Mapp (id, args) ->
let type_ = get_type ctx (unloc id) in
let args =
begin
match type_ with
| Tstorage ->
let args = storage_var::args in
args
| Tcontainer (Toperation, Collection) ->
let args = operations_var::args in
args
| Ttuple [Tcontainer (Toperation, Collection); Tstorage] ->
let args = storage_var::operations_var::args in
args
| _ -> args
end
in
{
mt with
node = Mapp (id, args);
type_ = type_;
}, s
| Mletin (ids, init, t, body, o) ->
let (ids : lident list) (t : type_ option) : (ident * type_) list =
begin
match ids, t with
| ids, Some Ttuple tl -> List.map2 (fun x y -> (unloc x, y)) ids tl
| [id], Some t -> [unloc id, t]
| _ -> []
end
in
let ctx = {
ctx with
vars = ctx.vars @ extract_vars ids t;
} in
let init, s = process_mtern ctx s init in
let body, s = process_mtern ctx s body in
mk_mterm (Mletin (ids, init, t, body, o)) body.type_, s
| Mif (c, t, e) when is_fail t e ->
let c, s = process_mtern ctx s c in
mk_mterm (Mif (c, t, None)) Tunit, s
| Mif (c, t, e) ->
let c, s = process_mtern ctx s c in
let target, subs =
(match ctx.target with
| Some {node = (Mtuple _l); _} ->
let subs : (ident * type_) list = compute_side_effect_for_list ctx ([t] @ (Option.map_dfl (fun x -> [x]) [] e)) in
mk_mterm (Mtuple (storage_var::(List.map (fun (x, y : ident * type_) -> mk_mterm (Mvarlocal (dumloc x)) y) subs)))
(Ttuple (Tstorage::(List.map (fun (_x, y : ident * type_) -> y) subs))), subs
| _ -> storage_var, [])
in
let t, s = process_non_empty_list_term ctx s [t; target] in
let e, s =
begin
match e with
| Some v -> process_non_empty_list_term ctx s [v; target]
|> (fun (x, y) -> Some x, y)
| None -> Some target, s
end
in
mk_mterm (Mif (c, t, e)) target.type_, {s with subs = subs}
| Mseq l ->
let l : mterm list = List.filter (fun (x : mterm) ->
match x.node with
| Massert _ -> false
| _ -> true) l in
begin
match l with
| [] -> mt, s
| i::[] ->
process_mtern ctx s i
| _ ->
let subs : (ident * type_) list = compute_side_effect_for_list ctx l in
let l = (
match subs with
| [] -> l
| _ ->
let target = mk_mterm (Mtuple (storage_var::(List.map (fun (x, y : ident * type_) -> mk_mterm (Mvarlocal (dumloc x)) y) subs)))
(Ttuple (Tstorage::(List.map (fun (_x, y : ident * type_) -> y) subs))) in
l @ [target]
) in
let s = {s with subs = subs} in
process_non_empty_list_term ctx s l
end
| Mfor (a, col, body, _) ->
let col, s = process_mtern ctx s col in
let subs : (ident * type_) list = compute_side_effect ctx body in
let is = [storage_lident] @ (List.map (fun (x, _y) -> dumloc x) subs) in
let type_tuple = Ttuple ([Tstorage] @ List.map snd subs) in
let tuple : mterm = mk_mterm (Mtuple ([storage_var] @ List.map (fun (x, y) -> mk_mterm (Mvarlocal (dumloc x)) y) subs)) type_tuple in
let ctx = {
ctx with
target = Some tuple;
} in
let body, s = process_non_empty_list_term ctx s [body; tuple] in
mk_mterm (Mfold (a, is, col, body)) tuple.type_, s
| Mtransfer _ ->
let ops = { mt with type_ = Toperation } in
let node = Mapp (dumloc "add_list", [operations_var; ops]) in
let mt = mk_mterm node operations_storage_type in
mt, {s with with_ops = true}
| _ ->
let g (x : mterm__node) : mterm = { mt with node = x; } in
fold_map_term g (process_mtern ctx) s mt
let process_body (ctx : ctx_red) (mt : mterm) : mterm =
let s : s_red = {
with_ops = false;
subs = [];
} in
let target = Option.get ctx.target in
let bb = extract_list mt target in
let mt, _s = process_non_empty_list_term ctx s bb in
simplify mt
let analyse_type (_mt : mterm) : type_ = Tstorage
let process_functions (model : model) : model =
let process_functions l =
let process_function__ (ctx : ctx_red) (function__ : function__) : function__ * ctx_red =
let process_function_node (function_node : function_node) : function_node * ctx_red =
match function_node with
| Function (fs, t) ->
begin
match t with
| Tunit ->
let ret : type_ = analyse_type fs.body in
let args, target =
begin
match ret with
| Tstorage ->
let arg : argument = (storage_lident, Tstorage, None) in
let args = arg::fs.args in
args, storage_var
| Tcontainer (Toperation, Collection) ->
let arg : argument = (operations_lident, operations_type, None) in
let args = arg::fs.args in
args, operations_var
| Ttuple [Tcontainer (Toperation, Collection); Tstorage] ->
let arg_s_ : argument = (storage_lident, Tstorage, None) in
let arg_ops_ : argument = (operations_lident, operations_type, None) in
let args = arg_s_::arg_ops_::fs.args in
args, operations_storage_var
| _ -> assert false
end in
let ctx : ctx_red = {
ctx with
target = Some target;
} in
let body = process_body ctx fs.body in
let fs = {
fs with
args = args;
body = body;
} in
let ctx : ctx_red = {
ctx with
local_fun_types = (unloc fs.name, ret)::ctx.local_fun_types;
target = None;
} in
Function (fs, ret), ctx
| _ -> assert false
end
| Entry fs ->
let ctx = {
ctx with
target = Some operations_storage_var;
} in
let body = process_body ctx fs.body in
let body = mk_mterm (Mletin ([operations_lident], operations_init, Some operations_type, body, None)) operations_storage_type in
let fs = {
fs with
body = body;
} in
let ctx = {
ctx with
target = None;
} in
Entry fs, ctx
in
let node, ctx = process_function_node function__.node in
{
function__ with
node = node;
}, ctx
in
let ctx : ctx_red = {
local_fun_types = [];
vars = [];
target = None;
} in
let res, _ = List.fold_left (fun (l, ctx) f ->
let item, ctx = process_function__ ctx f in
(l @ [item], ctx)
) ([], ctx) l in
res
in
{
model with
functions = process_functions model.functions;
}
let reduce (model : model) : model =
model
|> process_functions